Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layer-shell: rework arranging, use wlroots rectpack helper #8274

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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