diff options
Diffstat (limited to 'sway/desktop/layer_shell.c')
-rw-r--r-- | sway/desktop/layer_shell.c | 773 |
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 | ||
20 | static void apply_exclusive(struct wlr_box *usable_area, | 22 | struct 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 | ||
93 | static void arrange_layer(struct sway_output *output, struct wl_list *list, | 55 | static 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 | 94 | static 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 && | 111 | static 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 | ||
243 | static struct sway_layer_surface *find_mapped_layer_by_client( | 145 | static 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 | ||
264 | static void handle_output_destroy(struct wl_listener *listener, void *data) { | 172 | static 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 | ||
285 | static void handle_surface_commit(struct wl_listener *listener, void *data) { | 180 | static 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(); | |
326 | static 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 | |||
343 | static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface); | ||
344 | |||
345 | static 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 | ||
378 | static 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 | ||
391 | static 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 | ||
397 | static 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 | ||
409 | static void subsurface_handle_unmap(struct wl_listener *listener, void *data) { | 219 | static 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 | |||
415 | static 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 | |||
421 | static 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 | |||
427 | static 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 | |||
436 | static 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 | ||
443 | static 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 | |||
468 | static 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 | ||
476 | static 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 | ||
484 | static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { | 243 | static 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 | ||
509 | static 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 | ||
518 | static void popup_handle_unmap(struct wl_listener *listener, void *data) { | 268 | static 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 | ||
523 | static 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 | ||
528 | static void popup_handle_destroy(struct wl_listener *listener, void *data) { | 281 | static 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 | ||
539 | static void popup_unconstrain(struct sway_layer_popup *popup) { | 291 | static 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 | ||
316 | static 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 | |||
559 | static void popup_handle_new_popup(struct wl_listener *listener, void *data); | 323 | static void popup_handle_new_popup(struct wl_listener *listener, void *data); |
560 | 324 | ||
561 | static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, | 325 | static 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 | ||
596 | static void handle_new_popup(struct wl_listener *listener, void *data) { | 359 | static 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 | |||
603 | struct 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 | ||
608 | void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | 366 | void 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 | } |