diff options
Diffstat (limited to 'sway/desktop')
-rw-r--r-- | sway/desktop/desktop.c | 9 | ||||
-rw-r--r-- | sway/desktop/idle_inhibit_v1.c | 16 | ||||
-rw-r--r-- | sway/desktop/layer_shell.c | 186 | ||||
-rw-r--r-- | sway/desktop/output.c | 275 | ||||
-rw-r--r-- | sway/desktop/render.c | 211 | ||||
-rw-r--r-- | sway/desktop/surface.c | 2 | ||||
-rw-r--r-- | sway/desktop/transaction.c | 253 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 185 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 96 |
9 files changed, 659 insertions, 574 deletions
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c index ec45d80a..c8d4502c 100644 --- a/sway/desktop/desktop.c +++ b/sway/desktop/desktop.c | |||
@@ -6,10 +6,11 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, | |||
6 | bool whole) { | 6 | bool whole) { |
7 | for (int i = 0; i < root->outputs->length; ++i) { | 7 | for (int i = 0; i < root->outputs->length; ++i) { |
8 | struct sway_output *output = root->outputs->items[i]; | 8 | struct sway_output *output = root->outputs->items[i]; |
9 | struct wlr_box *output_box = wlr_output_layout_get_box( | 9 | struct wlr_box output_box; |
10 | root->output_layout, output->wlr_output); | 10 | wlr_output_layout_get_box(root->output_layout, |
11 | output_damage_surface(output, lx - output_box->x, | 11 | output->wlr_output, &output_box); |
12 | ly - output_box->y, surface, whole); | 12 | output_damage_surface(output, lx - output_box.x, |
13 | ly - output_box.y, surface, whole); | ||
13 | } | 14 | } |
14 | } | 15 | } |
15 | 16 | ||
diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index a5cfd5b2..82353038 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c | |||
@@ -36,7 +36,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { | |||
36 | 36 | ||
37 | inhibitor->manager = manager; | 37 | inhibitor->manager = manager; |
38 | inhibitor->mode = INHIBIT_IDLE_APPLICATION; | 38 | inhibitor->mode = INHIBIT_IDLE_APPLICATION; |
39 | inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface); | 39 | inhibitor->wlr_inhibitor = wlr_inhibitor; |
40 | wl_list_insert(&manager->inhibitors, &inhibitor->link); | 40 | wl_list_insert(&manager->inhibitors, &inhibitor->link); |
41 | 41 | ||
42 | inhibitor->destroy.notify = handle_destroy; | 42 | inhibitor->destroy.notify = handle_destroy; |
@@ -69,8 +69,8 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( | |||
69 | struct sway_idle_inhibitor_v1 *inhibitor; | 69 | struct sway_idle_inhibitor_v1 *inhibitor; |
70 | wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, | 70 | wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, |
71 | link) { | 71 | link) { |
72 | if (inhibitor->view == view && | 72 | if (inhibitor->mode != INHIBIT_IDLE_APPLICATION && |
73 | inhibitor->mode != INHIBIT_IDLE_APPLICATION) { | 73 | inhibitor->view == view) { |
74 | return inhibitor; | 74 | return inhibitor; |
75 | } | 75 | } |
76 | } | 76 | } |
@@ -82,8 +82,8 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_vi | |||
82 | struct sway_idle_inhibitor_v1 *inhibitor; | 82 | struct sway_idle_inhibitor_v1 *inhibitor; |
83 | wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, | 83 | wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, |
84 | link) { | 84 | link) { |
85 | if (inhibitor->view == view && | 85 | if (inhibitor->mode == INHIBIT_IDLE_APPLICATION && |
86 | inhibitor->mode == INHIBIT_IDLE_APPLICATION) { | 86 | view_from_wlr_surface(inhibitor->wlr_inhibitor->surface) == view) { |
87 | return inhibitor; | 87 | return inhibitor; |
88 | } | 88 | } |
89 | } | 89 | } |
@@ -104,10 +104,10 @@ void sway_idle_inhibit_v1_user_inhibitor_destroy( | |||
104 | 104 | ||
105 | bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { | 105 | bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { |
106 | switch (inhibitor->mode) { | 106 | switch (inhibitor->mode) { |
107 | case INHIBIT_IDLE_APPLICATION: | 107 | case INHIBIT_IDLE_APPLICATION:; |
108 | // If there is no view associated with the inhibitor, assume visible | 108 | // If there is no view associated with the inhibitor, assume visible |
109 | return !inhibitor->view || !inhibitor->view->container || | 109 | struct sway_view *view = view_from_wlr_surface(inhibitor->wlr_inhibitor->surface); |
110 | view_is_visible(inhibitor->view); | 110 | return !view || !view->container || view_is_visible(view); |
111 | case INHIBIT_IDLE_FOCUS:; | 111 | case INHIBIT_IDLE_FOCUS:; |
112 | struct sway_seat *seat = NULL; | 112 | struct sway_seat *seat = NULL; |
113 | wl_list_for_each(seat, &server.input->seats, link) { | 113 | wl_list_for_each(seat, &server.input->seats, link) { |
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index d4ca4fb4..d44d6338 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c | |||
@@ -2,10 +2,10 @@ | |||
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> | 6 | #include <wlr/types/wlr_output_damage.h> |
8 | #include <wlr/types/wlr_output.h> | 7 | #include <wlr/types/wlr_output.h> |
8 | #include <wlr/types/wlr_subcompositor.h> | ||
9 | #include "log.h" | 9 | #include "log.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" |
@@ -115,9 +115,10 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list, | |||
115 | // Horizontal axis | 115 | // Horizontal axis |
116 | const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | 116 | const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
117 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; | 117 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; |
118 | if ((state->anchor & both_horiz) && box.width == 0) { | 118 | if (box.width == 0) { |
119 | box.x = bounds.x; | 119 | box.x = bounds.x; |
120 | box.width = bounds.width; | 120 | } else if ((state->anchor & both_horiz) == both_horiz) { |
121 | box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); | ||
121 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { | 122 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { |
122 | box.x = bounds.x; | 123 | box.x = bounds.x; |
123 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { | 124 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { |
@@ -128,9 +129,10 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list, | |||
128 | // Vertical axis | 129 | // Vertical axis |
129 | const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | 130 | const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
130 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; | 131 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; |
131 | if ((state->anchor & both_vert) && box.height == 0) { | 132 | if (box.height == 0) { |
132 | box.y = bounds.y; | 133 | box.y = bounds.y; |
133 | box.height = bounds.height; | 134 | } else if ((state->anchor & both_vert) == both_vert) { |
135 | box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); | ||
134 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { | 136 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { |
135 | box.y = bounds.y; | 137 | box.y = bounds.y; |
136 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { | 138 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { |
@@ -139,25 +141,30 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list, | |||
139 | box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); | 141 | box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); |
140 | } | 142 | } |
141 | // Margin | 143 | // Margin |
142 | if ((state->anchor & both_horiz) == both_horiz) { | 144 | if (box.width == 0) { |
143 | box.x += state->margin.left; | 145 | box.x += state->margin.left; |
144 | box.width -= state->margin.left + state->margin.right; | 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 | ||
145 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { | 150 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { |
146 | box.x += state->margin.left; | 151 | box.x += state->margin.left; |
147 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { | 152 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { |
148 | box.x -= state->margin.right; | 153 | box.x -= state->margin.right; |
149 | } | 154 | } |
150 | if ((state->anchor & both_vert) == both_vert) { | 155 | if (box.height == 0) { |
151 | box.y += state->margin.top; | 156 | box.y += state->margin.top; |
152 | box.height -= state->margin.top + state->margin.bottom; | 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 | ||
153 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { | 161 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { |
154 | box.y += state->margin.top; | 162 | box.y += state->margin.top; |
155 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { | 163 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { |
156 | box.y -= state->margin.bottom; | 164 | box.y -= state->margin.bottom; |
157 | } | 165 | } |
158 | if (box.width < 0 || box.height < 0) { | 166 | if (!sway_assert(box.width >= 0 && box.height >= 0, |
159 | // TODO: Bubble up a protocol error? | 167 | "Expected layer surface to have positive size")) { |
160 | wlr_layer_surface_v1_close(layer); | ||
161 | continue; | 168 | continue; |
162 | } | 169 | } |
163 | // Apply | 170 | // Apply |
@@ -191,7 +198,7 @@ void arrange_layers(struct sway_output *output) { | |||
191 | arrange_output(output); | 198 | arrange_output(output); |
192 | } | 199 | } |
193 | 200 | ||
194 | // Arrange non-exlusive surfaces from top->bottom | 201 | // Arrange non-exclusive surfaces from top->bottom |
195 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], | 202 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], |
196 | &usable_area, false); | 203 | &usable_area, false); |
197 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], | 204 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], |
@@ -264,10 +271,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) { | |||
264 | wl_resource_get_client(sway_layer->layer_surface->resource); | 271 | wl_resource_get_client(sway_layer->layer_surface->resource); |
265 | bool set_focus = seat->exclusive_client == client; | 272 | bool set_focus = seat->exclusive_client == client; |
266 | 273 | ||
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) { | 274 | if (set_focus) { |
272 | struct sway_layer_surface *layer = | 275 | struct sway_layer_surface *layer = |
273 | find_mapped_layer_by_client(client, sway_layer->layer_surface->output); | 276 | find_mapped_layer_by_client(client, sway_layer->layer_surface->output); |
@@ -276,8 +279,7 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) { | |||
276 | } | 279 | } |
277 | } | 280 | } |
278 | 281 | ||
279 | sway_layer->layer_surface->output = NULL; | 282 | wlr_layer_surface_v1_destroy(sway_layer->layer_surface); |
280 | wlr_layer_surface_v1_close(sway_layer->layer_surface); | ||
281 | } | 283 | } |
282 | 284 | ||
283 | static void handle_surface_commit(struct wl_listener *listener, void *data) { | 285 | static void handle_surface_commit(struct wl_listener *listener, void *data) { |
@@ -285,26 +287,32 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { | |||
285 | wl_container_of(listener, layer, surface_commit); | 287 | wl_container_of(listener, layer, surface_commit); |
286 | struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; | 288 | struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; |
287 | struct wlr_output *wlr_output = layer_surface->output; | 289 | struct wlr_output *wlr_output = layer_surface->output; |
288 | if (wlr_output == NULL) { | 290 | sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); |
289 | return; | 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); | ||
290 | } | 306 | } |
291 | 307 | ||
292 | struct sway_output *output = wlr_output->data; | 308 | wlr_surface_get_extends(layer_surface->surface, &layer->extent); |
293 | struct wlr_box old_geo = layer->geo; | 309 | layer->extent.x += layer->geo.x; |
294 | arrange_layers(output); | 310 | layer->extent.y += layer->geo.y; |
295 | 311 | ||
296 | bool geo_changed = | 312 | bool extent_changed = |
297 | memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0; | 313 | memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0; |
298 | bool layer_changed = layer->layer != layer_surface->current.layer; | 314 | if (extent_changed || layer_changed) { |
299 | if (layer_changed) { | 315 | output_damage_box(output, &old_extent); |
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, | 316 | output_damage_surface(output, layer->geo.x, layer->geo.y, |
309 | layer_surface->surface, true); | 317 | layer_surface->surface, true); |
310 | } else { | 318 | } else { |
@@ -326,17 +334,14 @@ static void unmap(struct sway_layer_surface *sway_layer) { | |||
326 | cursor_rebase_all(); | 334 | cursor_rebase_all(); |
327 | 335 | ||
328 | struct wlr_output *wlr_output = sway_layer->layer_surface->output; | 336 | struct wlr_output *wlr_output = sway_layer->layer_surface->output; |
329 | if (wlr_output == NULL) { | 337 | sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); |
330 | return; | ||
331 | } | ||
332 | struct sway_output *output = wlr_output->data; | 338 | 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, | 339 | output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, |
337 | sway_layer->layer_surface->surface, true); | 340 | sway_layer->layer_surface->surface, true); |
338 | } | 341 | } |
339 | 342 | ||
343 | static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface); | ||
344 | |||
340 | static void handle_destroy(struct wl_listener *listener, void *data) { | 345 | static void handle_destroy(struct wl_listener *listener, void *data) { |
341 | struct sway_layer_surface *sway_layer = | 346 | struct sway_layer_surface *sway_layer = |
342 | wl_container_of(listener, sway_layer, destroy); | 347 | wl_container_of(listener, sway_layer, destroy); |
@@ -345,6 +350,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
345 | if (sway_layer->layer_surface->mapped) { | 350 | if (sway_layer->layer_surface->mapped) { |
346 | unmap(sway_layer); | 351 | unmap(sway_layer); |
347 | } | 352 | } |
353 | |||
354 | struct sway_layer_subsurface *subsurface, *subsurface_tmp; | ||
355 | wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) { | ||
356 | layer_subsurface_destroy(subsurface); | ||
357 | } | ||
358 | |||
348 | wl_list_remove(&sway_layer->link); | 359 | wl_list_remove(&sway_layer->link); |
349 | wl_list_remove(&sway_layer->destroy.link); | 360 | wl_list_remove(&sway_layer->destroy.link); |
350 | wl_list_remove(&sway_layer->map.link); | 361 | wl_list_remove(&sway_layer->map.link); |
@@ -352,22 +363,24 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
352 | wl_list_remove(&sway_layer->surface_commit.link); | 363 | wl_list_remove(&sway_layer->surface_commit.link); |
353 | wl_list_remove(&sway_layer->new_popup.link); | 364 | wl_list_remove(&sway_layer->new_popup.link); |
354 | wl_list_remove(&sway_layer->new_subsurface.link); | 365 | wl_list_remove(&sway_layer->new_subsurface.link); |
355 | if (sway_layer->layer_surface->output != NULL) { | 366 | |
356 | struct sway_output *output = sway_layer->layer_surface->output->data; | 367 | struct wlr_output *wlr_output = sway_layer->layer_surface->output; |
357 | if (output != NULL) { | 368 | sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); |
358 | arrange_layers(output); | 369 | struct sway_output *output = wlr_output->data; |
359 | transaction_commit_dirty(); | 370 | arrange_layers(output); |
360 | } | 371 | transaction_commit_dirty(); |
361 | wl_list_remove(&sway_layer->output_destroy.link); | 372 | wl_list_remove(&sway_layer->output_destroy.link); |
362 | sway_layer->layer_surface->output = NULL; | 373 | sway_layer->layer_surface->output = NULL; |
363 | } | 374 | |
364 | free(sway_layer); | 375 | free(sway_layer); |
365 | } | 376 | } |
366 | 377 | ||
367 | static void handle_map(struct wl_listener *listener, void *data) { | 378 | static void handle_map(struct wl_listener *listener, void *data) { |
368 | struct sway_layer_surface *sway_layer = wl_container_of(listener, | 379 | struct sway_layer_surface *sway_layer = wl_container_of(listener, |
369 | sway_layer, map); | 380 | sway_layer, map); |
370 | struct sway_output *output = sway_layer->layer_surface->output->data; | 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; | ||
371 | output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, | 384 | output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, |
372 | sway_layer->layer_surface->surface, true); | 385 | sway_layer->layer_surface->surface, true); |
373 | wlr_surface_send_enter(sway_layer->layer_surface->surface, | 386 | wlr_surface_send_enter(sway_layer->layer_surface->surface, |
@@ -385,9 +398,7 @@ static void subsurface_damage(struct sway_layer_subsurface *subsurface, | |||
385 | bool whole) { | 398 | bool whole) { |
386 | struct sway_layer_surface *layer = subsurface->layer_surface; | 399 | struct sway_layer_surface *layer = subsurface->layer_surface; |
387 | struct wlr_output *wlr_output = layer->layer_surface->output; | 400 | struct wlr_output *wlr_output = layer->layer_surface->output; |
388 | if (!wlr_output) { | 401 | sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); |
389 | return; | ||
390 | } | ||
391 | struct sway_output *output = wlr_output->data; | 402 | struct sway_output *output = wlr_output->data; |
392 | int ox = subsurface->wlr_subsurface->current.x + layer->geo.x; | 403 | int ox = subsurface->wlr_subsurface->current.x + layer->geo.x; |
393 | int oy = subsurface->wlr_subsurface->current.y + layer->geo.y; | 404 | int oy = subsurface->wlr_subsurface->current.y + layer->geo.y; |
@@ -413,11 +424,8 @@ static void subsurface_handle_commit(struct wl_listener *listener, void *data) { | |||
413 | subsurface_damage(subsurface, false); | 424 | subsurface_damage(subsurface, false); |
414 | } | 425 | } |
415 | 426 | ||
416 | static void subsurface_handle_destroy(struct wl_listener *listener, | 427 | static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) { |
417 | void *data) { | 428 | wl_list_remove(&subsurface->link); |
418 | struct sway_layer_subsurface *subsurface = | ||
419 | wl_container_of(listener, subsurface, destroy); | ||
420 | |||
421 | wl_list_remove(&subsurface->map.link); | 429 | wl_list_remove(&subsurface->map.link); |
422 | wl_list_remove(&subsurface->unmap.link); | 430 | wl_list_remove(&subsurface->unmap.link); |
423 | wl_list_remove(&subsurface->destroy.link); | 431 | wl_list_remove(&subsurface->destroy.link); |
@@ -425,17 +433,25 @@ static void subsurface_handle_destroy(struct wl_listener *listener, | |||
425 | free(subsurface); | 433 | free(subsurface); |
426 | } | 434 | } |
427 | 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 | |||
428 | static struct sway_layer_subsurface *create_subsurface( | 443 | static struct sway_layer_subsurface *create_subsurface( |
429 | struct wlr_subsurface *wlr_subsurface, | 444 | struct wlr_subsurface *wlr_subsurface, |
430 | struct sway_layer_surface *layer_surface) { | 445 | struct sway_layer_surface *layer_surface) { |
431 | struct sway_layer_subsurface *subsurface = | 446 | struct sway_layer_subsurface *subsurface = |
432 | calloc(1, sizeof(struct sway_layer_surface)); | 447 | calloc(1, sizeof(struct sway_layer_subsurface)); |
433 | if (subsurface == NULL) { | 448 | if (subsurface == NULL) { |
434 | return NULL; | 449 | return NULL; |
435 | } | 450 | } |
436 | 451 | ||
437 | subsurface->wlr_subsurface = wlr_subsurface; | 452 | subsurface->wlr_subsurface = wlr_subsurface; |
438 | subsurface->layer_surface = layer_surface; | 453 | subsurface->layer_surface = layer_surface; |
454 | wl_list_insert(&layer_surface->subsurfaces, &subsurface->link); | ||
439 | 455 | ||
440 | subsurface->map.notify = subsurface_handle_map; | 456 | subsurface->map.notify = subsurface_handle_map; |
441 | wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); | 457 | wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); |
@@ -468,15 +484,15 @@ static struct sway_layer_surface *popup_get_layer( | |||
468 | static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { | 484 | static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { |
469 | struct wlr_xdg_popup *popup = layer_popup->wlr_popup; | 485 | struct wlr_xdg_popup *popup = layer_popup->wlr_popup; |
470 | struct wlr_surface *surface = popup->base->surface; | 486 | struct wlr_surface *surface = popup->base->surface; |
471 | int popup_sx = popup->geometry.x - popup->base->geometry.x; | 487 | int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x; |
472 | int popup_sy = popup->geometry.y - popup->base->geometry.y; | 488 | int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y; |
473 | int ox = popup_sx, oy = popup_sy; | 489 | int ox = popup_sx, oy = popup_sy; |
474 | struct sway_layer_surface *layer; | 490 | struct sway_layer_surface *layer; |
475 | while (true) { | 491 | while (true) { |
476 | if (layer_popup->parent_type == LAYER_PARENT_POPUP) { | 492 | if (layer_popup->parent_type == LAYER_PARENT_POPUP) { |
477 | layer_popup = layer_popup->parent_popup; | 493 | layer_popup = layer_popup->parent_popup; |
478 | ox += layer_popup->wlr_popup->geometry.x; | 494 | ox += layer_popup->wlr_popup->current.geometry.x; |
479 | oy += layer_popup->wlr_popup->geometry.y; | 495 | oy += layer_popup->wlr_popup->current.geometry.y; |
480 | } else { | 496 | } else { |
481 | layer = layer_popup->parent_layer; | 497 | layer = layer_popup->parent_layer; |
482 | ox += layer->geo.x; | 498 | ox += layer->geo.x; |
@@ -485,6 +501,7 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { | |||
485 | } | 501 | } |
486 | } | 502 | } |
487 | struct wlr_output *wlr_output = layer->layer_surface->output; | 503 | struct wlr_output *wlr_output = layer->layer_surface->output; |
504 | sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); | ||
488 | struct sway_output *output = wlr_output->data; | 505 | struct sway_output *output = wlr_output->data; |
489 | output_damage_surface(output, ox, oy, surface, whole); | 506 | output_damage_surface(output, ox, oy, surface, whole); |
490 | } | 507 | } |
@@ -493,6 +510,7 @@ static void popup_handle_map(struct wl_listener *listener, void *data) { | |||
493 | struct sway_layer_popup *popup = wl_container_of(listener, popup, map); | 510 | struct sway_layer_popup *popup = wl_container_of(listener, popup, map); |
494 | struct sway_layer_surface *layer = popup_get_layer(popup); | 511 | struct sway_layer_surface *layer = popup_get_layer(popup); |
495 | struct wlr_output *wlr_output = layer->layer_surface->output; | 512 | struct wlr_output *wlr_output = layer->layer_surface->output; |
513 | sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); | ||
496 | wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output); | 514 | wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output); |
497 | popup_damage(popup, true); | 515 | popup_damage(popup, true); |
498 | } | 516 | } |
@@ -522,7 +540,9 @@ static void popup_unconstrain(struct sway_layer_popup *popup) { | |||
522 | struct sway_layer_surface *layer = popup_get_layer(popup); | 540 | struct sway_layer_surface *layer = popup_get_layer(popup); |
523 | struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; | 541 | struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; |
524 | 542 | ||
525 | struct sway_output *output = layer->layer_surface->output->data; | 543 | struct wlr_output *wlr_output = layer->layer_surface->output; |
544 | sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); | ||
545 | struct sway_output *output = wlr_output->data; | ||
526 | 546 | ||
527 | // the output box expressed in the coordinate system of the toplevel parent | 547 | // the output box expressed in the coordinate system of the toplevel parent |
528 | // of the popup | 548 | // of the popup |
@@ -590,14 +610,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 | 610 | sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32 |
591 | " size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",", | 611 | " size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",", |
592 | layer_surface->namespace, | 612 | layer_surface->namespace, |
593 | layer_surface->client_pending.layer, | 613 | layer_surface->pending.layer, |
594 | layer_surface->client_pending.anchor, | 614 | layer_surface->pending.anchor, |
595 | layer_surface->client_pending.desired_width, | 615 | layer_surface->pending.desired_width, |
596 | layer_surface->client_pending.desired_height, | 616 | layer_surface->pending.desired_height, |
597 | layer_surface->client_pending.margin.top, | 617 | layer_surface->pending.margin.top, |
598 | layer_surface->client_pending.margin.right, | 618 | layer_surface->pending.margin.right, |
599 | layer_surface->client_pending.margin.bottom, | 619 | layer_surface->pending.margin.bottom, |
600 | layer_surface->client_pending.margin.left); | 620 | layer_surface->pending.margin.left); |
601 | 621 | ||
602 | if (!layer_surface->output) { | 622 | if (!layer_surface->output) { |
603 | // Assign last active output | 623 | // Assign last active output |
@@ -609,12 +629,16 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
609 | output = ws->output; | 629 | output = ws->output; |
610 | } | 630 | } |
611 | } | 631 | } |
612 | if (!output || output == root->noop_output) { | 632 | if (!output || output == root->fallback_output) { |
613 | if (!root->outputs->length) { | 633 | if (!root->outputs->length) { |
614 | sway_log(SWAY_ERROR, | 634 | sway_log(SWAY_ERROR, |
615 | "no output to auto-assign layer surface '%s' to", | 635 | "no output to auto-assign layer surface '%s' to", |
616 | layer_surface->namespace); | 636 | layer_surface->namespace); |
617 | wlr_layer_surface_v1_close(layer_surface); | 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); | ||
618 | return; | 642 | return; |
619 | } | 643 | } |
620 | output = root->outputs->items[0]; | 644 | output = root->outputs->items[0]; |
@@ -628,6 +652,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
628 | return; | 652 | return; |
629 | } | 653 | } |
630 | 654 | ||
655 | wl_list_init(&sway_layer->subsurfaces); | ||
656 | |||
631 | sway_layer->surface_commit.notify = handle_surface_commit; | 657 | sway_layer->surface_commit.notify = handle_surface_commit; |
632 | wl_signal_add(&layer_surface->surface->events.commit, | 658 | wl_signal_add(&layer_surface->surface->events.commit, |
633 | &sway_layer->surface_commit); | 659 | &sway_layer->surface_commit); |
@@ -649,15 +675,15 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
649 | 675 | ||
650 | struct sway_output *output = layer_surface->output->data; | 676 | struct sway_output *output = layer_surface->output->data; |
651 | sway_layer->output_destroy.notify = handle_output_destroy; | 677 | sway_layer->output_destroy.notify = handle_output_destroy; |
652 | wl_signal_add(&output->events.destroy, &sway_layer->output_destroy); | 678 | wl_signal_add(&output->events.disable, &sway_layer->output_destroy); |
653 | 679 | ||
654 | wl_list_insert(&output->layers[layer_surface->client_pending.layer], | 680 | wl_list_insert(&output->layers[layer_surface->pending.layer], |
655 | &sway_layer->link); | 681 | &sway_layer->link); |
656 | 682 | ||
657 | // Temporarily set the layer's current state to client_pending | 683 | // Temporarily set the layer's current state to pending |
658 | // So that we can easily arrange it | 684 | // So that we can easily arrange it |
659 | struct wlr_layer_surface_v1_state old_state = layer_surface->current; | 685 | struct wlr_layer_surface_v1_state old_state = layer_surface->current; |
660 | layer_surface->current = layer_surface->client_pending; | 686 | layer_surface->current = layer_surface->pending; |
661 | arrange_layers(output); | 687 | arrange_layers(output); |
662 | layer_surface->current = old_state; | 688 | layer_surface->current = old_state; |
663 | } | 689 | } |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 5edc8f96..7bb9dab2 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -4,15 +4,17 @@ | |||
4 | #include <strings.h> | 4 | #include <strings.h> |
5 | #include <time.h> | 5 | #include <time.h> |
6 | #include <wayland-server-core.h> | 6 | #include <wayland-server-core.h> |
7 | #include <wlr/backend/drm.h> | ||
8 | #include <wlr/backend/headless.h> | ||
7 | #include <wlr/render/wlr_renderer.h> | 9 | #include <wlr/render/wlr_renderer.h> |
8 | #include <wlr/types/wlr_box.h> | ||
9 | #include <wlr/types/wlr_buffer.h> | 10 | #include <wlr/types/wlr_buffer.h> |
11 | #include <wlr/types/wlr_drm_lease_v1.h> | ||
10 | #include <wlr/types/wlr_matrix.h> | 12 | #include <wlr/types/wlr_matrix.h> |
11 | #include <wlr/types/wlr_output_damage.h> | 13 | #include <wlr/types/wlr_output_damage.h> |
12 | #include <wlr/types/wlr_output_layout.h> | 14 | #include <wlr/types/wlr_output_layout.h> |
13 | #include <wlr/types/wlr_output.h> | 15 | #include <wlr/types/wlr_output.h> |
14 | #include <wlr/types/wlr_presentation_time.h> | 16 | #include <wlr/types/wlr_presentation_time.h> |
15 | #include <wlr/types/wlr_surface.h> | 17 | #include <wlr/types/wlr_compositor.h> |
16 | #include <wlr/util/region.h> | 18 | #include <wlr/util/region.h> |
17 | #include "config.h" | 19 | #include "config.h" |
18 | #include "log.h" | 20 | #include "log.h" |
@@ -56,26 +58,6 @@ struct sway_output *all_output_by_name_or_id(const char *name_or_id) { | |||
56 | return NULL; | 58 | return NULL; |
57 | } | 59 | } |
58 | 60 | ||
59 | /** | ||
60 | * Rotate a child's position relative to a parent. The parent size is (pw, ph), | ||
61 | * the child position is (*sx, *sy) and its size is (sw, sh). | ||
62 | */ | ||
63 | static void rotate_child_position(double *sx, double *sy, double sw, double sh, | ||
64 | double pw, double ph, float rotation) { | ||
65 | if (rotation == 0.0f) { | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | // Coordinates relative to the center of the subsurface | ||
70 | double ox = *sx - pw/2 + sw/2, | ||
71 | oy = *sy - ph/2 + sh/2; | ||
72 | // Rotated coordinates | ||
73 | double rx = cos(-rotation)*ox - sin(-rotation)*oy, | ||
74 | ry = cos(-rotation)*oy + sin(-rotation)*ox; | ||
75 | *sx = rx + pw/2 - sw/2; | ||
76 | *sy = ry + ph/2 - sh/2; | ||
77 | } | ||
78 | |||
79 | struct surface_iterator_data { | 61 | struct surface_iterator_data { |
80 | sway_surface_iterator_func_t user_iterator; | 62 | sway_surface_iterator_func_t user_iterator; |
81 | void *user_data; | 63 | void *user_data; |
@@ -84,7 +66,6 @@ struct surface_iterator_data { | |||
84 | struct sway_view *view; | 66 | struct sway_view *view; |
85 | double ox, oy; | 67 | double ox, oy; |
86 | int width, height; | 68 | int width, height; |
87 | float rotation; | ||
88 | }; | 69 | }; |
89 | 70 | ||
90 | static bool get_surface_box(struct surface_iterator_data *data, | 71 | static bool get_surface_box(struct surface_iterator_data *data, |
@@ -99,14 +80,9 @@ static bool get_surface_box(struct surface_iterator_data *data, | |||
99 | int sw = surface->current.width; | 80 | int sw = surface->current.width; |
100 | int sh = surface->current.height; | 81 | int sh = surface->current.height; |
101 | 82 | ||
102 | double _sx = sx + surface->sx; | ||
103 | double _sy = sy + surface->sy; | ||
104 | rotate_child_position(&_sx, &_sy, sw, sh, data->width, data->height, | ||
105 | data->rotation); | ||
106 | |||
107 | struct wlr_box box = { | 83 | struct wlr_box box = { |
108 | .x = data->ox + _sx, | 84 | .x = floor(data->ox + sx), |
109 | .y = data->oy + _sy, | 85 | .y = floor(data->oy + sy), |
110 | .width = sw, | 86 | .width = sw, |
111 | .height = sh, | 87 | .height = sh, |
112 | }; | 88 | }; |
@@ -114,16 +90,13 @@ static bool get_surface_box(struct surface_iterator_data *data, | |||
114 | memcpy(surface_box, &box, sizeof(struct wlr_box)); | 90 | memcpy(surface_box, &box, sizeof(struct wlr_box)); |
115 | } | 91 | } |
116 | 92 | ||
117 | struct wlr_box rotated_box; | ||
118 | wlr_box_rotated_bounds(&rotated_box, &box, data->rotation); | ||
119 | |||
120 | struct wlr_box output_box = { | 93 | struct wlr_box output_box = { |
121 | .width = output->width, | 94 | .width = output->width, |
122 | .height = output->height, | 95 | .height = output->height, |
123 | }; | 96 | }; |
124 | 97 | ||
125 | struct wlr_box intersection; | 98 | struct wlr_box intersection; |
126 | return wlr_box_intersection(&intersection, &output_box, &rotated_box); | 99 | return wlr_box_intersection(&intersection, &output_box, &box); |
127 | } | 100 | } |
128 | 101 | ||
129 | static void output_for_each_surface_iterator(struct wlr_surface *surface, | 102 | static void output_for_each_surface_iterator(struct wlr_surface *surface, |
@@ -136,7 +109,7 @@ static void output_for_each_surface_iterator(struct wlr_surface *surface, | |||
136 | return; | 109 | return; |
137 | } | 110 | } |
138 | 111 | ||
139 | data->user_iterator(data->output, data->view, surface, &box, data->rotation, | 112 | data->user_iterator(data->output, data->view, surface, &box, |
140 | data->user_data); | 113 | data->user_data); |
141 | } | 114 | } |
142 | 115 | ||
@@ -152,7 +125,6 @@ void output_surface_for_each_surface(struct sway_output *output, | |||
152 | .oy = oy, | 125 | .oy = oy, |
153 | .width = surface->current.width, | 126 | .width = surface->current.width, |
154 | .height = surface->current.height, | 127 | .height = surface->current.height, |
155 | .rotation = 0, | ||
156 | }; | 128 | }; |
157 | 129 | ||
158 | wlr_surface_for_each_surface(surface, | 130 | wlr_surface_for_each_surface(surface, |
@@ -173,7 +145,6 @@ void output_view_for_each_surface(struct sway_output *output, | |||
173 | - view->geometry.y, | 145 | - view->geometry.y, |
174 | .width = view->container->current.content_width, | 146 | .width = view->container->current.content_width, |
175 | .height = view->container->current.content_height, | 147 | .height = view->container->current.content_height, |
176 | .rotation = 0, // TODO | ||
177 | }; | 148 | }; |
178 | 149 | ||
179 | view_for_each_surface(view, output_for_each_surface_iterator, &data); | 150 | view_for_each_surface(view, output_for_each_surface_iterator, &data); |
@@ -193,7 +164,6 @@ void output_view_for_each_popup_surface(struct sway_output *output, | |||
193 | - view->geometry.y, | 164 | - view->geometry.y, |
194 | .width = view->container->current.content_width, | 165 | .width = view->container->current.content_width, |
195 | .height = view->container->current.content_height, | 166 | .height = view->container->current.content_height, |
196 | .rotation = 0, // TODO | ||
197 | }; | 167 | }; |
198 | 168 | ||
199 | view_for_each_popup_surface(view, output_for_each_surface_iterator, &data); | 169 | view_for_each_popup_surface(view, output_for_each_surface_iterator, &data); |
@@ -206,40 +176,19 @@ void output_layer_for_each_surface(struct sway_output *output, | |||
206 | wl_list_for_each(layer_surface, layer_surfaces, link) { | 176 | wl_list_for_each(layer_surface, layer_surfaces, link) { |
207 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = | 177 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = |
208 | layer_surface->layer_surface; | 178 | layer_surface->layer_surface; |
209 | output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, | 179 | struct wlr_surface *surface = wlr_layer_surface_v1->surface; |
210 | layer_surface->geo.x, layer_surface->geo.y, iterator, | 180 | struct surface_iterator_data data = { |
211 | user_data); | 181 | .user_iterator = iterator, |
212 | 182 | .user_data = user_data, | |
213 | struct wlr_xdg_popup *state; | 183 | .output = output, |
214 | wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) { | 184 | .view = NULL, |
215 | struct wlr_xdg_surface *popup = state->base; | 185 | .ox = layer_surface->geo.x, |
216 | if (!popup->configured) { | 186 | .oy = layer_surface->geo.y, |
217 | continue; | 187 | .width = surface->current.width, |
218 | } | 188 | .height = surface->current.height, |
219 | 189 | }; | |
220 | double popup_sx, popup_sy; | 190 | wlr_layer_surface_v1_for_each_surface(wlr_layer_surface_v1, |
221 | popup_sx = layer_surface->geo.x + | 191 | output_for_each_surface_iterator, &data); |
222 | popup->popup->geometry.x - popup->geometry.x; | ||
223 | popup_sy = layer_surface->geo.y + | ||
224 | popup->popup->geometry.y - popup->geometry.y; | ||
225 | |||
226 | struct wlr_surface *surface = popup->surface; | ||
227 | |||
228 | struct surface_iterator_data data = { | ||
229 | .user_iterator = iterator, | ||
230 | .user_data = user_data, | ||
231 | .output = output, | ||
232 | .view = NULL, | ||
233 | .ox = popup_sx, | ||
234 | .oy = popup_sy, | ||
235 | .width = surface->current.width, | ||
236 | .height = surface->current.height, | ||
237 | .rotation = 0, | ||
238 | }; | ||
239 | |||
240 | wlr_xdg_surface_for_each_surface( | ||
241 | popup, output_for_each_surface_iterator, &data); | ||
242 | } | ||
243 | } | 192 | } |
244 | } | 193 | } |
245 | 194 | ||
@@ -264,37 +213,19 @@ void output_layer_for_each_popup_surface(struct sway_output *output, | |||
264 | wl_list_for_each(layer_surface, layer_surfaces, link) { | 213 | wl_list_for_each(layer_surface, layer_surfaces, link) { |
265 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = | 214 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = |
266 | layer_surface->layer_surface; | 215 | layer_surface->layer_surface; |
267 | 216 | struct wlr_surface *surface = wlr_layer_surface_v1->surface; | |
268 | struct wlr_xdg_popup *state; | 217 | struct surface_iterator_data data = { |
269 | wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) { | 218 | .user_iterator = iterator, |
270 | struct wlr_xdg_surface *popup = state->base; | 219 | .user_data = user_data, |
271 | if (!popup->configured) { | 220 | .output = output, |
272 | continue; | 221 | .view = NULL, |
273 | } | 222 | .ox = layer_surface->geo.x, |
274 | 223 | .oy = layer_surface->geo.y, | |
275 | double popup_sx, popup_sy; | 224 | .width = surface->current.width, |
276 | popup_sx = layer_surface->geo.x + | 225 | .height = surface->current.height, |
277 | popup->popup->geometry.x - popup->geometry.x; | 226 | }; |
278 | popup_sy = layer_surface->geo.y + | 227 | wlr_layer_surface_v1_for_each_popup_surface(wlr_layer_surface_v1, |
279 | popup->popup->geometry.y - popup->geometry.y; | 228 | output_for_each_surface_iterator, &data); |
280 | |||
281 | struct wlr_surface *surface = popup->surface; | ||
282 | |||
283 | struct surface_iterator_data data = { | ||
284 | .user_iterator = iterator, | ||
285 | .user_data = user_data, | ||
286 | .output = output, | ||
287 | .view = NULL, | ||
288 | .ox = popup_sx, | ||
289 | .oy = popup_sy, | ||
290 | .width = surface->current.width, | ||
291 | .height = surface->current.height, | ||
292 | .rotation = 0, | ||
293 | }; | ||
294 | |||
295 | wlr_xdg_surface_for_each_surface( | ||
296 | popup, output_for_each_surface_iterator, &data); | ||
297 | } | ||
298 | } | 229 | } |
299 | } | 230 | } |
300 | 231 | ||
@@ -344,6 +275,25 @@ static void for_each_surface_container_iterator(struct sway_container *con, | |||
344 | 275 | ||
345 | static void output_for_each_surface(struct sway_output *output, | 276 | static void output_for_each_surface(struct sway_output *output, |
346 | sway_surface_iterator_func_t iterator, void *user_data) { | 277 | sway_surface_iterator_func_t iterator, void *user_data) { |
278 | if (server.session_lock.locked) { | ||
279 | if (server.session_lock.lock == NULL) { | ||
280 | return; | ||
281 | } | ||
282 | struct wlr_session_lock_surface_v1 *lock_surface; | ||
283 | wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) { | ||
284 | if (lock_surface->output != output->wlr_output) { | ||
285 | continue; | ||
286 | } | ||
287 | if (!lock_surface->mapped) { | ||
288 | continue; | ||
289 | } | ||
290 | |||
291 | output_surface_for_each_surface(output, lock_surface->surface, | ||
292 | 0.0, 0.0, iterator, user_data); | ||
293 | } | ||
294 | return; | ||
295 | } | ||
296 | |||
347 | if (output_has_opaque_overlay_layer_surface(output)) { | 297 | if (output_has_opaque_overlay_layer_surface(output)) { |
348 | goto overlay; | 298 | goto overlay; |
349 | } | 299 | } |
@@ -463,9 +413,9 @@ struct send_frame_done_data { | |||
463 | int msec_until_refresh; | 413 | int msec_until_refresh; |
464 | }; | 414 | }; |
465 | 415 | ||
466 | static void send_frame_done_iterator(struct sway_output *output, struct sway_view *view, | 416 | static void send_frame_done_iterator(struct sway_output *output, |
467 | struct wlr_surface *surface, struct wlr_box *box, float rotation, | 417 | struct sway_view *view, struct wlr_surface *surface, |
468 | void *user_data) { | 418 | struct wlr_box *box, void *user_data) { |
469 | int view_max_render_time = 0; | 419 | int view_max_render_time = 0; |
470 | if (view != NULL) { | 420 | if (view != NULL) { |
471 | view_max_render_time = view->max_render_time; | 421 | view_max_render_time = view->max_render_time; |
@@ -488,9 +438,9 @@ static void send_frame_done(struct sway_output *output, struct send_frame_done_d | |||
488 | output_for_each_surface(output, send_frame_done_iterator, data); | 438 | output_for_each_surface(output, send_frame_done_iterator, data); |
489 | } | 439 | } |
490 | 440 | ||
491 | static void count_surface_iterator(struct sway_output *output, struct sway_view *view, | 441 | static void count_surface_iterator(struct sway_output *output, |
492 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | 442 | struct sway_view *view, struct wlr_surface *surface, |
493 | void *data) { | 443 | struct wlr_box *box, void *data) { |
494 | size_t *n = data; | 444 | size_t *n = data; |
495 | (*n)++; | 445 | (*n)++; |
496 | } | 446 | } |
@@ -503,6 +453,10 @@ static bool scan_out_fullscreen_view(struct sway_output *output, | |||
503 | return false; | 453 | return false; |
504 | } | 454 | } |
505 | 455 | ||
456 | if (server.session_lock.locked) { | ||
457 | return false; | ||
458 | } | ||
459 | |||
506 | if (!wl_list_empty(&view->saved_buffers)) { | 460 | if (!wl_list_empty(&view->saved_buffers)) { |
507 | return false; | 461 | return false; |
508 | } | 462 | } |
@@ -577,7 +531,7 @@ static int output_repaint_timer_handler(void *data) { | |||
577 | fullscreen_con = workspace->current.fullscreen; | 531 | fullscreen_con = workspace->current.fullscreen; |
578 | } | 532 | } |
579 | 533 | ||
580 | if (fullscreen_con && fullscreen_con->view) { | 534 | if (fullscreen_con && fullscreen_con->view && !debug.noscanout) { |
581 | // Try to scan-out the fullscreen view | 535 | // Try to scan-out the fullscreen view |
582 | static bool last_scanned_out = false; | 536 | static bool last_scanned_out = false; |
583 | bool scanned_out = | 537 | bool scanned_out = |
@@ -590,6 +544,7 @@ static int output_repaint_timer_handler(void *data) { | |||
590 | if (last_scanned_out && !scanned_out) { | 544 | if (last_scanned_out && !scanned_out) { |
591 | sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out on %s", | 545 | sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out on %s", |
592 | output->wlr_output->name); | 546 | output->wlr_output->name); |
547 | output_damage_whole(output); | ||
593 | } | 548 | } |
594 | last_scanned_out = scanned_out; | 549 | last_scanned_out = scanned_out; |
595 | 550 | ||
@@ -693,38 +648,30 @@ void output_damage_whole(struct sway_output *output) { | |||
693 | } | 648 | } |
694 | } | 649 | } |
695 | 650 | ||
696 | static void damage_surface_iterator(struct sway_output *output, struct sway_view *view, | 651 | static void damage_surface_iterator(struct sway_output *output, |
697 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | 652 | struct sway_view *view, struct wlr_surface *surface, |
698 | void *_data) { | 653 | struct wlr_box *_box, void *_data) { |
699 | bool *data = _data; | 654 | bool *data = _data; |
700 | bool whole = *data; | 655 | bool whole = *data; |
701 | 656 | ||
702 | struct wlr_box box = *_box; | 657 | struct wlr_box box = *_box; |
703 | scale_box(&box, output->wlr_output->scale); | 658 | scale_box(&box, output->wlr_output->scale); |
704 | 659 | ||
705 | int center_x = box.x + box.width/2; | 660 | pixman_region32_t damage; |
706 | int center_y = box.y + box.height/2; | 661 | pixman_region32_init(&damage); |
707 | 662 | wlr_surface_get_effective_damage(surface, &damage); | |
708 | if (pixman_region32_not_empty(&surface->buffer_damage)) { | 663 | wlr_region_scale(&damage, &damage, output->wlr_output->scale); |
709 | pixman_region32_t damage; | 664 | if (ceil(output->wlr_output->scale) > surface->current.scale) { |
710 | pixman_region32_init(&damage); | 665 | // When scaling up a surface, it'll become blurry so we need to |
711 | wlr_surface_get_effective_damage(surface, &damage); | 666 | // expand the damage region |
712 | wlr_region_scale(&damage, &damage, output->wlr_output->scale); | 667 | wlr_region_expand(&damage, &damage, |
713 | if (ceil(output->wlr_output->scale) > surface->current.scale) { | 668 | ceil(output->wlr_output->scale) - surface->current.scale); |
714 | // When scaling up a surface, it'll become blurry so we need to | ||
715 | // expand the damage region | ||
716 | wlr_region_expand(&damage, &damage, | ||
717 | ceil(output->wlr_output->scale) - surface->current.scale); | ||
718 | } | ||
719 | pixman_region32_translate(&damage, box.x, box.y); | ||
720 | wlr_region_rotated_bounds(&damage, &damage, rotation, | ||
721 | center_x, center_y); | ||
722 | wlr_output_damage_add(output->damage, &damage); | ||
723 | pixman_region32_fini(&damage); | ||
724 | } | 669 | } |
670 | pixman_region32_translate(&damage, box.x, box.y); | ||
671 | wlr_output_damage_add(output->damage, &damage); | ||
672 | pixman_region32_fini(&damage); | ||
725 | 673 | ||
726 | if (whole) { | 674 | if (whole) { |
727 | wlr_box_rotated_bounds(&box, &box, rotation); | ||
728 | wlr_output_damage_add_box(output->damage, &box); | 675 | wlr_output_damage_add_box(output->damage, &box); |
729 | } | 676 | } |
730 | 677 | ||
@@ -808,19 +755,20 @@ static void update_output_manager_config(struct sway_server *server) { | |||
808 | 755 | ||
809 | struct sway_output *output; | 756 | struct sway_output *output; |
810 | wl_list_for_each(output, &root->all_outputs, link) { | 757 | wl_list_for_each(output, &root->all_outputs, link) { |
811 | if (output == root->noop_output) { | 758 | if (output == root->fallback_output) { |
812 | continue; | 759 | continue; |
813 | } | 760 | } |
814 | struct wlr_output_configuration_head_v1 *config_head = | 761 | struct wlr_output_configuration_head_v1 *config_head = |
815 | wlr_output_configuration_head_v1_create(config, output->wlr_output); | 762 | wlr_output_configuration_head_v1_create(config, output->wlr_output); |
816 | struct wlr_box *output_box = wlr_output_layout_get_box( | 763 | struct wlr_box output_box; |
817 | root->output_layout, output->wlr_output); | 764 | wlr_output_layout_get_box(root->output_layout, |
818 | // We mark the output enabled even if it is switched off by DPMS | 765 | output->wlr_output, &output_box); |
819 | config_head->state.enabled = output->enabled; | 766 | // We mark the output enabled when it's switched off but not disabled |
767 | config_head->state.enabled = output->current_mode != NULL && output->enabled; | ||
820 | config_head->state.mode = output->current_mode; | 768 | config_head->state.mode = output->current_mode; |
821 | if (output_box) { | 769 | if (!wlr_box_empty(&output_box)) { |
822 | config_head->state.x = output_box->x; | 770 | config_head->state.x = output_box.x; |
823 | config_head->state.y = output_box->y; | 771 | config_head->state.y = output_box.y; |
824 | } | 772 | } |
825 | } | 773 | } |
826 | 774 | ||
@@ -830,18 +778,22 @@ static void update_output_manager_config(struct sway_server *server) { | |||
830 | static void handle_destroy(struct wl_listener *listener, void *data) { | 778 | static void handle_destroy(struct wl_listener *listener, void *data) { |
831 | struct sway_output *output = wl_container_of(listener, output, destroy); | 779 | struct sway_output *output = wl_container_of(listener, output, destroy); |
832 | struct sway_server *server = output->server; | 780 | struct sway_server *server = output->server; |
833 | wl_signal_emit(&output->events.destroy, output); | 781 | output_begin_destroy(output); |
834 | 782 | ||
835 | if (output->enabled) { | 783 | if (output->enabled) { |
836 | output_disable(output); | 784 | output_disable(output); |
837 | } | 785 | } |
838 | output_begin_destroy(output); | 786 | |
787 | wl_list_remove(&output->link); | ||
839 | 788 | ||
840 | wl_list_remove(&output->destroy.link); | 789 | wl_list_remove(&output->destroy.link); |
841 | wl_list_remove(&output->commit.link); | 790 | wl_list_remove(&output->commit.link); |
842 | wl_list_remove(&output->mode.link); | 791 | wl_list_remove(&output->mode.link); |
843 | wl_list_remove(&output->present.link); | 792 | wl_list_remove(&output->present.link); |
844 | 793 | ||
794 | output->wlr_output->data = NULL; | ||
795 | output->wlr_output = NULL; | ||
796 | |||
845 | transaction_commit_dirty(); | 797 | transaction_commit_dirty(); |
846 | 798 | ||
847 | update_output_manager_config(server); | 799 | update_output_manager_config(server); |
@@ -902,7 +854,7 @@ static void handle_present(struct wl_listener *listener, void *data) { | |||
902 | struct sway_output *output = wl_container_of(listener, output, present); | 854 | struct sway_output *output = wl_container_of(listener, output, present); |
903 | struct wlr_output_event_present *output_event = data; | 855 | struct wlr_output_event_present *output_event = data; |
904 | 856 | ||
905 | if (!output->enabled) { | 857 | if (!output->enabled || !output_event->presented) { |
906 | return; | 858 | return; |
907 | } | 859 | } |
908 | 860 | ||
@@ -910,10 +862,39 @@ static void handle_present(struct wl_listener *listener, void *data) { | |||
910 | output->refresh_nsec = output_event->refresh; | 862 | output->refresh_nsec = output_event->refresh; |
911 | } | 863 | } |
912 | 864 | ||
865 | static unsigned int last_headless_num = 0; | ||
866 | |||
913 | void handle_new_output(struct wl_listener *listener, void *data) { | 867 | void handle_new_output(struct wl_listener *listener, void *data) { |
914 | struct sway_server *server = wl_container_of(listener, server, new_output); | 868 | struct sway_server *server = wl_container_of(listener, server, new_output); |
915 | struct wlr_output *wlr_output = data; | 869 | struct wlr_output *wlr_output = data; |
916 | sway_log(SWAY_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); | 870 | |
871 | if (wlr_output == root->fallback_output->wlr_output) { | ||
872 | return; | ||
873 | } | ||
874 | |||
875 | if (wlr_output_is_headless(wlr_output)) { | ||
876 | char name[64]; | ||
877 | snprintf(name, sizeof(name), "HEADLESS-%u", ++last_headless_num); | ||
878 | wlr_output_set_name(wlr_output, name); | ||
879 | } | ||
880 | |||
881 | sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)", | ||
882 | wlr_output, wlr_output->name, wlr_output->non_desktop); | ||
883 | |||
884 | if (wlr_output->non_desktop) { | ||
885 | sway_log(SWAY_DEBUG, "Not configuring non-desktop output"); | ||
886 | if (server->drm_lease_manager) { | ||
887 | wlr_drm_lease_v1_manager_offer_output(server->drm_lease_manager, | ||
888 | wlr_output); | ||
889 | } | ||
890 | return; | ||
891 | } | ||
892 | |||
893 | if (!wlr_output_init_render(wlr_output, server->allocator, | ||
894 | server->renderer)) { | ||
895 | sway_log(SWAY_ERROR, "Failed to init output render"); | ||
896 | return; | ||
897 | } | ||
917 | 898 | ||
918 | struct sway_output *output = output_create(wlr_output); | 899 | struct sway_output *output = output_create(wlr_output); |
919 | if (!output) { | 900 | if (!output) { |
@@ -1047,10 +1028,10 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener, | |||
1047 | struct output_config *oc = new_output_config(output->wlr_output->name); | 1028 | struct output_config *oc = new_output_config(output->wlr_output->name); |
1048 | switch (event->mode) { | 1029 | switch (event->mode) { |
1049 | case ZWLR_OUTPUT_POWER_V1_MODE_OFF: | 1030 | case ZWLR_OUTPUT_POWER_V1_MODE_OFF: |
1050 | oc->dpms_state = DPMS_OFF; | 1031 | oc->power = 0; |
1051 | break; | 1032 | break; |
1052 | case ZWLR_OUTPUT_POWER_V1_MODE_ON: | 1033 | case ZWLR_OUTPUT_POWER_V1_MODE_ON: |
1053 | oc->dpms_state = DPMS_ON; | 1034 | oc->power = 1; |
1054 | break; | 1035 | break; |
1055 | } | 1036 | } |
1056 | oc = store_output_config(oc); | 1037 | oc = store_output_config(oc); |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index bd85282c..ed9ad490 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -7,13 +7,12 @@ | |||
7 | #include <wayland-server-core.h> | 7 | #include <wayland-server-core.h> |
8 | #include <wlr/render/gles2.h> | 8 | #include <wlr/render/gles2.h> |
9 | #include <wlr/render/wlr_renderer.h> | 9 | #include <wlr/render/wlr_renderer.h> |
10 | #include <wlr/types/wlr_box.h> | ||
11 | #include <wlr/types/wlr_buffer.h> | 10 | #include <wlr/types/wlr_buffer.h> |
12 | #include <wlr/types/wlr_matrix.h> | 11 | #include <wlr/types/wlr_matrix.h> |
13 | #include <wlr/types/wlr_output_damage.h> | 12 | #include <wlr/types/wlr_output_damage.h> |
14 | #include <wlr/types/wlr_output_layout.h> | 13 | #include <wlr/types/wlr_output_layout.h> |
15 | #include <wlr/types/wlr_output.h> | 14 | #include <wlr/types/wlr_output.h> |
16 | #include <wlr/types/wlr_surface.h> | 15 | #include <wlr/types/wlr_compositor.h> |
17 | #include <wlr/util/region.h> | 16 | #include <wlr/util/region.h> |
18 | #include "log.h" | 17 | #include "log.h" |
19 | #include "config.h" | 18 | #include "config.h" |
@@ -32,6 +31,7 @@ | |||
32 | struct render_data { | 31 | struct render_data { |
33 | pixman_region32_t *damage; | 32 | pixman_region32_t *damage; |
34 | float alpha; | 33 | float alpha; |
34 | struct wlr_box *clip_box; | ||
35 | }; | 35 | }; |
36 | 36 | ||
37 | /** | 37 | /** |
@@ -52,7 +52,7 @@ static int scale_length(int length, int offset, float scale) { | |||
52 | 52 | ||
53 | static void scissor_output(struct wlr_output *wlr_output, | 53 | static void scissor_output(struct wlr_output *wlr_output, |
54 | pixman_box32_t *rect) { | 54 | pixman_box32_t *rect) { |
55 | struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); | 55 | struct wlr_renderer *renderer = wlr_output->renderer; |
56 | assert(renderer); | 56 | assert(renderer); |
57 | 57 | ||
58 | struct wlr_box box = { | 58 | struct wlr_box box = { |
@@ -100,13 +100,9 @@ static void render_texture(struct wlr_output *wlr_output, | |||
100 | pixman_region32_t *output_damage, struct wlr_texture *texture, | 100 | pixman_region32_t *output_damage, struct wlr_texture *texture, |
101 | const struct wlr_fbox *src_box, const struct wlr_box *dst_box, | 101 | const struct wlr_fbox *src_box, const struct wlr_box *dst_box, |
102 | const float matrix[static 9], float alpha) { | 102 | const float matrix[static 9], float alpha) { |
103 | struct wlr_renderer *renderer = | 103 | struct wlr_renderer *renderer = wlr_output->renderer; |
104 | wlr_backend_get_renderer(wlr_output->backend); | ||
105 | struct sway_output *output = wlr_output->data; | 104 | struct sway_output *output = wlr_output->data; |
106 | 105 | ||
107 | struct wlr_gles2_texture_attribs attribs; | ||
108 | wlr_gles2_texture_get_attribs(texture, &attribs); | ||
109 | |||
110 | pixman_region32_t damage; | 106 | pixman_region32_t damage; |
111 | pixman_region32_init(&damage); | 107 | pixman_region32_init(&damage); |
112 | pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, | 108 | pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, |
@@ -133,9 +129,9 @@ damage_finish: | |||
133 | pixman_region32_fini(&damage); | 129 | pixman_region32_fini(&damage); |
134 | } | 130 | } |
135 | 131 | ||
136 | static void render_surface_iterator(struct sway_output *output, struct sway_view *view, | 132 | static void render_surface_iterator(struct sway_output *output, |
137 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | 133 | struct sway_view *view, struct wlr_surface *surface, |
138 | void *_data) { | 134 | struct wlr_box *_box, void *_data) { |
139 | struct render_data *data = _data; | 135 | struct render_data *data = _data; |
140 | struct wlr_output *wlr_output = output->wlr_output; | 136 | struct wlr_output *wlr_output = output->wlr_output; |
141 | pixman_region32_t *output_damage = data->damage; | 137 | pixman_region32_t *output_damage = data->damage; |
@@ -149,15 +145,23 @@ static void render_surface_iterator(struct sway_output *output, struct sway_view | |||
149 | struct wlr_fbox src_box; | 145 | struct wlr_fbox src_box; |
150 | wlr_surface_get_buffer_source_box(surface, &src_box); | 146 | wlr_surface_get_buffer_source_box(surface, &src_box); |
151 | 147 | ||
152 | struct wlr_box dst_box = *_box; | 148 | struct wlr_box proj_box = *_box; |
153 | scale_box(&dst_box, wlr_output->scale); | 149 | scale_box(&proj_box, wlr_output->scale); |
154 | 150 | ||
155 | float matrix[9]; | 151 | float matrix[9]; |
156 | enum wl_output_transform transform = | 152 | enum wl_output_transform transform = |
157 | wlr_output_transform_invert(surface->current.transform); | 153 | wlr_output_transform_invert(surface->current.transform); |
158 | wlr_matrix_project_box(matrix, &dst_box, transform, rotation, | 154 | wlr_matrix_project_box(matrix, &proj_box, transform, 0.0, |
159 | wlr_output->transform_matrix); | 155 | wlr_output->transform_matrix); |
160 | 156 | ||
157 | struct wlr_box dst_box = *_box; | ||
158 | struct wlr_box *clip_box = data->clip_box; | ||
159 | if (clip_box != NULL) { | ||
160 | dst_box.width = fmin(dst_box.width, clip_box->width); | ||
161 | dst_box.height = fmin(dst_box.height, clip_box->height); | ||
162 | } | ||
163 | scale_box(&dst_box, wlr_output->scale); | ||
164 | |||
161 | render_texture(wlr_output, output_damage, texture, | 165 | render_texture(wlr_output, output_damage, texture, |
162 | &src_box, &dst_box, matrix, alpha); | 166 | &src_box, &dst_box, matrix, alpha); |
163 | 167 | ||
@@ -213,8 +217,7 @@ void render_rect(struct sway_output *output, | |||
213 | pixman_region32_t *output_damage, const struct wlr_box *_box, | 217 | pixman_region32_t *output_damage, const struct wlr_box *_box, |
214 | float color[static 4]) { | 218 | float color[static 4]) { |
215 | struct wlr_output *wlr_output = output->wlr_output; | 219 | struct wlr_output *wlr_output = output->wlr_output; |
216 | struct wlr_renderer *renderer = | 220 | struct wlr_renderer *renderer = wlr_output->renderer; |
217 | wlr_backend_get_renderer(wlr_output->backend); | ||
218 | 221 | ||
219 | struct wlr_box box; | 222 | struct wlr_box box; |
220 | memcpy(&box, _box, sizeof(struct wlr_box)); | 223 | memcpy(&box, _box, sizeof(struct wlr_box)); |
@@ -256,6 +259,14 @@ static void render_view_toplevels(struct sway_view *view, | |||
256 | .damage = damage, | 259 | .damage = damage, |
257 | .alpha = alpha, | 260 | .alpha = alpha, |
258 | }; | 261 | }; |
262 | struct wlr_box clip_box; | ||
263 | if (!container_is_current_floating(view->container)) { | ||
264 | // As we pass the geometry offsets to the surface iterator, we will | ||
265 | // need to account for the offsets in the clip dimensions. | ||
266 | clip_box.width = view->container->current.content_width + view->geometry.x; | ||
267 | clip_box.height = view->container->current.content_height + view->geometry.y; | ||
268 | data.clip_box = &clip_box; | ||
269 | } | ||
259 | // Render all toplevels without descending into popups | 270 | // Render all toplevels without descending into popups |
260 | double ox = view->container->surface_x - | 271 | double ox = view->container->surface_x - |
261 | output->lx - view->geometry.x; | 272 | output->lx - view->geometry.x; |
@@ -282,17 +293,18 @@ static void render_saved_view(struct sway_view *view, | |||
282 | if (wl_list_empty(&view->saved_buffers)) { | 293 | if (wl_list_empty(&view->saved_buffers)) { |
283 | return; | 294 | return; |
284 | } | 295 | } |
296 | |||
297 | bool floating = container_is_current_floating(view->container); | ||
298 | |||
285 | struct sway_saved_buffer *saved_buf; | 299 | struct sway_saved_buffer *saved_buf; |
286 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { | 300 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { |
287 | if (!saved_buf->buffer->texture) { | 301 | if (!saved_buf->buffer->texture) { |
288 | continue; | 302 | continue; |
289 | } | 303 | } |
290 | 304 | ||
291 | struct wlr_box box = { | 305 | struct wlr_box proj_box = { |
292 | .x = view->container->surface_x - output->lx - | 306 | .x = saved_buf->x - view->saved_geometry.x - output->lx, |
293 | view->saved_geometry.x + saved_buf->x, | 307 | .y = saved_buf->y - view->saved_geometry.y - output->ly, |
294 | .y = view->container->surface_y - output->ly - | ||
295 | view->saved_geometry.y + saved_buf->y, | ||
296 | .width = saved_buf->width, | 308 | .width = saved_buf->width, |
297 | .height = saved_buf->height, | 309 | .height = saved_buf->height, |
298 | }; | 310 | }; |
@@ -303,20 +315,31 @@ static void render_saved_view(struct sway_view *view, | |||
303 | }; | 315 | }; |
304 | 316 | ||
305 | struct wlr_box intersection; | 317 | struct wlr_box intersection; |
306 | bool intersects = wlr_box_intersection(&intersection, &output_box, &box); | 318 | bool intersects = wlr_box_intersection(&intersection, &output_box, &proj_box); |
307 | if (!intersects) { | 319 | if (!intersects) { |
308 | continue; | 320 | continue; |
309 | } | 321 | } |
310 | 322 | ||
311 | scale_box(&box, wlr_output->scale); | 323 | struct wlr_box dst_box = proj_box; |
324 | scale_box(&proj_box, wlr_output->scale); | ||
312 | 325 | ||
313 | float matrix[9]; | 326 | float matrix[9]; |
314 | enum wl_output_transform transform = wlr_output_transform_invert(saved_buf->transform); | 327 | enum wl_output_transform transform = wlr_output_transform_invert(saved_buf->transform); |
315 | wlr_matrix_project_box(matrix, &box, transform, 0, | 328 | wlr_matrix_project_box(matrix, &proj_box, transform, 0, |
316 | wlr_output->transform_matrix); | 329 | wlr_output->transform_matrix); |
317 | 330 | ||
331 | if (!floating) { | ||
332 | dst_box.width = fmin(dst_box.width, | ||
333 | view->container->current.content_width - | ||
334 | (saved_buf->x - view->container->current.content_x) + view->saved_geometry.x); | ||
335 | dst_box.height = fmin(dst_box.height, | ||
336 | view->container->current.content_height - | ||
337 | (saved_buf->y - view->container->current.content_y) + view->saved_geometry.y); | ||
338 | } | ||
339 | scale_box(&dst_box, wlr_output->scale); | ||
340 | |||
318 | render_texture(wlr_output, damage, saved_buf->buffer->texture, | 341 | render_texture(wlr_output, damage, saved_buf->buffer->texture, |
319 | &saved_buf->source_box, &box, matrix, alpha); | 342 | &saved_buf->source_box, &dst_box, matrix, alpha); |
320 | } | 343 | } |
321 | 344 | ||
322 | // FIXME: we should set the surface that this saved buffer originates from | 345 | // FIXME: we should set the surface that this saved buffer originates from |
@@ -348,8 +371,8 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
348 | if (state->border_left) { | 371 | if (state->border_left) { |
349 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 372 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
350 | premultiply_alpha(color, con->alpha); | 373 | premultiply_alpha(color, con->alpha); |
351 | box.x = state->x; | 374 | box.x = floor(state->x); |
352 | box.y = state->content_y; | 375 | box.y = floor(state->content_y); |
353 | box.width = state->border_thickness; | 376 | box.width = state->border_thickness; |
354 | box.height = state->content_height; | 377 | box.height = state->content_height; |
355 | scale_box(&box, output_scale); | 378 | scale_box(&box, output_scale); |
@@ -361,14 +384,14 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
361 | container_current_parent_layout(con); | 384 | container_current_parent_layout(con); |
362 | 385 | ||
363 | if (state->border_right) { | 386 | if (state->border_right) { |
364 | if (!container_is_floating(con) && siblings->length == 1 && layout == L_HORIZ) { | 387 | if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_HORIZ) { |
365 | memcpy(&color, colors->indicator, sizeof(float) * 4); | 388 | memcpy(&color, colors->indicator, sizeof(float) * 4); |
366 | } else { | 389 | } else { |
367 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 390 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
368 | } | 391 | } |
369 | premultiply_alpha(color, con->alpha); | 392 | premultiply_alpha(color, con->alpha); |
370 | box.x = state->content_x + state->content_width; | 393 | box.x = floor(state->content_x + state->content_width); |
371 | box.y = state->content_y; | 394 | box.y = floor(state->content_y); |
372 | box.width = state->border_thickness; | 395 | box.width = state->border_thickness; |
373 | box.height = state->content_height; | 396 | box.height = state->content_height; |
374 | scale_box(&box, output_scale); | 397 | scale_box(&box, output_scale); |
@@ -376,14 +399,14 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
376 | } | 399 | } |
377 | 400 | ||
378 | if (state->border_bottom) { | 401 | if (state->border_bottom) { |
379 | if (!container_is_floating(con) && siblings->length == 1 && layout == L_VERT) { | 402 | if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_VERT) { |
380 | memcpy(&color, colors->indicator, sizeof(float) * 4); | 403 | memcpy(&color, colors->indicator, sizeof(float) * 4); |
381 | } else { | 404 | } else { |
382 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 405 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
383 | } | 406 | } |
384 | premultiply_alpha(color, con->alpha); | 407 | premultiply_alpha(color, con->alpha); |
385 | box.x = state->x; | 408 | box.x = floor(state->x); |
386 | box.y = state->content_y + state->content_height; | 409 | box.y = floor(state->content_y + state->content_height); |
387 | box.width = state->width; | 410 | box.width = state->width; |
388 | box.height = state->border_thickness; | 411 | box.height = state->border_thickness; |
389 | scale_box(&box, output_scale); | 412 | scale_box(&box, output_scale); |
@@ -464,9 +487,10 @@ static void render_titlebar(struct sway_output *output, | |||
464 | int ob_marks_x = 0; // output-buffer-local | 487 | int ob_marks_x = 0; // output-buffer-local |
465 | int ob_marks_width = 0; // output-buffer-local | 488 | int ob_marks_width = 0; // output-buffer-local |
466 | if (config->show_marks && marks_texture) { | 489 | if (config->show_marks && marks_texture) { |
467 | struct wlr_box texture_box; | 490 | struct wlr_box texture_box = { |
468 | wlr_texture_get_size(marks_texture, | 491 | .width = marks_texture->width, |
469 | &texture_box.width, &texture_box.height); | 492 | .height = marks_texture->height, |
493 | }; | ||
470 | ob_marks_width = texture_box.width; | 494 | ob_marks_width = texture_box.width; |
471 | 495 | ||
472 | // The marks texture might be shorter than the config->font_height, in | 496 | // The marks texture might be shorter than the config->font_height, in |
@@ -517,15 +541,23 @@ static void render_titlebar(struct sway_output *output, | |||
517 | int ob_title_x = 0; // output-buffer-local | 541 | int ob_title_x = 0; // output-buffer-local |
518 | int ob_title_width = 0; // output-buffer-local | 542 | int ob_title_width = 0; // output-buffer-local |
519 | if (title_texture) { | 543 | if (title_texture) { |
520 | struct wlr_box texture_box; | 544 | struct wlr_box texture_box = { |
521 | wlr_texture_get_size(title_texture, | 545 | .width = title_texture->width, |
522 | &texture_box.width, &texture_box.height); | 546 | .height = title_texture->height, |
547 | }; | ||
548 | |||
549 | // The effective output may be NULL when con is not on any output. | ||
550 | // This can happen because we render all children of containers, | ||
551 | // even those that are out of the bounds of any output. | ||
552 | struct sway_output *effective = container_get_effective_output(con); | ||
553 | float title_scale = effective ? effective->wlr_output->scale : output_scale; | ||
554 | texture_box.width = texture_box.width * output_scale / title_scale; | ||
555 | texture_box.height = texture_box.height * output_scale / title_scale; | ||
523 | ob_title_width = texture_box.width; | 556 | ob_title_width = texture_box.width; |
524 | 557 | ||
525 | // The title texture might be shorter than the config->font_height, | 558 | // The title texture might be shorter than the config->font_height, |
526 | // in which case we need to pad it above and below. | 559 | // in which case we need to pad it above and below. |
527 | int ob_padding_above = round((config->font_baseline - | 560 | int ob_padding_above = round((titlebar_v_padding - |
528 | con->title_baseline + titlebar_v_padding - | ||
529 | titlebar_border_thickness) * output_scale); | 561 | titlebar_border_thickness) * output_scale); |
530 | int ob_padding_below = ob_bg_height - ob_padding_above - | 562 | int ob_padding_below = ob_bg_height - ob_padding_above - |
531 | texture_box.height; | 563 | texture_box.height; |
@@ -660,8 +692,8 @@ static void render_top_border(struct sway_output *output, | |||
660 | // Child border - top edge | 692 | // Child border - top edge |
661 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 693 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
662 | premultiply_alpha(color, con->alpha); | 694 | premultiply_alpha(color, con->alpha); |
663 | box.x = state->x; | 695 | box.x = floor(state->x); |
664 | box.y = state->y; | 696 | box.y = floor(state->y); |
665 | box.width = state->width; | 697 | box.width = state->width; |
666 | box.height = state->border_thickness; | 698 | box.height = state->border_thickness; |
667 | scale_box(&box, output_scale); | 699 | scale_box(&box, output_scale); |
@@ -716,8 +748,8 @@ static void render_containers_linear(struct sway_output *output, | |||
716 | } | 748 | } |
717 | 749 | ||
718 | if (state->border == B_NORMAL) { | 750 | if (state->border == B_NORMAL) { |
719 | render_titlebar(output, damage, child, state->x, | 751 | render_titlebar(output, damage, child, floor(state->x), |
720 | state->y, state->width, colors, | 752 | floor(state->y), state->width, colors, |
721 | title_texture, marks_texture); | 753 | title_texture, marks_texture); |
722 | } else if (state->border == B_PIXEL) { | 754 | } else if (state->border == B_PIXEL) { |
723 | render_top_border(output, damage, child, colors); | 755 | render_top_border(output, damage, child, colors); |
@@ -730,6 +762,14 @@ static void render_containers_linear(struct sway_output *output, | |||
730 | } | 762 | } |
731 | } | 763 | } |
732 | 764 | ||
765 | static bool container_is_focused(struct sway_container *con, void *data) { | ||
766 | return con->current.focused; | ||
767 | } | ||
768 | |||
769 | static bool container_has_focused_child(struct sway_container *con) { | ||
770 | return container_find_child(con, container_is_focused, NULL); | ||
771 | } | ||
772 | |||
733 | /** | 773 | /** |
734 | * Render a container's children using the L_TABBED layout. | 774 | * Render a container's children using the L_TABBED layout. |
735 | */ | 775 | */ |
@@ -761,6 +801,10 @@ static void render_containers_tabbed(struct sway_output *output, | |||
761 | colors = &config->border_colors.focused; | 801 | colors = &config->border_colors.focused; |
762 | title_texture = child->title_focused; | 802 | title_texture = child->title_focused; |
763 | marks_texture = child->marks_focused; | 803 | marks_texture = child->marks_focused; |
804 | } else if (config->has_focused_tab_title && container_has_focused_child(child)) { | ||
805 | colors = &config->border_colors.focused_tab_title; | ||
806 | title_texture = child->title_focused_tab_title; | ||
807 | marks_texture = child->marks_focused_tab_title; | ||
764 | } else if (child == parent->active_child) { | 808 | } else if (child == parent->active_child) { |
765 | colors = &config->border_colors.focused_inactive; | 809 | colors = &config->border_colors.focused_inactive; |
766 | title_texture = child->title_focused_inactive; | 810 | title_texture = child->title_focused_inactive; |
@@ -771,7 +815,7 @@ static void render_containers_tabbed(struct sway_output *output, | |||
771 | marks_texture = child->marks_unfocused; | 815 | marks_texture = child->marks_unfocused; |
772 | } | 816 | } |
773 | 817 | ||
774 | int x = cstate->x + tab_width * i; | 818 | int x = floor(cstate->x + tab_width * i); |
775 | 819 | ||
776 | // Make last tab use the remaining width of the parent | 820 | // Make last tab use the remaining width of the parent |
777 | if (i == parent->children->length - 1) { | 821 | if (i == parent->children->length - 1) { |
@@ -826,7 +870,11 @@ static void render_containers_stacked(struct sway_output *output, | |||
826 | colors = &config->border_colors.focused; | 870 | colors = &config->border_colors.focused; |
827 | title_texture = child->title_focused; | 871 | title_texture = child->title_focused; |
828 | marks_texture = child->marks_focused; | 872 | marks_texture = child->marks_focused; |
829 | } else if (child == parent->active_child) { | 873 | } else if (config->has_focused_tab_title && container_has_focused_child(child)) { |
874 | colors = &config->border_colors.focused_tab_title; | ||
875 | title_texture = child->title_focused_tab_title; | ||
876 | marks_texture = child->marks_focused_tab_title; | ||
877 | } else if (child == parent->active_child) { | ||
830 | colors = &config->border_colors.focused_inactive; | 878 | colors = &config->border_colors.focused_inactive; |
831 | title_texture = child->title_focused_inactive; | 879 | title_texture = child->title_focused_inactive; |
832 | marks_texture = child->marks_focused_inactive; | 880 | marks_texture = child->marks_focused_inactive; |
@@ -884,8 +932,8 @@ static void render_container(struct sway_output *output, | |||
884 | struct parent_data data = { | 932 | struct parent_data data = { |
885 | .layout = con->current.layout, | 933 | .layout = con->current.layout, |
886 | .box = { | 934 | .box = { |
887 | .x = con->current.x, | 935 | .x = floor(con->current.x), |
888 | .y = con->current.y, | 936 | .y = floor(con->current.y), |
889 | .width = con->current.width, | 937 | .width = con->current.width, |
890 | .height = con->current.height, | 938 | .height = con->current.height, |
891 | }, | 939 | }, |
@@ -901,8 +949,8 @@ static void render_workspace(struct sway_output *output, | |||
901 | struct parent_data data = { | 949 | struct parent_data data = { |
902 | .layout = ws->current.layout, | 950 | .layout = ws->current.layout, |
903 | .box = { | 951 | .box = { |
904 | .x = ws->current.x, | 952 | .x = floor(ws->current.x), |
905 | .y = ws->current.y, | 953 | .y = floor(ws->current.y), |
906 | .width = ws->current.width, | 954 | .width = ws->current.width, |
907 | .height = ws->current.height, | 955 | .height = ws->current.height, |
908 | }, | 956 | }, |
@@ -936,8 +984,8 @@ static void render_floating_container(struct sway_output *soutput, | |||
936 | } | 984 | } |
937 | 985 | ||
938 | if (con->current.border == B_NORMAL) { | 986 | if (con->current.border == B_NORMAL) { |
939 | render_titlebar(soutput, damage, con, con->current.x, | 987 | render_titlebar(soutput, damage, con, floor(con->current.x), |
940 | con->current.y, con->current.width, colors, | 988 | floor(con->current.y), con->current.width, colors, |
941 | title_texture, marks_texture); | 989 | title_texture, marks_texture); |
942 | } else if (con->current.border == B_PIXEL) { | 990 | } else if (con->current.border == B_PIXEL) { |
943 | render_top_border(soutput, damage, con, colors); | 991 | render_top_border(soutput, damage, con, colors); |
@@ -959,7 +1007,7 @@ static void render_floating(struct sway_output *soutput, | |||
959 | } | 1007 | } |
960 | for (int k = 0; k < ws->current.floating->length; ++k) { | 1008 | for (int k = 0; k < ws->current.floating->length; ++k) { |
961 | struct sway_container *floater = ws->current.floating->items[k]; | 1009 | struct sway_container *floater = ws->current.floating->items[k]; |
962 | if (floater->fullscreen_mode != FULLSCREEN_NONE) { | 1010 | if (floater->current.fullscreen_mode != FULLSCREEN_NONE) { |
963 | continue; | 1011 | continue; |
964 | } | 1012 | } |
965 | render_floating_container(soutput, damage, floater); | 1013 | render_floating_container(soutput, damage, floater); |
@@ -979,13 +1027,7 @@ static void render_seatops(struct sway_output *output, | |||
979 | void output_render(struct sway_output *output, struct timespec *when, | 1027 | void output_render(struct sway_output *output, struct timespec *when, |
980 | pixman_region32_t *damage) { | 1028 | pixman_region32_t *damage) { |
981 | struct wlr_output *wlr_output = output->wlr_output; | 1029 | struct wlr_output *wlr_output = output->wlr_output; |
982 | 1030 | struct wlr_renderer *renderer = output->server->renderer; | |
983 | struct wlr_renderer *renderer = | ||
984 | wlr_backend_get_renderer(wlr_output->backend); | ||
985 | if (!sway_assert(renderer != NULL, | ||
986 | "expected the output backend to have a renderer")) { | ||
987 | return; | ||
988 | } | ||
989 | 1031 | ||
990 | struct sway_workspace *workspace = output->current.active_workspace; | 1032 | struct sway_workspace *workspace = output->current.active_workspace; |
991 | if (workspace == NULL) { | 1033 | if (workspace == NULL) { |
@@ -999,6 +1041,12 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
999 | 1041 | ||
1000 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); | 1042 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); |
1001 | 1043 | ||
1044 | if (debug.damage == DAMAGE_RERENDER) { | ||
1045 | int width, height; | ||
1046 | wlr_output_transformed_resolution(wlr_output, &width, &height); | ||
1047 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | ||
1048 | } | ||
1049 | |||
1002 | if (!pixman_region32_not_empty(damage)) { | 1050 | if (!pixman_region32_not_empty(damage)) { |
1003 | // Output isn't damaged but needs buffer swap | 1051 | // Output isn't damaged but needs buffer swap |
1004 | goto renderer_end; | 1052 | goto renderer_end; |
@@ -1006,10 +1054,41 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
1006 | 1054 | ||
1007 | if (debug.damage == DAMAGE_HIGHLIGHT) { | 1055 | if (debug.damage == DAMAGE_HIGHLIGHT) { |
1008 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | 1056 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); |
1009 | } else if (debug.damage == DAMAGE_RERENDER) { | 1057 | } |
1010 | int width, height; | 1058 | |
1011 | wlr_output_transformed_resolution(wlr_output, &width, &height); | 1059 | if (server.session_lock.locked) { |
1012 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | 1060 | float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; |
1061 | if (server.session_lock.lock == NULL) { | ||
1062 | // abandoned lock -> red BG | ||
1063 | clear_color[0] = 1.f; | ||
1064 | } | ||
1065 | int nrects; | ||
1066 | pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); | ||
1067 | for (int i = 0; i < nrects; ++i) { | ||
1068 | scissor_output(wlr_output, &rects[i]); | ||
1069 | wlr_renderer_clear(renderer, clear_color); | ||
1070 | } | ||
1071 | |||
1072 | if (server.session_lock.lock != NULL) { | ||
1073 | struct render_data data = { | ||
1074 | .damage = damage, | ||
1075 | .alpha = 1.0f, | ||
1076 | }; | ||
1077 | |||
1078 | struct wlr_session_lock_surface_v1 *lock_surface; | ||
1079 | wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) { | ||
1080 | if (lock_surface->output != wlr_output) { | ||
1081 | continue; | ||
1082 | } | ||
1083 | if (!lock_surface->mapped) { | ||
1084 | continue; | ||
1085 | } | ||
1086 | |||
1087 | output_surface_for_each_surface(output, lock_surface->surface, | ||
1088 | 0.0, 0.0, render_surface_iterator, &data); | ||
1089 | } | ||
1090 | } | ||
1091 | goto renderer_end; | ||
1013 | } | 1092 | } |
1014 | 1093 | ||
1015 | if (output_has_opaque_overlay_layer_surface(output)) { | 1094 | if (output_has_opaque_overlay_layer_surface(output)) { |
@@ -1110,7 +1189,7 @@ renderer_end: | |||
1110 | wlr_region_transform(&frame_damage, &output->damage->current, | 1189 | wlr_region_transform(&frame_damage, &output->damage->current, |
1111 | transform, width, height); | 1190 | transform, width, height); |
1112 | 1191 | ||
1113 | if (debug.damage == DAMAGE_HIGHLIGHT) { | 1192 | if (debug.damage != DAMAGE_DEFAULT) { |
1114 | pixman_region32_union_rect(&frame_damage, &frame_damage, | 1193 | pixman_region32_union_rect(&frame_damage, &frame_damage, |
1115 | 0, 0, wlr_output->width, wlr_output->height); | 1194 | 0, 0, wlr_output->width, wlr_output->height); |
1116 | } | 1195 | } |
diff --git a/sway/desktop/surface.c b/sway/desktop/surface.c index 767b2045..1d7b536d 100644 --- a/sway/desktop/surface.c +++ b/sway/desktop/surface.c | |||
@@ -1,7 +1,7 @@ | |||
1 | #define _POSIX_C_SOURCE 200112L | 1 | #define _POSIX_C_SOURCE 200112L |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <time.h> | 3 | #include <time.h> |
4 | #include <wlr/types/wlr_surface.h> | 4 | #include <wlr/types/wlr_compositor.h> |
5 | #include "sway/server.h" | 5 | #include "sway/server.h" |
6 | #include "sway/surface.h" | 6 | #include "sway/surface.h" |
7 | 7 | ||
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index eac38991..f5a3a053 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -35,6 +35,8 @@ struct sway_transaction_instruction { | |||
35 | struct sway_container_state container_state; | 35 | struct sway_container_state container_state; |
36 | }; | 36 | }; |
37 | uint32_t serial; | 37 | uint32_t serial; |
38 | bool server_request; | ||
39 | bool waiting; | ||
38 | }; | 40 | }; |
39 | 41 | ||
40 | static struct sway_transaction *transaction_create(void) { | 42 | static struct sway_transaction *transaction_create(void) { |
@@ -86,7 +88,11 @@ static void transaction_destroy(struct sway_transaction *transaction) { | |||
86 | static void copy_output_state(struct sway_output *output, | 88 | static void copy_output_state(struct sway_output *output, |
87 | struct sway_transaction_instruction *instruction) { | 89 | struct sway_transaction_instruction *instruction) { |
88 | struct sway_output_state *state = &instruction->output_state; | 90 | struct sway_output_state *state = &instruction->output_state; |
89 | state->workspaces = create_list(); | 91 | if (state->workspaces) { |
92 | state->workspaces->length = 0; | ||
93 | } else { | ||
94 | state->workspaces = create_list(); | ||
95 | } | ||
90 | list_cat(state->workspaces, output->workspaces); | 96 | list_cat(state->workspaces, output->workspaces); |
91 | 97 | ||
92 | state->active_workspace = output_get_active_workspace(output); | 98 | state->active_workspace = output_get_active_workspace(output); |
@@ -104,8 +110,16 @@ static void copy_workspace_state(struct sway_workspace *ws, | |||
104 | state->layout = ws->layout; | 110 | state->layout = ws->layout; |
105 | 111 | ||
106 | state->output = ws->output; | 112 | state->output = ws->output; |
107 | state->floating = create_list(); | 113 | if (state->floating) { |
108 | state->tiling = create_list(); | 114 | state->floating->length = 0; |
115 | } else { | ||
116 | state->floating = create_list(); | ||
117 | } | ||
118 | if (state->tiling) { | ||
119 | state->tiling->length = 0; | ||
120 | } else { | ||
121 | state->tiling = create_list(); | ||
122 | } | ||
109 | list_cat(state->floating, ws->floating); | 123 | list_cat(state->floating, ws->floating); |
110 | list_cat(state->tiling, ws->tiling); | 124 | list_cat(state->tiling, ws->tiling); |
111 | 125 | ||
@@ -115,8 +129,8 @@ static void copy_workspace_state(struct sway_workspace *ws, | |||
115 | // Set focused_inactive_child to the direct tiling child | 129 | // Set focused_inactive_child to the direct tiling child |
116 | struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws); | 130 | struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws); |
117 | if (focus) { | 131 | if (focus) { |
118 | while (focus->parent) { | 132 | while (focus->pending.parent) { |
119 | focus = focus->parent; | 133 | focus = focus->pending.parent; |
120 | } | 134 | } |
121 | } | 135 | } |
122 | state->focused_inactive_child = focus; | 136 | state->focused_inactive_child = focus; |
@@ -126,28 +140,19 @@ static void copy_container_state(struct sway_container *container, | |||
126 | struct sway_transaction_instruction *instruction) { | 140 | struct sway_transaction_instruction *instruction) { |
127 | struct sway_container_state *state = &instruction->container_state; | 141 | struct sway_container_state *state = &instruction->container_state; |
128 | 142 | ||
129 | state->layout = container->layout; | 143 | if (state->children) { |
130 | state->x = container->x; | 144 | list_free(state->children); |
131 | state->y = container->y; | 145 | } |
132 | state->width = container->width; | 146 | |
133 | state->height = container->height; | 147 | memcpy(state, &container->pending, sizeof(struct sway_container_state)); |
134 | state->fullscreen_mode = container->fullscreen_mode; | ||
135 | state->parent = container->parent; | ||
136 | state->workspace = container->workspace; | ||
137 | state->border = container->border; | ||
138 | state->border_thickness = container->border_thickness; | ||
139 | state->border_top = container->border_top; | ||
140 | state->border_left = container->border_left; | ||
141 | state->border_right = container->border_right; | ||
142 | state->border_bottom = container->border_bottom; | ||
143 | state->content_x = container->content_x; | ||
144 | state->content_y = container->content_y; | ||
145 | state->content_width = container->content_width; | ||
146 | state->content_height = container->content_height; | ||
147 | 148 | ||
148 | if (!container->view) { | 149 | if (!container->view) { |
150 | // We store a copy of the child list to avoid having it mutated after | ||
151 | // we copy the state. | ||
149 | state->children = create_list(); | 152 | state->children = create_list(); |
150 | list_cat(state->children, container->children); | 153 | list_cat(state->children, container->pending.children); |
154 | } else { | ||
155 | state->children = NULL; | ||
151 | } | 156 | } |
152 | 157 | ||
153 | struct sway_seat *seat = input_manager_current_seat(); | 158 | struct sway_seat *seat = input_manager_current_seat(); |
@@ -161,14 +166,36 @@ static void copy_container_state(struct sway_container *container, | |||
161 | } | 166 | } |
162 | 167 | ||
163 | static void transaction_add_node(struct sway_transaction *transaction, | 168 | static void transaction_add_node(struct sway_transaction *transaction, |
164 | struct sway_node *node) { | 169 | struct sway_node *node, bool server_request) { |
165 | struct sway_transaction_instruction *instruction = | 170 | struct sway_transaction_instruction *instruction = NULL; |
166 | calloc(1, sizeof(struct sway_transaction_instruction)); | 171 | |
167 | if (!sway_assert(instruction, "Unable to allocate instruction")) { | 172 | // Check if we have an instruction for this node already, in which case we |
168 | return; | 173 | // update that instead of creating a new one. |
174 | if (node->ntxnrefs > 0) { | ||
175 | for (int idx = 0; idx < transaction->instructions->length; idx++) { | ||
176 | struct sway_transaction_instruction *other = | ||
177 | transaction->instructions->items[idx]; | ||
178 | if (other->node == node) { | ||
179 | instruction = other; | ||
180 | break; | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | if (!instruction) { | ||
186 | instruction = calloc(1, sizeof(struct sway_transaction_instruction)); | ||
187 | if (!sway_assert(instruction, "Unable to allocate instruction")) { | ||
188 | return; | ||
189 | } | ||
190 | instruction->transaction = transaction; | ||
191 | instruction->node = node; | ||
192 | instruction->server_request = server_request; | ||
193 | |||
194 | list_add(transaction->instructions, instruction); | ||
195 | node->ntxnrefs++; | ||
196 | } else if (server_request) { | ||
197 | instruction->server_request = true; | ||
169 | } | 198 | } |
170 | instruction->transaction = transaction; | ||
171 | instruction->node = node; | ||
172 | 199 | ||
173 | switch (node->type) { | 200 | switch (node->type) { |
174 | case N_ROOT: | 201 | case N_ROOT: |
@@ -183,9 +210,6 @@ static void transaction_add_node(struct sway_transaction *transaction, | |||
183 | copy_container_state(node->sway_container, instruction); | 210 | copy_container_state(node->sway_container, instruction); |
184 | break; | 211 | break; |
185 | } | 212 | } |
186 | |||
187 | list_add(transaction->instructions, instruction); | ||
188 | node->ntxnrefs++; | ||
189 | } | 213 | } |
190 | 214 | ||
191 | static void apply_output_state(struct sway_output *output, | 215 | static void apply_output_state(struct sway_output *output, |
@@ -214,8 +238,8 @@ static void apply_container_state(struct sway_container *container, | |||
214 | struct sway_saved_buffer *saved_buf; | 238 | struct sway_saved_buffer *saved_buf; |
215 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { | 239 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { |
216 | struct wlr_box box = { | 240 | struct wlr_box box = { |
217 | .x = container->current.content_x - view->saved_geometry.x + saved_buf->x, | 241 | .x = saved_buf->x - view->saved_geometry.x, |
218 | .y = container->current.content_y - view->saved_geometry.y + saved_buf->y, | 242 | .y = saved_buf->y - view->saved_geometry.y, |
219 | .width = saved_buf->width, | 243 | .width = saved_buf->width, |
220 | .height = saved_buf->height, | 244 | .height = saved_buf->height, |
221 | }; | 245 | }; |
@@ -238,6 +262,13 @@ static void apply_container_state(struct sway_container *container, | |||
238 | } | 262 | } |
239 | } | 263 | } |
240 | 264 | ||
265 | // If the view hasn't responded to the configure, center it within | ||
266 | // the container. This is important for fullscreen views which | ||
267 | // refuse to resize to the size of the output. | ||
268 | if (view && view->surface) { | ||
269 | view_center_surface(view); | ||
270 | } | ||
271 | |||
241 | // Damage the new location | 272 | // Damage the new location |
242 | desktop_damage_whole_container(container); | 273 | desktop_damage_whole_container(container); |
243 | if (view && view->surface) { | 274 | if (view && view->surface) { |
@@ -251,24 +282,6 @@ static void apply_container_state(struct sway_container *container, | |||
251 | desktop_damage_box(&box); | 282 | desktop_damage_box(&box); |
252 | } | 283 | } |
253 | 284 | ||
254 | // If the view hasn't responded to the configure, center it within | ||
255 | // the container. This is important for fullscreen views which | ||
256 | // refuse to resize to the size of the output. | ||
257 | if (view && view->surface) { | ||
258 | if (view->geometry.width < container->current.content_width) { | ||
259 | container->surface_x = container->current.content_x + | ||
260 | (container->current.content_width - view->geometry.width) / 2; | ||
261 | } else { | ||
262 | container->surface_x = container->current.content_x; | ||
263 | } | ||
264 | if (view->geometry.height < container->current.content_height) { | ||
265 | container->surface_y = container->current.content_y + | ||
266 | (container->current.content_height - view->geometry.height) / 2; | ||
267 | } else { | ||
268 | container->surface_y = container->current.content_y; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | if (!container->node.destroying) { | 285 | if (!container->node.destroying) { |
273 | container_discover_outputs(container); | 286 | container_discover_outputs(container); |
274 | } | 287 | } |
@@ -317,70 +330,25 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
317 | cursor_rebase_all(); | 330 | cursor_rebase_all(); |
318 | } | 331 | } |
319 | 332 | ||
320 | static void transaction_commit(struct sway_transaction *transaction); | 333 | static void transaction_commit_pending(void); |
321 | 334 | ||
322 | // Return true if both transactions operate on the same nodes | 335 | static void transaction_progress(void) { |
323 | static bool transaction_same_nodes(struct sway_transaction *a, | 336 | if (!server.queued_transaction) { |
324 | struct sway_transaction *b) { | ||
325 | if (a->instructions->length != b->instructions->length) { | ||
326 | return false; | ||
327 | } | ||
328 | for (int i = 0; i < a->instructions->length; ++i) { | ||
329 | struct sway_transaction_instruction *a_inst = a->instructions->items[i]; | ||
330 | struct sway_transaction_instruction *b_inst = b->instructions->items[i]; | ||
331 | if (a_inst->node != b_inst->node) { | ||
332 | return false; | ||
333 | } | ||
334 | } | ||
335 | return true; | ||
336 | } | ||
337 | |||
338 | static void transaction_progress_queue(void) { | ||
339 | if (!server.transactions->length) { | ||
340 | return; | 337 | return; |
341 | } | 338 | } |
342 | // Only the first transaction in the queue is committed, so that's the one | 339 | if (server.queued_transaction->num_waiting > 0) { |
343 | // we try to process. | ||
344 | struct sway_transaction *transaction = server.transactions->items[0]; | ||
345 | if (transaction->num_waiting) { | ||
346 | return; | 340 | return; |
347 | } | 341 | } |
348 | transaction_apply(transaction); | 342 | transaction_apply(server.queued_transaction); |
349 | transaction_destroy(transaction); | 343 | transaction_destroy(server.queued_transaction); |
350 | list_del(server.transactions, 0); | 344 | server.queued_transaction = NULL; |
351 | 345 | ||
352 | if (server.transactions->length == 0) { | 346 | if (!server.pending_transaction) { |
353 | // The transaction queue is empty, so we're done. | ||
354 | sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); | 347 | sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); |
355 | return; | 348 | return; |
356 | } | 349 | } |
357 | 350 | ||
358 | // If there's a bunch of consecutive transactions which all apply to the | 351 | transaction_commit_pending(); |
359 | // same views, skip all except the last one. | ||
360 | while (server.transactions->length >= 2) { | ||
361 | struct sway_transaction *txn = server.transactions->items[0]; | ||
362 | struct sway_transaction *dup = NULL; | ||
363 | |||
364 | for (int i = 1; i < server.transactions->length; i++) { | ||
365 | struct sway_transaction *maybe_dup = server.transactions->items[i]; | ||
366 | if (transaction_same_nodes(txn, maybe_dup)) { | ||
367 | dup = maybe_dup; | ||
368 | break; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | if (dup) { | ||
373 | list_del(server.transactions, 0); | ||
374 | transaction_destroy(txn); | ||
375 | } else { | ||
376 | break; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | // We again commit the first transaction in the queue to process it. | ||
381 | transaction = server.transactions->items[0]; | ||
382 | transaction_commit(transaction); | ||
383 | transaction_progress_queue(); | ||
384 | } | 352 | } |
385 | 353 | ||
386 | static int handle_timeout(void *data) { | 354 | static int handle_timeout(void *data) { |
@@ -388,7 +356,7 @@ static int handle_timeout(void *data) { | |||
388 | sway_log(SWAY_DEBUG, "Transaction %p timed out (%zi waiting)", | 356 | sway_log(SWAY_DEBUG, "Transaction %p timed out (%zi waiting)", |
389 | transaction, transaction->num_waiting); | 357 | transaction, transaction->num_waiting); |
390 | transaction->num_waiting = 0; | 358 | transaction->num_waiting = 0; |
391 | transaction_progress_queue(); | 359 | transaction_progress(); |
392 | return 0; | 360 | return 0; |
393 | } | 361 | } |
394 | 362 | ||
@@ -400,6 +368,9 @@ static bool should_configure(struct sway_node *node, | |||
400 | if (node->destroying) { | 368 | if (node->destroying) { |
401 | return false; | 369 | return false; |
402 | } | 370 | } |
371 | if (!instruction->server_request) { | ||
372 | return false; | ||
373 | } | ||
403 | struct sway_container_state *cstate = &node->sway_container->current; | 374 | struct sway_container_state *cstate = &node->sway_container->current; |
404 | struct sway_container_state *istate = &instruction->container_state; | 375 | struct sway_container_state *istate = &instruction->container_state; |
405 | #if HAVE_XWAYLAND | 376 | #if HAVE_XWAYLAND |
@@ -431,13 +402,18 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
431 | struct sway_transaction_instruction *instruction = | 402 | struct sway_transaction_instruction *instruction = |
432 | transaction->instructions->items[i]; | 403 | transaction->instructions->items[i]; |
433 | struct sway_node *node = instruction->node; | 404 | struct sway_node *node = instruction->node; |
405 | bool hidden = node_is_view(node) && !node->destroying && | ||
406 | !view_is_visible(node->sway_container->view); | ||
434 | if (should_configure(node, instruction)) { | 407 | if (should_configure(node, instruction)) { |
435 | instruction->serial = view_configure(node->sway_container->view, | 408 | instruction->serial = view_configure(node->sway_container->view, |
436 | instruction->container_state.content_x, | 409 | instruction->container_state.content_x, |
437 | instruction->container_state.content_y, | 410 | instruction->container_state.content_y, |
438 | instruction->container_state.content_width, | 411 | instruction->container_state.content_width, |
439 | instruction->container_state.content_height); | 412 | instruction->container_state.content_height); |
440 | ++transaction->num_waiting; | 413 | if (!hidden) { |
414 | instruction->waiting = true; | ||
415 | ++transaction->num_waiting; | ||
416 | } | ||
441 | 417 | ||
442 | // From here on we are rendering a saved buffer of the view, which | 418 | // From here on we are rendering a saved buffer of the view, which |
443 | // means we can send a frame done event to make the client redraw it | 419 | // means we can send a frame done event to make the client redraw it |
@@ -448,7 +424,8 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
448 | wlr_surface_send_frame_done( | 424 | wlr_surface_send_frame_done( |
449 | node->sway_container->view->surface, &now); | 425 | node->sway_container->view->surface, &now); |
450 | } | 426 | } |
451 | if (node_is_view(node) && wl_list_empty(&node->sway_container->view->saved_buffers)) { | 427 | if (!hidden && node_is_view(node) && |
428 | wl_list_empty(&node->sway_container->view->saved_buffers)) { | ||
452 | view_save_buffer(node->sway_container->view); | 429 | view_save_buffer(node->sway_container->view); |
453 | memcpy(&node->sway_container->view->saved_geometry, | 430 | memcpy(&node->sway_container->view->saved_geometry, |
454 | &node->sway_container->view->geometry, | 431 | &node->sway_container->view->geometry, |
@@ -483,6 +460,17 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
483 | } | 460 | } |
484 | } | 461 | } |
485 | 462 | ||
463 | static void transaction_commit_pending(void) { | ||
464 | if (server.queued_transaction) { | ||
465 | return; | ||
466 | } | ||
467 | struct sway_transaction *transaction = server.pending_transaction; | ||
468 | server.pending_transaction = NULL; | ||
469 | server.queued_transaction = transaction; | ||
470 | transaction_commit(transaction); | ||
471 | transaction_progress(); | ||
472 | } | ||
473 | |||
486 | static void set_instruction_ready( | 474 | static void set_instruction_ready( |
487 | struct sway_transaction_instruction *instruction) { | 475 | struct sway_transaction_instruction *instruction) { |
488 | struct sway_transaction *transaction = instruction->transaction; | 476 | struct sway_transaction *transaction = instruction->transaction; |
@@ -501,13 +489,14 @@ static void set_instruction_ready( | |||
501 | } | 489 | } |
502 | 490 | ||
503 | // If the transaction has timed out then its num_waiting will be 0 already. | 491 | // If the transaction has timed out then its num_waiting will be 0 already. |
504 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { | 492 | if (instruction->waiting && transaction->num_waiting > 0 && |
493 | --transaction->num_waiting == 0) { | ||
505 | sway_log(SWAY_DEBUG, "Transaction %p is ready", transaction); | 494 | sway_log(SWAY_DEBUG, "Transaction %p is ready", transaction); |
506 | wl_event_source_timer_update(transaction->timer, 0); | 495 | wl_event_source_timer_update(transaction->timer, 0); |
507 | } | 496 | } |
508 | 497 | ||
509 | instruction->node->instruction = NULL; | 498 | instruction->node->instruction = NULL; |
510 | transaction_progress_queue(); | 499 | transaction_progress(); |
511 | } | 500 | } |
512 | 501 | ||
513 | void transaction_notify_view_ready_by_serial(struct sway_view *view, | 502 | void transaction_notify_view_ready_by_serial(struct sway_view *view, |
@@ -532,36 +521,32 @@ void transaction_notify_view_ready_by_geometry(struct sway_view *view, | |||
532 | } | 521 | } |
533 | } | 522 | } |
534 | 523 | ||
535 | void transaction_notify_view_ready_immediately(struct sway_view *view) { | 524 | static void _transaction_commit_dirty(bool server_request) { |
536 | struct sway_transaction_instruction *instruction = | ||
537 | view->container->node.instruction; | ||
538 | if (instruction != NULL) { | ||
539 | set_instruction_ready(instruction); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | void transaction_commit_dirty(void) { | ||
544 | if (!server.dirty_nodes->length) { | 525 | if (!server.dirty_nodes->length) { |
545 | return; | 526 | return; |
546 | } | 527 | } |
547 | struct sway_transaction *transaction = transaction_create(); | 528 | |
548 | if (!transaction) { | 529 | if (!server.pending_transaction) { |
549 | return; | 530 | server.pending_transaction = transaction_create(); |
531 | if (!server.pending_transaction) { | ||
532 | return; | ||
533 | } | ||
550 | } | 534 | } |
535 | |||
551 | for (int i = 0; i < server.dirty_nodes->length; ++i) { | 536 | for (int i = 0; i < server.dirty_nodes->length; ++i) { |
552 | struct sway_node *node = server.dirty_nodes->items[i]; | 537 | struct sway_node *node = server.dirty_nodes->items[i]; |
553 | transaction_add_node(transaction, node); | 538 | transaction_add_node(server.pending_transaction, node, server_request); |
554 | node->dirty = false; | 539 | node->dirty = false; |
555 | } | 540 | } |
556 | server.dirty_nodes->length = 0; | 541 | server.dirty_nodes->length = 0; |
557 | 542 | ||
558 | list_add(server.transactions, transaction); | 543 | transaction_commit_pending(); |
544 | } | ||
559 | 545 | ||
560 | // We only commit the first transaction added to the queue. | 546 | void transaction_commit_dirty(void) { |
561 | if (server.transactions->length == 1) { | 547 | _transaction_commit_dirty(true); |
562 | transaction_commit(transaction); | 548 | } |
563 | // Attempting to progress the queue here is useful | 549 | |
564 | // if the transaction has nothing to wait for. | 550 | void transaction_commit_dirty_client(void) { |
565 | transaction_progress_queue(); | 551 | _transaction_commit_dirty(false); |
566 | } | ||
567 | } | 552 | } |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 667fb9e5..8da922d5 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -21,18 +21,15 @@ | |||
21 | 21 | ||
22 | static const struct sway_view_child_impl popup_impl; | 22 | static const struct sway_view_child_impl popup_impl; |
23 | 23 | ||
24 | static void popup_get_root_coords(struct sway_view_child *child, | 24 | static void popup_get_view_coords(struct sway_view_child *child, |
25 | int *root_sx, int *root_sy) { | 25 | int *sx, int *sy) { |
26 | struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; | 26 | struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; |
27 | struct wlr_xdg_surface *surface = popup->wlr_xdg_surface; | 27 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; |
28 | 28 | ||
29 | int x_offset = -child->view->geometry.x - surface->geometry.x; | 29 | wlr_xdg_popup_get_toplevel_coords(wlr_popup, |
30 | int y_offset = -child->view->geometry.y - surface->geometry.y; | 30 | wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x, |
31 | 31 | wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y, | |
32 | wlr_xdg_popup_get_toplevel_coords(surface->popup, | 32 | sx, sy); |
33 | x_offset + surface->popup->geometry.x, | ||
34 | y_offset + surface->popup->geometry.y, | ||
35 | root_sx, root_sy); | ||
36 | } | 33 | } |
37 | 34 | ||
38 | static void popup_destroy(struct sway_view_child *child) { | 35 | static void popup_destroy(struct sway_view_child *child) { |
@@ -47,7 +44,7 @@ static void popup_destroy(struct sway_view_child *child) { | |||
47 | } | 44 | } |
48 | 45 | ||
49 | static const struct sway_view_child_impl popup_impl = { | 46 | static const struct sway_view_child_impl popup_impl = { |
50 | .get_root_coords = popup_get_root_coords, | 47 | .get_view_coords = popup_get_view_coords, |
51 | .destroy = popup_destroy, | 48 | .destroy = popup_destroy, |
52 | }; | 49 | }; |
53 | 50 | ||
@@ -68,15 +65,15 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { | |||
68 | 65 | ||
69 | static void popup_unconstrain(struct sway_xdg_popup *popup) { | 66 | static void popup_unconstrain(struct sway_xdg_popup *popup) { |
70 | struct sway_view *view = popup->child.view; | 67 | struct sway_view *view = popup->child.view; |
71 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; | 68 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; |
72 | 69 | ||
73 | struct sway_output *output = view->container->workspace->output; | 70 | struct sway_output *output = view->container->pending.workspace->output; |
74 | 71 | ||
75 | // the output box expressed in the coordinate system of the toplevel parent | 72 | // the output box expressed in the coordinate system of the toplevel parent |
76 | // of the popup | 73 | // of the popup |
77 | struct wlr_box output_toplevel_sx_box = { | 74 | struct wlr_box output_toplevel_sx_box = { |
78 | .x = output->lx - view->container->content_x, | 75 | .x = output->lx - view->container->pending.content_x + view->geometry.x, |
79 | .y = output->ly - view->container->content_y, | 76 | .y = output->ly - view->container->pending.content_y + view->geometry.y, |
80 | .width = output->width, | 77 | .width = output->width, |
81 | .height = output->height, | 78 | .height = output->height, |
82 | }; | 79 | }; |
@@ -94,7 +91,7 @@ static struct sway_xdg_popup *popup_create( | |||
94 | return NULL; | 91 | return NULL; |
95 | } | 92 | } |
96 | view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); | 93 | view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); |
97 | popup->wlr_xdg_surface = xdg_surface; | 94 | popup->wlr_xdg_popup = xdg_surface->popup; |
98 | 95 | ||
99 | wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); | 96 | wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); |
100 | popup->new_popup.notify = popup_handle_new_popup; | 97 | popup->new_popup.notify = popup_handle_new_popup; |
@@ -122,7 +119,7 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view( | |||
122 | static void get_constraints(struct sway_view *view, double *min_width, | 119 | static void get_constraints(struct sway_view *view, double *min_width, |
123 | double *max_width, double *min_height, double *max_height) { | 120 | double *max_width, double *min_height, double *max_height) { |
124 | struct wlr_xdg_toplevel_state *state = | 121 | struct wlr_xdg_toplevel_state *state = |
125 | &view->wlr_xdg_surface->toplevel->current; | 122 | &view->wlr_xdg_toplevel->current; |
126 | *min_width = state->min_width > 0 ? state->min_width : DBL_MIN; | 123 | *min_width = state->min_width > 0 ? state->min_width : DBL_MIN; |
127 | *max_width = state->max_width > 0 ? state->max_width : DBL_MAX; | 124 | *max_width = state->max_width > 0 ? state->max_width : DBL_MAX; |
128 | *min_height = state->min_height > 0 ? state->min_height : DBL_MIN; | 125 | *min_height = state->min_height > 0 ? state->min_height : DBL_MIN; |
@@ -136,9 +133,9 @@ static const char *get_string_prop(struct sway_view *view, | |||
136 | } | 133 | } |
137 | switch (prop) { | 134 | switch (prop) { |
138 | case VIEW_PROP_TITLE: | 135 | case VIEW_PROP_TITLE: |
139 | return view->wlr_xdg_surface->toplevel->title; | 136 | return view->wlr_xdg_toplevel->title; |
140 | case VIEW_PROP_APP_ID: | 137 | case VIEW_PROP_APP_ID: |
141 | return view->wlr_xdg_surface->toplevel->app_id; | 138 | return view->wlr_xdg_toplevel->app_id; |
142 | default: | 139 | default: |
143 | return NULL; | 140 | return NULL; |
144 | } | 141 | } |
@@ -151,50 +148,45 @@ static uint32_t configure(struct sway_view *view, double lx, double ly, | |||
151 | if (xdg_shell_view == NULL) { | 148 | if (xdg_shell_view == NULL) { |
152 | return 0; | 149 | return 0; |
153 | } | 150 | } |
154 | return wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height); | 151 | return wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel, |
152 | width, height); | ||
155 | } | 153 | } |
156 | 154 | ||
157 | static void set_activated(struct sway_view *view, bool activated) { | 155 | static void set_activated(struct sway_view *view, bool activated) { |
158 | if (xdg_shell_view_from_view(view) == NULL) { | 156 | if (xdg_shell_view_from_view(view) == NULL) { |
159 | return; | 157 | return; |
160 | } | 158 | } |
161 | struct wlr_xdg_surface *surface = view->wlr_xdg_surface; | 159 | wlr_xdg_toplevel_set_activated(view->wlr_xdg_toplevel, activated); |
162 | if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||
163 | wlr_xdg_toplevel_set_activated(surface, activated); | ||
164 | } | ||
165 | } | 160 | } |
166 | 161 | ||
167 | static void set_tiled(struct sway_view *view, bool tiled) { | 162 | static void set_tiled(struct sway_view *view, bool tiled) { |
168 | if (xdg_shell_view_from_view(view) == NULL) { | 163 | if (xdg_shell_view_from_view(view) == NULL) { |
169 | return; | 164 | return; |
170 | } | 165 | } |
171 | struct wlr_xdg_surface *surface = view->wlr_xdg_surface; | ||
172 | enum wlr_edges edges = WLR_EDGE_NONE; | 166 | enum wlr_edges edges = WLR_EDGE_NONE; |
173 | if (tiled) { | 167 | if (tiled) { |
174 | edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | | 168 | edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | |
175 | WLR_EDGE_BOTTOM; | 169 | WLR_EDGE_BOTTOM; |
176 | } | 170 | } |
177 | wlr_xdg_toplevel_set_tiled(surface, edges); | 171 | wlr_xdg_toplevel_set_tiled(view->wlr_xdg_toplevel, edges); |
178 | } | 172 | } |
179 | 173 | ||
180 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { | 174 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { |
181 | if (xdg_shell_view_from_view(view) == NULL) { | 175 | if (xdg_shell_view_from_view(view) == NULL) { |
182 | return; | 176 | return; |
183 | } | 177 | } |
184 | struct wlr_xdg_surface *surface = view->wlr_xdg_surface; | 178 | wlr_xdg_toplevel_set_fullscreen(view->wlr_xdg_toplevel, fullscreen); |
185 | wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); | ||
186 | } | 179 | } |
187 | 180 | ||
188 | static void set_resizing(struct sway_view *view, bool resizing) { | 181 | static void set_resizing(struct sway_view *view, bool resizing) { |
189 | if (xdg_shell_view_from_view(view) == NULL) { | 182 | if (xdg_shell_view_from_view(view) == NULL) { |
190 | return; | 183 | return; |
191 | } | 184 | } |
192 | struct wlr_xdg_surface *surface = view->wlr_xdg_surface; | 185 | wlr_xdg_toplevel_set_resizing(view->wlr_xdg_toplevel, resizing); |
193 | wlr_xdg_toplevel_set_resizing(surface, resizing); | ||
194 | } | 186 | } |
195 | 187 | ||
196 | static bool wants_floating(struct sway_view *view) { | 188 | static bool wants_floating(struct sway_view *view) { |
197 | struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_surface->toplevel; | 189 | struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel; |
198 | struct wlr_xdg_toplevel_state *state = &toplevel->current; | 190 | struct wlr_xdg_toplevel_state *state = &toplevel->current; |
199 | return (state->min_width != 0 && state->min_height != 0 | 191 | return (state->min_width != 0 && state->min_height != 0 |
200 | && (state->min_width == state->max_width | 192 | && (state->min_width == state->max_width |
@@ -207,7 +199,7 @@ static void for_each_surface(struct sway_view *view, | |||
207 | if (xdg_shell_view_from_view(view) == NULL) { | 199 | if (xdg_shell_view_from_view(view) == NULL) { |
208 | return; | 200 | return; |
209 | } | 201 | } |
210 | wlr_xdg_surface_for_each_surface(view->wlr_xdg_surface, iterator, | 202 | wlr_xdg_surface_for_each_surface(view->wlr_xdg_toplevel->base, iterator, |
211 | user_data); | 203 | user_data); |
212 | } | 204 | } |
213 | 205 | ||
@@ -216,8 +208,8 @@ static void for_each_popup_surface(struct sway_view *view, | |||
216 | if (xdg_shell_view_from_view(view) == NULL) { | 208 | if (xdg_shell_view_from_view(view) == NULL) { |
217 | return; | 209 | return; |
218 | } | 210 | } |
219 | wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_surface, iterator, | 211 | wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_toplevel->base, |
220 | user_data); | 212 | iterator, user_data); |
221 | } | 213 | } |
222 | 214 | ||
223 | static bool is_transient_for(struct sway_view *child, | 215 | static bool is_transient_for(struct sway_view *child, |
@@ -225,12 +217,12 @@ static bool is_transient_for(struct sway_view *child, | |||
225 | if (xdg_shell_view_from_view(child) == NULL) { | 217 | if (xdg_shell_view_from_view(child) == NULL) { |
226 | return false; | 218 | return false; |
227 | } | 219 | } |
228 | struct wlr_xdg_surface *surface = child->wlr_xdg_surface; | 220 | struct wlr_xdg_toplevel *toplevel = child->wlr_xdg_toplevel; |
229 | while (surface && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | 221 | while (toplevel) { |
230 | if (surface->toplevel->parent == ancestor->wlr_xdg_surface) { | 222 | if (toplevel->parent == ancestor->wlr_xdg_toplevel) { |
231 | return true; | 223 | return true; |
232 | } | 224 | } |
233 | surface = surface->toplevel->parent; | 225 | toplevel = toplevel->parent; |
234 | } | 226 | } |
235 | return false; | 227 | return false; |
236 | } | 228 | } |
@@ -239,17 +231,13 @@ static void _close(struct sway_view *view) { | |||
239 | if (xdg_shell_view_from_view(view) == NULL) { | 231 | if (xdg_shell_view_from_view(view) == NULL) { |
240 | return; | 232 | return; |
241 | } | 233 | } |
242 | struct wlr_xdg_surface *surface = view->wlr_xdg_surface; | 234 | wlr_xdg_toplevel_send_close(view->wlr_xdg_toplevel); |
243 | if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL | ||
244 | && surface->toplevel) { | ||
245 | wlr_xdg_toplevel_send_close(surface); | ||
246 | } | ||
247 | } | 235 | } |
248 | 236 | ||
249 | static void close_popups(struct sway_view *view) { | 237 | static void close_popups(struct sway_view *view) { |
250 | struct wlr_xdg_popup *popup, *tmp; | 238 | struct wlr_xdg_popup *popup, *tmp; |
251 | wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_surface->popups, link) { | 239 | wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_toplevel->base->popups, link) { |
252 | wlr_xdg_popup_destroy(popup->base); | 240 | wlr_xdg_popup_destroy(popup); |
253 | } | 241 | } |
254 | } | 242 | } |
255 | 243 | ||
@@ -283,7 +271,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
283 | struct sway_xdg_shell_view *xdg_shell_view = | 271 | struct sway_xdg_shell_view *xdg_shell_view = |
284 | wl_container_of(listener, xdg_shell_view, commit); | 272 | wl_container_of(listener, xdg_shell_view, commit); |
285 | struct sway_view *view = &xdg_shell_view->view; | 273 | struct sway_view *view = &xdg_shell_view->view; |
286 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; | 274 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base; |
287 | 275 | ||
288 | struct wlr_box new_geo; | 276 | struct wlr_box new_geo; |
289 | wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); | 277 | wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); |
@@ -293,19 +281,23 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
293 | new_geo.y != view->geometry.y; | 281 | new_geo.y != view->geometry.y; |
294 | 282 | ||
295 | if (new_size) { | 283 | if (new_size) { |
296 | // The view has unexpectedly sent a new size | 284 | // The client changed its surface size in this commit. For floating |
285 | // containers, we resize the container to match. For tiling containers, | ||
286 | // we only recenter the surface. | ||
297 | desktop_damage_view(view); | 287 | desktop_damage_view(view); |
298 | view_update_size(view, new_geo.width, new_geo.height); | ||
299 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | 288 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); |
289 | if (container_is_floating(view->container)) { | ||
290 | view_update_size(view); | ||
291 | transaction_commit_dirty_client(); | ||
292 | } else { | ||
293 | view_center_surface(view); | ||
294 | } | ||
300 | desktop_damage_view(view); | 295 | desktop_damage_view(view); |
301 | transaction_commit_dirty(); | ||
302 | } | 296 | } |
303 | 297 | ||
304 | if (view->container->node.instruction) { | 298 | if (view->container->node.instruction) { |
305 | transaction_notify_view_ready_by_serial(view, | 299 | transaction_notify_view_ready_by_serial(view, |
306 | xdg_surface->configure_serial); | 300 | xdg_surface->current.configure_serial); |
307 | } else if (new_size) { | ||
308 | transaction_notify_view_ready_immediately(view); | ||
309 | } | 301 | } |
310 | 302 | ||
311 | view_damage_from(view); | 303 | view_damage_from(view); |
@@ -333,28 +325,30 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { | |||
333 | popup_create(wlr_popup, &xdg_shell_view->view); | 325 | popup_create(wlr_popup, &xdg_shell_view->view); |
334 | } | 326 | } |
335 | 327 | ||
328 | static void handle_request_maximize(struct wl_listener *listener, void *data) { | ||
329 | struct sway_xdg_shell_view *xdg_shell_view = | ||
330 | wl_container_of(listener, xdg_shell_view, request_maximize); | ||
331 | struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel; | ||
332 | wlr_xdg_surface_schedule_configure(toplevel->base); | ||
333 | } | ||
334 | |||
336 | static void handle_request_fullscreen(struct wl_listener *listener, void *data) { | 335 | static void handle_request_fullscreen(struct wl_listener *listener, void *data) { |
337 | struct sway_xdg_shell_view *xdg_shell_view = | 336 | struct sway_xdg_shell_view *xdg_shell_view = |
338 | wl_container_of(listener, xdg_shell_view, request_fullscreen); | 337 | wl_container_of(listener, xdg_shell_view, request_fullscreen); |
339 | struct wlr_xdg_toplevel_set_fullscreen_event *e = data; | 338 | struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel; |
340 | struct wlr_xdg_surface *xdg_surface = | ||
341 | xdg_shell_view->view.wlr_xdg_surface; | ||
342 | struct sway_view *view = &xdg_shell_view->view; | 339 | struct sway_view *view = &xdg_shell_view->view; |
343 | 340 | ||
344 | if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL, | 341 | if (!toplevel->base->mapped) { |
345 | "xdg_shell requested fullscreen of surface with role %i", | ||
346 | xdg_surface->role)) { | ||
347 | return; | ||
348 | } | ||
349 | if (!xdg_surface->mapped) { | ||
350 | return; | 342 | return; |
351 | } | 343 | } |
352 | 344 | ||
353 | struct sway_container *container = view->container; | 345 | struct sway_container *container = view->container; |
354 | if (e->fullscreen && e->output && e->output->data) { | 346 | struct wlr_xdg_toplevel_requested *req = &toplevel->requested; |
355 | struct sway_output *output = e->output->data; | 347 | if (req->fullscreen && req->fullscreen_output && req->fullscreen_output->data) { |
348 | struct sway_output *output = req->fullscreen_output->data; | ||
356 | struct sway_workspace *ws = output_get_active_workspace(output); | 349 | struct sway_workspace *ws = output_get_active_workspace(output); |
357 | if (ws && !container_is_scratchpad_hidden(container)) { | 350 | if (ws && !container_is_scratchpad_hidden(container) && |
351 | container->pending.workspace != ws) { | ||
358 | if (container_is_floating(container)) { | 352 | if (container_is_floating(container)) { |
359 | workspace_add_floating(ws, container); | 353 | workspace_add_floating(ws, container); |
360 | } else { | 354 | } else { |
@@ -363,22 +357,18 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
363 | } | 357 | } |
364 | } | 358 | } |
365 | 359 | ||
366 | container_set_fullscreen(container, e->fullscreen); | 360 | container_set_fullscreen(container, req->fullscreen); |
367 | 361 | ||
368 | arrange_root(); | 362 | arrange_root(); |
369 | transaction_commit_dirty(); | 363 | transaction_commit_dirty(); |
370 | } | 364 | } |
371 | 365 | ||
372 | static void handle_request_maximize(struct wl_listener *listener, void *data) { | ||
373 | struct wlr_xdg_surface *surface = data; | ||
374 | wlr_xdg_surface_schedule_configure(surface); | ||
375 | } | ||
376 | |||
377 | static void handle_request_move(struct wl_listener *listener, void *data) { | 366 | static void handle_request_move(struct wl_listener *listener, void *data) { |
378 | struct sway_xdg_shell_view *xdg_shell_view = | 367 | struct sway_xdg_shell_view *xdg_shell_view = |
379 | wl_container_of(listener, xdg_shell_view, request_move); | 368 | wl_container_of(listener, xdg_shell_view, request_move); |
380 | struct sway_view *view = &xdg_shell_view->view; | 369 | struct sway_view *view = &xdg_shell_view->view; |
381 | if (!container_is_floating(view->container)) { | 370 | if (!container_is_floating(view->container) || |
371 | view->container->pending.fullscreen_mode) { | ||
382 | return; | 372 | return; |
383 | } | 373 | } |
384 | struct wlr_xdg_toplevel_move_event *e = data; | 374 | struct wlr_xdg_toplevel_move_event *e = data; |
@@ -415,8 +405,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { | |||
415 | 405 | ||
416 | wl_list_remove(&xdg_shell_view->commit.link); | 406 | wl_list_remove(&xdg_shell_view->commit.link); |
417 | wl_list_remove(&xdg_shell_view->new_popup.link); | 407 | wl_list_remove(&xdg_shell_view->new_popup.link); |
418 | wl_list_remove(&xdg_shell_view->request_fullscreen.link); | ||
419 | wl_list_remove(&xdg_shell_view->request_maximize.link); | 408 | wl_list_remove(&xdg_shell_view->request_maximize.link); |
409 | wl_list_remove(&xdg_shell_view->request_fullscreen.link); | ||
420 | wl_list_remove(&xdg_shell_view->request_move.link); | 410 | wl_list_remove(&xdg_shell_view->request_move.link); |
421 | wl_list_remove(&xdg_shell_view->request_resize.link); | 411 | wl_list_remove(&xdg_shell_view->request_resize.link); |
422 | wl_list_remove(&xdg_shell_view->set_title.link); | 412 | wl_list_remove(&xdg_shell_view->set_title.link); |
@@ -427,62 +417,65 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
427 | struct sway_xdg_shell_view *xdg_shell_view = | 417 | struct sway_xdg_shell_view *xdg_shell_view = |
428 | wl_container_of(listener, xdg_shell_view, map); | 418 | wl_container_of(listener, xdg_shell_view, map); |
429 | struct sway_view *view = &xdg_shell_view->view; | 419 | struct sway_view *view = &xdg_shell_view->view; |
430 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; | 420 | struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel; |
431 | 421 | ||
432 | view->natural_width = view->wlr_xdg_surface->geometry.width; | 422 | view->natural_width = toplevel->base->current.geometry.width; |
433 | view->natural_height = view->wlr_xdg_surface->geometry.height; | 423 | view->natural_height = toplevel->base->current.geometry.height; |
434 | if (!view->natural_width && !view->natural_height) { | 424 | if (!view->natural_width && !view->natural_height) { |
435 | view->natural_width = view->wlr_xdg_surface->surface->current.width; | 425 | view->natural_width = toplevel->base->surface->current.width; |
436 | view->natural_height = view->wlr_xdg_surface->surface->current.height; | 426 | view->natural_height = toplevel->base->surface->current.height; |
437 | } | 427 | } |
438 | 428 | ||
439 | bool csd = false; | 429 | bool csd = false; |
440 | 430 | ||
441 | if (!view->xdg_decoration) { | 431 | if (view->xdg_decoration) { |
432 | enum wlr_xdg_toplevel_decoration_v1_mode mode = | ||
433 | view->xdg_decoration->wlr_xdg_decoration->requested_mode; | ||
434 | csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; | ||
435 | } else { | ||
442 | struct sway_server_decoration *deco = | 436 | struct sway_server_decoration *deco = |
443 | decoration_from_surface(xdg_surface->surface); | 437 | decoration_from_surface(toplevel->base->surface); |
444 | csd = !deco || deco->wlr_server_decoration->mode == | 438 | csd = !deco || deco->wlr_server_decoration->mode == |
445 | WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; | 439 | WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; |
446 | |||
447 | } | 440 | } |
448 | 441 | ||
449 | view_map(view, view->wlr_xdg_surface->surface, | 442 | view_map(view, toplevel->base->surface, |
450 | xdg_surface->toplevel->client_pending.fullscreen, | 443 | toplevel->requested.fullscreen, |
451 | xdg_surface->toplevel->client_pending.fullscreen_output, | 444 | toplevel->requested.fullscreen_output, |
452 | csd); | 445 | csd); |
453 | 446 | ||
454 | transaction_commit_dirty(); | 447 | transaction_commit_dirty(); |
455 | 448 | ||
456 | xdg_shell_view->commit.notify = handle_commit; | 449 | xdg_shell_view->commit.notify = handle_commit; |
457 | wl_signal_add(&xdg_surface->surface->events.commit, | 450 | wl_signal_add(&toplevel->base->surface->events.commit, |
458 | &xdg_shell_view->commit); | 451 | &xdg_shell_view->commit); |
459 | 452 | ||
460 | xdg_shell_view->new_popup.notify = handle_new_popup; | 453 | xdg_shell_view->new_popup.notify = handle_new_popup; |
461 | wl_signal_add(&xdg_surface->events.new_popup, | 454 | wl_signal_add(&toplevel->base->events.new_popup, |
462 | &xdg_shell_view->new_popup); | 455 | &xdg_shell_view->new_popup); |
463 | 456 | ||
464 | xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen; | ||
465 | wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, | ||
466 | &xdg_shell_view->request_fullscreen); | ||
467 | |||
468 | xdg_shell_view->request_maximize.notify = handle_request_maximize; | 457 | xdg_shell_view->request_maximize.notify = handle_request_maximize; |
469 | wl_signal_add(&xdg_surface->toplevel->events.request_maximize, | 458 | wl_signal_add(&toplevel->events.request_maximize, |
470 | &xdg_shell_view->request_maximize); | 459 | &xdg_shell_view->request_maximize); |
471 | 460 | ||
461 | xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen; | ||
462 | wl_signal_add(&toplevel->events.request_fullscreen, | ||
463 | &xdg_shell_view->request_fullscreen); | ||
464 | |||
472 | xdg_shell_view->request_move.notify = handle_request_move; | 465 | xdg_shell_view->request_move.notify = handle_request_move; |
473 | wl_signal_add(&xdg_surface->toplevel->events.request_move, | 466 | wl_signal_add(&toplevel->events.request_move, |
474 | &xdg_shell_view->request_move); | 467 | &xdg_shell_view->request_move); |
475 | 468 | ||
476 | xdg_shell_view->request_resize.notify = handle_request_resize; | 469 | xdg_shell_view->request_resize.notify = handle_request_resize; |
477 | wl_signal_add(&xdg_surface->toplevel->events.request_resize, | 470 | wl_signal_add(&toplevel->events.request_resize, |
478 | &xdg_shell_view->request_resize); | 471 | &xdg_shell_view->request_resize); |
479 | 472 | ||
480 | xdg_shell_view->set_title.notify = handle_set_title; | 473 | xdg_shell_view->set_title.notify = handle_set_title; |
481 | wl_signal_add(&xdg_surface->toplevel->events.set_title, | 474 | wl_signal_add(&toplevel->events.set_title, |
482 | &xdg_shell_view->set_title); | 475 | &xdg_shell_view->set_title); |
483 | 476 | ||
484 | xdg_shell_view->set_app_id.notify = handle_set_app_id; | 477 | xdg_shell_view->set_app_id.notify = handle_set_app_id; |
485 | wl_signal_add(&xdg_surface->toplevel->events.set_app_id, | 478 | wl_signal_add(&toplevel->events.set_app_id, |
486 | &xdg_shell_view->set_app_id); | 479 | &xdg_shell_view->set_app_id); |
487 | } | 480 | } |
488 | 481 | ||
@@ -496,7 +489,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
496 | wl_list_remove(&xdg_shell_view->destroy.link); | 489 | wl_list_remove(&xdg_shell_view->destroy.link); |
497 | wl_list_remove(&xdg_shell_view->map.link); | 490 | wl_list_remove(&xdg_shell_view->map.link); |
498 | wl_list_remove(&xdg_shell_view->unmap.link); | 491 | wl_list_remove(&xdg_shell_view->unmap.link); |
499 | view->wlr_xdg_surface = NULL; | 492 | view->wlr_xdg_toplevel = NULL; |
500 | if (view->xdg_decoration) { | 493 | if (view->xdg_decoration) { |
501 | view->xdg_decoration->view = NULL; | 494 | view->xdg_decoration->view = NULL; |
502 | } | 495 | } |
@@ -527,7 +520,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { | |||
527 | } | 520 | } |
528 | 521 | ||
529 | view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); | 522 | view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); |
530 | xdg_shell_view->view.wlr_xdg_surface = xdg_surface; | 523 | xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel; |
531 | 524 | ||
532 | xdg_shell_view->map.notify = handle_map; | 525 | xdg_shell_view->map.notify = handle_map; |
533 | wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); | 526 | wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index e1a2e463..7c5dde53 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <wlr/types/wlr_output_layout.h> | 6 | #include <wlr/types/wlr_output_layout.h> |
7 | #include <wlr/types/wlr_output.h> | 7 | #include <wlr/types/wlr_output.h> |
8 | #include <wlr/xwayland.h> | 8 | #include <wlr/xwayland.h> |
9 | #include <xcb/xcb_icccm.h> | ||
9 | #include "log.h" | 10 | #include "log.h" |
10 | #include "sway/desktop.h" | 11 | #include "sway/desktop.h" |
11 | #include "sway/desktop/transaction.h" | 12 | #include "sway/desktop/transaction.h" |
@@ -105,14 +106,10 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
105 | if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { | 106 | if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { |
106 | // This simply returns focus to the parent surface if there's one available. | 107 | // This simply returns focus to the parent surface if there's one available. |
107 | // This seems to handle JetBrains issues. | 108 | // This seems to handle JetBrains issues. |
108 | if (xsurface->parent && xsurface->parent->surface && | 109 | if (xsurface->parent && xsurface->parent->surface |
109 | wlr_surface_is_xwayland_surface(xsurface->parent->surface)) { | 110 | && wlr_xwayland_or_surface_wants_focus(xsurface->parent)) { |
110 | struct wlr_xwayland_surface *next_surface = | 111 | seat_set_focus_surface(seat, xsurface->parent->surface, false); |
111 | wlr_xwayland_surface_from_wlr_surface(xsurface->parent->surface); | 112 | return; |
112 | if (wlr_xwayland_or_surface_wants_focus(next_surface)) { | ||
113 | seat_set_focus_surface(seat, xsurface->parent->surface, false); | ||
114 | return; | ||
115 | } | ||
116 | } | 113 | } |
117 | 114 | ||
118 | // Restore focus | 115 | // Restore focus |
@@ -125,6 +122,20 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
125 | } | 122 | } |
126 | } | 123 | } |
127 | 124 | ||
125 | static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) { | ||
126 | struct wlr_xwayland_surface *xsurface = data; | ||
127 | if (!xsurface->mapped) { | ||
128 | return; | ||
129 | } | ||
130 | struct sway_seat *seat = input_manager_current_seat(); | ||
131 | struct sway_container *focus = seat_get_focused_container(seat); | ||
132 | if (focus && focus->view && focus->view->pid != xsurface->pid) { | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | seat_set_focus_surface(seat, xsurface->surface, false); | ||
137 | } | ||
138 | |||
128 | static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { | 139 | static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { |
129 | struct sway_xwayland_unmanaged *surface = | 140 | struct sway_xwayland_unmanaged *surface = |
130 | wl_container_of(listener, surface, destroy); | 141 | wl_container_of(listener, surface, destroy); |
@@ -133,6 +144,7 @@ static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { | |||
133 | wl_list_remove(&surface->unmap.link); | 144 | wl_list_remove(&surface->unmap.link); |
134 | wl_list_remove(&surface->destroy.link); | 145 | wl_list_remove(&surface->destroy.link); |
135 | wl_list_remove(&surface->override_redirect.link); | 146 | wl_list_remove(&surface->override_redirect.link); |
147 | wl_list_remove(&surface->request_activate.link); | ||
136 | free(surface); | 148 | free(surface); |
137 | } | 149 | } |
138 | 150 | ||
@@ -180,6 +192,8 @@ static struct sway_xwayland_unmanaged *create_unmanaged( | |||
180 | surface->destroy.notify = unmanaged_handle_destroy; | 192 | surface->destroy.notify = unmanaged_handle_destroy; |
181 | wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); | 193 | wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); |
182 | surface->override_redirect.notify = unmanaged_handle_override_redirect; | 194 | surface->override_redirect.notify = unmanaged_handle_override_redirect; |
195 | wl_signal_add(&xsurface->events.request_activate, &surface->request_activate); | ||
196 | surface->request_activate.notify = unmanaged_handle_request_activate; | ||
183 | 197 | ||
184 | return surface; | 198 | return surface; |
185 | } | 199 | } |
@@ -258,6 +272,7 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
258 | } | 272 | } |
259 | 273 | ||
260 | wlr_xwayland_surface_activate(surface, activated); | 274 | wlr_xwayland_surface_activate(surface, activated); |
275 | wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE); | ||
261 | } | 276 | } |
262 | 277 | ||
263 | static void set_tiled(struct sway_view *view, bool tiled) { | 278 | static void set_tiled(struct sway_view *view, bool tiled) { |
@@ -297,7 +312,7 @@ static bool wants_floating(struct sway_view *view) { | |||
297 | } | 312 | } |
298 | } | 313 | } |
299 | 314 | ||
300 | struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints; | 315 | xcb_size_hints_t *size_hints = surface->size_hints; |
301 | if (size_hints != NULL && | 316 | if (size_hints != NULL && |
302 | size_hints->min_width > 0 && size_hints->min_height > 0 && | 317 | size_hints->min_width > 0 && size_hints->min_height > 0 && |
303 | (size_hints->max_width == size_hints->min_width || | 318 | (size_hints->max_width == size_hints->min_width || |
@@ -351,7 +366,7 @@ static void destroy(struct sway_view *view) { | |||
351 | static void get_constraints(struct sway_view *view, double *min_width, | 366 | static void get_constraints(struct sway_view *view, double *min_width, |
352 | double *max_width, double *min_height, double *max_height) { | 367 | double *max_width, double *min_height, double *max_height) { |
353 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; | 368 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; |
354 | struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints; | 369 | xcb_size_hints_t *size_hints = surface->size_hints; |
355 | 370 | ||
356 | if (size_hints == NULL) { | 371 | if (size_hints == NULL) { |
357 | *min_width = DBL_MIN; | 372 | *min_width = DBL_MIN; |
@@ -399,30 +414,31 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
399 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 414 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
400 | struct wlr_surface_state *state = &xsurface->surface->current; | 415 | struct wlr_surface_state *state = &xsurface->surface->current; |
401 | 416 | ||
417 | struct wlr_box new_geo; | ||
418 | get_geometry(view, &new_geo); | ||
419 | bool new_size = new_geo.width != view->geometry.width || | ||
420 | new_geo.height != view->geometry.height || | ||
421 | new_geo.x != view->geometry.x || | ||
422 | new_geo.y != view->geometry.y; | ||
423 | |||
424 | if (new_size) { | ||
425 | // The client changed its surface size in this commit. For floating | ||
426 | // containers, we resize the container to match. For tiling containers, | ||
427 | // we only recenter the surface. | ||
428 | desktop_damage_view(view); | ||
429 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
430 | if (container_is_floating(view->container)) { | ||
431 | view_update_size(view); | ||
432 | transaction_commit_dirty_client(); | ||
433 | } else { | ||
434 | view_center_surface(view); | ||
435 | } | ||
436 | desktop_damage_view(view); | ||
437 | } | ||
438 | |||
402 | if (view->container->node.instruction) { | 439 | if (view->container->node.instruction) { |
403 | get_geometry(view, &view->geometry); | ||
404 | transaction_notify_view_ready_by_geometry(view, | 440 | transaction_notify_view_ready_by_geometry(view, |
405 | xsurface->x, xsurface->y, state->width, state->height); | 441 | xsurface->x, xsurface->y, state->width, state->height); |
406 | } else { | ||
407 | struct wlr_box new_geo; | ||
408 | get_geometry(view, &new_geo); | ||
409 | |||
410 | if ((new_geo.width != view->geometry.width || | ||
411 | new_geo.height != view->geometry.height || | ||
412 | new_geo.x != view->geometry.x || | ||
413 | new_geo.y != view->geometry.y)) { | ||
414 | // The view has unexpectedly sent a new size | ||
415 | // eg. The Firefox "Save As" dialog when downloading a file | ||
416 | desktop_damage_view(view); | ||
417 | view_update_size(view, new_geo.width, new_geo.height); | ||
418 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
419 | desktop_damage_view(view); | ||
420 | transaction_commit_dirty(); | ||
421 | transaction_notify_view_ready_by_geometry(view, | ||
422 | xsurface->x, xsurface->y, new_geo.width, new_geo.height); | ||
423 | } else { | ||
424 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
425 | } | ||
426 | } | 442 | } |
427 | 443 | ||
428 | view_damage_from(view); | 444 | view_damage_from(view); |
@@ -438,6 +454,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
438 | wl_list_remove(&xwayland_view->commit.link); | 454 | wl_list_remove(&xwayland_view->commit.link); |
439 | } | 455 | } |
440 | 456 | ||
457 | xwayland_view->view.wlr_xwayland_surface = NULL; | ||
458 | |||
441 | wl_list_remove(&xwayland_view->destroy.link); | 459 | wl_list_remove(&xwayland_view->destroy.link); |
442 | wl_list_remove(&xwayland_view->request_configure.link); | 460 | wl_list_remove(&xwayland_view->request_configure.link); |
443 | wl_list_remove(&xwayland_view->request_fullscreen.link); | 461 | wl_list_remove(&xwayland_view->request_fullscreen.link); |
@@ -527,10 +545,10 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { | |||
527 | view->natural_height = ev->height; | 545 | view->natural_height = ev->height; |
528 | container_floating_resize_and_center(view->container); | 546 | container_floating_resize_and_center(view->container); |
529 | 547 | ||
530 | configure(view, view->container->content_x, | 548 | configure(view, view->container->pending.content_x, |
531 | view->container->content_y, | 549 | view->container->pending.content_y, |
532 | view->container->content_width, | 550 | view->container->pending.content_width, |
533 | view->container->content_height); | 551 | view->container->pending.content_height); |
534 | node_set_dirty(&view->container->node); | 552 | node_set_dirty(&view->container->node); |
535 | } else { | 553 | } else { |
536 | configure(view, view->container->current.content_x, | 554 | configure(view, view->container->current.content_x, |
@@ -577,7 +595,8 @@ static void handle_request_move(struct wl_listener *listener, void *data) { | |||
577 | if (!xsurface->mapped) { | 595 | if (!xsurface->mapped) { |
578 | return; | 596 | return; |
579 | } | 597 | } |
580 | if (!container_is_floating(view->container)) { | 598 | if (!container_is_floating(view->container) || |
599 | view->container->pending.fullscreen_mode) { | ||
581 | return; | 600 | return; |
582 | } | 601 | } |
583 | struct sway_seat *seat = input_manager_current_seat(); | 602 | struct sway_seat *seat = input_manager_current_seat(); |
@@ -666,14 +685,15 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { | |||
666 | if (!xsurface->mapped) { | 685 | if (!xsurface->mapped) { |
667 | return; | 686 | return; |
668 | } | 687 | } |
669 | if (!xsurface->hints_urgency && view->urgent_timer) { | 688 | const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints); |
689 | if (!hints_urgency && view->urgent_timer) { | ||
670 | // The view is in the timeout period. We'll ignore the request to | 690 | // The view is in the timeout period. We'll ignore the request to |
671 | // unset urgency so that the view remains urgent until the timer clears | 691 | // unset urgency so that the view remains urgent until the timer clears |
672 | // it. | 692 | // it. |
673 | return; | 693 | return; |
674 | } | 694 | } |
675 | if (view->allow_request_urgent) { | 695 | if (view->allow_request_urgent) { |
676 | view_set_urgent(view, (bool)xsurface->hints_urgency); | 696 | view_set_urgent(view, hints_urgency); |
677 | } | 697 | } |
678 | } | 698 | } |
679 | 699 | ||