layer-shell: rework arranging, use wlroots rectpack helper

This commit is contained in:
Kirill Primak 2024-08-04 17:23:30 +03:00
parent 6e4ccb99c3
commit 399abc8763
3 changed files with 72 additions and 41 deletions

View file

@ -10,7 +10,7 @@ struct sway_layer_surface {
struct wl_listener unmap;
struct wl_listener surface_commit;
struct wl_listener output_destroy;
struct wl_listener node_destroy;
struct wl_listener layer_surface_destroy;
struct wl_listener new_popup;
bool mapped;
@ -19,8 +19,7 @@ struct sway_layer_surface {
struct sway_popup_desc desc;
struct sway_output *output;
struct wlr_scene_layer_surface_v1 *scene;
struct wlr_scene_tree *tree;
struct wlr_scene_tree *scene_tree;
struct wlr_layer_surface_v1 *layer_surface;
};

View file

@ -8,6 +8,7 @@
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/rectpack.h>
#include "log.h"
#include "sway/scene_descriptor.h"
#include "sway/desktop/transaction.h"
@ -53,10 +54,10 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
} while (true);
}
static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
struct wlr_box *usable_area, struct wlr_scene_tree *tree) {
static void arrange_surface(struct sway_output *output, const struct wlr_box *bounds,
pixman_region32_t *exclusive, struct wlr_scene_tree *tree, bool configure_exclusive) {
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,
SWAY_SCENE_DESC_LAYER_SHELL);
// surface could be null during destruction
@ -64,24 +65,59 @@ static void arrange_surface(struct sway_output *output, const struct wlr_box *fu
continue;
}
if (!surface->scene->layer_surface->initialized) {
if (!surface->layer_surface->initialized) {
continue;
}
if ((surface->layer_surface->current.exclusive_zone > 0) != configure_exclusive) {
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) {
struct wlr_box usable_area = { 0 };
wlr_output_effective_resolution(output->wlr_output,
&usable_area.width, &usable_area.height);
const struct wlr_box full_area = usable_area;
struct wlr_box bounds = {0};
wlr_output_effective_resolution(output->wlr_output, &bounds.width, &bounds.height);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay);
pixman_region32_t exclusive;
pixman_region32_init(&exclusive);
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)) {
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(
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));
if (!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;
}
surface->desc.relative = &scene->tree->node;
surface->desc.relative = &scene_tree->node;
if (!scene_descriptor_assign(&popups->node,
SWAY_SCENE_DESC_POPUP, &surface->desc)) {
@ -171,9 +207,8 @@ static struct sway_layer_surface *sway_layer_surface_create(
return NULL;
}
surface->tree = scene->tree;
surface->scene = scene;
surface->layer_surface = scene->layer_surface;
surface->scene_tree = scene_tree;
surface->layer_surface = layer_surface;
surface->popups = popups;
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);
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) {
struct sway_layer_surface *layer =
wl_container_of(listener, layer, node_destroy);
static void handle_layer_surface_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *layer = wl_container_of(listener, layer, layer_surface_destroy);
// destroy the scene descriptor straight away if it exists, otherwise
// 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,
// 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->unmap.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);
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;
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
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) {
@ -282,8 +316,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct sway_layer_surface *surface = wl_container_of(listener,
surface, map);
struct wlr_layer_surface_v1 *layer_surface =
surface->scene->layer_surface;
struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
// focus on new surface
if (layer_surface->current.keyboard_interactive &&
@ -337,7 +370,7 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
}
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
// 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;
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
output, layer_type);
struct wlr_scene_layer_surface_v1 *scene_surface =
wlr_scene_layer_surface_v1_create(output_layer, layer_surface);
struct wlr_scene_tree *scene_surface =
wlr_scene_subsurface_tree_create(output_layer, layer_surface->surface);
if (!scene_surface) {
sway_log(SWAY_ERROR, "Could not allocate a layer_surface_v1");
return;
}
struct sway_layer_surface *surface =
sway_layer_surface_create(scene_surface);
struct sway_layer_surface *surface = sway_layer_surface_create(layer_surface, scene_surface);
if (!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");
return;
}
if (!scene_descriptor_assign(&scene_surface->tree->node,
SWAY_SCENE_DESC_LAYER_SHELL, surface)) {
if (!scene_descriptor_assign(&scene_surface->node, SWAY_SCENE_DESC_LAYER_SHELL, surface)) {
sway_log(SWAY_ERROR, "Failed to allocate a layer surface descriptor");
// destroying the layer_surface will also destroy its corresponding
// scene node
@ -489,6 +521,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
surface->output_destroy.notify = handle_output_destroy;
wl_signal_add(&output->events.disable, &surface->output_destroy);
surface->node_destroy.notify = handle_node_destroy;
wl_signal_add(&scene_surface->tree->node.events.destroy, &surface->node_destroy);
surface->layer_surface_destroy.notify = handle_layer_surface_destroy;
wl_signal_add(&layer_surface->events.destroy, &surface->layer_surface_destroy);
}

View file

@ -318,11 +318,11 @@ static void input_popup_update(struct sway_input_popup *popup) {
return;
}
relative_parent = layer->scene->tree;
relative_parent = layer->scene_tree;
struct wlr_output *output = layer->layer_surface->output;
wlr_output_layout_get_box(root->output_layout, output, &output_box);
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.y = ly;
popup->desc.view = NULL;