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