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