mirror of
https://github.com/swaywm/sway.git
synced 2024-11-24 08:51:27 +00:00
layer-shell: rework arranging, use wlroots rectpack helper
This commit is contained in:
parent
6e4ccb99c3
commit
399abc8763
|
@ -10,7 +10,7 @@ struct sway_layer_surface {
|
||||||
struct wl_listener unmap;
|
struct wl_listener unmap;
|
||||||
struct wl_listener surface_commit;
|
struct wl_listener surface_commit;
|
||||||
struct wl_listener output_destroy;
|
struct wl_listener output_destroy;
|
||||||
struct wl_listener node_destroy;
|
struct wl_listener layer_surface_destroy;
|
||||||
struct wl_listener new_popup;
|
struct wl_listener new_popup;
|
||||||
|
|
||||||
bool mapped;
|
bool mapped;
|
||||||
|
@ -19,8 +19,7 @@ struct sway_layer_surface {
|
||||||
struct sway_popup_desc desc;
|
struct sway_popup_desc desc;
|
||||||
|
|
||||||
struct sway_output *output;
|
struct sway_output *output;
|
||||||
struct wlr_scene_layer_surface_v1 *scene;
|
struct wlr_scene_tree *scene_tree;
|
||||||
struct wlr_scene_tree *tree;
|
|
||||||
struct wlr_layer_surface_v1 *layer_surface;
|
struct wlr_layer_surface_v1 *layer_surface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <wlr/types/wlr_scene.h>
|
||||||
#include <wlr/types/wlr_subcompositor.h>
|
#include <wlr/types/wlr_subcompositor.h>
|
||||||
#include <wlr/types/wlr_xdg_shell.h>
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
|
#include <wlr/util/rectpack.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sway/scene_descriptor.h"
|
#include "sway/scene_descriptor.h"
|
||||||
#include "sway/desktop/transaction.h"
|
#include "sway/desktop/transaction.h"
|
||||||
|
@ -53,10 +54,10 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
|
static void arrange_surface(struct sway_output *output, const struct wlr_box *bounds,
|
||||||
struct wlr_box *usable_area, struct wlr_scene_tree *tree) {
|
pixman_region32_t *exclusive, struct wlr_scene_tree *tree, bool configure_exclusive) {
|
||||||
struct wlr_scene_node *node;
|
struct wlr_scene_node *node;
|
||||||
wl_list_for_each(node, &tree->children, link) {
|
wl_list_for_each_reverse(node, &tree->children, link) {
|
||||||
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
|
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
|
||||||
SWAY_SCENE_DESC_LAYER_SHELL);
|
SWAY_SCENE_DESC_LAYER_SHELL);
|
||||||
// surface could be null during destruction
|
// surface could be null during destruction
|
||||||
|
@ -64,24 +65,59 @@ static void arrange_surface(struct sway_output *output, const struct wlr_box *fu
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!surface->scene->layer_surface->initialized) {
|
if (!surface->layer_surface->initialized) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((surface->layer_surface->current.exclusive_zone > 0) != configure_exclusive) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);
|
struct wlr_box box;
|
||||||
|
if (!wlr_rectpack_place_wlr_layer_surface_v1(bounds, exclusive, surface->layer_surface, &box)) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to allocate an area for a layer surface");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_scene_node_set_position(&surface->scene_tree->node, box.x, box.y);
|
||||||
|
wlr_layer_surface_v1_configure(surface->layer_surface, box.width, box.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void arrange_layers(struct sway_output *output) {
|
void arrange_layers(struct sway_output *output) {
|
||||||
struct wlr_box usable_area = { 0 };
|
struct wlr_box bounds = {0};
|
||||||
wlr_output_effective_resolution(output->wlr_output,
|
wlr_output_effective_resolution(output->wlr_output, &bounds.width, &bounds.height);
|
||||||
&usable_area.width, &usable_area.height);
|
|
||||||
const struct wlr_box full_area = usable_area;
|
|
||||||
|
|
||||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background);
|
pixman_region32_t exclusive;
|
||||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom);
|
pixman_region32_init(&exclusive);
|
||||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top);
|
|
||||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay);
|
arrange_surface(output, &bounds, &exclusive, output->layers.shell_overlay, true);
|
||||||
|
arrange_surface(output, &bounds, &exclusive, output->layers.shell_top, true);
|
||||||
|
arrange_surface(output, &bounds, &exclusive, output->layers.shell_bottom, true);
|
||||||
|
arrange_surface(output, &bounds, &exclusive, output->layers.shell_background, true);
|
||||||
|
|
||||||
|
arrange_surface(output, &bounds, &exclusive, output->layers.shell_overlay, false);
|
||||||
|
arrange_surface(output, &bounds, &exclusive, output->layers.shell_top, false);
|
||||||
|
arrange_surface(output, &bounds, &exclusive, output->layers.shell_bottom, false);
|
||||||
|
arrange_surface(output, &bounds, &exclusive, output->layers.shell_background, false);
|
||||||
|
|
||||||
|
struct wlr_rectpack_rules window_rules = {
|
||||||
|
.grow_width = true,
|
||||||
|
.grow_height = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int min_size = 50; // Arbitrary
|
||||||
|
struct wlr_box usable_area = {
|
||||||
|
.x = bounds.width / 2 - min_size / 2,
|
||||||
|
.y = bounds.height / 2 - min_size / 2,
|
||||||
|
.width = min_size,
|
||||||
|
.height = min_size,
|
||||||
|
};
|
||||||
|
if (!wlr_rectpack_place(&bounds, &exclusive, &usable_area, &window_rules, &usable_area)) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to allocate an area for windows, "
|
||||||
|
"falling back to the whole output area");
|
||||||
|
usable_area = bounds;
|
||||||
|
}
|
||||||
|
pixman_region32_fini(&exclusive);
|
||||||
|
|
||||||
if (!wlr_box_equal(&usable_area, &output->usable_area)) {
|
if (!wlr_box_equal(&usable_area, &output->usable_area)) {
|
||||||
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
|
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
|
||||||
|
@ -147,7 +183,7 @@ static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sway_layer_surface *sway_layer_surface_create(
|
static struct sway_layer_surface *sway_layer_surface_create(
|
||||||
struct wlr_scene_layer_surface_v1 *scene) {
|
struct wlr_layer_surface_v1 *layer_surface, struct wlr_scene_tree *scene_tree) {
|
||||||
struct sway_layer_surface *surface = calloc(1, sizeof(*surface));
|
struct sway_layer_surface *surface = calloc(1, sizeof(*surface));
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
sway_log(SWAY_ERROR, "Could not allocate a scene_layer surface");
|
sway_log(SWAY_ERROR, "Could not allocate a scene_layer surface");
|
||||||
|
@ -161,7 +197,7 @@ static struct sway_layer_surface *sway_layer_surface_create(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
surface->desc.relative = &scene->tree->node;
|
surface->desc.relative = &scene_tree->node;
|
||||||
|
|
||||||
if (!scene_descriptor_assign(&popups->node,
|
if (!scene_descriptor_assign(&popups->node,
|
||||||
SWAY_SCENE_DESC_POPUP, &surface->desc)) {
|
SWAY_SCENE_DESC_POPUP, &surface->desc)) {
|
||||||
|
@ -171,9 +207,8 @@ static struct sway_layer_surface *sway_layer_surface_create(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
surface->tree = scene->tree;
|
surface->scene_tree = scene_tree;
|
||||||
surface->scene = scene;
|
surface->layer_surface = layer_surface;
|
||||||
surface->layer_surface = scene->layer_surface;
|
|
||||||
surface->popups = popups;
|
surface->popups = popups;
|
||||||
surface->layer_surface->data = surface;
|
surface->layer_surface->data = surface;
|
||||||
|
|
||||||
|
@ -212,16 +247,15 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_container_of(listener, layer, output_destroy);
|
wl_container_of(listener, layer, output_destroy);
|
||||||
|
|
||||||
layer->output = NULL;
|
layer->output = NULL;
|
||||||
wlr_scene_node_destroy(&layer->scene->tree->node);
|
wlr_scene_node_destroy(&layer->scene_tree->node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_node_destroy(struct wl_listener *listener, void *data) {
|
static void handle_layer_surface_destroy(struct wl_listener *listener, void *data) {
|
||||||
struct sway_layer_surface *layer =
|
struct sway_layer_surface *layer = wl_container_of(listener, layer, layer_surface_destroy);
|
||||||
wl_container_of(listener, layer, node_destroy);
|
|
||||||
|
|
||||||
// destroy the scene descriptor straight away if it exists, otherwise
|
// destroy the scene descriptor straight away if it exists, otherwise
|
||||||
// we will try to reflow still considering the destroyed node.
|
// we will try to reflow still considering the destroyed node.
|
||||||
scene_descriptor_destroy(&layer->tree->node, SWAY_SCENE_DESC_LAYER_SHELL);
|
scene_descriptor_destroy(&layer->scene_tree->node, SWAY_SCENE_DESC_LAYER_SHELL);
|
||||||
|
|
||||||
// Determine if this layer is being used by an exclusive client. If it is,
|
// Determine if this layer is being used by an exclusive client. If it is,
|
||||||
// try and find another layer owned by this client to pass focus to.
|
// try and find another layer owned by this client to pass focus to.
|
||||||
|
@ -246,7 +280,7 @@ static void handle_node_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_list_remove(&layer->map.link);
|
wl_list_remove(&layer->map.link);
|
||||||
wl_list_remove(&layer->unmap.link);
|
wl_list_remove(&layer->unmap.link);
|
||||||
wl_list_remove(&layer->surface_commit.link);
|
wl_list_remove(&layer->surface_commit.link);
|
||||||
wl_list_remove(&layer->node_destroy.link);
|
wl_list_remove(&layer->layer_surface_destroy.link);
|
||||||
wl_list_remove(&layer->output_destroy.link);
|
wl_list_remove(&layer->output_destroy.link);
|
||||||
|
|
||||||
layer->layer_surface->data = NULL;
|
layer->layer_surface->data = NULL;
|
||||||
|
@ -268,7 +302,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
|
||||||
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->current.layer;
|
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->current.layer;
|
||||||
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
|
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
|
||||||
surface->output, layer_type);
|
surface->output, layer_type);
|
||||||
wlr_scene_node_reparent(&surface->scene->tree->node, output_layer);
|
wlr_scene_node_reparent(&surface->scene_tree->node, output_layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layer_surface->initial_commit || committed || layer_surface->surface->mapped != surface->mapped) {
|
if (layer_surface->initial_commit || committed || layer_surface->surface->mapped != surface->mapped) {
|
||||||
|
@ -282,8 +316,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
||||||
struct sway_layer_surface *surface = wl_container_of(listener,
|
struct sway_layer_surface *surface = wl_container_of(listener,
|
||||||
surface, map);
|
surface, map);
|
||||||
|
|
||||||
struct wlr_layer_surface_v1 *layer_surface =
|
struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
|
||||||
surface->scene->layer_surface;
|
|
||||||
|
|
||||||
// focus on new surface
|
// focus on new surface
|
||||||
if (layer_surface->current.keyboard_interactive &&
|
if (layer_surface->current.keyboard_interactive &&
|
||||||
|
@ -337,7 +370,7 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int lx, ly;
|
int lx, ly;
|
||||||
wlr_scene_node_coords(&popup->toplevel->scene->tree->node, &lx, &ly);
|
wlr_scene_node_coords(&popup->toplevel->scene_tree->node, &lx, &ly);
|
||||||
|
|
||||||
// the output box expressed in the coordinate system of the toplevel parent
|
// the output box expressed in the coordinate system of the toplevel parent
|
||||||
// of the popup
|
// of the popup
|
||||||
|
@ -443,24 +476,23 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
||||||
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->pending.layer;
|
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->pending.layer;
|
||||||
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
|
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
|
||||||
output, layer_type);
|
output, layer_type);
|
||||||
struct wlr_scene_layer_surface_v1 *scene_surface =
|
struct wlr_scene_tree *scene_surface =
|
||||||
wlr_scene_layer_surface_v1_create(output_layer, layer_surface);
|
wlr_scene_subsurface_tree_create(output_layer, layer_surface->surface);
|
||||||
if (!scene_surface) {
|
if (!scene_surface) {
|
||||||
sway_log(SWAY_ERROR, "Could not allocate a layer_surface_v1");
|
sway_log(SWAY_ERROR, "Could not allocate a layer_surface_v1");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sway_layer_surface *surface =
|
struct sway_layer_surface *surface = sway_layer_surface_create(layer_surface, scene_surface);
|
||||||
sway_layer_surface_create(scene_surface);
|
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
wlr_layer_surface_v1_destroy(layer_surface);
|
wlr_layer_surface_v1_destroy(layer_surface);
|
||||||
|
wlr_scene_node_destroy(&scene_surface->node);
|
||||||
|
|
||||||
sway_log(SWAY_ERROR, "Could not allocate a sway_layer_surface");
|
sway_log(SWAY_ERROR, "Could not allocate a sway_layer_surface");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scene_descriptor_assign(&scene_surface->tree->node,
|
if (!scene_descriptor_assign(&scene_surface->node, SWAY_SCENE_DESC_LAYER_SHELL, surface)) {
|
||||||
SWAY_SCENE_DESC_LAYER_SHELL, surface)) {
|
|
||||||
sway_log(SWAY_ERROR, "Failed to allocate a layer surface descriptor");
|
sway_log(SWAY_ERROR, "Failed to allocate a layer surface descriptor");
|
||||||
// destroying the layer_surface will also destroy its corresponding
|
// destroying the layer_surface will also destroy its corresponding
|
||||||
// scene node
|
// scene node
|
||||||
|
@ -489,6 +521,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
||||||
surface->output_destroy.notify = handle_output_destroy;
|
surface->output_destroy.notify = handle_output_destroy;
|
||||||
wl_signal_add(&output->events.disable, &surface->output_destroy);
|
wl_signal_add(&output->events.disable, &surface->output_destroy);
|
||||||
|
|
||||||
surface->node_destroy.notify = handle_node_destroy;
|
surface->layer_surface_destroy.notify = handle_layer_surface_destroy;
|
||||||
wl_signal_add(&scene_surface->tree->node.events.destroy, &surface->node_destroy);
|
wl_signal_add(&layer_surface->events.destroy, &surface->layer_surface_destroy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,11 +318,11 @@ static void input_popup_update(struct sway_input_popup *popup) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
relative_parent = layer->scene->tree;
|
relative_parent = layer->scene_tree;
|
||||||
struct wlr_output *output = layer->layer_surface->output;
|
struct wlr_output *output = layer->layer_surface->output;
|
||||||
wlr_output_layout_get_box(root->output_layout, output, &output_box);
|
wlr_output_layout_get_box(root->output_layout, output, &output_box);
|
||||||
int lx, ly;
|
int lx, ly;
|
||||||
wlr_scene_node_coords(&layer->tree->node, &lx, &ly);
|
wlr_scene_node_coords(&layer->scene_tree->node, &lx, &ly);
|
||||||
parent.x = lx;
|
parent.x = lx;
|
||||||
parent.y = ly;
|
parent.y = ly;
|
||||||
popup->desc.view = NULL;
|
popup->desc.view = NULL;
|
||||||
|
|
Loading…
Reference in a new issue