aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/layer_shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop/layer_shell.c')
-rw-r--r--sway/desktop/layer_shell.c773
1 files changed, 267 insertions, 506 deletions
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index d44d6338..4b2584b6 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -3,10 +3,12 @@
3#include <string.h> 3#include <string.h>
4#include <wayland-server-core.h> 4#include <wayland-server-core.h>
5#include <wlr/types/wlr_layer_shell_v1.h> 5#include <wlr/types/wlr_layer_shell_v1.h>
6#include <wlr/types/wlr_output_damage.h>
7#include <wlr/types/wlr_output.h> 6#include <wlr/types/wlr_output.h>
7#include <wlr/types/wlr_scene.h>
8#include <wlr/types/wlr_subcompositor.h> 8#include <wlr/types/wlr_subcompositor.h>
9#include <wlr/types/wlr_xdg_shell.h>
9#include "log.h" 10#include "log.h"
11#include "sway/scene_descriptor.h"
10#include "sway/desktop/transaction.h" 12#include "sway/desktop/transaction.h"
11#include "sway/input/cursor.h" 13#include "sway/input/cursor.h"
12#include "sway/input/input-manager.h" 14#include "sway/input/input-manager.h"
@@ -17,162 +19,55 @@
17#include "sway/tree/arrange.h" 19#include "sway/tree/arrange.h"
18#include "sway/tree/workspace.h" 20#include "sway/tree/workspace.h"
19 21
20static void apply_exclusive(struct wlr_box *usable_area, 22struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
21 uint32_t anchor, int32_t exclusive, 23 struct wlr_surface *surface) {
22 int32_t margin_top, int32_t margin_right, 24 struct wlr_layer_surface_v1 *layer;
23 int32_t margin_bottom, int32_t margin_left) { 25 do {
24 if (exclusive <= 0) { 26 if (!surface) {
25 return; 27 return NULL;
26 } 28 }
27 struct { 29 // Topmost layer surface
28 uint32_t singular_anchor; 30 if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) {
29 uint32_t anchor_triplet; 31 return layer;
30 int *positive_axis; 32 }
31 int *negative_axis; 33 // Layer subsurface
32 int margin; 34 if (wlr_subsurface_try_from_wlr_surface(surface)) {
33 } edges[] = { 35 surface = wlr_surface_get_root_surface(surface);
34 // Top 36 continue;
35 { 37 }
36 .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, 38
37 .anchor_triplet = 39 // Layer surface popup
38 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | 40 struct wlr_xdg_surface *xdg_surface = NULL;
39 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | 41 if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(surface)) &&
40 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, 42 xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && xdg_surface->popup != NULL) {
41 .positive_axis = &usable_area->y, 43 if (!xdg_surface->popup->parent) {
42 .negative_axis = &usable_area->height, 44 return NULL;
43 .margin = margin_top,
44 },
45 // Bottom
46 {
47 .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
48 .anchor_triplet =
49 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
50 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
51 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
52 .positive_axis = NULL,
53 .negative_axis = &usable_area->height,
54 .margin = margin_bottom,
55 },
56 // Left
57 {
58 .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,
59 .anchor_triplet =
60 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
61 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
62 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
63 .positive_axis = &usable_area->x,
64 .negative_axis = &usable_area->width,
65 .margin = margin_left,
66 },
67 // Right
68 {
69 .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
70 .anchor_triplet =
71 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
72 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
73 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
74 .positive_axis = NULL,
75 .negative_axis = &usable_area->width,
76 .margin = margin_right,
77 },
78 };
79 for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) {
80 if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet)
81 && exclusive + edges[i].margin > 0) {
82 if (edges[i].positive_axis) {
83 *edges[i].positive_axis += exclusive + edges[i].margin;
84 }
85 if (edges[i].negative_axis) {
86 *edges[i].negative_axis -= exclusive + edges[i].margin;
87 } 45 }
88 break; 46 surface = wlr_surface_get_root_surface(xdg_surface->popup->parent);
47 continue;
89 } 48 }
90 } 49
50 // Return early if the surface is not a layer/xdg_popup/sub surface
51 return NULL;
52 } while (true);
91} 53}
92 54
93static void arrange_layer(struct sway_output *output, struct wl_list *list, 55static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
94 struct wlr_box *usable_area, bool exclusive) { 56 struct wlr_box *usable_area, struct wlr_scene_tree *tree) {
95 struct sway_layer_surface *sway_layer; 57 struct wlr_scene_node *node;
96 struct wlr_box full_area = { 0 }; 58 wl_list_for_each(node, &tree->children, link) {
97 wlr_output_effective_resolution(output->wlr_output, 59 struct sway_layer_surface *surface = scene_descriptor_try_get(node,
98 &full_area.width, &full_area.height); 60 SWAY_SCENE_DESC_LAYER_SHELL);
99 wl_list_for_each(sway_layer, list, link) { 61 // surface could be null during destruction
100 struct wlr_layer_surface_v1 *layer = sway_layer->layer_surface; 62 if (!surface) {
101 struct wlr_layer_surface_v1_state *state = &layer->current;
102 if (exclusive != (state->exclusive_zone > 0)) {
103 continue; 63 continue;
104 } 64 }
105 struct wlr_box bounds; 65
106 if (state->exclusive_zone == -1) { 66 if (!surface->scene->layer_surface->initialized) {
107 bounds = full_area;
108 } else {
109 bounds = *usable_area;
110 }
111 struct wlr_box box = {
112 .width = state->desired_width,
113 .height = state->desired_height
114 };
115 // Horizontal axis
116 const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
117 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
118 if (box.width == 0) {
119 box.x = bounds.x;
120 } else if ((state->anchor & both_horiz) == both_horiz) {
121 box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
122 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
123 box.x = bounds.x;
124 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
125 box.x = bounds.x + (bounds.width - box.width);
126 } else {
127 box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
128 }
129 // Vertical axis
130 const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
131 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
132 if (box.height == 0) {
133 box.y = bounds.y;
134 } else if ((state->anchor & both_vert) == both_vert) {
135 box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
136 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
137 box.y = bounds.y;
138 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
139 box.y = bounds.y + (bounds.height - box.height);
140 } else {
141 box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
142 }
143 // Margin
144 if (box.width == 0) {
145 box.x += state->margin.left;
146 box.width = bounds.width -
147 (state->margin.left + state->margin.right);
148 } else if ((state->anchor & both_horiz) == both_horiz) {
149 // don't apply margins
150 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
151 box.x += state->margin.left;
152 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
153 box.x -= state->margin.right;
154 }
155 if (box.height == 0) {
156 box.y += state->margin.top;
157 box.height = bounds.height -
158 (state->margin.top + state->margin.bottom);
159 } else if ((state->anchor & both_vert) == both_vert) {
160 // don't apply margins
161 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
162 box.y += state->margin.top;
163 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
164 box.y -= state->margin.bottom;
165 }
166 if (!sway_assert(box.width >= 0 && box.height >= 0,
167 "Expected layer surface to have positive size")) {
168 continue; 67 continue;
169 } 68 }
170 // Apply 69
171 sway_layer->geo = box; 70 wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);
172 apply_exclusive(usable_area, state->anchor, state->exclusive_zone,
173 state->margin.top, state->margin.right,
174 state->margin.bottom, state->margin.left);
175 wlr_layer_surface_v1_configure(layer, box.width, box.height);
176 } 71 }
177} 72}
178 73
@@ -180,81 +75,94 @@ void arrange_layers(struct sway_output *output) {
180 struct wlr_box usable_area = { 0 }; 75 struct wlr_box usable_area = { 0 };
181 wlr_output_effective_resolution(output->wlr_output, 76 wlr_output_effective_resolution(output->wlr_output,
182 &usable_area.width, &usable_area.height); 77 &usable_area.width, &usable_area.height);
78 const struct wlr_box full_area = usable_area;
79
80 arrange_surface(output, &full_area, &usable_area, output->layers.shell_background);
81 arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom);
82 arrange_surface(output, &full_area, &usable_area, output->layers.shell_top);
83 arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay);
183 84
184 // Arrange exclusive surfaces from top->bottom 85 if (!wlr_box_equal(&usable_area, &output->usable_area)) {
185 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
186 &usable_area, true);
187 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
188 &usable_area, true);
189 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
190 &usable_area, true);
191 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
192 &usable_area, true);
193
194 if (memcmp(&usable_area, &output->usable_area,
195 sizeof(struct wlr_box)) != 0) {
196 sway_log(SWAY_DEBUG, "Usable area changed, rearranging output"); 86 sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
197 memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); 87 output->usable_area = usable_area;
198 arrange_output(output); 88 arrange_output(output);
89 } else {
90 arrange_popups(root->layers.popup);
199 } 91 }
92}
200 93
201 // Arrange non-exclusive surfaces from top->bottom 94static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
202 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], 95 enum zwlr_layer_shell_v1_layer type) {
203 &usable_area, false); 96 switch (type) {
204 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], 97 case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
205 &usable_area, false); 98 return output->layers.shell_background;
206 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], 99 case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
207 &usable_area, false); 100 return output->layers.shell_bottom;
208 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], 101 case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
209 &usable_area, false); 102 return output->layers.shell_top;
210 103 case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
211 // Find topmost keyboard interactive layer, if such a layer exists 104 return output->layers.shell_overlay;
212 uint32_t layers_above_shell[] = {
213 ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
214 ZWLR_LAYER_SHELL_V1_LAYER_TOP,
215 };
216 size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
217 struct sway_layer_surface *layer, *topmost = NULL;
218 for (size_t i = 0; i < nlayers; ++i) {
219 wl_list_for_each_reverse(layer,
220 &output->layers[layers_above_shell[i]], link) {
221 if (layer->layer_surface->current.keyboard_interactive &&
222 layer->layer_surface->mapped) {
223 topmost = layer;
224 break;
225 }
226 }
227 if (topmost != NULL) {
228 break;
229 }
230 } 105 }
231 106
232 struct sway_seat *seat; 107 sway_assert(false, "unreachable");
233 wl_list_for_each(seat, &server.input->seats, link) { 108 return NULL;
234 if (topmost != NULL) { 109}
235 seat_set_focus_layer(seat, topmost->layer_surface); 110
236 } else if (seat->focused_layer && 111static struct sway_layer_surface *sway_layer_surface_create(
237 !seat->focused_layer->current.keyboard_interactive) { 112 struct wlr_scene_layer_surface_v1 *scene) {
238 seat_set_focus_layer(seat, NULL); 113 struct sway_layer_surface *surface = calloc(1, sizeof(*surface));
239 } 114 if (!surface) {
115 sway_log(SWAY_ERROR, "Could not allocate a scene_layer surface");
116 return NULL;
240 } 117 }
118
119 struct wlr_scene_tree *popups = wlr_scene_tree_create(root->layers.popup);
120 if (!popups) {
121 sway_log(SWAY_ERROR, "Could not allocate a scene_layer popup node");
122 free(surface);
123 return NULL;
124 }
125
126 surface->desc.relative = &scene->tree->node;
127
128 if (!scene_descriptor_assign(&popups->node,
129 SWAY_SCENE_DESC_POPUP, &surface->desc)) {
130 sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor");
131 wlr_scene_node_destroy(&popups->node);
132 free(surface);
133 return NULL;
134 }
135
136 surface->tree = scene->tree;
137 surface->scene = scene;
138 surface->layer_surface = scene->layer_surface;
139 surface->popups = popups;
140 surface->layer_surface->data = surface;
141
142 return surface;
241} 143}
242 144
243static struct sway_layer_surface *find_mapped_layer_by_client( 145static struct sway_layer_surface *find_mapped_layer_by_client(
244 struct wl_client *client, struct wlr_output *ignore_output) { 146 struct wl_client *client, struct sway_output *ignore_output) {
245 for (int i = 0; i < root->outputs->length; ++i) { 147 for (int i = 0; i < root->outputs->length; ++i) {
246 struct sway_output *output = root->outputs->items[i]; 148 struct sway_output *output = root->outputs->items[i];
247 if (output->wlr_output == ignore_output) { 149 if (output == ignore_output) {
248 continue; 150 continue;
249 } 151 }
250 // For now we'll only check the overlay layer 152 // For now we'll only check the overlay layer
251 struct sway_layer_surface *lsurface; 153 struct wlr_scene_node *node;
252 wl_list_for_each(lsurface, 154 wl_list_for_each (node, &output->layers.shell_overlay->children, link) {
253 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) { 155 struct sway_layer_surface *surface = scene_descriptor_try_get(node,
254 struct wl_resource *resource = lsurface->layer_surface->resource; 156 SWAY_SCENE_DESC_LAYER_SHELL);
157 if (!surface) {
158 continue;
159 }
160
161 struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
162 struct wl_resource *resource = layer_surface->resource;
255 if (wl_resource_get_client(resource) == client 163 if (wl_resource_get_client(resource) == client
256 && lsurface->layer_surface->mapped) { 164 && layer_surface->surface->mapped) {
257 return lsurface; 165 return surface;
258 } 166 }
259 } 167 }
260 } 168 }
@@ -262,293 +170,142 @@ static struct sway_layer_surface *find_mapped_layer_by_client(
262} 170}
263 171
264static void handle_output_destroy(struct wl_listener *listener, void *data) { 172static void handle_output_destroy(struct wl_listener *listener, void *data) {
265 struct sway_layer_surface *sway_layer = 173 struct sway_layer_surface *layer =
266 wl_container_of(listener, sway_layer, output_destroy); 174 wl_container_of(listener, layer, output_destroy);
267 // Determine if this layer is being used by an exclusive client. If it is,
268 // try and find another layer owned by this client to pass focus to.
269 struct sway_seat *seat = input_manager_get_default_seat();
270 struct wl_client *client =
271 wl_resource_get_client(sway_layer->layer_surface->resource);
272 bool set_focus = seat->exclusive_client == client;
273
274 if (set_focus) {
275 struct sway_layer_surface *layer =
276 find_mapped_layer_by_client(client, sway_layer->layer_surface->output);
277 if (layer) {
278 seat_set_focus_layer(seat, layer->layer_surface);
279 }
280 }
281 175
282 wlr_layer_surface_v1_destroy(sway_layer->layer_surface); 176 layer->output = NULL;
177 wlr_scene_node_destroy(&layer->scene->tree->node);
283} 178}
284 179
285static void handle_surface_commit(struct wl_listener *listener, void *data) { 180static void handle_node_destroy(struct wl_listener *listener, void *data) {
286 struct sway_layer_surface *layer = 181 struct sway_layer_surface *layer =
287 wl_container_of(listener, layer, surface_commit); 182 wl_container_of(listener, layer, node_destroy);
288 struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface;
289 struct wlr_output *wlr_output = layer_surface->output;
290 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
291 struct sway_output *output = wlr_output->data;
292 struct wlr_box old_extent = layer->extent;
293
294 bool layer_changed = false;
295 if (layer_surface->current.committed != 0
296 || layer->mapped != layer_surface->mapped) {
297 layer->mapped = layer_surface->mapped;
298 layer_changed = layer->layer != layer_surface->current.layer;
299 if (layer_changed) {
300 wl_list_remove(&layer->link);
301 wl_list_insert(&output->layers[layer_surface->current.layer],
302 &layer->link);
303 layer->layer = layer_surface->current.layer;
304 }
305 arrange_layers(output);
306 }
307
308 wlr_surface_get_extends(layer_surface->surface, &layer->extent);
309 layer->extent.x += layer->geo.x;
310 layer->extent.y += layer->geo.y;
311 183
312 bool extent_changed = 184 // destroy the scene descriptor straight away if it exists, otherwise
313 memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0; 185 // we will try to reflow still considering the destroyed node.
314 if (extent_changed || layer_changed) { 186 scene_descriptor_destroy(&layer->tree->node, SWAY_SCENE_DESC_LAYER_SHELL);
315 output_damage_box(output, &old_extent);
316 output_damage_surface(output, layer->geo.x, layer->geo.y,
317 layer_surface->surface, true);
318 } else {
319 output_damage_surface(output, layer->geo.x, layer->geo.y,
320 layer_surface->surface, false);
321 }
322 187
323 transaction_commit_dirty(); 188 // Determine if this layer is being used by an exclusive client. If it is,
324} 189 // try and find another layer owned by this client to pass focus to.
325 190 struct sway_seat *seat = input_manager_get_default_seat();
326static void unmap(struct sway_layer_surface *sway_layer) { 191 struct wl_client *client =
327 struct sway_seat *seat; 192 wl_resource_get_client(layer->layer_surface->resource);
328 wl_list_for_each(seat, &server.input->seats, link) { 193 if (!server.session_lock.lock) {
329 if (seat->focused_layer == sway_layer->layer_surface) { 194 struct sway_layer_surface *consider_layer =
330 seat_set_focus_layer(seat, NULL); 195 find_mapped_layer_by_client(client, layer->output);
196 if (consider_layer) {
197 seat_set_focus_layer(seat, consider_layer->layer_surface);
331 } 198 }
332 } 199 }
333 200
334 cursor_rebase_all(); 201 if (layer->output) {
335 202 arrange_layers(layer->output);
336 struct wlr_output *wlr_output = sway_layer->layer_surface->output; 203 transaction_commit_dirty();
337 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
338 struct sway_output *output = wlr_output->data;
339 output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
340 sway_layer->layer_surface->surface, true);
341}
342
343static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface);
344
345static void handle_destroy(struct wl_listener *listener, void *data) {
346 struct sway_layer_surface *sway_layer =
347 wl_container_of(listener, sway_layer, destroy);
348 sway_log(SWAY_DEBUG, "Layer surface destroyed (%s)",
349 sway_layer->layer_surface->namespace);
350 if (sway_layer->layer_surface->mapped) {
351 unmap(sway_layer);
352 }
353
354 struct sway_layer_subsurface *subsurface, *subsurface_tmp;
355 wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) {
356 layer_subsurface_destroy(subsurface);
357 } 204 }
358 205
359 wl_list_remove(&sway_layer->link); 206 wlr_scene_node_destroy(&layer->popups->node);
360 wl_list_remove(&sway_layer->destroy.link);
361 wl_list_remove(&sway_layer->map.link);
362 wl_list_remove(&sway_layer->unmap.link);
363 wl_list_remove(&sway_layer->surface_commit.link);
364 wl_list_remove(&sway_layer->new_popup.link);
365 wl_list_remove(&sway_layer->new_subsurface.link);
366
367 struct wlr_output *wlr_output = sway_layer->layer_surface->output;
368 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
369 struct sway_output *output = wlr_output->data;
370 arrange_layers(output);
371 transaction_commit_dirty();
372 wl_list_remove(&sway_layer->output_destroy.link);
373 sway_layer->layer_surface->output = NULL;
374
375 free(sway_layer);
376}
377 207
378static void handle_map(struct wl_listener *listener, void *data) { 208 wl_list_remove(&layer->map.link);
379 struct sway_layer_surface *sway_layer = wl_container_of(listener, 209 wl_list_remove(&layer->unmap.link);
380 sway_layer, map); 210 wl_list_remove(&layer->surface_commit.link);
381 struct wlr_output *wlr_output = sway_layer->layer_surface->output; 211 wl_list_remove(&layer->node_destroy.link);
382 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); 212 wl_list_remove(&layer->output_destroy.link);
383 struct sway_output *output = wlr_output->data;
384 output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
385 sway_layer->layer_surface->surface, true);
386 wlr_surface_send_enter(sway_layer->layer_surface->surface,
387 sway_layer->layer_surface->output);
388 cursor_rebase_all();
389}
390 213
391static void handle_unmap(struct wl_listener *listener, void *data) { 214 layer->layer_surface->data = NULL;
392 struct sway_layer_surface *sway_layer = wl_container_of(
393 listener, sway_layer, unmap);
394 unmap(sway_layer);
395}
396 215
397static void subsurface_damage(struct sway_layer_subsurface *subsurface, 216 free(layer);
398 bool whole) {
399 struct sway_layer_surface *layer = subsurface->layer_surface;
400 struct wlr_output *wlr_output = layer->layer_surface->output;
401 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
402 struct sway_output *output = wlr_output->data;
403 int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
404 int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
405 output_damage_surface(
406 output, ox, oy, subsurface->wlr_subsurface->surface, whole);
407} 217}
408 218
409static void subsurface_handle_unmap(struct wl_listener *listener, void *data) { 219static void handle_surface_commit(struct wl_listener *listener, void *data) {
410 struct sway_layer_subsurface *subsurface = 220 struct sway_layer_surface *surface =
411 wl_container_of(listener, subsurface, unmap); 221 wl_container_of(listener, surface, surface_commit);
412 subsurface_damage(subsurface, true);
413}
414
415static void subsurface_handle_map(struct wl_listener *listener, void *data) {
416 struct sway_layer_subsurface *subsurface =
417 wl_container_of(listener, subsurface, map);
418 subsurface_damage(subsurface, true);
419}
420
421static void subsurface_handle_commit(struct wl_listener *listener, void *data) {
422 struct sway_layer_subsurface *subsurface =
423 wl_container_of(listener, subsurface, commit);
424 subsurface_damage(subsurface, false);
425}
426
427static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) {
428 wl_list_remove(&subsurface->link);
429 wl_list_remove(&subsurface->map.link);
430 wl_list_remove(&subsurface->unmap.link);
431 wl_list_remove(&subsurface->destroy.link);
432 wl_list_remove(&subsurface->commit.link);
433 free(subsurface);
434}
435
436static void subsurface_handle_destroy(struct wl_listener *listener,
437 void *data) {
438 struct sway_layer_subsurface *subsurface =
439 wl_container_of(listener, subsurface, destroy);
440 layer_subsurface_destroy(subsurface);
441}
442 222
443static struct sway_layer_subsurface *create_subsurface( 223 struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
444 struct wlr_subsurface *wlr_subsurface, 224 if (!layer_surface->initialized) {
445 struct sway_layer_surface *layer_surface) { 225 return;
446 struct sway_layer_subsurface *subsurface =
447 calloc(1, sizeof(struct sway_layer_subsurface));
448 if (subsurface == NULL) {
449 return NULL;
450 } 226 }
451 227
452 subsurface->wlr_subsurface = wlr_subsurface; 228 uint32_t committed = layer_surface->current.committed;
453 subsurface->layer_surface = layer_surface; 229 if (committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) {
454 wl_list_insert(&layer_surface->subsurfaces, &subsurface->link); 230 enum zwlr_layer_shell_v1_layer layer_type = layer_surface->current.layer;
455 231 struct wlr_scene_tree *output_layer = sway_layer_get_scene(
456 subsurface->map.notify = subsurface_handle_map; 232 surface->output, layer_type);
457 wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); 233 wlr_scene_node_reparent(&surface->scene->tree->node, output_layer);
458 subsurface->unmap.notify = subsurface_handle_unmap; 234 }
459 wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap);
460 subsurface->destroy.notify = subsurface_handle_destroy;
461 wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
462 subsurface->commit.notify = subsurface_handle_commit;
463 wl_signal_add(&wlr_subsurface->surface->events.commit, &subsurface->commit);
464
465 return subsurface;
466}
467
468static void handle_new_subsurface(struct wl_listener *listener, void *data) {
469 struct sway_layer_surface *sway_layer_surface =
470 wl_container_of(listener, sway_layer_surface, new_subsurface);
471 struct wlr_subsurface *wlr_subsurface = data;
472 create_subsurface(wlr_subsurface, sway_layer_surface);
473}
474
475 235
476static struct sway_layer_surface *popup_get_layer( 236 if (layer_surface->initial_commit || committed || layer_surface->surface->mapped != surface->mapped) {
477 struct sway_layer_popup *popup) { 237 surface->mapped = layer_surface->surface->mapped;
478 while (popup->parent_type == LAYER_PARENT_POPUP) { 238 arrange_layers(surface->output);
479 popup = popup->parent_popup; 239 transaction_commit_dirty();
480 } 240 }
481 return popup->parent_layer;
482} 241}
483 242
484static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { 243static void handle_map(struct wl_listener *listener, void *data) {
485 struct wlr_xdg_popup *popup = layer_popup->wlr_popup; 244 struct sway_layer_surface *surface = wl_container_of(listener,
486 struct wlr_surface *surface = popup->base->surface; 245 surface, map);
487 int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x; 246
488 int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y; 247 struct wlr_layer_surface_v1 *layer_surface =
489 int ox = popup_sx, oy = popup_sy; 248 surface->scene->layer_surface;
490 struct sway_layer_surface *layer; 249
491 while (true) { 250 // focus on new surface
492 if (layer_popup->parent_type == LAYER_PARENT_POPUP) { 251 if (layer_surface->current.keyboard_interactive &&
493 layer_popup = layer_popup->parent_popup; 252 (layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ||
494 ox += layer_popup->wlr_popup->current.geometry.x; 253 layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP)) {
495 oy += layer_popup->wlr_popup->current.geometry.y; 254 struct sway_seat *seat;
496 } else { 255 wl_list_for_each(seat, &server.input->seats, link) {
497 layer = layer_popup->parent_layer; 256 // but only if the currently focused layer has a lower precedence
498 ox += layer->geo.x; 257 if (!seat->focused_layer ||
499 oy += layer->geo.y; 258 seat->focused_layer->current.layer >= layer_surface->current.layer) {
500 break; 259 seat_set_focus_layer(seat, layer_surface);
260 }
501 } 261 }
262 arrange_layers(surface->output);
502 } 263 }
503 struct wlr_output *wlr_output = layer->layer_surface->output;
504 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
505 struct sway_output *output = wlr_output->data;
506 output_damage_surface(output, ox, oy, surface, whole);
507}
508 264
509static void popup_handle_map(struct wl_listener *listener, void *data) { 265 cursor_rebase_all();
510 struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
511 struct sway_layer_surface *layer = popup_get_layer(popup);
512 struct wlr_output *wlr_output = layer->layer_surface->output;
513 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
514 wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
515 popup_damage(popup, true);
516} 266}
517 267
518static void popup_handle_unmap(struct wl_listener *listener, void *data) { 268static void handle_unmap(struct wl_listener *listener, void *data) {
519 struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap); 269 struct sway_layer_surface *surface = wl_container_of(
520 popup_damage(popup, true); 270 listener, surface, unmap);
521} 271 struct sway_seat *seat;
272 wl_list_for_each(seat, &server.input->seats, link) {
273 if (seat->focused_layer == surface->layer_surface) {
274 seat_set_focus_layer(seat, NULL);
275 }
276 }
522 277
523static void popup_handle_commit(struct wl_listener *listener, void *data) { 278 cursor_rebase_all();
524 struct sway_layer_popup *popup = wl_container_of(listener, popup, commit);
525 popup_damage(popup, false);
526} 279}
527 280
528static void popup_handle_destroy(struct wl_listener *listener, void *data) { 281static void popup_handle_destroy(struct wl_listener *listener, void *data) {
529 struct sway_layer_popup *popup = 282 struct sway_layer_popup *popup =
530 wl_container_of(listener, popup, destroy); 283 wl_container_of(listener, popup, destroy);
531 284
532 wl_list_remove(&popup->map.link);
533 wl_list_remove(&popup->unmap.link);
534 wl_list_remove(&popup->destroy.link); 285 wl_list_remove(&popup->destroy.link);
286 wl_list_remove(&popup->new_popup.link);
535 wl_list_remove(&popup->commit.link); 287 wl_list_remove(&popup->commit.link);
536 free(popup); 288 free(popup);
537} 289}
538 290
539static void popup_unconstrain(struct sway_layer_popup *popup) { 291static void popup_unconstrain(struct sway_layer_popup *popup) {
540 struct sway_layer_surface *layer = popup_get_layer(popup);
541 struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; 292 struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
293 struct sway_output *output = popup->toplevel->output;
294
295 // if a client tries to create a popup while we are in the process of destroying
296 // its output, don't crash.
297 if (!output) {
298 return;
299 }
542 300
543 struct wlr_output *wlr_output = layer->layer_surface->output; 301 int lx, ly;
544 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); 302 wlr_scene_node_coords(&popup->toplevel->scene->tree->node, &lx, &ly);
545 struct sway_output *output = wlr_output->data;
546 303
547 // the output box expressed in the coordinate system of the toplevel parent 304 // the output box expressed in the coordinate system of the toplevel parent
548 // of the popup 305 // of the popup
549 struct wlr_box output_toplevel_sx_box = { 306 struct wlr_box output_toplevel_sx_box = {
550 .x = -layer->geo.x, 307 .x = output->lx - lx,
551 .y = -layer->geo.y, 308 .y = output->ly - ly,
552 .width = output->width, 309 .width = output->width,
553 .height = output->height, 310 .height = output->height,
554 }; 311 };
@@ -556,32 +313,38 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
556 wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); 313 wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
557} 314}
558 315
316static void popup_handle_commit(struct wl_listener *listener, void *data) {
317 struct sway_layer_popup *popup = wl_container_of(listener, popup, commit);
318 if (popup->wlr_popup->base->initial_commit) {
319 popup_unconstrain(popup);
320 }
321}
322
559static void popup_handle_new_popup(struct wl_listener *listener, void *data); 323static void popup_handle_new_popup(struct wl_listener *listener, void *data);
560 324
561static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, 325static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
562 enum layer_parent parent_type, void *parent) { 326 struct sway_layer_surface *toplevel, struct wlr_scene_tree *parent) {
563 struct sway_layer_popup *popup = 327 struct sway_layer_popup *popup = calloc(1, sizeof(*popup));
564 calloc(1, sizeof(struct sway_layer_popup));
565 if (popup == NULL) { 328 if (popup == NULL) {
566 return NULL; 329 return NULL;
567 } 330 }
568 331
332 popup->toplevel = toplevel;
569 popup->wlr_popup = wlr_popup; 333 popup->wlr_popup = wlr_popup;
570 popup->parent_type = parent_type; 334 popup->scene = wlr_scene_xdg_surface_create(parent,
571 popup->parent_layer = parent; 335 wlr_popup->base);
336
337 if (!popup->scene) {
338 free(popup);
339 return NULL;
340 }
572 341
573 popup->map.notify = popup_handle_map;
574 wl_signal_add(&wlr_popup->base->events.map, &popup->map);
575 popup->unmap.notify = popup_handle_unmap;
576 wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap);
577 popup->destroy.notify = popup_handle_destroy; 342 popup->destroy.notify = popup_handle_destroy;
578 wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); 343 wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
579 popup->commit.notify = popup_handle_commit;
580 wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
581 popup->new_popup.notify = popup_handle_new_popup; 344 popup->new_popup.notify = popup_handle_new_popup;
582 wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); 345 wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
583 346 popup->commit.notify = popup_handle_commit;
584 popup_unconstrain(popup); 347 wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
585 348
586 return popup; 349 return popup;
587} 350}
@@ -590,19 +353,14 @@ static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
590 struct sway_layer_popup *sway_layer_popup = 353 struct sway_layer_popup *sway_layer_popup =
591 wl_container_of(listener, sway_layer_popup, new_popup); 354 wl_container_of(listener, sway_layer_popup, new_popup);
592 struct wlr_xdg_popup *wlr_popup = data; 355 struct wlr_xdg_popup *wlr_popup = data;
593 create_popup(wlr_popup, LAYER_PARENT_POPUP, sway_layer_popup); 356 create_popup(wlr_popup, sway_layer_popup->toplevel, sway_layer_popup->scene);
594} 357}
595 358
596static void handle_new_popup(struct wl_listener *listener, void *data) { 359static void handle_new_popup(struct wl_listener *listener, void *data) {
597 struct sway_layer_surface *sway_layer_surface = 360 struct sway_layer_surface *sway_layer_surface =
598 wl_container_of(listener, sway_layer_surface, new_popup); 361 wl_container_of(listener, sway_layer_surface, new_popup);
599 struct wlr_xdg_popup *wlr_popup = data; 362 struct wlr_xdg_popup *wlr_popup = data;
600 create_popup(wlr_popup, LAYER_PARENT_LAYER, sway_layer_surface); 363 create_popup(wlr_popup, sway_layer_surface, sway_layer_surface->popups);
601}
602
603struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
604 struct wlr_layer_surface_v1 *layer_surface) {
605 return layer_surface->data;
606} 364}
607 365
608void handle_layer_shell_surface(struct wl_listener *listener, void *data) { 366void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
@@ -634,10 +392,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
634 sway_log(SWAY_ERROR, 392 sway_log(SWAY_ERROR,
635 "no output to auto-assign layer surface '%s' to", 393 "no output to auto-assign layer surface '%s' to",
636 layer_surface->namespace); 394 layer_surface->namespace);
637 // Note that layer_surface->output can be NULL
638 // here, but none of our destroy callbacks are
639 // registered yet so we don't have to make them
640 // handle that case.
641 wlr_layer_surface_v1_destroy(layer_surface); 395 wlr_layer_surface_v1_destroy(layer_surface);
642 return; 396 return;
643 } 397 }
@@ -646,44 +400,51 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
646 layer_surface->output = output->wlr_output; 400 layer_surface->output = output->wlr_output;
647 } 401 }
648 402
649 struct sway_layer_surface *sway_layer = 403 struct sway_output *output = layer_surface->output->data;
650 calloc(1, sizeof(struct sway_layer_surface)); 404
651 if (!sway_layer) { 405 enum zwlr_layer_shell_v1_layer layer_type = layer_surface->pending.layer;
406 struct wlr_scene_tree *output_layer = sway_layer_get_scene(
407 output, layer_type);
408 struct wlr_scene_layer_surface_v1 *scene_surface =
409 wlr_scene_layer_surface_v1_create(output_layer, layer_surface);
410 if (!scene_surface) {
411 sway_log(SWAY_ERROR, "Could not allocate a layer_surface_v1");
412 return;
413 }
414
415 struct sway_layer_surface *surface =
416 sway_layer_surface_create(scene_surface);
417 if (!surface) {
418 wlr_layer_surface_v1_destroy(layer_surface);
419
420 sway_log(SWAY_ERROR, "Could not allocate a sway_layer_surface");
652 return; 421 return;
653 } 422 }
654 423
655 wl_list_init(&sway_layer->subsurfaces); 424 if (!scene_descriptor_assign(&scene_surface->tree->node,
425 SWAY_SCENE_DESC_LAYER_SHELL, surface)) {
426 sway_log(SWAY_ERROR, "Failed to allocate a layer surface descriptor");
427 // destroying the layer_surface will also destroy its corresponding
428 // scene node
429 wlr_layer_surface_v1_destroy(layer_surface);
430 return;
431 }
656 432
657 sway_layer->surface_commit.notify = handle_surface_commit; 433 surface->output = output;
658 wl_signal_add(&layer_surface->surface->events.commit,
659 &sway_layer->surface_commit);
660
661 sway_layer->destroy.notify = handle_destroy;
662 wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy);
663 sway_layer->map.notify = handle_map;
664 wl_signal_add(&layer_surface->events.map, &sway_layer->map);
665 sway_layer->unmap.notify = handle_unmap;
666 wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap);
667 sway_layer->new_popup.notify = handle_new_popup;
668 wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup);
669 sway_layer->new_subsurface.notify = handle_new_subsurface;
670 wl_signal_add(&layer_surface->surface->events.new_subsurface,
671 &sway_layer->new_subsurface);
672
673 sway_layer->layer_surface = layer_surface;
674 layer_surface->data = sway_layer;
675 434
676 struct sway_output *output = layer_surface->output->data; 435 surface->surface_commit.notify = handle_surface_commit;
677 sway_layer->output_destroy.notify = handle_output_destroy; 436 wl_signal_add(&layer_surface->surface->events.commit,
678 wl_signal_add(&output->events.disable, &sway_layer->output_destroy); 437 &surface->surface_commit);
679 438 surface->map.notify = handle_map;
680 wl_list_insert(&output->layers[layer_surface->pending.layer], 439 wl_signal_add(&layer_surface->surface->events.map, &surface->map);
681 &sway_layer->link); 440 surface->unmap.notify = handle_unmap;
682 441 wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap);
683 // Temporarily set the layer's current state to pending 442 surface->new_popup.notify = handle_new_popup;
684 // So that we can easily arrange it 443 wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
685 struct wlr_layer_surface_v1_state old_state = layer_surface->current; 444
686 layer_surface->current = layer_surface->pending; 445 surface->output_destroy.notify = handle_output_destroy;
687 arrange_layers(output); 446 wl_signal_add(&output->events.disable, &surface->output_destroy);
688 layer_surface->current = old_state; 447
448 surface->node_destroy.notify = handle_node_destroy;
449 wl_signal_add(&scene_surface->tree->node.events.destroy, &surface->node_destroy);
689} 450}