Skip to content

Commit

Permalink
layer-shell: rework arranging, use wlroots rectpack helper
Browse files Browse the repository at this point in the history
  • Loading branch information
vyivel committed Aug 5, 2024
1 parent 6e4ccb9 commit 399abc8
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 41 deletions.
5 changes: 2 additions & 3 deletions include/sway/layers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};

Expand Down
104 changes: 68 additions & 36 deletions sway/desktop/layer_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -53,35 +54,70 @@ 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
if (!surface) {
continue;
}

if (!surface->scene->layer_surface->initialized) {
if (!surface->layer_surface->initialized) {
continue;
}
if ((surface->layer_surface->current.exclusive_zone > 0) != configure_exclusive) {
continue;
}

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_layer_surface_v1_configure(surface->scene, full_area, usable_area);
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);

pixman_region32_t exclusive;
pixman_region32_init(&exclusive);

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);
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");
Expand Down Expand Up @@ -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");
Expand All @@ -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)) {
Expand All @@ -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;

Expand Down Expand Up @@ -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.
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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 &&
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
4 changes: 2 additions & 2 deletions sway/input/text_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 399abc8

Please sign in to comment.