aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
authorAlexander Orzechowski <alex@ozal.ski>2024-01-18 10:04:51 -0500
committerKirill Primak <vyivel@eclair.cafe>2024-01-18 18:36:54 +0300
commit188811f80861caacd016b857b0d07f6d2d62d15a (patch)
treedc68ea00b707b25ce398c71fe1ad996f0eb820ea /sway
parent5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d (diff)
scene_graph: Port layer_shell
Diffstat (limited to 'sway')
-rw-r--r--sway/desktop/layer_shell.c720
-rw-r--r--sway/desktop/output.c85
-rw-r--r--sway/input/cursor.c6
-rw-r--r--sway/tree/output.c13
-rw-r--r--sway/tree/root.c5
5 files changed, 237 insertions, 592 deletions
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 6480d7ce..a52d27fa 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -6,6 +6,7 @@
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_subcompositor.h>
#include "log.h"
+#include "sway/scene_descriptor.h"
#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/input-manager.h"
@@ -16,6 +17,7 @@
#include "sway/surface.h"
#include "sway/tree/arrange.h"
#include "sway/tree/workspace.h"
+#include <wlr/types/wlr_scene.h>
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
struct wlr_surface *surface) {
@@ -50,165 +52,22 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
} while (true);
}
-static void apply_exclusive(struct wlr_box *usable_area,
- uint32_t anchor, int32_t exclusive,
- int32_t margin_top, int32_t margin_right,
- int32_t margin_bottom, int32_t margin_left) {
- if (exclusive <= 0) {
- return;
- }
- struct {
- uint32_t singular_anchor;
- uint32_t anchor_triplet;
- int *positive_axis;
- int *negative_axis;
- int margin;
- } edges[] = {
- // Top
- {
- .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
- .anchor_triplet =
- ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
- .positive_axis = &usable_area->y,
- .negative_axis = &usable_area->height,
- .margin = margin_top,
- },
- // Bottom
- {
- .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
- .anchor_triplet =
- ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
- .positive_axis = NULL,
- .negative_axis = &usable_area->height,
- .margin = margin_bottom,
- },
- // Left
- {
- .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,
- .anchor_triplet =
- ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
- .positive_axis = &usable_area->x,
- .negative_axis = &usable_area->width,
- .margin = margin_left,
- },
- // Right
- {
- .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
- .anchor_triplet =
- ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
- .positive_axis = NULL,
- .negative_axis = &usable_area->width,
- .margin = margin_right,
- },
- };
- for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) {
- if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet)
- && exclusive + edges[i].margin > 0) {
- if (edges[i].positive_axis) {
- *edges[i].positive_axis += exclusive + edges[i].margin;
- }
- if (edges[i].negative_axis) {
- *edges[i].negative_axis -= exclusive + edges[i].margin;
- }
- break;
+static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
+ struct wlr_box *usable_area, struct wlr_scene_tree *tree) {
+ struct wlr_scene_node *node;
+ wl_list_for_each(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;
}
- }
-}
-static void arrange_layer(struct sway_output *output, struct wl_list *list,
- struct wlr_box *usable_area, bool exclusive) {
- struct sway_layer_surface *sway_layer;
- struct wlr_box full_area = { 0 };
- wlr_output_effective_resolution(output->wlr_output,
- &full_area.width, &full_area.height);
- wl_list_for_each(sway_layer, list, link) {
- struct wlr_layer_surface_v1 *layer = sway_layer->layer_surface;
- if (!layer->initialized) {
+ if (!surface->scene->layer_surface->initialized) {
return;
}
- struct wlr_layer_surface_v1_state *state = &layer->current;
- if (exclusive != (state->exclusive_zone > 0)) {
- continue;
- }
- struct wlr_box bounds;
- if (state->exclusive_zone == -1) {
- bounds = full_area;
- } else {
- bounds = *usable_area;
- }
- struct wlr_box box = {
- .width = state->desired_width,
- .height = state->desired_height
- };
- // Horizontal axis
- const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
- | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
- if (box.width == 0) {
- box.x = bounds.x;
- } else if ((state->anchor & both_horiz) == both_horiz) {
- box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
- } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
- box.x = bounds.x;
- } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
- box.x = bounds.x + (bounds.width - box.width);
- } else {
- box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
- }
- // Vertical axis
- const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
- | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
- if (box.height == 0) {
- box.y = bounds.y;
- } else if ((state->anchor & both_vert) == both_vert) {
- box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
- } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
- box.y = bounds.y;
- } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
- box.y = bounds.y + (bounds.height - box.height);
- } else {
- box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
- }
- // Margin
- if (box.width == 0) {
- box.x += state->margin.left;
- box.width = bounds.width -
- (state->margin.left + state->margin.right);
- } else if ((state->anchor & both_horiz) == both_horiz) {
- // don't apply margins
- } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
- box.x += state->margin.left;
- } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
- box.x -= state->margin.right;
- }
- if (box.height == 0) {
- box.y += state->margin.top;
- box.height = bounds.height -
- (state->margin.top + state->margin.bottom);
- } else if ((state->anchor & both_vert) == both_vert) {
- // don't apply margins
- } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
- box.y += state->margin.top;
- } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
- box.y -= state->margin.bottom;
- }
- if (!sway_assert(box.width >= 0 && box.height >= 0,
- "Expected layer surface to have positive size")) {
- continue;
- }
- // Apply
- sway_layer->geo = box;
- apply_exclusive(usable_area, state->anchor, state->exclusive_zone,
- state->margin.top, state->margin.right,
- state->margin.bottom, state->margin.left);
- wlr_layer_surface_v1_configure(layer, box.width, box.height);
+
+ wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);
}
}
@@ -216,83 +75,78 @@ 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;
- // Arrange exclusive surfaces from top->bottom
- arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
- &usable_area, true);
- arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
- &usable_area, true);
- arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
- &usable_area, true);
- arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
- &usable_area, true);
-
- if (memcmp(&usable_area, &output->usable_area,
- sizeof(struct wlr_box)) != 0) {
+ 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);
+
+ if (!wlr_box_equal(&usable_area, &output->usable_area)) {
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
- memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
+ output->usable_area = usable_area;
arrange_output(output);
}
+}
- // Arrange non-exclusive surfaces from top->bottom
- arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
- &usable_area, false);
- arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
- &usable_area, false);
- arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
- &usable_area, false);
- arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
- &usable_area, false);
-
- // Find topmost keyboard interactive layer, if such a layer exists
- uint32_t layers_above_shell[] = {
- ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
- ZWLR_LAYER_SHELL_V1_LAYER_TOP,
- };
- size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
- struct sway_layer_surface *layer, *topmost = NULL;
- for (size_t i = 0; i < nlayers; ++i) {
- wl_list_for_each_reverse(layer,
- &output->shell_layers[layers_above_shell[i]], link) {
- if (layer->layer_surface->current.keyboard_interactive &&
- layer->layer_surface->surface->mapped) {
- topmost = layer;
- break;
- }
- }
- if (topmost != NULL) {
- break;
- }
+static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
+ enum zwlr_layer_shell_v1_layer type) {
+ switch (type) {
+ case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
+ return output->layers.shell_background;
+ case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
+ return output->layers.shell_bottom;
+ case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
+ return output->layers.shell_top;
+ case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
+ return output->layers.shell_overlay;
}
- struct sway_seat *seat;
- wl_list_for_each(seat, &server.input->seats, link) {
- seat->has_exclusive_layer = false;
- if (topmost != NULL) {
- seat_set_focus_layer(seat, topmost->layer_surface);
- } else if (seat->focused_layer &&
- seat->focused_layer->current.keyboard_interactive
- != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
- seat_set_focus_layer(seat, NULL);
- }
+ sway_assert(false, "unreachable");
+ return NULL;
+}
+
+static struct sway_layer_surface *sway_layer_surface_create(
+ struct wlr_scene_layer_surface_v1 *scene) {
+ struct sway_layer_surface *surface = calloc(1, sizeof(*surface));
+ if (!surface) {
+ sway_log(SWAY_ERROR, "Could not allocate a scene_layer surface");
+ return NULL;
}
+
+ struct wlr_scene_tree *popups = wlr_scene_tree_create(root->layers.popup);
+ if (!popups) {
+ sway_log(SWAY_ERROR, "Could not allocate a scene_layer popup node");
+ free(surface);
+ return NULL;
+ }
+
+ surface->tree = scene->tree;
+ surface->scene = scene;
+ surface->layer_surface = scene->layer_surface;
+ surface->popups = popups;
+
+ return surface;
}
static struct sway_layer_surface *find_mapped_layer_by_client(
- struct wl_client *client, struct wlr_output *ignore_output) {
+ struct wl_client *client, struct sway_output *ignore_output) {
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
- if (output->wlr_output == ignore_output) {
+ if (output == ignore_output) {
continue;
}
// For now we'll only check the overlay layer
- struct sway_layer_surface *lsurface;
- wl_list_for_each(lsurface,
- &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) {
- struct wl_resource *resource = lsurface->layer_surface->resource;
+ struct wlr_scene_node *node;
+ wl_list_for_each (node, &output->layers.shell_overlay->children, link) {
+ struct sway_layer_surface *surface = scene_descriptor_try_get(node,
+ SWAY_SCENE_DESC_LAYER_SHELL);
+
+ struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
+ struct wl_resource *resource = layer_surface->resource;
if (wl_resource_get_client(resource) == client
- && lsurface->layer_surface->surface->mapped) {
- return lsurface;
+ && layer_surface->surface->mapped) {
+ return surface;
}
}
}
@@ -300,262 +154,144 @@ static struct sway_layer_surface *find_mapped_layer_by_client(
}
static void handle_output_destroy(struct wl_listener *listener, void *data) {
- struct sway_layer_surface *sway_layer =
- wl_container_of(listener, sway_layer, output_destroy);
+ struct sway_layer_surface *layer =
+ wl_container_of(listener, layer, output_destroy);
+
+ layer->output = NULL;
+ 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);
+
+ // 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);
+
// 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.
struct sway_seat *seat = input_manager_get_default_seat();
struct wl_client *client =
- wl_resource_get_client(sway_layer->layer_surface->resource);
-
- if (!server.session_lock.locked) {
- struct sway_layer_surface *layer =
- find_mapped_layer_by_client(client, sway_layer->layer_surface->output);
- if (layer) {
- seat_set_focus_layer(seat, layer->layer_surface);
+ wl_resource_get_client(layer->layer_surface->resource);
+ if (!server.session_lock.lock) {
+ struct sway_layer_surface *consider_layer =
+ find_mapped_layer_by_client(client, layer->output);
+ if (consider_layer) {
+ seat_set_focus_layer(seat, consider_layer->layer_surface);
}
}
- wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
+ if (layer->output) {
+ arrange_layers(layer->output);
+ transaction_commit_dirty();
+ }
+
+ wlr_scene_node_destroy(&layer->popups->node);
+
+ 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->output_destroy.link);
+
+ free(layer);
}
static void handle_surface_commit(struct wl_listener *listener, void *data) {
- struct sway_layer_surface *layer =
- wl_container_of(listener, layer, surface_commit);
- struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface;
- struct wlr_output *wlr_output = layer_surface->output;
- sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
- struct sway_output *output = wlr_output->data;
-
- if (layer_surface->initial_commit) {
- surface_enter_output(layer_surface->surface, output);
- } else if (!layer_surface->initialized) {
+ struct sway_layer_surface *surface =
+ wl_container_of(listener, surface, surface_commit);
+
+ struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
+ if (!layer_surface->initialized) {
return;
}
- struct wlr_box old_extent = layer->extent;
-
- bool layer_changed = false;
- if (layer_surface->initial_commit || layer_surface->current.committed != 0
- || layer->mapped != layer_surface->surface->mapped) {
- layer->mapped = layer_surface->surface->mapped;
- layer_changed = layer->layer != layer_surface->current.layer;
- if (layer_changed) {
- wl_list_remove(&layer->link);
- wl_list_insert(&output->shell_layers[layer_surface->current.layer],
- &layer->link);
- layer->layer = layer_surface->current.layer;
- }
- arrange_layers(output);
+ uint32_t committed = layer_surface->current.committed;
+ if (committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) {
+ 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_surface_get_extends(layer_surface->surface, &layer->extent);
- layer->extent.x += layer->geo.x;
- layer->extent.y += layer->geo.y;
-
- bool extent_changed =
- memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0;
- if (extent_changed || layer_changed) {
- old_extent.x += output->lx;
- old_extent.y += output->ly;
- output_damage_box(output, &old_extent);
- output_damage_surface(output, layer->geo.x, layer->geo.y,
- layer_surface->surface, true);
- } else {
- output_damage_surface(output, layer->geo.x, layer->geo.y,
- layer_surface->surface, false);
+ if (layer_surface->initial_commit || committed || layer_surface->surface->mapped != surface->mapped) {
+ surface->mapped = layer_surface->surface->mapped;
+ arrange_layers(surface->output);
+ transaction_commit_dirty();
}
- transaction_commit_dirty();
+ int lx, ly;
+ wlr_scene_node_coords(&surface->scene->tree->node, &lx, &ly);
+ wlr_scene_node_set_position(&surface->popups->node, lx, ly);
}
-static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface);
-
-static void handle_destroy(struct wl_listener *listener, void *data) {
- struct sway_layer_surface *sway_layer =
- wl_container_of(listener, sway_layer, destroy);
- sway_log(SWAY_DEBUG, "Layer surface destroyed (%s)",
- sway_layer->layer_surface->namespace);
-
- struct sway_layer_subsurface *subsurface, *subsurface_tmp;
- wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) {
- layer_subsurface_destroy(subsurface);
+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;
+
+ // focus on new surface
+ if (layer_surface->current.keyboard_interactive &&
+ (layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ||
+ layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP)) {
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ // but only if the currently focused layer has a lower precedence
+ if (!seat->focused_layer ||
+ seat->focused_layer->current.layer >= layer_surface->current.layer) {
+ seat_set_focus_layer(seat, layer_surface);
+ }
+ }
+ arrange_layers(surface->output);
}
- wl_list_remove(&sway_layer->link);
- wl_list_remove(&sway_layer->destroy.link);
- wl_list_remove(&sway_layer->map.link);
- wl_list_remove(&sway_layer->unmap.link);
- wl_list_remove(&sway_layer->surface_commit.link);
- wl_list_remove(&sway_layer->new_popup.link);
- wl_list_remove(&sway_layer->new_subsurface.link);
-
- struct wlr_output *wlr_output = sway_layer->layer_surface->output;
- sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
- struct sway_output *output = wlr_output->data;
- arrange_layers(output);
- transaction_commit_dirty();
- wl_list_remove(&sway_layer->output_destroy.link);
- sway_layer->layer_surface->output = NULL;
-
- free(sway_layer);
-}
-
-static void handle_map(struct wl_listener *listener, void *data) {
- struct sway_layer_surface *sway_layer = wl_container_of(listener,
- sway_layer, map);
- struct wlr_output *wlr_output = sway_layer->layer_surface->output;
- sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
- struct sway_output *output = wlr_output->data;
- output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
- sway_layer->layer_surface->surface, true);
cursor_rebase_all();
}
static void handle_unmap(struct wl_listener *listener, void *data) {
- struct sway_layer_surface *sway_layer = wl_container_of(
- listener, sway_layer, unmap);
+ struct sway_layer_surface *surface = wl_container_of(
+ listener, surface, unmap);
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
- if (seat->focused_layer == sway_layer->layer_surface) {
+ if (seat->focused_layer == surface->layer_surface) {
seat_set_focus_layer(seat, NULL);
}
}
cursor_rebase_all();
-
- struct wlr_output *wlr_output = sway_layer->layer_surface->output;
- sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
- struct sway_output *output = wlr_output->data;
- output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
- sway_layer->layer_surface->surface, true);
-}
-
-static void subsurface_damage(struct sway_layer_subsurface *subsurface,
- bool whole) {
- struct sway_layer_surface *layer = subsurface->layer_surface;
- struct wlr_output *wlr_output = layer->layer_surface->output;
- sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
- struct sway_output *output = wlr_output->data;
- int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
- int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
- output_damage_surface(
- output, ox, oy, subsurface->wlr_subsurface->surface, whole);
}
-static void subsurface_handle_unmap(struct wl_listener *listener, void *data) {
- struct sway_layer_subsurface *subsurface =
- wl_container_of(listener, subsurface, unmap);
- subsurface_damage(subsurface, true);
-}
-
-static void subsurface_handle_map(struct wl_listener *listener, void *data) {
- struct sway_layer_subsurface *subsurface =
- wl_container_of(listener, subsurface, map);
- subsurface_damage(subsurface, true);
-}
-
-static void subsurface_handle_commit(struct wl_listener *listener, void *data) {
- struct sway_layer_subsurface *subsurface =
- wl_container_of(listener, subsurface, commit);
- subsurface_damage(subsurface, false);
-}
-
-static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) {
- wl_list_remove(&subsurface->link);
- wl_list_remove(&subsurface->map.link);
- wl_list_remove(&subsurface->unmap.link);
- wl_list_remove(&subsurface->destroy.link);
- wl_list_remove(&subsurface->commit.link);
- free(subsurface);
-}
-
-static void subsurface_handle_destroy(struct wl_listener *listener,
- void *data) {
- struct sway_layer_subsurface *subsurface =
- wl_container_of(listener, subsurface, destroy);
- layer_subsurface_destroy(subsurface);
-}
-
-static struct sway_layer_subsurface *create_subsurface(
- struct wlr_subsurface *wlr_subsurface,
- struct sway_layer_surface *layer_surface) {
- struct sway_layer_subsurface *subsurface =
- calloc(1, sizeof(struct sway_layer_subsurface));
- if (subsurface == NULL) {
- return NULL;
- }
-
- subsurface->wlr_subsurface = wlr_subsurface;
- subsurface->layer_surface = layer_surface;
- wl_list_insert(&layer_surface->subsurfaces, &subsurface->link);
-
- subsurface->map.notify = subsurface_handle_map;
- wl_signal_add(&wlr_subsurface->surface->events.map, &subsurface->map);
- subsurface->unmap.notify = subsurface_handle_unmap;
- wl_signal_add(&wlr_subsurface->surface->events.unmap, &subsurface->unmap);
- subsurface->destroy.notify = subsurface_handle_destroy;
- wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
- subsurface->commit.notify = subsurface_handle_commit;
- wl_signal_add(&wlr_subsurface->surface->events.commit, &subsurface->commit);
-
- return subsurface;
-}
-
-static void handle_new_subsurface(struct wl_listener *listener, void *data) {
- struct sway_layer_surface *sway_layer_surface =
- wl_container_of(listener, sway_layer_surface, new_subsurface);
- struct wlr_subsurface *wlr_subsurface = data;
- create_subsurface(wlr_subsurface, sway_layer_surface);
-}
-
-
-static struct sway_layer_surface *popup_get_layer(
- struct sway_layer_popup *popup) {
- while (popup->parent_type == LAYER_PARENT_POPUP) {
- popup = popup->parent_popup;
- }
- return popup->parent_layer;
-}
+static void popup_handle_destroy(struct wl_listener *listener, void *data) {
+ struct sway_layer_popup *popup =
+ wl_container_of(listener, popup, destroy);
-static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
- struct wlr_xdg_popup *popup = layer_popup->wlr_popup;
- struct wlr_surface *surface = popup->base->surface;
- int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x;
- int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y;
- int ox = popup_sx, oy = popup_sy;
- struct sway_layer_surface *layer;
- while (true) {
- if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
- layer_popup = layer_popup->parent_popup;
- ox += layer_popup->wlr_popup->current.geometry.x;
- oy += layer_popup->wlr_popup->current.geometry.y;
- } else {
- layer = layer_popup->parent_layer;
- ox += layer->geo.x;
- oy += layer->geo.y;
- break;
- }
- }
- struct wlr_output *wlr_output = layer->layer_surface->output;
- sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
- struct sway_output *output = wlr_output->data;
- output_damage_surface(output, ox, oy, surface, whole);
+ wl_list_remove(&popup->destroy.link);
+ wl_list_remove(&popup->new_popup.link);
+ wl_list_remove(&popup->commit.link);
+ free(popup);
}
static void popup_unconstrain(struct sway_layer_popup *popup) {
- struct sway_layer_surface *layer = popup_get_layer(popup);
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
+ struct sway_output *output = popup->toplevel->output;
+
+ // if a client tries to create a popup while we are in the process of destroying
+ // its output, don't crash.
+ if (!output) {
+ return;
+ }
- struct wlr_output *wlr_output = layer->layer_surface->output;
- sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
- struct sway_output *output = wlr_output->data;
+ int 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
struct wlr_box output_toplevel_sx_box = {
- .x = -layer->geo.x,
- .y = -layer->geo.y,
+ .x = output->lx - lx,
+ .y = output->ly - ly,
.width = output->width,
.height = output->height,
};
@@ -563,63 +299,38 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
}
-static void popup_handle_map(struct wl_listener *listener, void *data) {
- struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
- struct sway_layer_surface *layer = popup_get_layer(popup);
- struct wlr_output *wlr_output = layer->layer_surface->output;
- sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
- surface_enter_output(popup->wlr_popup->base->surface, wlr_output->data);
- popup_damage(popup, true);
-}
-
-static void popup_handle_unmap(struct wl_listener *listener, void *data) {
- struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap);
- popup_damage(popup, true);
-}
-
static void popup_handle_commit(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, commit);
if (popup->wlr_popup->base->initial_commit) {
popup_unconstrain(popup);
}
- popup_damage(popup, false);
-}
-
-static void popup_handle_destroy(struct wl_listener *listener, void *data) {
- struct sway_layer_popup *popup =
- wl_container_of(listener, popup, destroy);
-
- wl_list_remove(&popup->map.link);
- wl_list_remove(&popup->unmap.link);
- wl_list_remove(&popup->destroy.link);
- wl_list_remove(&popup->commit.link);
- free(popup);
}
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
- enum layer_parent parent_type, void *parent) {
- struct sway_layer_popup *popup =
- calloc(1, sizeof(struct sway_layer_popup));
+ struct sway_layer_surface *toplevel, struct wlr_scene_tree *parent) {
+ struct sway_layer_popup *popup = calloc(1, sizeof(*popup));
if (popup == NULL) {
return NULL;
}
+ popup->toplevel = toplevel;
popup->wlr_popup = wlr_popup;
- popup->parent_type = parent_type;
- popup->parent_layer = parent;
+ popup->scene = wlr_scene_xdg_surface_create(parent,
+ wlr_popup->base);
+
+ if (!popup->scene) {
+ free(popup);
+ return NULL;
+ }
- popup->map.notify = popup_handle_map;
- wl_signal_add(&wlr_popup->base->surface->events.map, &popup->map);
- popup->unmap.notify = popup_handle_unmap;
- wl_signal_add(&wlr_popup->base->surface->events.unmap, &popup->unmap);
popup->destroy.notify = popup_handle_destroy;
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
- popup->commit.notify = popup_handle_commit;
- wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
popup->new_popup.notify = popup_handle_new_popup;
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
+ popup->commit.notify = popup_handle_commit;
+ wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
return popup;
}
@@ -628,19 +339,14 @@ static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
struct sway_layer_popup *sway_layer_popup =
wl_container_of(listener, sway_layer_popup, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
- create_popup(wlr_popup, LAYER_PARENT_POPUP, sway_layer_popup);
+ create_popup(wlr_popup, sway_layer_popup->toplevel, sway_layer_popup->scene);
}
static void handle_new_popup(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer_surface =
wl_container_of(listener, sway_layer_surface, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
- create_popup(wlr_popup, LAYER_PARENT_LAYER, sway_layer_surface);
-}
-
-struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
- struct wlr_layer_surface_v1 *layer_surface) {
- return layer_surface->data;
+ create_popup(wlr_popup, sway_layer_surface, sway_layer_surface->popups);
}
void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
@@ -672,10 +378,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
sway_log(SWAY_ERROR,
"no output to auto-assign layer surface '%s' to",
layer_surface->namespace);
- // Note that layer_surface->output can be NULL
- // here, but none of our destroy callbacks are
- // registered yet so we don't have to make them
- // handle that case.
wlr_layer_surface_v1_destroy(layer_surface);
return;
}
@@ -684,37 +386,51 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
layer_surface->output = output->wlr_output;
}
- struct sway_layer_surface *sway_layer =
- calloc(1, sizeof(struct sway_layer_surface));
- if (!sway_layer) {
+ struct sway_output *output = layer_surface->output->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);
+ if (!scene_surface) {
+ sway_log(SWAY_ERROR, "Could not allocate a layer_surface_v1");
return;
}
- wl_list_init(&sway_layer->subsurfaces);
+ struct sway_layer_surface *surface =
+ sway_layer_surface_create(scene_surface);
+ if (!surface) {
+ wlr_layer_surface_v1_destroy(layer_surface);
- sway_layer->surface_commit.notify = handle_surface_commit;
- wl_signal_add(&layer_surface->surface->events.commit,
- &sway_layer->surface_commit);
-
- sway_layer->destroy.notify = handle_destroy;
- wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy);
- sway_layer->map.notify = handle_map;
- wl_signal_add(&layer_surface->surface->events.map, &sway_layer->map);
- sway_layer->unmap.notify = handle_unmap;
- wl_signal_add(&layer_surface->surface->events.unmap, &sway_layer->unmap);
- sway_layer->new_popup.notify = handle_new_popup;
- wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup);
- sway_layer->new_subsurface.notify = handle_new_subsurface;
- wl_signal_add(&layer_surface->surface->events.new_subsurface,
- &sway_layer->new_subsurface);
-
- sway_layer->layer_surface = layer_surface;
- layer_surface->data = sway_layer;
+ sway_log(SWAY_ERROR, "Could not allocate a sway_layer_surface");
+ return;
+ }
- struct sway_output *output = layer_surface->output->data;
- sway_layer->output_destroy.notify = handle_output_destroy;
- wl_signal_add(&output->events.disable, &sway_layer->output_destroy);
+ if (!scene_descriptor_assign(&scene_surface->tree->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
+ wlr_layer_surface_v1_destroy(layer_surface);
+ return;
+ }
- wl_list_insert(&output->shell_layers[layer_surface->pending.layer],
- &sway_layer->link);
+ surface->output = output;
+
+ surface->surface_commit.notify = handle_surface_commit;
+ wl_signal_add(&layer_surface->surface->events.commit,
+ &surface->surface_commit);
+ surface->map.notify = handle_map;
+ wl_signal_add(&layer_surface->surface->events.map, &surface->map);
+ surface->unmap.notify = handle_unmap;
+ wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap);
+ surface->new_popup.notify = handle_new_popup;
+ wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
+
+ 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);
}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 1e4474ce..942bc780 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -182,66 +182,6 @@ void output_view_for_each_popup_surface(struct sway_output *output,
view_for_each_popup_surface(view, output_for_each_surface_iterator, &data);
}
-void output_layer_for_each_surface(struct sway_output *output,
- struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
- void *user_data) {
- struct sway_layer_surface *layer_surface;
- wl_list_for_each(layer_surface, layer_surfaces, link) {
- struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
- layer_surface->layer_surface;
- struct wlr_surface *surface = wlr_layer_surface_v1->surface;
- struct surface_iterator_data data = {
- .user_iterator = iterator,
- .user_data = user_data,
- .output = output,
- .view = NULL,
- .ox = layer_surface->geo.x,
- .oy = layer_surface->geo.y,
- .width = surface->current.width,
- .height = surface->current.height,
- };
- wlr_layer_surface_v1_for_each_surface(wlr_layer_surface_v1,
- output_for_each_surface_iterator, &data);
- }
-}
-
-void output_layer_for_each_toplevel_surface(struct sway_output *output,
- struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
- void *user_data) {
- struct sway_layer_surface *layer_surface;
- wl_list_for_each(layer_surface, layer_surfaces, link) {
- struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
- layer_surface->layer_surface;
- output_surface_for_each_surface(output, wlr_layer_surface_v1->surface,
- layer_surface->geo.x, layer_surface->geo.y, iterator,
- user_data);
- }
-}
-
-
-void output_layer_for_each_popup_surface(struct sway_output *output,
- struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
- void *user_data) {
- struct sway_layer_surface *layer_surface;
- wl_list_for_each(layer_surface, layer_surfaces, link) {
- struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
- layer_surface->layer_surface;
- struct wlr_surface *surface = wlr_layer_surface_v1->surface;
- struct surface_iterator_data data = {
- .user_iterator = iterator,
- .user_data = user_data,
- .output = output,
- .view = NULL,
- .ox = layer_surface->geo.x,
- .oy = layer_surface->geo.y,
- .width = surface->current.width,
- .height = surface->current.height,
- };
- wlr_layer_surface_v1_for_each_popup_surface(wlr_layer_surface_v1,
- output_for_each_surface_iterator, &data);
- }
-}
-
#if HAVE_XWAYLAND
void output_unmanaged_for_each_surface(struct sway_output *output,
struct wl_list *unmanaged, sway_surface_iterator_func_t iterator,
@@ -282,31 +222,6 @@ struct sway_workspace *output_get_active_workspace(struct sway_output *output) {
return focus->sway_workspace;
}
-bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
- struct sway_layer_surface *sway_layer_surface;
- wl_list_for_each(sway_layer_surface,
- &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) {
- struct wlr_surface *wlr_surface = sway_layer_surface->layer_surface->surface;
- pixman_box32_t output_box = {
- .x2 = output->width,
- .y2 = output->height,
- };
- pixman_region32_t surface_opaque_box;
- pixman_region32_init(&surface_opaque_box);
- pixman_region32_copy(&surface_opaque_box, &wlr_surface->opaque_region);
- pixman_region32_translate(&surface_opaque_box,
- sway_layer_surface->geo.x, sway_layer_surface->geo.y);
- pixman_region_overlap_t contains =
- pixman_region32_contains_rectangle(&surface_opaque_box, &output_box);
- pixman_region32_fini(&surface_opaque_box);
-
- if (contains == PIXMAN_REGION_IN) {
- return true;
- }
- }
- return false;
-}
-
struct send_frame_done_data {
struct timespec when;
int msec_until_refresh;
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 79373e40..30df76f4 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -94,6 +94,12 @@ struct sway_node *node_at_coords(
}
}
+ if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_LAYER_SHELL)) {
+ // We don't want to feed through the current workspace on
+ // layer shells
+ return NULL;
+ }
+
if (!current->parent) {
break;
}
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 64ca3d75..3c8823dc 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -93,8 +93,12 @@ static void destroy_scene_layers(struct sway_output *output) {
scene_node_disown_children(output->layers.tiling);
scene_node_disown_children(output->layers.fullscreen);
+ wlr_scene_node_destroy(&output->layers.shell_background->node);
+ wlr_scene_node_destroy(&output->layers.shell_bottom->node);
wlr_scene_node_destroy(&output->layers.tiling->node);
wlr_scene_node_destroy(&output->layers.fullscreen->node);
+ wlr_scene_node_destroy(&output->layers.shell_top->node);
+ wlr_scene_node_destroy(&output->layers.shell_overlay->node);
wlr_scene_node_destroy(&output->layers.session_lock->node);
}
@@ -103,8 +107,12 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
node_init(&output->node, N_OUTPUT, output);
bool failed = false;
+ output->layers.shell_background = alloc_scene_tree(root->staging, &failed);
+ output->layers.shell_bottom = alloc_scene_tree(root->staging, &failed);
output->layers.tiling = alloc_scene_tree(root->staging, &failed);
output->layers.fullscreen = alloc_scene_tree(root->staging, &failed);
+ output->layers.shell_top = alloc_scene_tree(root->staging, &failed);
+ output->layers.shell_overlay = alloc_scene_tree(root->staging, &failed);
output->layers.session_lock = alloc_scene_tree(root->staging, &failed);
if (!failed) {
@@ -136,11 +144,6 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
output->workspaces = create_list();
output->current.workspaces = create_list();
- size_t len = sizeof(output->shell_layers) / sizeof(output->shell_layers[0]);
- for (size_t i = 0; i < len; ++i) {
- wl_list_init(&output->shell_layers[i]);
- }
-
return output;
}
diff --git a/sway/tree/root.c b/sway/tree/root.c
index fbdd9a96..7c8f9ea6 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -47,10 +47,15 @@ struct sway_root *root_create(struct wl_display *wl_display) {
root->staging = alloc_scene_tree(&root_scene->tree, &failed);
root->layer_tree = alloc_scene_tree(&root_scene->tree, &failed);
+ root->layers.shell_background = alloc_scene_tree(root->layer_tree, &failed);
+ root->layers.shell_bottom = alloc_scene_tree(root->layer_tree, &failed);
root->layers.tiling = alloc_scene_tree(root->layer_tree, &failed);
root->layers.floating = alloc_scene_tree(root->layer_tree, &failed);
+ root->layers.shell_top = alloc_scene_tree(root->layer_tree, &failed);
root->layers.fullscreen = alloc_scene_tree(root->layer_tree, &failed);
root->layers.fullscreen_global = alloc_scene_tree(root->layer_tree, &failed);
+ root->layers.shell_overlay = alloc_scene_tree(root->layer_tree, &failed);
+ root->layers.popup = alloc_scene_tree(root->layer_tree, &failed);
root->layers.seat = alloc_scene_tree(root->layer_tree, &failed);
root->layers.session_lock = alloc_scene_tree(root->layer_tree, &failed);