aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop')
-rw-r--r--sway/desktop/desktop.c9
-rw-r--r--sway/desktop/idle_inhibit_v1.c16
-rw-r--r--sway/desktop/layer_shell.c186
-rw-r--r--sway/desktop/output.c275
-rw-r--r--sway/desktop/render.c211
-rw-r--r--sway/desktop/surface.c2
-rw-r--r--sway/desktop/transaction.c253
-rw-r--r--sway/desktop/xdg_shell.c185
-rw-r--r--sway/desktop/xwayland.c96
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
105bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { 105bool 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
283static void handle_surface_commit(struct wl_listener *listener, void *data) { 285static 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
343static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface);
344
340static void handle_destroy(struct wl_listener *listener, void *data) { 345static 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
367static void handle_map(struct wl_listener *listener, void *data) { 378static 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
416static void subsurface_handle_destroy(struct wl_listener *listener, 427static 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
436static 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
428static struct sway_layer_subsurface *create_subsurface( 443static 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(
468static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { 484static 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 */
63static 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
79struct surface_iterator_data { 61struct 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
90static bool get_surface_box(struct surface_iterator_data *data, 71static 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
129static void output_for_each_surface_iterator(struct wlr_surface *surface, 102static 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
345static void output_for_each_surface(struct sway_output *output, 276static 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
466static void send_frame_done_iterator(struct sway_output *output, struct sway_view *view, 416static 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
491static void count_surface_iterator(struct sway_output *output, struct sway_view *view, 441static 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
696static void damage_surface_iterator(struct sway_output *output, struct sway_view *view, 651static 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) {
830static void handle_destroy(struct wl_listener *listener, void *data) { 778static 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
865static unsigned int last_headless_num = 0;
866
913void handle_new_output(struct wl_listener *listener, void *data) { 867void 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 @@
32struct render_data { 31struct 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
53static void scissor_output(struct wlr_output *wlr_output, 53static 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
136static void render_surface_iterator(struct sway_output *output, struct sway_view *view, 132static 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
765static bool container_is_focused(struct sway_container *con, void *data) {
766 return con->current.focused;
767}
768
769static 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,
979void output_render(struct sway_output *output, struct timespec *when, 1027void 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
40static struct sway_transaction *transaction_create(void) { 42static struct sway_transaction *transaction_create(void) {
@@ -86,7 +88,11 @@ static void transaction_destroy(struct sway_transaction *transaction) {
86static void copy_output_state(struct sway_output *output, 88static 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
163static void transaction_add_node(struct sway_transaction *transaction, 168static 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
191static void apply_output_state(struct sway_output *output, 215static 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
320static void transaction_commit(struct sway_transaction *transaction); 333static void transaction_commit_pending(void);
321 334
322// Return true if both transactions operate on the same nodes 335static void transaction_progress(void) {
323static 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
338static 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
386static int handle_timeout(void *data) { 354static 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
463static 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
486static void set_instruction_ready( 474static 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
513void transaction_notify_view_ready_by_serial(struct sway_view *view, 502void 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
535void transaction_notify_view_ready_immediately(struct sway_view *view) { 524static 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
543void 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. 546void 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. 550void 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
22static const struct sway_view_child_impl popup_impl; 22static const struct sway_view_child_impl popup_impl;
23 23
24static void popup_get_root_coords(struct sway_view_child *child, 24static 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
38static void popup_destroy(struct sway_view_child *child) { 35static 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
49static const struct sway_view_child_impl popup_impl = { 46static 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
69static void popup_unconstrain(struct sway_xdg_popup *popup) { 66static 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(
122static void get_constraints(struct sway_view *view, double *min_width, 119static 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
157static void set_activated(struct sway_view *view, bool activated) { 155static 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
167static void set_tiled(struct sway_view *view, bool tiled) { 162static 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
180static void set_fullscreen(struct sway_view *view, bool fullscreen) { 174static 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
188static void set_resizing(struct sway_view *view, bool resizing) { 181static 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
196static bool wants_floating(struct sway_view *view) { 188static 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
223static bool is_transient_for(struct sway_view *child, 215static 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
249static void close_popups(struct sway_view *view) { 237static 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
328static 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
336static void handle_request_fullscreen(struct wl_listener *listener, void *data) { 335static 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
372static 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
377static void handle_request_move(struct wl_listener *listener, void *data) { 366static 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
125static 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
128static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { 139static 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
263static void set_tiled(struct sway_view *view, bool tiled) { 278static 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) {
351static void get_constraints(struct sway_view *view, double *min_width, 366static 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