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