aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree')
-rw-r--r--sway/tree/arrange.c70
-rw-r--r--sway/tree/container.c622
-rw-r--r--sway/tree/node.c18
-rw-r--r--sway/tree/output.c14
-rw-r--r--sway/tree/root.c33
-rw-r--r--sway/tree/view.c363
-rw-r--r--sway/tree/workspace.c77
7 files changed, 647 insertions, 550 deletions
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index bac9f2fa..4aa82c35 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -55,7 +55,7 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
55 // Calculate gap size 55 // Calculate gap size
56 double inner_gap = 0; 56 double inner_gap = 0;
57 struct sway_container *child = children->items[0]; 57 struct sway_container *child = children->items[0];
58 struct sway_workspace *ws = child->workspace; 58 struct sway_workspace *ws = child->pending.workspace;
59 if (ws) { 59 if (ws) {
60 inner_gap = ws->gaps_inner; 60 inner_gap = ws->gaps_inner;
61 } 61 }
@@ -66,7 +66,7 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
66 if (layout == L_TABBED || layout == L_STACKED) { 66 if (layout == L_TABBED || layout == L_STACKED) {
67 inner_gap = 0; 67 inner_gap = 0;
68 } 68 }
69 temp = temp->parent; 69 temp = temp->pending.parent;
70 } 70 }
71 double total_gap = fmin(inner_gap * (children->length - 1), 71 double total_gap = fmin(inner_gap * (children->length - 1),
72 fmax(0, parent->width - MIN_SANE_W * children->length)); 72 fmax(0, parent->width - MIN_SANE_W * children->length));
@@ -79,15 +79,15 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
79 for (int i = 0; i < children->length; ++i) { 79 for (int i = 0; i < children->length; ++i) {
80 struct sway_container *child = children->items[i]; 80 struct sway_container *child = children->items[i];
81 child->child_total_width = child_total_width; 81 child->child_total_width = child_total_width;
82 child->x = child_x; 82 child->pending.x = child_x;
83 child->y = parent->y; 83 child->pending.y = parent->y;
84 child->width = round(child->width_fraction * child_total_width); 84 child->pending.width = round(child->width_fraction * child_total_width);
85 child->height = parent->height; 85 child->pending.height = parent->height;
86 child_x += child->width + inner_gap; 86 child_x += child->pending.width + inner_gap;
87 87
88 // Make last child use remaining width of parent 88 // Make last child use remaining width of parent
89 if (i == children->length - 1) { 89 if (i == children->length - 1) {
90 child->width = parent->x + parent->width - child->x; 90 child->pending.width = parent->x + parent->width - child->pending.x;
91 } 91 }
92 } 92 }
93} 93}
@@ -134,7 +134,7 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) {
134 // Calculate gap size 134 // Calculate gap size
135 double inner_gap = 0; 135 double inner_gap = 0;
136 struct sway_container *child = children->items[0]; 136 struct sway_container *child = children->items[0];
137 struct sway_workspace *ws = child->workspace; 137 struct sway_workspace *ws = child->pending.workspace;
138 if (ws) { 138 if (ws) {
139 inner_gap = ws->gaps_inner; 139 inner_gap = ws->gaps_inner;
140 } 140 }
@@ -145,7 +145,7 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) {
145 if (layout == L_TABBED || layout == L_STACKED) { 145 if (layout == L_TABBED || layout == L_STACKED) {
146 inner_gap = 0; 146 inner_gap = 0;
147 } 147 }
148 temp = temp->parent; 148 temp = temp->pending.parent;
149 } 149 }
150 double total_gap = fmin(inner_gap * (children->length - 1), 150 double total_gap = fmin(inner_gap * (children->length - 1),
151 fmax(0, parent->height - MIN_SANE_H * children->length)); 151 fmax(0, parent->height - MIN_SANE_H * children->length));
@@ -158,15 +158,15 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) {
158 for (int i = 0; i < children->length; ++i) { 158 for (int i = 0; i < children->length; ++i) {
159 struct sway_container *child = children->items[i]; 159 struct sway_container *child = children->items[i];
160 child->child_total_height = child_total_height; 160 child->child_total_height = child_total_height;
161 child->x = parent->x; 161 child->pending.x = parent->x;
162 child->y = child_y; 162 child->pending.y = child_y;
163 child->width = parent->width; 163 child->pending.width = parent->width;
164 child->height = round(child->height_fraction * child_total_height); 164 child->pending.height = round(child->height_fraction * child_total_height);
165 child_y += child->height + inner_gap; 165 child_y += child->pending.height + inner_gap;
166 166
167 // Make last child use remaining height of parent 167 // Make last child use remaining height of parent
168 if (i == children->length - 1) { 168 if (i == children->length - 1) {
169 child->height = parent->y + parent->height - child->y; 169 child->pending.height = parent->y + parent->height - child->pending.y;
170 } 170 }
171 } 171 }
172} 172}
@@ -178,10 +178,10 @@ static void apply_tabbed_layout(list_t *children, struct wlr_box *parent) {
178 for (int i = 0; i < children->length; ++i) { 178 for (int i = 0; i < children->length; ++i) {
179 struct sway_container *child = children->items[i]; 179 struct sway_container *child = children->items[i];
180 int parent_offset = child->view ? 0 : container_titlebar_height(); 180 int parent_offset = child->view ? 0 : container_titlebar_height();
181 child->x = parent->x; 181 child->pending.x = parent->x;
182 child->y = parent->y + parent_offset; 182 child->pending.y = parent->y + parent_offset;
183 child->width = parent->width; 183 child->pending.width = parent->width;
184 child->height = parent->height - parent_offset; 184 child->pending.height = parent->height - parent_offset;
185 } 185 }
186} 186}
187 187
@@ -193,10 +193,10 @@ static void apply_stacked_layout(list_t *children, struct wlr_box *parent) {
193 struct sway_container *child = children->items[i]; 193 struct sway_container *child = children->items[i];
194 int parent_offset = child->view ? 0 : 194 int parent_offset = child->view ? 0 :
195 container_titlebar_height() * children->length; 195 container_titlebar_height() * children->length;
196 child->x = parent->x; 196 child->pending.x = parent->x;
197 child->y = parent->y + parent_offset; 197 child->pending.y = parent->y + parent_offset;
198 child->width = parent->width; 198 child->pending.width = parent->width;
199 child->height = parent->height - parent_offset; 199 child->pending.height = parent->height - parent_offset;
200 } 200 }
201} 201}
202 202
@@ -246,7 +246,7 @@ void arrange_container(struct sway_container *container) {
246 } 246 }
247 struct wlr_box box; 247 struct wlr_box box;
248 container_get_box(container, &box); 248 container_get_box(container, &box);
249 arrange_children(container->children, container->layout, &box); 249 arrange_children(container->pending.children, container->pending.layout, &box);
250 node_set_dirty(&container->node); 250 node_set_dirty(&container->node);
251} 251}
252 252
@@ -278,8 +278,8 @@ void arrange_workspace(struct sway_workspace *workspace) {
278 for (int i = 0; i < workspace->floating->length; ++i) { 278 for (int i = 0; i < workspace->floating->length; ++i) {
279 struct sway_container *floater = workspace->floating->items[i]; 279 struct sway_container *floater = workspace->floating->items[i];
280 container_floating_translate(floater, diff_x, diff_y); 280 container_floating_translate(floater, diff_x, diff_y);
281 double center_x = floater->x + floater->width / 2; 281 double center_x = floater->pending.x + floater->pending.width / 2;
282 double center_y = floater->y + floater->height / 2; 282 double center_y = floater->pending.y + floater->pending.height / 2;
283 struct wlr_box workspace_box; 283 struct wlr_box workspace_box;
284 workspace_get_box(workspace, &workspace_box); 284 workspace_get_box(workspace, &workspace_box);
285 if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { 285 if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) {
@@ -294,10 +294,10 @@ void arrange_workspace(struct sway_workspace *workspace) {
294 workspace->x, workspace->y); 294 workspace->x, workspace->y);
295 if (workspace->fullscreen) { 295 if (workspace->fullscreen) {
296 struct sway_container *fs = workspace->fullscreen; 296 struct sway_container *fs = workspace->fullscreen;
297 fs->x = output->lx; 297 fs->pending.x = output->lx;
298 fs->y = output->ly; 298 fs->pending.y = output->ly;
299 fs->width = output->width; 299 fs->pending.width = output->width;
300 fs->height = output->height; 300 fs->pending.height = output->height;
301 arrange_container(fs); 301 arrange_container(fs);
302 } else { 302 } else {
303 struct wlr_box box; 303 struct wlr_box box;
@@ -337,10 +337,10 @@ void arrange_root(void) {
337 337
338 if (root->fullscreen_global) { 338 if (root->fullscreen_global) {
339 struct sway_container *fs = root->fullscreen_global; 339 struct sway_container *fs = root->fullscreen_global;
340 fs->x = root->x; 340 fs->pending.x = root->x;
341 fs->y = root->y; 341 fs->pending.y = root->y;
342 fs->width = root->width; 342 fs->pending.width = root->width;
343 fs->height = root->height; 343 fs->pending.height = root->height;
344 arrange_container(fs); 344 arrange_container(fs);
345 } else { 345 } else {
346 for (int i = 0; i < root->outputs->length; ++i) { 346 for (int i = 0; i < root->outputs->length; ++i) {
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 6a9ce1c4..6a01eab3 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -1,12 +1,13 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 2#include <assert.h>
3#include <drm_fourcc.h>
3#include <stdint.h> 4#include <stdint.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <string.h> 6#include <string.h>
6#include <strings.h> 7#include <strings.h>
7#include <wayland-server-core.h> 8#include <wayland-server-core.h>
8#include <wlr/types/wlr_output_layout.h> 9#include <wlr/types/wlr_output_layout.h>
9#include "cairo.h" 10#include "cairo_util.h"
10#include "pango.h" 11#include "pango.h"
11#include "sway/config.h" 12#include "sway/config.h"
12#include "sway/desktop.h" 13#include "sway/desktop.h"
@@ -19,6 +20,7 @@
19#include "sway/tree/arrange.h" 20#include "sway/tree/arrange.h"
20#include "sway/tree/view.h" 21#include "sway/tree/view.h"
21#include "sway/tree/workspace.h" 22#include "sway/tree/workspace.h"
23#include "sway/xdg_decoration.h"
22#include "list.h" 24#include "list.h"
23#include "log.h" 25#include "log.h"
24#include "stringop.h" 26#include "stringop.h"
@@ -30,12 +32,12 @@ struct sway_container *container_create(struct sway_view *view) {
30 return NULL; 32 return NULL;
31 } 33 }
32 node_init(&c->node, N_CONTAINER, c); 34 node_init(&c->node, N_CONTAINER, c);
33 c->layout = L_NONE; 35 c->pending.layout = L_NONE;
34 c->view = view; 36 c->view = view;
35 c->alpha = 1.0f; 37 c->alpha = 1.0f;
36 38
37 if (!view) { 39 if (!view) {
38 c->children = create_list(); 40 c->pending.children = create_list();
39 c->current.children = create_list(); 41 c->current.children = create_list();
40 } 42 }
41 c->marks = create_list(); 43 c->marks = create_list();
@@ -62,7 +64,7 @@ void container_destroy(struct sway_container *con) {
62 wlr_texture_destroy(con->title_focused_inactive); 64 wlr_texture_destroy(con->title_focused_inactive);
63 wlr_texture_destroy(con->title_unfocused); 65 wlr_texture_destroy(con->title_unfocused);
64 wlr_texture_destroy(con->title_urgent); 66 wlr_texture_destroy(con->title_urgent);
65 list_free(con->children); 67 list_free(con->pending.children);
66 list_free(con->current.children); 68 list_free(con->current.children);
67 list_free(con->outputs); 69 list_free(con->outputs);
68 70
@@ -90,10 +92,10 @@ void container_begin_destroy(struct sway_container *con) {
90 } 92 }
91 // The workspace must have the fullscreen pointer cleared so that the 93 // The workspace must have the fullscreen pointer cleared so that the
92 // seat code can find an appropriate new focus. 94 // seat code can find an appropriate new focus.
93 if (con->fullscreen_mode == FULLSCREEN_WORKSPACE && con->workspace) { 95 if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE && con->pending.workspace) {
94 con->workspace->fullscreen = NULL; 96 con->pending.workspace->fullscreen = NULL;
95 } 97 }
96 if (con->scratchpad && con->fullscreen_mode == FULLSCREEN_GLOBAL) { 98 if (con->scratchpad && con->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
97 container_fullscreen_disable(con); 99 container_fullscreen_disable(con);
98 } 100 }
99 101
@@ -108,11 +110,11 @@ void container_begin_destroy(struct sway_container *con) {
108 root_scratchpad_remove_container(con); 110 root_scratchpad_remove_container(con);
109 } 111 }
110 112
111 if (con->fullscreen_mode == FULLSCREEN_GLOBAL) { 113 if (con->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
112 container_fullscreen_disable(con); 114 container_fullscreen_disable(con);
113 } 115 }
114 116
115 if (con->parent || con->workspace) { 117 if (con->pending.parent || con->pending.workspace) {
116 container_detach(con); 118 container_detach(con);
117 } 119 }
118} 120}
@@ -121,12 +123,12 @@ void container_reap_empty(struct sway_container *con) {
121 if (con->view) { 123 if (con->view) {
122 return; 124 return;
123 } 125 }
124 struct sway_workspace *ws = con->workspace; 126 struct sway_workspace *ws = con->pending.workspace;
125 while (con) { 127 while (con) {
126 if (con->children->length) { 128 if (con->pending.children->length) {
127 return; 129 return;
128 } 130 }
129 struct sway_container *parent = con->parent; 131 struct sway_container *parent = con->pending.parent;
130 container_begin_destroy(con); 132 container_begin_destroy(con);
131 con = parent; 133 con = parent;
132 } 134 }
@@ -139,9 +141,9 @@ struct sway_container *container_flatten(struct sway_container *container) {
139 if (container->view) { 141 if (container->view) {
140 return NULL; 142 return NULL;
141 } 143 }
142 while (container && container->children->length == 1) { 144 while (container && container->pending.children->length == 1) {
143 struct sway_container *child = container->children->items[0]; 145 struct sway_container *child = container->pending.children->items[0];
144 struct sway_container *parent = container->parent; 146 struct sway_container *parent = container->pending.parent;
145 container_replace(container, child); 147 container_replace(container, child);
146 container_begin_destroy(container); 148 container_begin_destroy(container);
147 container = parent; 149 container = parent;
@@ -151,11 +153,11 @@ struct sway_container *container_flatten(struct sway_container *container) {
151 153
152struct sway_container *container_find_child(struct sway_container *container, 154struct sway_container *container_find_child(struct sway_container *container,
153 bool (*test)(struct sway_container *con, void *data), void *data) { 155 bool (*test)(struct sway_container *con, void *data), void *data) {
154 if (!container->children) { 156 if (!container->pending.children) {
155 return NULL; 157 return NULL;
156 } 158 }
157 for (int i = 0; i < container->children->length; ++i) { 159 for (int i = 0; i < container->pending.children->length; ++i) {
158 struct sway_container *child = container->children->items[i]; 160 struct sway_container *child = container->pending.children->items[i];
159 if (test(child, data)) { 161 if (test(child, data)) {
160 return child; 162 return child;
161 } 163 }
@@ -310,7 +312,7 @@ static struct sway_container *floating_container_at(double lx, double ly,
310 return NULL; 312 return NULL;
311} 313}
312 314
313struct sway_container *view_container_at(struct sway_node *parent, 315static struct sway_container *view_container_content_at(struct sway_node *parent,
314 double lx, double ly, 316 double lx, double ly,
315 struct wlr_surface **surface, double *sx, double *sy) { 317 struct wlr_surface **surface, double *sx, double *sy) {
316 if (!sway_assert(node_is_view(parent), "Expected a view")) { 318 if (!sway_assert(node_is_view(parent), "Expected a view")) {
@@ -319,10 +321,33 @@ struct sway_container *view_container_at(struct sway_node *parent,
319 321
320 struct sway_container *container = parent->sway_container; 322 struct sway_container *container = parent->sway_container;
321 struct wlr_box box = { 323 struct wlr_box box = {
322 .x = container->x, 324 .x = container->pending.content_x,
323 .y = container->y, 325 .y = container->pending.content_y,
324 .width = container->width, 326 .width = container->pending.content_width,
325 .height = container->height, 327 .height = container->pending.content_height,
328 };
329
330 if (wlr_box_contains_point(&box, lx, ly)) {
331 surface_at_view(parent->sway_container, lx, ly, surface, sx, sy);
332 return container;
333 }
334
335 return NULL;
336}
337
338static struct sway_container *view_container_at(struct sway_node *parent,
339 double lx, double ly,
340 struct wlr_surface **surface, double *sx, double *sy) {
341 if (!sway_assert(node_is_view(parent), "Expected a view")) {
342 return NULL;
343 }
344
345 struct sway_container *container = parent->sway_container;
346 struct wlr_box box = {
347 .x = container->pending.x,
348 .y = container->pending.y,
349 .width = container->pending.width,
350 .height = container->pending.height,
326 }; 351 };
327 352
328 if (wlr_box_contains_point(&box, lx, ly)) { 353 if (wlr_box_contains_point(&box, lx, ly)) {
@@ -394,7 +419,7 @@ struct sway_container *container_at(struct sway_workspace *workspace,
394 } 419 }
395 // Tiling (focused) 420 // Tiling (focused)
396 if (focus && focus->view && !is_floating) { 421 if (focus && focus->view && !is_floating) {
397 if ((c = surface_at_view(focus, lx, ly, surface, sx, sy))) { 422 if ((c = view_container_content_at(&focus->node, lx, ly, surface, sx, sy))) {
398 return c; 423 return c;
399 } 424 }
400 } 425 }
@@ -408,19 +433,41 @@ struct sway_container *container_at(struct sway_workspace *workspace,
408void container_for_each_child(struct sway_container *container, 433void container_for_each_child(struct sway_container *container,
409 void (*f)(struct sway_container *container, void *data), 434 void (*f)(struct sway_container *container, void *data),
410 void *data) { 435 void *data) {
411 if (container->children) { 436 if (container->pending.children) {
412 for (int i = 0; i < container->children->length; ++i) { 437 for (int i = 0; i < container->pending.children->length; ++i) {
413 struct sway_container *child = container->children->items[i]; 438 struct sway_container *child = container->pending.children->items[i];
414 f(child, data); 439 f(child, data);
415 container_for_each_child(child, f, data); 440 container_for_each_child(child, f, data);
416 } 441 }
417 } 442 }
418} 443}
419 444
445struct sway_container *container_obstructing_fullscreen_container(struct sway_container *container)
446{
447 struct sway_workspace *workspace = container->pending.workspace;
448
449 if (workspace && workspace->fullscreen && !container_is_fullscreen_or_child(container)) {
450 if (container_is_transient_for(container, workspace->fullscreen)) {
451 return NULL;
452 }
453 return workspace->fullscreen;
454 }
455
456 struct sway_container *fullscreen_global = root->fullscreen_global;
457 if (fullscreen_global && container != fullscreen_global && !container_has_ancestor(container, fullscreen_global)) {
458 if (container_is_transient_for(container, fullscreen_global)) {
459 return NULL;
460 }
461 return fullscreen_global;
462 }
463
464 return NULL;
465}
466
420bool container_has_ancestor(struct sway_container *descendant, 467bool container_has_ancestor(struct sway_container *descendant,
421 struct sway_container *ancestor) { 468 struct sway_container *ancestor) {
422 while (descendant) { 469 while (descendant) {
423 descendant = descendant->parent; 470 descendant = descendant->pending.parent;
424 if (descendant == ancestor) { 471 if (descendant == ancestor) {
425 return true; 472 return true;
426 } 473 }
@@ -446,23 +493,13 @@ struct sway_output *container_get_effective_output(struct sway_container *con) {
446 return con->outputs->items[con->outputs->length - 1]; 493 return con->outputs->items[con->outputs->length - 1];
447} 494}
448 495
449static void update_title_texture(struct sway_container *con, 496static void render_titlebar_text_texture(struct sway_output *output,
450 struct wlr_texture **texture, struct border_colors *class) { 497 struct sway_container *con, struct wlr_texture **texture,
451 struct sway_output *output = container_get_effective_output(con); 498 struct border_colors *class, bool pango_markup, char *text) {
452 if (!output) {
453 return;
454 }
455 if (*texture) {
456 wlr_texture_destroy(*texture);
457 *texture = NULL;
458 }
459 if (!con->formatted_title) {
460 return;
461 }
462
463 double scale = output->wlr_output->scale; 499 double scale = output->wlr_output->scale;
464 int width = 0; 500 int width = 0;
465 int height = con->title_height * scale; 501 int height = config->font_height * scale;
502 int baseline;
466 503
467 // We must use a non-nil cairo_t for cairo_set_font_options to work. 504 // We must use a non-nil cairo_t for cairo_set_font_options to work.
468 // Therefore, we cannot use cairo_create(NULL). 505 // Therefore, we cannot use cairo_create(NULL).
@@ -480,11 +517,19 @@ static void update_title_texture(struct sway_container *con,
480 to_cairo_subpixel_order(output->wlr_output->subpixel)); 517 to_cairo_subpixel_order(output->wlr_output->subpixel));
481 } 518 }
482 cairo_set_font_options(c, fo); 519 cairo_set_font_options(c, fo);
483 get_text_size(c, config->font, &width, NULL, NULL, scale, 520 get_text_size(c, config->font, &width, NULL, &baseline, scale,
484 config->pango_markup, "%s", con->formatted_title); 521 config->pango_markup, "%s", text);
485 cairo_surface_destroy(dummy_surface); 522 cairo_surface_destroy(dummy_surface);
486 cairo_destroy(c); 523 cairo_destroy(c);
487 524
525 if (width == 0 || height == 0) {
526 return;
527 }
528
529 if (height > config->font_height * scale) {
530 height = config->font_height * scale;
531 }
532
488 cairo_surface_t *surface = cairo_image_surface_create( 533 cairo_surface_t *surface = cairo_image_surface_create(
489 CAIRO_FORMAT_ARGB32, width, height); 534 CAIRO_FORMAT_ARGB32, width, height);
490 cairo_t *cairo = cairo_create(surface); 535 cairo_t *cairo = cairo_create(surface);
@@ -497,23 +542,40 @@ static void update_title_texture(struct sway_container *con,
497 PangoContext *pango = pango_cairo_create_context(cairo); 542 PangoContext *pango = pango_cairo_create_context(cairo);
498 cairo_set_source_rgba(cairo, class->text[0], class->text[1], 543 cairo_set_source_rgba(cairo, class->text[0], class->text[1],
499 class->text[2], class->text[3]); 544 class->text[2], class->text[3]);
500 cairo_move_to(cairo, 0, 0); 545 cairo_move_to(cairo, 0, config->font_baseline * scale - baseline);
501 546
502 pango_printf(cairo, config->font, scale, config->pango_markup, 547 render_text(cairo, config->font, scale, pango_markup, "%s", text);
503 "%s", con->formatted_title);
504 548
505 cairo_surface_flush(surface); 549 cairo_surface_flush(surface);
506 unsigned char *data = cairo_image_surface_get_data(surface); 550 unsigned char *data = cairo_image_surface_get_data(surface);
507 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); 551 int stride = cairo_image_surface_get_stride(surface);
508 struct wlr_renderer *renderer = wlr_backend_get_renderer( 552 struct wlr_renderer *renderer = wlr_backend_get_renderer(
509 output->wlr_output->backend); 553 output->wlr_output->backend);
510 *texture = wlr_texture_from_pixels( 554 *texture = wlr_texture_from_pixels(
511 renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); 555 renderer, DRM_FORMAT_ARGB8888, stride, width, height, data);
512 cairo_surface_destroy(surface); 556 cairo_surface_destroy(surface);
513 g_object_unref(pango); 557 g_object_unref(pango);
514 cairo_destroy(cairo); 558 cairo_destroy(cairo);
515} 559}
516 560
561static void update_title_texture(struct sway_container *con,
562 struct wlr_texture **texture, struct border_colors *class) {
563 struct sway_output *output = container_get_effective_output(con);
564 if (!output) {
565 return;
566 }
567 if (*texture) {
568 wlr_texture_destroy(*texture);
569 *texture = NULL;
570 }
571 if (!con->formatted_title) {
572 return;
573 }
574
575 render_titlebar_text_texture(output, con, texture, class,
576 config->pango_markup, con->formatted_title);
577}
578
517void container_update_title_textures(struct sway_container *container) { 579void container_update_title_textures(struct sway_container *container) {
518 update_title_texture(container, &container->title_focused, 580 update_title_texture(container, &container->title_focused,
519 &config->border_colors.focused); 581 &config->border_colors.focused);
@@ -526,21 +588,6 @@ void container_update_title_textures(struct sway_container *container) {
526 container_damage_whole(container); 588 container_damage_whole(container);
527} 589}
528 590
529void container_calculate_title_height(struct sway_container *container) {
530 if (!container->formatted_title) {
531 container->title_height = 0;
532 return;
533 }
534 cairo_t *cairo = cairo_create(NULL);
535 int height;
536 int baseline;
537 get_text_size(cairo, config->font, NULL, &height, &baseline, 1,
538 config->pango_markup, "%s", container->formatted_title);
539 cairo_destroy(cairo);
540 container->title_height = height;
541 container->title_baseline = baseline;
542}
543
544/** 591/**
545 * Calculate and return the length of the tree representation. 592 * Calculate and return the length of the tree representation.
546 * An example tree representation is: V[Terminal, Firefox] 593 * An example tree representation is: V[Terminal, Firefox]
@@ -596,23 +643,22 @@ size_t container_build_representation(enum sway_container_layout layout,
596 643
597void container_update_representation(struct sway_container *con) { 644void container_update_representation(struct sway_container *con) {
598 if (!con->view) { 645 if (!con->view) {
599 size_t len = container_build_representation(con->layout, 646 size_t len = container_build_representation(con->pending.layout,
600 con->children, NULL); 647 con->pending.children, NULL);
601 free(con->formatted_title); 648 free(con->formatted_title);
602 con->formatted_title = calloc(len + 1, sizeof(char)); 649 con->formatted_title = calloc(len + 1, sizeof(char));
603 if (!sway_assert(con->formatted_title, 650 if (!sway_assert(con->formatted_title,
604 "Unable to allocate title string")) { 651 "Unable to allocate title string")) {
605 return; 652 return;
606 } 653 }
607 container_build_representation(con->layout, con->children, 654 container_build_representation(con->pending.layout, con->pending.children,
608 con->formatted_title); 655 con->formatted_title);
609 container_calculate_title_height(con);
610 container_update_title_textures(con); 656 container_update_title_textures(con);
611 } 657 }
612 if (con->parent) { 658 if (con->pending.parent) {
613 container_update_representation(con->parent); 659 container_update_representation(con->pending.parent);
614 } else if (con->workspace) { 660 } else if (con->pending.workspace) {
615 workspace_update_representation(con->workspace); 661 workspace_update_representation(con->pending.workspace);
616 } 662 }
617} 663}
618 664
@@ -663,20 +709,20 @@ static void floating_natural_resize(struct sway_container *con) {
663 floating_calculate_constraints(&min_width, &max_width, 709 floating_calculate_constraints(&min_width, &max_width,
664 &min_height, &max_height); 710 &min_height, &max_height);
665 if (!con->view) { 711 if (!con->view) {
666 con->width = fmax(min_width, fmin(con->width, max_width)); 712 con->pending.width = fmax(min_width, fmin(con->pending.width, max_width));
667 con->height = fmax(min_height, fmin(con->height, max_height)); 713 con->pending.height = fmax(min_height, fmin(con->pending.height, max_height));
668 } else { 714 } else {
669 struct sway_view *view = con->view; 715 struct sway_view *view = con->view;
670 con->content_width = 716 con->pending.content_width =
671 fmax(min_width, fmin(view->natural_width, max_width)); 717 fmax(min_width, fmin(view->natural_width, max_width));
672 con->content_height = 718 con->pending.content_height =
673 fmax(min_height, fmin(view->natural_height, max_height)); 719 fmax(min_height, fmin(view->natural_height, max_height));
674 container_set_geometry_from_content(con); 720 container_set_geometry_from_content(con);
675 } 721 }
676} 722}
677 723
678void container_floating_resize_and_center(struct sway_container *con) { 724void container_floating_resize_and_center(struct sway_container *con) {
679 struct sway_workspace *ws = con->workspace; 725 struct sway_workspace *ws = con->pending.workspace;
680 if (!ws) { 726 if (!ws) {
681 // On scratchpad, just resize 727 // On scratchpad, just resize
682 floating_natural_resize(con); 728 floating_natural_resize(con);
@@ -687,42 +733,42 @@ void container_floating_resize_and_center(struct sway_container *con) {
687 ws->output->wlr_output); 733 ws->output->wlr_output);
688 if (!ob) { 734 if (!ob) {
689 // On NOOP output. Will be called again when moved to an output 735 // On NOOP output. Will be called again when moved to an output
690 con->x = 0; 736 con->pending.x = 0;
691 con->y = 0; 737 con->pending.y = 0;
692 con->width = 0; 738 con->pending.width = 0;
693 con->height = 0; 739 con->pending.height = 0;
694 return; 740 return;
695 } 741 }
696 742
697 floating_natural_resize(con); 743 floating_natural_resize(con);
698 if (!con->view) { 744 if (!con->view) {
699 if (con->width > ws->width || con->height > ws->height) { 745 if (con->pending.width > ws->width || con->pending.height > ws->height) {
700 con->x = ob->x + (ob->width - con->width) / 2; 746 con->pending.x = ob->x + (ob->width - con->pending.width) / 2;
701 con->y = ob->y + (ob->height - con->height) / 2; 747 con->pending.y = ob->y + (ob->height - con->pending.height) / 2;
702 } else { 748 } else {
703 con->x = ws->x + (ws->width - con->width) / 2; 749 con->pending.x = ws->x + (ws->width - con->pending.width) / 2;
704 con->y = ws->y + (ws->height - con->height) / 2; 750 con->pending.y = ws->y + (ws->height - con->pending.height) / 2;
705 } 751 }
706 } else { 752 } else {
707 if (con->content_width > ws->width 753 if (con->pending.content_width > ws->width
708 || con->content_height > ws->height) { 754 || con->pending.content_height > ws->height) {
709 con->content_x = ob->x + (ob->width - con->content_width) / 2; 755 con->pending.content_x = ob->x + (ob->width - con->pending.content_width) / 2;
710 con->content_y = ob->y + (ob->height - con->content_height) / 2; 756 con->pending.content_y = ob->y + (ob->height - con->pending.content_height) / 2;
711 } else { 757 } else {
712 con->content_x = ws->x + (ws->width - con->content_width) / 2; 758 con->pending.content_x = ws->x + (ws->width - con->pending.content_width) / 2;
713 con->content_y = ws->y + (ws->height - con->content_height) / 2; 759 con->pending.content_y = ws->y + (ws->height - con->pending.content_height) / 2;
714 } 760 }
715 761
716 // If the view's border is B_NONE then these properties are ignored. 762 // If the view's border is B_NONE then these properties are ignored.
717 con->border_top = con->border_bottom = true; 763 con->pending.border_top = con->pending.border_bottom = true;
718 con->border_left = con->border_right = true; 764 con->pending.border_left = con->pending.border_right = true;
719 765
720 container_set_geometry_from_content(con); 766 container_set_geometry_from_content(con);
721 } 767 }
722} 768}
723 769
724void container_floating_set_default_size(struct sway_container *con) { 770void container_floating_set_default_size(struct sway_container *con) {
725 if (!sway_assert(con->workspace, "Expected a container on a workspace")) { 771 if (!sway_assert(con->pending.workspace, "Expected a container on a workspace")) {
726 return; 772 return;
727 } 773 }
728 774
@@ -730,16 +776,16 @@ void container_floating_set_default_size(struct sway_container *con) {
730 floating_calculate_constraints(&min_width, &max_width, 776 floating_calculate_constraints(&min_width, &max_width,
731 &min_height, &max_height); 777 &min_height, &max_height);
732 struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); 778 struct wlr_box *box = calloc(1, sizeof(struct wlr_box));
733 workspace_get_box(con->workspace, box); 779 workspace_get_box(con->pending.workspace, box);
734 780
735 double width = fmax(min_width, fmin(box->width * 0.5, max_width)); 781 double width = fmax(min_width, fmin(box->width * 0.5, max_width));
736 double height = fmax(min_height, fmin(box->height * 0.75, max_height)); 782 double height = fmax(min_height, fmin(box->height * 0.75, max_height));
737 if (!con->view) { 783 if (!con->view) {
738 con->width = width; 784 con->pending.width = width;
739 con->height = height; 785 con->pending.height = height;
740 } else { 786 } else {
741 con->content_width = width; 787 con->pending.content_width = width;
742 con->content_height = height; 788 con->pending.content_height = height;
743 container_set_geometry_from_content(con); 789 container_set_geometry_from_content(con);
744 } 790 }
745 791
@@ -761,8 +807,8 @@ void container_set_resizing(struct sway_container *con, bool resizing) {
761 con->view->impl->set_resizing(con->view, resizing); 807 con->view->impl->set_resizing(con->view, resizing);
762 } 808 }
763 } else { 809 } else {
764 for (int i = 0; i < con->children->length; ++i ) { 810 for (int i = 0; i < con->pending.children->length; ++i ) {
765 struct sway_container *child = con->children->items[i]; 811 struct sway_container *child = con->pending.children->items[i];
766 container_set_resizing(child, resizing); 812 container_set_resizing(child, resizing);
767 } 813 }
768 } 814 }
@@ -774,21 +820,33 @@ void container_set_floating(struct sway_container *container, bool enable) {
774 } 820 }
775 821
776 struct sway_seat *seat = input_manager_current_seat(); 822 struct sway_seat *seat = input_manager_current_seat();
777 struct sway_workspace *workspace = container->workspace; 823 struct sway_workspace *workspace = container->pending.workspace;
824 struct sway_container *focus = seat_get_focused_container(seat);
825 bool set_focus = focus == container;
778 826
779 if (enable) { 827 if (enable) {
780 struct sway_container *old_parent = container->parent; 828 struct sway_container *old_parent = container->pending.parent;
781 container_detach(container); 829 container_detach(container);
782 workspace_add_floating(workspace, container); 830 workspace_add_floating(workspace, container);
783 if (container->view) { 831 if (container->view) {
784 view_set_tiled(container->view, false); 832 view_set_tiled(container->view, false);
785 if (container->view->using_csd) { 833 if (container->view->using_csd) {
786 container->border = B_CSD; 834 container->saved_border = container->pending.border;
835 container->pending.border = B_CSD;
836 if (container->view->xdg_decoration) {
837 struct sway_xdg_decoration *deco = container->view->xdg_decoration;
838 wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration,
839 WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
840 }
787 } 841 }
788 } 842 }
789 container_floating_set_default_size(container); 843 container_floating_set_default_size(container);
790 container_floating_resize_and_center(container); 844 container_floating_resize_and_center(container);
791 if (old_parent) { 845 if (old_parent) {
846 if (set_focus) {
847 seat_set_raw_focus(seat, &old_parent->node);
848 seat_set_raw_focus(seat, &container->node);
849 }
792 container_reap_empty(old_parent); 850 container_reap_empty(old_parent);
793 } 851 }
794 } else { 852 } else {
@@ -800,19 +858,28 @@ void container_set_floating(struct sway_container *container, bool enable) {
800 struct sway_container *reference = 858 struct sway_container *reference =
801 seat_get_focus_inactive_tiling(seat, workspace); 859 seat_get_focus_inactive_tiling(seat, workspace);
802 if (reference) { 860 if (reference) {
803 container_add_sibling(reference, container, 1); 861 if (reference->view) {
804 container->width = reference->width; 862 container_add_sibling(reference, container, 1);
805 container->height = reference->height; 863 } else {
864 container_add_child(reference, container);
865 }
866 container->pending.width = reference->pending.width;
867 container->pending.height = reference->pending.height;
806 } else { 868 } else {
807 struct sway_container *other = 869 struct sway_container *other =
808 workspace_add_tiling(workspace, container); 870 workspace_add_tiling(workspace, container);
809 other->width = workspace->width; 871 other->pending.width = workspace->width;
810 other->height = workspace->height; 872 other->pending.height = workspace->height;
811 } 873 }
812 if (container->view) { 874 if (container->view) {
813 view_set_tiled(container->view, true); 875 view_set_tiled(container->view, true);
814 if (container->view->using_csd) { 876 if (container->view->using_csd) {
815 container->border = container->saved_border; 877 container->pending.border = container->saved_border;
878 if (container->view->xdg_decoration) {
879 struct sway_xdg_decoration *deco = container->view->xdg_decoration;
880 wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration,
881 WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
882 }
816 } 883 }
817 } 884 }
818 container->width_fraction = 0; 885 container->width_fraction = 0;
@@ -834,22 +901,33 @@ void container_set_geometry_from_content(struct sway_container *con) {
834 size_t border_width = 0; 901 size_t border_width = 0;
835 size_t top = 0; 902 size_t top = 0;
836 903
837 if (con->border != B_CSD) { 904 if (con->pending.border != B_CSD && !con->pending.fullscreen_mode) {
838 border_width = con->border_thickness * (con->border != B_NONE); 905 border_width = con->pending.border_thickness * (con->pending.border != B_NONE);
839 top = con->border == B_NORMAL ? 906 top = con->pending.border == B_NORMAL ?
840 container_titlebar_height() : border_width; 907 container_titlebar_height() : border_width;
841 } 908 }
842 909
843 con->x = con->content_x - border_width; 910 con->pending.x = con->pending.content_x - border_width;
844 con->y = con->content_y - top; 911 con->pending.y = con->pending.content_y - top;
845 con->width = con->content_width + border_width * 2; 912 con->pending.width = con->pending.content_width + border_width * 2;
846 con->height = top + con->content_height + border_width; 913 con->pending.height = top + con->pending.content_height + border_width;
847 node_set_dirty(&con->node); 914 node_set_dirty(&con->node);
848} 915}
849 916
850bool container_is_floating(struct sway_container *container) { 917bool container_is_floating(struct sway_container *container) {
851 if (!container->parent && container->workspace && 918 if (!container->pending.parent && container->pending.workspace &&
852 list_find(container->workspace->floating, container) != -1) { 919 list_find(container->pending.workspace->floating, container) != -1) {
920 return true;
921 }
922 if (container->scratchpad) {
923 return true;
924 }
925 return false;
926}
927
928bool container_is_current_floating(struct sway_container *container) {
929 if (!container->current.parent && container->current.workspace &&
930 list_find(container->current.workspace->floating, container) != -1) {
853 return true; 931 return true;
854 } 932 }
855 if (container->scratchpad) { 933 if (container->scratchpad) {
@@ -859,10 +937,10 @@ bool container_is_floating(struct sway_container *container) {
859} 937}
860 938
861void container_get_box(struct sway_container *container, struct wlr_box *box) { 939void container_get_box(struct sway_container *container, struct wlr_box *box) {
862 box->x = container->x; 940 box->x = container->pending.x;
863 box->y = container->y; 941 box->y = container->pending.y;
864 box->width = container->width; 942 box->width = container->pending.width;
865 box->height = container->height; 943 box->height = container->pending.height;
866} 944}
867 945
868/** 946/**
@@ -870,14 +948,14 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) {
870 */ 948 */
871void container_floating_translate(struct sway_container *con, 949void container_floating_translate(struct sway_container *con,
872 double x_amount, double y_amount) { 950 double x_amount, double y_amount) {
873 con->x += x_amount; 951 con->pending.x += x_amount;
874 con->y += y_amount; 952 con->pending.y += y_amount;
875 con->content_x += x_amount; 953 con->pending.content_x += x_amount;
876 con->content_y += y_amount; 954 con->pending.content_y += y_amount;
877 955
878 if (con->children) { 956 if (con->pending.children) {
879 for (int i = 0; i < con->children->length; ++i) { 957 for (int i = 0; i < con->pending.children->length; ++i) {
880 struct sway_container *child = con->children->items[i]; 958 struct sway_container *child = con->pending.children->items[i];
881 container_floating_translate(child, x_amount, y_amount); 959 container_floating_translate(child, x_amount, y_amount);
882 } 960 }
883 } 961 }
@@ -893,8 +971,8 @@ void container_floating_translate(struct sway_container *con,
893 * center. 971 * center.
894 */ 972 */
895struct sway_output *container_floating_find_output(struct sway_container *con) { 973struct sway_output *container_floating_find_output(struct sway_container *con) {
896 double center_x = con->x + con->width / 2; 974 double center_x = con->pending.x + con->pending.width / 2;
897 double center_y = con->y + con->height / 2; 975 double center_y = con->pending.y + con->pending.height / 2;
898 struct sway_output *closest_output = NULL; 976 struct sway_output *closest_output = NULL;
899 double closest_distance = DBL_MAX; 977 double closest_distance = DBL_MAX;
900 for (int i = 0; i < root->outputs->length; ++i) { 978 for (int i = 0; i < root->outputs->length; ++i) {
@@ -925,11 +1003,11 @@ void container_floating_move_to(struct sway_container *con,
925 "Expected a floating container")) { 1003 "Expected a floating container")) {
926 return; 1004 return;
927 } 1005 }
928 container_floating_translate(con, lx - con->x, ly - con->y); 1006 container_floating_translate(con, lx - con->pending.x, ly - con->pending.y);
929 if (container_is_scratchpad_hidden(con)) { 1007 if (container_is_scratchpad_hidden(con)) {
930 return; 1008 return;
931 } 1009 }
932 struct sway_workspace *old_workspace = con->workspace; 1010 struct sway_workspace *old_workspace = con->pending.workspace;
933 struct sway_output *new_output = container_floating_find_output(con); 1011 struct sway_output *new_output = container_floating_find_output(con);
934 if (!sway_assert(new_output, "Unable to find any output")) { 1012 if (!sway_assert(new_output, "Unable to find any output")) {
935 return; 1013 return;
@@ -951,10 +1029,10 @@ void container_floating_move_to_center(struct sway_container *con) {
951 "Expected a floating container")) { 1029 "Expected a floating container")) {
952 return; 1030 return;
953 } 1031 }
954 struct sway_workspace *ws = con->workspace; 1032 struct sway_workspace *ws = con->pending.workspace;
955 double new_lx = ws->x + (ws->width - con->width) / 2; 1033 double new_lx = ws->x + (ws->width - con->pending.width) / 2;
956 double new_ly = ws->y + (ws->height - con->height) / 2; 1034 double new_ly = ws->y + (ws->height - con->pending.height) / 2;
957 container_floating_translate(con, new_lx - con->x, new_ly - con->y); 1035 container_floating_translate(con, new_lx - con->pending.x, new_ly - con->pending.y);
958} 1036}
959 1037
960static bool find_urgent_iterator(struct sway_container *con, void *data) { 1038static bool find_urgent_iterator(struct sway_container *con, void *data) {
@@ -972,42 +1050,39 @@ void container_end_mouse_operation(struct sway_container *container) {
972 } 1050 }
973} 1051}
974 1052
975static void set_fullscreen_iterator(struct sway_container *con, void *data) { 1053static void set_fullscreen(struct sway_container *con, bool enable) {
976 if (!con->view) { 1054 if (!con->view) {
977 return; 1055 return;
978 } 1056 }
979 if (con->view->impl->set_fullscreen) { 1057 if (con->view->impl->set_fullscreen) {
980 bool *enable = data; 1058 con->view->impl->set_fullscreen(con->view, enable);
981 con->view->impl->set_fullscreen(con->view, *enable);
982 if (con->view->foreign_toplevel) { 1059 if (con->view->foreign_toplevel) {
983 wlr_foreign_toplevel_handle_v1_set_fullscreen( 1060 wlr_foreign_toplevel_handle_v1_set_fullscreen(
984 con->view->foreign_toplevel, *enable); 1061 con->view->foreign_toplevel, enable);
985 } 1062 }
986 } 1063 }
987} 1064}
988 1065
989static void container_fullscreen_workspace(struct sway_container *con) { 1066static void container_fullscreen_workspace(struct sway_container *con) {
990 if (!sway_assert(con->fullscreen_mode == FULLSCREEN_NONE, 1067 if (!sway_assert(con->pending.fullscreen_mode == FULLSCREEN_NONE,
991 "Expected a non-fullscreen container")) { 1068 "Expected a non-fullscreen container")) {
992 return; 1069 return;
993 } 1070 }
994 bool enable = true; 1071 set_fullscreen(con, true);
995 set_fullscreen_iterator(con, &enable); 1072 con->pending.fullscreen_mode = FULLSCREEN_WORKSPACE;
996 container_for_each_child(con, set_fullscreen_iterator, &enable);
997 con->fullscreen_mode = FULLSCREEN_WORKSPACE;
998 1073
999 con->saved_x = con->x; 1074 con->saved_x = con->pending.x;
1000 con->saved_y = con->y; 1075 con->saved_y = con->pending.y;
1001 con->saved_width = con->width; 1076 con->saved_width = con->pending.width;
1002 con->saved_height = con->height; 1077 con->saved_height = con->pending.height;
1003 1078
1004 if (con->workspace) { 1079 if (con->pending.workspace) {
1005 con->workspace->fullscreen = con; 1080 con->pending.workspace->fullscreen = con;
1006 struct sway_seat *seat; 1081 struct sway_seat *seat;
1007 struct sway_workspace *focus_ws; 1082 struct sway_workspace *focus_ws;
1008 wl_list_for_each(seat, &server.input->seats, link) { 1083 wl_list_for_each(seat, &server.input->seats, link) {
1009 focus_ws = seat_get_focused_workspace(seat); 1084 focus_ws = seat_get_focused_workspace(seat);
1010 if (focus_ws == con->workspace) { 1085 if (focus_ws == con->pending.workspace) {
1011 seat_set_focus_container(seat, con); 1086 seat_set_focus_container(seat, con);
1012 } else { 1087 } else {
1013 struct sway_node *focus = 1088 struct sway_node *focus =
@@ -1023,19 +1098,17 @@ static void container_fullscreen_workspace(struct sway_container *con) {
1023} 1098}
1024 1099
1025static void container_fullscreen_global(struct sway_container *con) { 1100static void container_fullscreen_global(struct sway_container *con) {
1026 if (!sway_assert(con->fullscreen_mode == FULLSCREEN_NONE, 1101 if (!sway_assert(con->pending.fullscreen_mode == FULLSCREEN_NONE,
1027 "Expected a non-fullscreen container")) { 1102 "Expected a non-fullscreen container")) {
1028 return; 1103 return;
1029 } 1104 }
1030 bool enable = true; 1105 set_fullscreen(con, true);
1031 set_fullscreen_iterator(con, &enable);
1032 container_for_each_child(con, set_fullscreen_iterator, &enable);
1033 1106
1034 root->fullscreen_global = con; 1107 root->fullscreen_global = con;
1035 con->saved_x = con->x; 1108 con->saved_x = con->pending.x;
1036 con->saved_y = con->y; 1109 con->saved_y = con->pending.y;
1037 con->saved_width = con->width; 1110 con->saved_width = con->pending.width;
1038 con->saved_height = con->height; 1111 con->saved_height = con->pending.height;
1039 1112
1040 struct sway_seat *seat; 1113 struct sway_seat *seat;
1041 wl_list_for_each(seat, &server.input->seats, link) { 1114 wl_list_for_each(seat, &server.input->seats, link) {
@@ -1045,34 +1118,32 @@ static void container_fullscreen_global(struct sway_container *con) {
1045 } 1118 }
1046 } 1119 }
1047 1120
1048 con->fullscreen_mode = FULLSCREEN_GLOBAL; 1121 con->pending.fullscreen_mode = FULLSCREEN_GLOBAL;
1049 container_end_mouse_operation(con); 1122 container_end_mouse_operation(con);
1050 ipc_event_window(con, "fullscreen_mode"); 1123 ipc_event_window(con, "fullscreen_mode");
1051} 1124}
1052 1125
1053void container_fullscreen_disable(struct sway_container *con) { 1126void container_fullscreen_disable(struct sway_container *con) {
1054 if (!sway_assert(con->fullscreen_mode != FULLSCREEN_NONE, 1127 if (!sway_assert(con->pending.fullscreen_mode != FULLSCREEN_NONE,
1055 "Expected a fullscreen container")) { 1128 "Expected a fullscreen container")) {
1056 return; 1129 return;
1057 } 1130 }
1058 bool enable = false; 1131 set_fullscreen(con, false);
1059 set_fullscreen_iterator(con, &enable);
1060 container_for_each_child(con, set_fullscreen_iterator, &enable);
1061 1132
1062 if (container_is_floating(con)) { 1133 if (container_is_floating(con)) {
1063 con->x = con->saved_x; 1134 con->pending.x = con->saved_x;
1064 con->y = con->saved_y; 1135 con->pending.y = con->saved_y;
1065 con->width = con->saved_width; 1136 con->pending.width = con->saved_width;
1066 con->height = con->saved_height; 1137 con->pending.height = con->saved_height;
1067 } 1138 }
1068 1139
1069 if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { 1140 if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
1070 if (con->workspace) { 1141 if (con->pending.workspace) {
1071 con->workspace->fullscreen = NULL; 1142 con->pending.workspace->fullscreen = NULL;
1072 if (container_is_floating(con)) { 1143 if (container_is_floating(con)) {
1073 struct sway_output *output = 1144 struct sway_output *output =
1074 container_floating_find_output(con); 1145 container_floating_find_output(con);
1075 if (con->workspace->output != output) { 1146 if (con->pending.workspace->output != output) {
1076 container_floating_move_to_center(con); 1147 container_floating_move_to_center(con);
1077 } 1148 }
1078 } 1149 }
@@ -1084,11 +1155,11 @@ void container_fullscreen_disable(struct sway_container *con) {
1084 // If the container was mapped as fullscreen and set as floating by 1155 // If the container was mapped as fullscreen and set as floating by
1085 // criteria, it needs to be reinitialized as floating to get the proper 1156 // criteria, it needs to be reinitialized as floating to get the proper
1086 // size and location 1157 // size and location
1087 if (container_is_floating(con) && (con->width == 0 || con->height == 0)) { 1158 if (container_is_floating(con) && (con->pending.width == 0 || con->pending.height == 0)) {
1088 container_floating_resize_and_center(con); 1159 container_floating_resize_and_center(con);
1089 } 1160 }
1090 1161
1091 con->fullscreen_mode = FULLSCREEN_NONE; 1162 con->pending.fullscreen_mode = FULLSCREEN_NONE;
1092 container_end_mouse_operation(con); 1163 container_end_mouse_operation(con);
1093 ipc_event_window(con, "fullscreen_mode"); 1164 ipc_event_window(con, "fullscreen_mode");
1094 1165
@@ -1106,7 +1177,7 @@ void container_fullscreen_disable(struct sway_container *con) {
1106 1177
1107void container_set_fullscreen(struct sway_container *con, 1178void container_set_fullscreen(struct sway_container *con,
1108 enum sway_fullscreen_mode mode) { 1179 enum sway_fullscreen_mode mode) {
1109 if (con->fullscreen_mode == mode) { 1180 if (con->pending.fullscreen_mode == mode) {
1110 return; 1181 return;
1111 } 1182 }
1112 1183
@@ -1118,8 +1189,8 @@ void container_set_fullscreen(struct sway_container *con,
1118 if (root->fullscreen_global) { 1189 if (root->fullscreen_global) {
1119 container_fullscreen_disable(root->fullscreen_global); 1190 container_fullscreen_disable(root->fullscreen_global);
1120 } 1191 }
1121 if (con->workspace && con->workspace->fullscreen) { 1192 if (con->pending.workspace && con->pending.workspace->fullscreen) {
1122 container_fullscreen_disable(con->workspace->fullscreen); 1193 container_fullscreen_disable(con->pending.workspace->fullscreen);
1123 } 1194 }
1124 container_fullscreen_workspace(con); 1195 container_fullscreen_workspace(con);
1125 break; 1196 break;
@@ -1127,7 +1198,7 @@ void container_set_fullscreen(struct sway_container *con,
1127 if (root->fullscreen_global) { 1198 if (root->fullscreen_global) {
1128 container_fullscreen_disable(root->fullscreen_global); 1199 container_fullscreen_disable(root->fullscreen_global);
1129 } 1200 }
1130 if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { 1201 if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
1131 container_fullscreen_disable(con); 1202 container_fullscreen_disable(con);
1132 } 1203 }
1133 container_fullscreen_global(con); 1204 container_fullscreen_global(con);
@@ -1137,8 +1208,8 @@ void container_set_fullscreen(struct sway_container *con,
1137 1208
1138struct sway_container *container_toplevel_ancestor( 1209struct sway_container *container_toplevel_ancestor(
1139 struct sway_container *container) { 1210 struct sway_container *container) {
1140 while (container->parent) { 1211 while (container->pending.parent) {
1141 container = container->parent; 1212 container = container->pending.parent;
1142 } 1213 }
1143 1214
1144 return container; 1215 return container;
@@ -1150,10 +1221,10 @@ bool container_is_floating_or_child(struct sway_container *container) {
1150 1221
1151bool container_is_fullscreen_or_child(struct sway_container *container) { 1222bool container_is_fullscreen_or_child(struct sway_container *container) {
1152 do { 1223 do {
1153 if (container->fullscreen_mode) { 1224 if (container->pending.fullscreen_mode) {
1154 return true; 1225 return true;
1155 } 1226 }
1156 container = container->parent; 1227 container = container->pending.parent;
1157 } while (container); 1228 } while (container);
1158 1229
1159 return false; 1230 return false;
@@ -1226,11 +1297,11 @@ void container_discover_outputs(struct sway_container *con) {
1226} 1297}
1227 1298
1228enum sway_container_layout container_parent_layout(struct sway_container *con) { 1299enum sway_container_layout container_parent_layout(struct sway_container *con) {
1229 if (con->parent) { 1300 if (con->pending.parent) {
1230 return con->parent->layout; 1301 return con->pending.parent->pending.layout;
1231 } 1302 }
1232 if (con->workspace) { 1303 if (con->pending.workspace) {
1233 return con->workspace->layout; 1304 return con->pending.workspace->layout;
1234 } 1305 }
1235 return L_NONE; 1306 return L_NONE;
1236} 1307}
@@ -1244,16 +1315,16 @@ enum sway_container_layout container_current_parent_layout(
1244} 1315}
1245 1316
1246list_t *container_get_siblings(struct sway_container *container) { 1317list_t *container_get_siblings(struct sway_container *container) {
1247 if (container->parent) { 1318 if (container->pending.parent) {
1248 return container->parent->children; 1319 return container->pending.parent->pending.children;
1249 } 1320 }
1250 if (container_is_scratchpad_hidden(container)) { 1321 if (container_is_scratchpad_hidden(container)) {
1251 return NULL; 1322 return NULL;
1252 } 1323 }
1253 if (list_find(container->workspace->tiling, container) != -1) { 1324 if (list_find(container->pending.workspace->tiling, container) != -1) {
1254 return container->workspace->tiling; 1325 return container->pending.workspace->tiling;
1255 } 1326 }
1256 return container->workspace->floating; 1327 return container->pending.workspace->floating;
1257} 1328}
1258 1329
1259int container_sibling_index(struct sway_container *child) { 1330int container_sibling_index(struct sway_container *child) {
@@ -1268,30 +1339,30 @@ list_t *container_get_current_siblings(struct sway_container *container) {
1268} 1339}
1269 1340
1270void container_handle_fullscreen_reparent(struct sway_container *con) { 1341void container_handle_fullscreen_reparent(struct sway_container *con) {
1271 if (con->fullscreen_mode != FULLSCREEN_WORKSPACE || !con->workspace || 1342 if (con->pending.fullscreen_mode != FULLSCREEN_WORKSPACE || !con->pending.workspace ||
1272 con->workspace->fullscreen == con) { 1343 con->pending.workspace->fullscreen == con) {
1273 return; 1344 return;
1274 } 1345 }
1275 if (con->workspace->fullscreen) { 1346 if (con->pending.workspace->fullscreen) {
1276 container_fullscreen_disable(con->workspace->fullscreen); 1347 container_fullscreen_disable(con->pending.workspace->fullscreen);
1277 } 1348 }
1278 con->workspace->fullscreen = con; 1349 con->pending.workspace->fullscreen = con;
1279 1350
1280 arrange_workspace(con->workspace); 1351 arrange_workspace(con->pending.workspace);
1281} 1352}
1282 1353
1283static void set_workspace(struct sway_container *container, void *data) { 1354static void set_workspace(struct sway_container *container, void *data) {
1284 container->workspace = container->parent->workspace; 1355 container->pending.workspace = container->pending.parent->pending.workspace;
1285} 1356}
1286 1357
1287void container_insert_child(struct sway_container *parent, 1358void container_insert_child(struct sway_container *parent,
1288 struct sway_container *child, int i) { 1359 struct sway_container *child, int i) {
1289 if (child->workspace) { 1360 if (child->pending.workspace) {
1290 container_detach(child); 1361 container_detach(child);
1291 } 1362 }
1292 list_insert(parent->children, i, child); 1363 list_insert(parent->pending.children, i, child);
1293 child->parent = parent; 1364 child->pending.parent = parent;
1294 child->workspace = parent->workspace; 1365 child->pending.workspace = parent->pending.workspace;
1295 container_for_each_child(child, set_workspace, NULL); 1366 container_for_each_child(child, set_workspace, NULL);
1296 container_handle_fullscreen_reparent(child); 1367 container_handle_fullscreen_reparent(child);
1297 container_update_representation(parent); 1368 container_update_representation(parent);
@@ -1299,14 +1370,14 @@ void container_insert_child(struct sway_container *parent,
1299 1370
1300void container_add_sibling(struct sway_container *fixed, 1371void container_add_sibling(struct sway_container *fixed,
1301 struct sway_container *active, bool after) { 1372 struct sway_container *active, bool after) {
1302 if (active->workspace) { 1373 if (active->pending.workspace) {
1303 container_detach(active); 1374 container_detach(active);
1304 } 1375 }
1305 list_t *siblings = container_get_siblings(fixed); 1376 list_t *siblings = container_get_siblings(fixed);
1306 int index = list_find(siblings, fixed); 1377 int index = list_find(siblings, fixed);
1307 list_insert(siblings, index + after, active); 1378 list_insert(siblings, index + after, active);
1308 active->parent = fixed->parent; 1379 active->pending.parent = fixed->pending.parent;
1309 active->workspace = fixed->workspace; 1380 active->pending.workspace = fixed->pending.workspace;
1310 container_for_each_child(active, set_workspace, NULL); 1381 container_for_each_child(active, set_workspace, NULL);
1311 container_handle_fullscreen_reparent(active); 1382 container_handle_fullscreen_reparent(active);
1312 container_update_representation(active); 1383 container_update_representation(active);
@@ -1314,17 +1385,13 @@ void container_add_sibling(struct sway_container *fixed,
1314 1385
1315void container_add_child(struct sway_container *parent, 1386void container_add_child(struct sway_container *parent,
1316 struct sway_container *child) { 1387 struct sway_container *child) {
1317 if (child->workspace) { 1388 if (child->pending.workspace) {
1318 container_detach(child); 1389 container_detach(child);
1319 } 1390 }
1320 list_add(parent->children, child); 1391 list_add(parent->pending.children, child);
1321 child->parent = parent; 1392 child->pending.parent = parent;
1322 child->workspace = parent->workspace; 1393 child->pending.workspace = parent->pending.workspace;
1323 container_for_each_child(child, set_workspace, NULL); 1394 container_for_each_child(child, set_workspace, NULL);
1324 bool fullscreen = child->fullscreen_mode != FULLSCREEN_NONE ||
1325 parent->fullscreen_mode != FULLSCREEN_NONE;
1326 set_fullscreen_iterator(child, &fullscreen);
1327 container_for_each_child(child, set_fullscreen_iterator, &fullscreen);
1328 container_handle_fullscreen_reparent(child); 1395 container_handle_fullscreen_reparent(child);
1329 container_update_representation(parent); 1396 container_update_representation(parent);
1330 node_set_dirty(&child->node); 1397 node_set_dirty(&child->node);
@@ -1332,15 +1399,15 @@ void container_add_child(struct sway_container *parent,
1332} 1399}
1333 1400
1334void container_detach(struct sway_container *child) { 1401void container_detach(struct sway_container *child) {
1335 if (child->fullscreen_mode == FULLSCREEN_WORKSPACE) { 1402 if (child->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
1336 child->workspace->fullscreen = NULL; 1403 child->pending.workspace->fullscreen = NULL;
1337 } 1404 }
1338 if (child->fullscreen_mode == FULLSCREEN_GLOBAL) { 1405 if (child->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
1339 root->fullscreen_global = NULL; 1406 root->fullscreen_global = NULL;
1340 } 1407 }
1341 1408
1342 struct sway_container *old_parent = child->parent; 1409 struct sway_container *old_parent = child->pending.parent;
1343 struct sway_workspace *old_workspace = child->workspace; 1410 struct sway_workspace *old_workspace = child->pending.workspace;
1344 list_t *siblings = container_get_siblings(child); 1411 list_t *siblings = container_get_siblings(child);
1345 if (siblings) { 1412 if (siblings) {
1346 int index = list_find(siblings, child); 1413 int index = list_find(siblings, child);
@@ -1348,8 +1415,8 @@ void container_detach(struct sway_container *child) {
1348 list_del(siblings, index); 1415 list_del(siblings, index);
1349 } 1416 }
1350 } 1417 }
1351 child->parent = NULL; 1418 child->pending.parent = NULL;
1352 child->workspace = NULL; 1419 child->pending.workspace = NULL;
1353 container_for_each_child(child, set_workspace, NULL); 1420 container_for_each_child(child, set_workspace, NULL);
1354 1421
1355 if (old_parent) { 1422 if (old_parent) {
@@ -1364,18 +1431,18 @@ void container_detach(struct sway_container *child) {
1364 1431
1365void container_replace(struct sway_container *container, 1432void container_replace(struct sway_container *container,
1366 struct sway_container *replacement) { 1433 struct sway_container *replacement) {
1367 enum sway_fullscreen_mode fullscreen = container->fullscreen_mode; 1434 enum sway_fullscreen_mode fullscreen = container->pending.fullscreen_mode;
1368 bool scratchpad = container->scratchpad; 1435 bool scratchpad = container->scratchpad;
1369 struct sway_workspace *ws = NULL; 1436 struct sway_workspace *ws = NULL;
1370 if (fullscreen != FULLSCREEN_NONE) { 1437 if (fullscreen != FULLSCREEN_NONE) {
1371 container_fullscreen_disable(container); 1438 container_fullscreen_disable(container);
1372 } 1439 }
1373 if (scratchpad) { 1440 if (scratchpad) {
1374 ws = container->workspace; 1441 ws = container->pending.workspace;
1375 root_scratchpad_show(container); 1442 root_scratchpad_show(container);
1376 root_scratchpad_remove_container(container); 1443 root_scratchpad_remove_container(container);
1377 } 1444 }
1378 if (container->parent || container->workspace) { 1445 if (container->pending.parent || container->pending.workspace) {
1379 float width_fraction = container->width_fraction; 1446 float width_fraction = container->width_fraction;
1380 float height_fraction = container->height_fraction; 1447 float height_fraction = container->height_fraction;
1381 container_add_sibling(container, replacement, 1); 1448 container_add_sibling(container, replacement, 1);
@@ -1403,7 +1470,7 @@ struct sway_container *container_split(struct sway_container *child,
1403 enum sway_container_layout layout) { 1470 enum sway_container_layout layout) {
1404 // i3 doesn't split singleton H/V containers 1471 // i3 doesn't split singleton H/V containers
1405 // https://github.com/i3/i3/blob/3cd1c45eba6de073bc4300eebb4e1cc1a0c4479a/src/tree.c#L354 1472 // https://github.com/i3/i3/blob/3cd1c45eba6de073bc4300eebb4e1cc1a0c4479a/src/tree.c#L354
1406 if (child->parent || child->workspace) { 1473 if (child->pending.parent || child->pending.workspace) {
1407 list_t *siblings = container_get_siblings(child); 1474 list_t *siblings = container_get_siblings(child);
1408 if (siblings->length == 1) { 1475 if (siblings->length == 1) {
1409 enum sway_container_layout current = container_parent_layout(child); 1476 enum sway_container_layout current = container_parent_layout(child);
@@ -1411,12 +1478,12 @@ struct sway_container *container_split(struct sway_container *child,
1411 current = L_NONE; 1478 current = L_NONE;
1412 } 1479 }
1413 if (current == L_HORIZ || current == L_VERT) { 1480 if (current == L_HORIZ || current == L_VERT) {
1414 if (child->parent) { 1481 if (child->pending.parent) {
1415 child->parent->layout = layout; 1482 child->pending.parent->pending.layout = layout;
1416 container_update_representation(child->parent); 1483 container_update_representation(child->pending.parent);
1417 } else { 1484 } else {
1418 child->workspace->layout = layout; 1485 child->pending.workspace->layout = layout;
1419 workspace_update_representation(child->workspace); 1486 workspace_update_representation(child->pending.workspace);
1420 } 1487 }
1421 return child; 1488 return child;
1422 } 1489 }
@@ -1429,25 +1496,25 @@ struct sway_container *container_split(struct sway_container *child,
1429 if (container_is_floating(child) && child->view) { 1496 if (container_is_floating(child) && child->view) {
1430 view_set_tiled(child->view, true); 1497 view_set_tiled(child->view, true);
1431 if (child->view->using_csd) { 1498 if (child->view->using_csd) {
1432 child->border = child->saved_border; 1499 child->pending.border = child->saved_border;
1433 } 1500 }
1434 } 1501 }
1435 1502
1436 struct sway_container *cont = container_create(NULL); 1503 struct sway_container *cont = container_create(NULL);
1437 cont->width = child->width; 1504 cont->pending.width = child->pending.width;
1438 cont->height = child->height; 1505 cont->pending.height = child->pending.height;
1439 cont->width_fraction = child->width_fraction; 1506 cont->width_fraction = child->width_fraction;
1440 cont->height_fraction = child->height_fraction; 1507 cont->height_fraction = child->height_fraction;
1441 cont->x = child->x; 1508 cont->pending.x = child->pending.x;
1442 cont->y = child->y; 1509 cont->pending.y = child->pending.y;
1443 cont->layout = layout; 1510 cont->pending.layout = layout;
1444 1511
1445 container_replace(child, cont); 1512 container_replace(child, cont);
1446 container_add_child(cont, child); 1513 container_add_child(cont, child);
1447 1514
1448 if (set_focus) { 1515 if (set_focus) {
1449 seat_set_raw_focus(seat, &cont->node); 1516 seat_set_raw_focus(seat, &cont->node);
1450 if (cont->fullscreen_mode == FULLSCREEN_GLOBAL) { 1517 if (cont->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
1451 seat_set_focus(seat, &child->node); 1518 seat_set_focus(seat, &child->node);
1452 } else { 1519 } else {
1453 seat_set_raw_focus(seat, &child->node); 1520 seat_set_raw_focus(seat, &child->node);
@@ -1554,39 +1621,8 @@ static void update_marks_texture(struct sway_container *con,
1554 } 1621 }
1555 free(part); 1622 free(part);
1556 1623
1557 double scale = output->wlr_output->scale; 1624 render_titlebar_text_texture(output, con, texture, class, false, buffer);
1558 int width = 0;
1559 int height = con->title_height * scale;
1560
1561 cairo_t *c = cairo_create(NULL);
1562 get_text_size(c, config->font, &width, NULL, NULL, scale, false,
1563 "%s", buffer);
1564 cairo_destroy(c);
1565 1625
1566 cairo_surface_t *surface = cairo_image_surface_create(
1567 CAIRO_FORMAT_ARGB32, width, height);
1568 cairo_t *cairo = cairo_create(surface);
1569 cairo_set_source_rgba(cairo, class->background[0], class->background[1],
1570 class->background[2], class->background[3]);
1571 cairo_paint(cairo);
1572 PangoContext *pango = pango_cairo_create_context(cairo);
1573 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
1574 cairo_set_source_rgba(cairo, class->text[0], class->text[1],
1575 class->text[2], class->text[3]);
1576 cairo_move_to(cairo, 0, 0);
1577
1578 pango_printf(cairo, config->font, scale, false, "%s", buffer);
1579
1580 cairo_surface_flush(surface);
1581 unsigned char *data = cairo_image_surface_get_data(surface);
1582 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
1583 struct wlr_renderer *renderer = wlr_backend_get_renderer(
1584 output->wlr_output->backend);
1585 *texture = wlr_texture_from_pixels(
1586 renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data);
1587 cairo_surface_destroy(surface);
1588 g_object_unref(pango);
1589 cairo_destroy(cairo);
1590 free(buffer); 1626 free(buffer);
1591} 1627}
1592 1628
@@ -1608,19 +1644,19 @@ void container_update_marks_textures(struct sway_container *con) {
1608void container_raise_floating(struct sway_container *con) { 1644void container_raise_floating(struct sway_container *con) {
1609 // Bring container to front by putting it at the end of the floating list. 1645 // Bring container to front by putting it at the end of the floating list.
1610 struct sway_container *floater = container_toplevel_ancestor(con); 1646 struct sway_container *floater = container_toplevel_ancestor(con);
1611 if (container_is_floating(floater) && floater->workspace) { 1647 if (container_is_floating(floater) && floater->pending.workspace) {
1612 list_move_to_end(floater->workspace->floating, floater); 1648 list_move_to_end(floater->pending.workspace->floating, floater);
1613 node_set_dirty(&floater->workspace->node); 1649 node_set_dirty(&floater->pending.workspace->node);
1614 } 1650 }
1615} 1651}
1616 1652
1617bool container_is_scratchpad_hidden(struct sway_container *con) { 1653bool container_is_scratchpad_hidden(struct sway_container *con) {
1618 return con->scratchpad && !con->workspace; 1654 return con->scratchpad && !con->pending.workspace;
1619} 1655}
1620 1656
1621bool container_is_scratchpad_hidden_or_child(struct sway_container *con) { 1657bool container_is_scratchpad_hidden_or_child(struct sway_container *con) {
1622 con = container_toplevel_ancestor(con); 1658 con = container_toplevel_ancestor(con);
1623 return con->scratchpad && !con->workspace; 1659 return con->scratchpad && !con->pending.workspace;
1624} 1660}
1625 1661
1626bool container_is_sticky(struct sway_container *con) { 1662bool container_is_sticky(struct sway_container *con) {
@@ -1648,39 +1684,39 @@ static bool is_parallel(enum sway_container_layout first,
1648static bool container_is_squashable(struct sway_container *con, 1684static bool container_is_squashable(struct sway_container *con,
1649 struct sway_container *child) { 1685 struct sway_container *child) {
1650 enum sway_container_layout gp_layout = container_parent_layout(con); 1686 enum sway_container_layout gp_layout = container_parent_layout(con);
1651 return (con->layout == L_HORIZ || con->layout == L_VERT) && 1687 return (con->pending.layout == L_HORIZ || con->pending.layout == L_VERT) &&
1652 (child->layout == L_HORIZ || child->layout == L_VERT) && 1688 (child->pending.layout == L_HORIZ || child->pending.layout == L_VERT) &&
1653 !is_parallel(con->layout, child->layout) && 1689 !is_parallel(con->pending.layout, child->pending.layout) &&
1654 is_parallel(gp_layout, child->layout); 1690 is_parallel(gp_layout, child->pending.layout);
1655} 1691}
1656 1692
1657static void container_squash_children(struct sway_container *con) { 1693static void container_squash_children(struct sway_container *con) {
1658 for (int i = 0; i < con->children->length; i++) { 1694 for (int i = 0; i < con->pending.children->length; i++) {
1659 struct sway_container *child = con->children->items[i]; 1695 struct sway_container *child = con->pending.children->items[i];
1660 i += container_squash(child); 1696 i += container_squash(child);
1661 } 1697 }
1662} 1698}
1663 1699
1664int container_squash(struct sway_container *con) { 1700int container_squash(struct sway_container *con) {
1665 if (!con->children) { 1701 if (!con->pending.children) {
1666 return 0; 1702 return 0;
1667 } 1703 }
1668 if (con->children->length != 1) { 1704 if (con->pending.children->length != 1) {
1669 container_squash_children(con); 1705 container_squash_children(con);
1670 return 0; 1706 return 0;
1671 } 1707 }
1672 struct sway_container *child = con->children->items[0]; 1708 struct sway_container *child = con->pending.children->items[0];
1673 int idx = container_sibling_index(con); 1709 int idx = container_sibling_index(con);
1674 int change = 0; 1710 int change = 0;
1675 if (container_is_squashable(con, child)) { 1711 if (container_is_squashable(con, child)) {
1676 // con and child are a redundant H/V pair. Destroy them. 1712 // con and child are a redundant H/V pair. Destroy them.
1677 while (child->children->length) { 1713 while (child->pending.children->length) {
1678 struct sway_container *current = child->children->items[0]; 1714 struct sway_container *current = child->pending.children->items[0];
1679 container_detach(current); 1715 container_detach(current);
1680 if (con->parent) { 1716 if (con->pending.parent) {
1681 container_insert_child(con->parent, current, idx); 1717 container_insert_child(con->pending.parent, current, idx);
1682 } else { 1718 } else {
1683 workspace_insert_tiling_direct(con->workspace, current, idx); 1719 workspace_insert_tiling_direct(con->pending.workspace, current, idx);
1684 } 1720 }
1685 change++; 1721 change++;
1686 } 1722 }
diff --git a/sway/tree/node.c b/sway/tree/node.c
index ffa7f2cc..bc7e2aa5 100644
--- a/sway/tree/node.c
+++ b/sway/tree/node.c
@@ -75,7 +75,7 @@ void node_get_box(struct sway_node *node, struct wlr_box *box) {
75struct sway_output *node_get_output(struct sway_node *node) { 75struct sway_output *node_get_output(struct sway_node *node) {
76 switch (node->type) { 76 switch (node->type) {
77 case N_CONTAINER: { 77 case N_CONTAINER: {
78 struct sway_workspace *ws = node->sway_container->workspace; 78 struct sway_workspace *ws = node->sway_container->pending.workspace;
79 return ws ? ws->output : NULL; 79 return ws ? ws->output : NULL;
80 } 80 }
81 case N_WORKSPACE: 81 case N_WORKSPACE:
@@ -91,7 +91,7 @@ struct sway_output *node_get_output(struct sway_node *node) {
91enum sway_container_layout node_get_layout(struct sway_node *node) { 91enum sway_container_layout node_get_layout(struct sway_node *node) {
92 switch (node->type) { 92 switch (node->type) {
93 case N_CONTAINER: 93 case N_CONTAINER:
94 return node->sway_container->layout; 94 return node->sway_container->pending.layout;
95 case N_WORKSPACE: 95 case N_WORKSPACE:
96 return node->sway_workspace->layout; 96 return node->sway_workspace->layout;
97 case N_OUTPUT: 97 case N_OUTPUT:
@@ -105,11 +105,11 @@ struct sway_node *node_get_parent(struct sway_node *node) {
105 switch (node->type) { 105 switch (node->type) {
106 case N_CONTAINER: { 106 case N_CONTAINER: {
107 struct sway_container *con = node->sway_container; 107 struct sway_container *con = node->sway_container;
108 if (con->parent) { 108 if (con->pending.parent) {
109 return &con->parent->node; 109 return &con->pending.parent->node;
110 } 110 }
111 if (con->workspace) { 111 if (con->pending.workspace) {
112 return &con->workspace->node; 112 return &con->pending.workspace->node;
113 } 113 }
114 } 114 }
115 return NULL; 115 return NULL;
@@ -131,7 +131,7 @@ struct sway_node *node_get_parent(struct sway_node *node) {
131list_t *node_get_children(struct sway_node *node) { 131list_t *node_get_children(struct sway_node *node) {
132 switch (node->type) { 132 switch (node->type) {
133 case N_CONTAINER: 133 case N_CONTAINER:
134 return node->sway_container->children; 134 return node->sway_container->pending.children;
135 case N_WORKSPACE: 135 case N_WORKSPACE:
136 return node->sway_workspace->tiling; 136 return node->sway_workspace->tiling;
137 case N_OUTPUT: 137 case N_OUTPUT:
@@ -143,7 +143,7 @@ list_t *node_get_children(struct sway_node *node) {
143 143
144bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) { 144bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) {
145 if (ancestor->type == N_ROOT && node->type == N_CONTAINER && 145 if (ancestor->type == N_ROOT && node->type == N_CONTAINER &&
146 node->sway_container->fullscreen_mode == FULLSCREEN_GLOBAL) { 146 node->sway_container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
147 return true; 147 return true;
148 } 148 }
149 struct sway_node *parent = node_get_parent(node); 149 struct sway_node *parent = node_get_parent(node);
@@ -152,7 +152,7 @@ bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) {
152 return true; 152 return true;
153 } 153 }
154 if (ancestor->type == N_ROOT && parent->type == N_CONTAINER && 154 if (ancestor->type == N_ROOT && parent->type == N_CONTAINER &&
155 parent->sway_container->fullscreen_mode == FULLSCREEN_GLOBAL) { 155 parent->sway_container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
156 return true; 156 return true;
157 } 157 }
158 parent = node_get_parent(parent); 158 parent = node_get_parent(parent);
diff --git a/sway/tree/output.c b/sway/tree/output.c
index a8ae30f7..c095dce0 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -70,13 +70,13 @@ static void restore_workspaces(struct sway_output *output) {
70 // floater re-centered 70 // floater re-centered
71 for (int i = 0; i < ws->floating->length; i++) { 71 for (int i = 0; i < ws->floating->length; i++) {
72 struct sway_container *floater = ws->floating->items[i]; 72 struct sway_container *floater = ws->floating->items[i];
73 if (floater->width == 0 || floater->height == 0 || 73 if (floater->pending.width == 0 || floater->pending.height == 0 ||
74 floater->width > output->width || 74 floater->pending.width > output->width ||
75 floater->height > output->height || 75 floater->pending.height > output->height ||
76 floater->x > output->lx + output->width || 76 floater->pending.x > output->lx + output->width ||
77 floater->y > output->ly + output->height || 77 floater->pending.y > output->ly + output->height ||
78 floater->x + floater->width < output->lx || 78 floater->pending.x + floater->pending.width < output->lx ||
79 floater->y + floater->height < output->ly) { 79 floater->pending.y + floater->pending.height < output->ly) {
80 container_floating_resize_and_center(floater); 80 container_floating_resize_and_center(floater);
81 } 81 }
82 } 82 }
diff --git a/sway/tree/root.c b/sway/tree/root.c
index ebd185ec..dd4d8e33 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -59,11 +59,11 @@ void root_scratchpad_add_container(struct sway_container *con, struct sway_works
59 return; 59 return;
60 } 60 }
61 61
62 struct sway_container *parent = con->parent; 62 struct sway_container *parent = con->pending.parent;
63 struct sway_workspace *workspace = con->workspace; 63 struct sway_workspace *workspace = con->pending.workspace;
64 64
65 // Clear the fullscreen mode when sending to the scratchpad 65 // Clear the fullscreen mode when sending to the scratchpad
66 if (con->fullscreen_mode != FULLSCREEN_NONE) { 66 if (con->pending.fullscreen_mode != FULLSCREEN_NONE) {
67 container_fullscreen_disable(con); 67 container_fullscreen_disable(con);
68 } 68 }
69 69
@@ -117,7 +117,7 @@ void root_scratchpad_show(struct sway_container *con) {
117 sway_log(SWAY_DEBUG, "No focused workspace to show scratchpad on"); 117 sway_log(SWAY_DEBUG, "No focused workspace to show scratchpad on");
118 return; 118 return;
119 } 119 }
120 struct sway_workspace *old_ws = con->workspace; 120 struct sway_workspace *old_ws = con->pending.workspace;
121 121
122 // If the current con or any of its parents are in fullscreen mode, we 122 // If the current con or any of its parents are in fullscreen mode, we
123 // first need to disable it before showing the scratchpad con. 123 // first need to disable it before showing the scratchpad con.
@@ -134,15 +134,15 @@ void root_scratchpad_show(struct sway_container *con) {
134 workspace_consider_destroy(old_ws); 134 workspace_consider_destroy(old_ws);
135 } else { 135 } else {
136 // Act on the ancestor of scratchpad hidden split containers 136 // Act on the ancestor of scratchpad hidden split containers
137 while (con->parent) { 137 while (con->pending.parent) {
138 con = con->parent; 138 con = con->pending.parent;
139 } 139 }
140 } 140 }
141 workspace_add_floating(new_ws, con); 141 workspace_add_floating(new_ws, con);
142 142
143 // Make sure the container's center point overlaps this workspace 143 // Make sure the container's center point overlaps this workspace
144 double center_lx = con->x + con->width / 2; 144 double center_lx = con->pending.x + con->pending.width / 2;
145 double center_ly = con->y + con->height / 2; 145 double center_ly = con->pending.y + con->pending.height / 2;
146 146
147 struct wlr_box workspace_box; 147 struct wlr_box workspace_box;
148 workspace_get_box(new_ws, &workspace_box); 148 workspace_get_box(new_ws, &workspace_box);
@@ -155,7 +155,7 @@ void root_scratchpad_show(struct sway_container *con) {
155} 155}
156 156
157static void disable_fullscreen(struct sway_container *con, void *data) { 157static void disable_fullscreen(struct sway_container *con, void *data) {
158 if (con->fullscreen_mode != FULLSCREEN_NONE) { 158 if (con->pending.fullscreen_mode != FULLSCREEN_NONE) {
159 container_fullscreen_disable(con); 159 container_fullscreen_disable(con);
160 } 160 }
161} 161}
@@ -163,9 +163,9 @@ static void disable_fullscreen(struct sway_container *con, void *data) {
163void root_scratchpad_hide(struct sway_container *con) { 163void root_scratchpad_hide(struct sway_container *con) {
164 struct sway_seat *seat = input_manager_current_seat(); 164 struct sway_seat *seat = input_manager_current_seat();
165 struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); 165 struct sway_node *focus = seat_get_focus_inactive(seat, &root->node);
166 struct sway_workspace *ws = con->workspace; 166 struct sway_workspace *ws = con->pending.workspace;
167 167
168 if (con->fullscreen_mode == FULLSCREEN_GLOBAL && !con->workspace) { 168 if (con->pending.fullscreen_mode == FULLSCREEN_GLOBAL && !con->pending.workspace) {
169 // If the container was made fullscreen global while in the scratchpad, 169 // If the container was made fullscreen global while in the scratchpad,
170 // it should be shown until fullscreen has been disabled 170 // it should be shown until fullscreen has been disabled
171 return; 171 return;
@@ -270,7 +270,16 @@ found:
270 sway_log(SWAY_DEBUG, 270 sway_log(SWAY_DEBUG,
271 "Creating workspace %s for pid %d because it disappeared", 271 "Creating workspace %s for pid %d because it disappeared",
272 pw->workspace, pid); 272 pw->workspace, pid);
273 ws = workspace_create(pw->output, pw->workspace); 273
274 struct sway_output *output = pw->output;
275 if (pw->output && !pw->output->enabled) {
276 sway_log(SWAY_DEBUG,
277 "Workspace output %s is disabled, trying another one",
278 pw->output->wlr_output->name);
279 output = NULL;
280 }
281
282 ws = workspace_create(output, pw->workspace);
274 } 283 }
275 284
276 pid_workspace_destroy(pw); 285 pid_workspace_destroy(pw);
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 7afcdf31..b2f70d70 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -56,6 +56,7 @@ void view_destroy(struct sway_view *view) {
56 "(might have a pending transaction?)")) { 56 "(might have a pending transaction?)")) {
57 return; 57 return;
58 } 58 }
59 wl_list_remove(&view->events.unmap.listener_list);
59 if (!wl_list_empty(&view->saved_buffers)) { 60 if (!wl_list_empty(&view->saved_buffers)) {
60 view_remove_saved_buffer(view); 61 view_remove_saved_buffer(view);
61 } 62 }
@@ -206,7 +207,7 @@ bool view_ancestor_is_only_visible(struct sway_view *view) {
206 } else { 207 } else {
207 only_visible = true; 208 only_visible = true;
208 } 209 }
209 con = con->parent; 210 con = con->pending.parent;
210 } 211 }
211 return only_visible; 212 return only_visible;
212} 213}
@@ -222,72 +223,73 @@ static bool view_is_only_visible(struct sway_view *view) {
222 } 223 }
223 } 224 }
224 225
225 con = con->parent; 226 con = con->pending.parent;
226 } 227 }
227 228
228 return true; 229 return true;
229} 230}
230 231
231static bool gaps_to_edge(struct sway_view *view) { 232static bool gaps_to_edge(struct sway_view *view) {
232 struct side_gaps gaps = view->container->workspace->current_gaps; 233 struct side_gaps gaps = view->container->pending.workspace->current_gaps;
233 return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0; 234 return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0;
234} 235}
235 236
236void view_autoconfigure(struct sway_view *view) { 237void view_autoconfigure(struct sway_view *view) {
237 struct sway_container *con = view->container; 238 struct sway_container *con = view->container;
238 struct sway_workspace *ws = con->workspace; 239 struct sway_workspace *ws = con->pending.workspace;
239 240
240 if (container_is_scratchpad_hidden(con) && 241 if (container_is_scratchpad_hidden(con) &&
241 con->fullscreen_mode != FULLSCREEN_GLOBAL) { 242 con->pending.fullscreen_mode != FULLSCREEN_GLOBAL) {
242 return; 243 return;
243 } 244 }
244 struct sway_output *output = ws ? ws->output : NULL; 245 struct sway_output *output = ws ? ws->output : NULL;
245 246
246 if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { 247 if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
247 con->content_x = output->lx; 248 con->pending.content_x = output->lx;
248 con->content_y = output->ly; 249 con->pending.content_y = output->ly;
249 con->content_width = output->width; 250 con->pending.content_width = output->width;
250 con->content_height = output->height; 251 con->pending.content_height = output->height;
251 return; 252 return;
252 } else if (con->fullscreen_mode == FULLSCREEN_GLOBAL) { 253 } else if (con->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
253 con->content_x = root->x; 254 con->pending.content_x = root->x;
254 con->content_y = root->y; 255 con->pending.content_y = root->y;
255 con->content_width = root->width; 256 con->pending.content_width = root->width;
256 con->content_height = root->height; 257 con->pending.content_height = root->height;
257 return; 258 return;
258 } 259 }
259 260
260 con->border_top = con->border_bottom = true; 261 con->pending.border_top = con->pending.border_bottom = true;
261 con->border_left = con->border_right = true; 262 con->pending.border_left = con->pending.border_right = true;
262 double y_offset = 0; 263 double y_offset = 0;
263 264
264 if (!container_is_floating(con) && ws) { 265 if (!container_is_floating_or_child(con) && ws) {
265 if (config->hide_edge_borders == E_BOTH 266 if (config->hide_edge_borders == E_BOTH
266 || config->hide_edge_borders == E_VERTICAL) { 267 || config->hide_edge_borders == E_VERTICAL) {
267 con->border_left = con->x != ws->x; 268 con->pending.border_left = con->pending.x != ws->x;
268 int right_x = con->x + con->width; 269 int right_x = con->pending.x + con->pending.width;
269 con->border_right = right_x != ws->x + ws->width; 270 con->pending.border_right = right_x != ws->x + ws->width;
270 } 271 }
271 272
272 if (config->hide_edge_borders == E_BOTH 273 if (config->hide_edge_borders == E_BOTH
273 || config->hide_edge_borders == E_HORIZONTAL) { 274 || config->hide_edge_borders == E_HORIZONTAL) {
274 con->border_top = con->y != ws->y; 275 con->pending.border_top = con->pending.y != ws->y;
275 int bottom_y = con->y + con->height; 276 int bottom_y = con->pending.y + con->pending.height;
276 con->border_bottom = bottom_y != ws->y + ws->height; 277 con->pending.border_bottom = bottom_y != ws->y + ws->height;
277 } 278 }
278 279
279 bool smart = config->hide_edge_borders_smart == ESMART_ON || 280 bool smart = config->hide_edge_borders_smart == ESMART_ON ||
280 (config->hide_edge_borders_smart == ESMART_NO_GAPS && 281 (config->hide_edge_borders_smart == ESMART_NO_GAPS &&
281 !gaps_to_edge(view)); 282 !gaps_to_edge(view));
282 if (smart) { 283 if (smart) {
283 bool show_border = container_is_floating_or_child(con) || 284 bool show_border = !view_is_only_visible(view);
284 !view_is_only_visible(view); 285 con->pending.border_left &= show_border;
285 con->border_left &= show_border; 286 con->pending.border_right &= show_border;
286 con->border_right &= show_border; 287 con->pending.border_top &= show_border;
287 con->border_top &= show_border; 288 con->pending.border_bottom &= show_border;
288 con->border_bottom &= show_border;
289 } 289 }
290 }
290 291
292 if (!container_is_floating(con)) {
291 // In a tabbed or stacked container, the container's y is the top of the 293 // In a tabbed or stacked container, the container's y is the top of the
292 // title area. We have to offset the surface y by the height of the title, 294 // title area. We have to offset the surface y by the height of the title,
293 // bar, and disable any top border because we'll always have the title bar. 295 // bar, and disable any top border because we'll always have the title bar.
@@ -298,56 +300,56 @@ void view_autoconfigure(struct sway_view *view) {
298 enum sway_container_layout layout = container_parent_layout(con); 300 enum sway_container_layout layout = container_parent_layout(con);
299 if (layout == L_TABBED) { 301 if (layout == L_TABBED) {
300 y_offset = container_titlebar_height(); 302 y_offset = container_titlebar_height();
301 con->border_top = false; 303 con->pending.border_top = false;
302 } else if (layout == L_STACKED) { 304 } else if (layout == L_STACKED) {
303 y_offset = container_titlebar_height() * siblings->length; 305 y_offset = container_titlebar_height() * siblings->length;
304 con->border_top = false; 306 con->pending.border_top = false;
305 } 307 }
306 } 308 }
307 } 309 }
308 310
309 double x, y, width, height; 311 double x, y, width, height;
310 switch (con->border) { 312 switch (con->pending.border) {
311 default: 313 default:
312 case B_CSD: 314 case B_CSD:
313 case B_NONE: 315 case B_NONE:
314 x = con->x; 316 x = con->pending.x;
315 y = con->y + y_offset; 317 y = con->pending.y + y_offset;
316 width = con->width; 318 width = con->pending.width;
317 height = con->height - y_offset; 319 height = con->pending.height - y_offset;
318 break; 320 break;
319 case B_PIXEL: 321 case B_PIXEL:
320 x = con->x + con->border_thickness * con->border_left; 322 x = con->pending.x + con->pending.border_thickness * con->pending.border_left;
321 y = con->y + con->border_thickness * con->border_top + y_offset; 323 y = con->pending.y + con->pending.border_thickness * con->pending.border_top + y_offset;
322 width = con->width 324 width = con->pending.width
323 - con->border_thickness * con->border_left 325 - con->pending.border_thickness * con->pending.border_left
324 - con->border_thickness * con->border_right; 326 - con->pending.border_thickness * con->pending.border_right;
325 height = con->height - y_offset 327 height = con->pending.height - y_offset
326 - con->border_thickness * con->border_top 328 - con->pending.border_thickness * con->pending.border_top
327 - con->border_thickness * con->border_bottom; 329 - con->pending.border_thickness * con->pending.border_bottom;
328 break; 330 break;
329 case B_NORMAL: 331 case B_NORMAL:
330 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border 332 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border
331 x = con->x + con->border_thickness * con->border_left; 333 x = con->pending.x + con->pending.border_thickness * con->pending.border_left;
332 width = con->width 334 width = con->pending.width
333 - con->border_thickness * con->border_left 335 - con->pending.border_thickness * con->pending.border_left
334 - con->border_thickness * con->border_right; 336 - con->pending.border_thickness * con->pending.border_right;
335 if (y_offset) { 337 if (y_offset) {
336 y = con->y + y_offset; 338 y = con->pending.y + y_offset;
337 height = con->height - y_offset 339 height = con->pending.height - y_offset
338 - con->border_thickness * con->border_bottom; 340 - con->pending.border_thickness * con->pending.border_bottom;
339 } else { 341 } else {
340 y = con->y + container_titlebar_height(); 342 y = con->pending.y + container_titlebar_height();
341 height = con->height - container_titlebar_height() 343 height = con->pending.height - container_titlebar_height()
342 - con->border_thickness * con->border_bottom; 344 - con->pending.border_thickness * con->pending.border_bottom;
343 } 345 }
344 break; 346 break;
345 } 347 }
346 348
347 con->content_x = x; 349 con->pending.content_x = x;
348 con->content_y = y; 350 con->pending.content_y = y;
349 con->content_width = width; 351 con->pending.content_width = width;
350 con->content_height = height; 352 con->pending.content_height = height;
351} 353}
352 354
353void view_set_activated(struct sway_view *view, bool activated) { 355void view_set_activated(struct sway_view *view, bool activated) {
@@ -361,7 +363,7 @@ void view_set_activated(struct sway_view *view, bool activated) {
361} 363}
362 364
363void view_request_activate(struct sway_view *view) { 365void view_request_activate(struct sway_view *view) {
364 struct sway_workspace *ws = view->container->workspace; 366 struct sway_workspace *ws = view->container->pending.workspace;
365 if (!ws) { // hidden scratchpad container 367 if (!ws) { // hidden scratchpad container
366 return; 368 return;
367 } 369 }
@@ -401,13 +403,13 @@ void view_set_csd_from_server(struct sway_view *view, bool enabled) {
401void view_update_csd_from_client(struct sway_view *view, bool enabled) { 403void view_update_csd_from_client(struct sway_view *view, bool enabled) {
402 sway_log(SWAY_DEBUG, "View %p updated CSD to %i", view, enabled); 404 sway_log(SWAY_DEBUG, "View %p updated CSD to %i", view, enabled);
403 struct sway_container *con = view->container; 405 struct sway_container *con = view->container;
404 if (enabled && con && con->border != B_CSD) { 406 if (enabled && con && con->pending.border != B_CSD) {
405 con->saved_border = con->border; 407 con->saved_border = con->pending.border;
406 if (container_is_floating(con)) { 408 if (container_is_floating(con)) {
407 con->border = B_CSD; 409 con->pending.border = B_CSD;
408 } 410 }
409 } else if (!enabled && con && con->border == B_CSD) { 411 } else if (!enabled && con && con->pending.border == B_CSD) {
410 con->border = con->saved_border; 412 con->pending.border = con->saved_border;
411 } 413 }
412 view->using_csd = enabled; 414 view->using_csd = enabled;
413} 415}
@@ -465,6 +467,9 @@ static void view_subsurface_create(struct sway_view *view,
465static void view_init_subsurfaces(struct sway_view *view, 467static void view_init_subsurfaces(struct sway_view *view,
466 struct wlr_surface *surface); 468 struct wlr_surface *surface);
467 469
470static void view_child_init_subsurfaces(struct sway_view_child *view_child,
471 struct wlr_surface *surface);
472
468static void view_handle_surface_new_subsurface(struct wl_listener *listener, 473static void view_handle_surface_new_subsurface(struct wl_listener *listener,
469 void *data) { 474 void *data) {
470 struct sway_view *view = 475 struct sway_view *view =
@@ -577,7 +582,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
577 if (node && node->type == N_WORKSPACE) { 582 if (node && node->type == N_WORKSPACE) {
578 return node->sway_workspace; 583 return node->sway_workspace;
579 } else if (node && node->type == N_CONTAINER) { 584 } else if (node && node->type == N_CONTAINER) {
580 return node->sway_container->workspace; 585 return node->sway_container->pending.workspace;
581 } 586 }
582 587
583 // When there's no outputs connected, the above should match a workspace on 588 // When there's no outputs connected, the above should match a workspace on
@@ -590,12 +595,17 @@ static bool should_focus(struct sway_view *view) {
590 struct sway_seat *seat = input_manager_current_seat(); 595 struct sway_seat *seat = input_manager_current_seat();
591 struct sway_container *prev_con = seat_get_focused_container(seat); 596 struct sway_container *prev_con = seat_get_focused_container(seat);
592 struct sway_workspace *prev_ws = seat_get_focused_workspace(seat); 597 struct sway_workspace *prev_ws = seat_get_focused_workspace(seat);
593 struct sway_workspace *map_ws = view->container->workspace; 598 struct sway_workspace *map_ws = view->container->pending.workspace;
594 599
595 if (view->container->fullscreen_mode == FULLSCREEN_GLOBAL) { 600 if (view->container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
596 return true; 601 return true;
597 } 602 }
598 603
604 // View opened "under" fullscreen view should not be given focus.
605 if (root->fullscreen_global || !map_ws || map_ws->fullscreen) {
606 return false;
607 }
608
599 // Views can only take focus if they are mapped into the active workspace 609 // Views can only take focus if they are mapped into the active workspace
600 if (prev_ws != map_ws) { 610 if (prev_ws != map_ws) {
601 return false; 611 return false;
@@ -603,9 +613,9 @@ static bool should_focus(struct sway_view *view) {
603 613
604 // If the view is the only one in the focused workspace, it'll get focus 614 // If the view is the only one in the focused workspace, it'll get focus
605 // regardless of any no_focus criteria. 615 // regardless of any no_focus criteria.
606 if (!view->container->parent && !prev_con) { 616 if (!view->container->pending.parent && !prev_con) {
607 size_t num_children = view->container->workspace->tiling->length + 617 size_t num_children = view->container->pending.workspace->tiling->length +
608 view->container->workspace->floating->length; 618 view->container->pending.workspace->floating->length;
609 if (num_children == 1) { 619 if (num_children == 1) {
610 return true; 620 return true;
611 } 621 }
@@ -635,6 +645,7 @@ static void handle_foreign_activate_request(
635 break; 645 break;
636 } 646 }
637 } 647 }
648 transaction_commit_dirty();
638} 649}
639 650
640static void handle_foreign_fullscreen_request( 651static void handle_foreign_fullscreen_request(
@@ -645,9 +656,21 @@ static void handle_foreign_fullscreen_request(
645 656
646 // Match fullscreen command behavior for scratchpad hidden views 657 // Match fullscreen command behavior for scratchpad hidden views
647 struct sway_container *container = view->container; 658 struct sway_container *container = view->container;
648 if (!container->workspace) { 659 if (!container->pending.workspace) {
649 while (container->parent) { 660 while (container->pending.parent) {
650 container = container->parent; 661 container = container->pending.parent;
662 }
663 }
664
665 if (event->fullscreen && event->output && event->output->data) {
666 struct sway_output *output = event->output->data;
667 struct sway_workspace *ws = output_get_active_workspace(output);
668 if (ws && !container_is_scratchpad_hidden(view->container)) {
669 if (container_is_floating(view->container)) {
670 workspace_add_floating(ws, view->container);
671 } else {
672 workspace_add_tiling(ws, view->container);
673 }
651 } 674 }
652 } 675 }
653 676
@@ -656,12 +679,13 @@ static void handle_foreign_fullscreen_request(
656 if (event->fullscreen) { 679 if (event->fullscreen) {
657 arrange_root(); 680 arrange_root();
658 } else { 681 } else {
659 if (container->parent) { 682 if (container->pending.parent) {
660 arrange_container(container->parent); 683 arrange_container(container->pending.parent);
661 } else if (container->workspace) { 684 } else if (container->pending.workspace) {
662 arrange_workspace(container->workspace); 685 arrange_workspace(container->pending.workspace);
663 } 686 }
664 } 687 }
688 transaction_commit_dirty();
665} 689}
666 690
667static void handle_foreign_close_request( 691static void handle_foreign_close_request(
@@ -742,7 +766,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
742 766
743 view_init_subsurfaces(view, wlr_surface); 767 view_init_subsurfaces(view, wlr_surface);
744 wl_signal_add(&wlr_surface->events.new_subsurface, 768 wl_signal_add(&wlr_surface->events.new_subsurface,
745 &view->surface_new_subsurface); 769 &view->surface_new_subsurface);
746 view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; 770 view->surface_new_subsurface.notify = view_handle_surface_new_subsurface;
747 771
748 if (decoration) { 772 if (decoration) {
@@ -750,20 +774,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
750 } 774 }
751 775
752 if (view->impl->wants_floating && view->impl->wants_floating(view)) { 776 if (view->impl->wants_floating && view->impl->wants_floating(view)) {
753 view->container->border = config->floating_border; 777 view->container->pending.border = config->floating_border;
754 view->container->border_thickness = config->floating_border_thickness; 778 view->container->pending.border_thickness = config->floating_border_thickness;
755 container_set_floating(view->container, true); 779 container_set_floating(view->container, true);
756 } else { 780 } else {
757 view->container->border = config->border; 781 view->container->pending.border = config->border;
758 view->container->border_thickness = config->border_thickness; 782 view->container->pending.border_thickness = config->border_thickness;
759 view_set_tiled(view, true); 783 view_set_tiled(view, true);
760 } 784 }
761 785
762 if (config->popup_during_fullscreen == POPUP_LEAVE && 786 if (config->popup_during_fullscreen == POPUP_LEAVE &&
763 container->workspace && 787 container->pending.workspace &&
764 container->workspace->fullscreen && 788 container->pending.workspace->fullscreen &&
765 container->workspace->fullscreen->view) { 789 container->pending.workspace->fullscreen->view) {
766 struct sway_container *fs = container->workspace->fullscreen; 790 struct sway_container *fs = container->pending.workspace->fullscreen;
767 if (view_is_transient_for(view, fs->view)) { 791 if (view_is_transient_for(view, fs->view)) {
768 container_set_fullscreen(fs, false); 792 container_set_fullscreen(fs, false);
769 } 793 }
@@ -774,12 +798,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
774 798
775 if (fullscreen) { 799 if (fullscreen) {
776 container_set_fullscreen(view->container, true); 800 container_set_fullscreen(view->container, true);
777 arrange_workspace(view->container->workspace); 801 arrange_workspace(view->container->pending.workspace);
778 } else { 802 } else {
779 if (container->parent) { 803 if (container->pending.parent) {
780 arrange_container(container->parent); 804 arrange_container(container->pending.parent);
781 } else if (container->workspace) { 805 } else if (container->pending.workspace) {
782 arrange_workspace(container->workspace); 806 arrange_workspace(container->pending.workspace);
783 } 807 }
784 } 808 }
785 809
@@ -790,9 +814,9 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
790#if HAVE_XWAYLAND 814#if HAVE_XWAYLAND
791 if (wlr_surface_is_xwayland_surface(wlr_surface)) { 815 if (wlr_surface_is_xwayland_surface(wlr_surface)) {
792 struct wlr_xwayland_surface *xsurface = 816 struct wlr_xwayland_surface *xsurface =
793 wlr_xwayland_surface_from_wlr_surface(wlr_surface); 817 wlr_xwayland_surface_from_wlr_surface(wlr_surface);
794 set_focus = (wlr_xwayland_icccm_input_model(xsurface) != 818 set_focus &= wlr_xwayland_icccm_input_model(xsurface) !=
795 WLR_ICCCM_INPUT_MODEL_NONE) && set_focus; 819 WLR_ICCCM_INPUT_MODEL_NONE;
796 } 820 }
797#endif 821#endif
798 822
@@ -803,11 +827,9 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
803 const char *app_id; 827 const char *app_id;
804 const char *class; 828 const char *class;
805 if ((app_id = view_get_app_id(view)) != NULL) { 829 if ((app_id = view_get_app_id(view)) != NULL) {
806 wlr_foreign_toplevel_handle_v1_set_app_id( 830 wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, app_id);
807 view->foreign_toplevel, app_id);
808 } else if ((class = view_get_class(view)) != NULL) { 831 } else if ((class = view_get_class(view)) != NULL) {
809 wlr_foreign_toplevel_handle_v1_set_app_id( 832 wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, class);
810 view->foreign_toplevel, class);
811 } 833 }
812} 834}
813 835
@@ -826,8 +848,8 @@ void view_unmap(struct sway_view *view) {
826 view->foreign_toplevel = NULL; 848 view->foreign_toplevel = NULL;
827 } 849 }
828 850
829 struct sway_container *parent = view->container->parent; 851 struct sway_container *parent = view->container->pending.parent;
830 struct sway_workspace *ws = view->container->workspace; 852 struct sway_workspace *ws = view->container->pending.workspace;
831 container_begin_destroy(view->container); 853 container_begin_destroy(view->container);
832 if (parent) { 854 if (parent) {
833 container_reap_empty(parent); 855 container_reap_empty(parent);
@@ -860,47 +882,38 @@ void view_unmap(struct sway_view *view) {
860 view->surface = NULL; 882 view->surface = NULL;
861} 883}
862 884
863void view_update_size(struct sway_view *view, int width, int height) { 885void view_update_size(struct sway_view *view) {
864 struct sway_container *con = view->container; 886 struct sway_container *con = view->container;
887 con->pending.content_width = view->geometry.width;
888 con->pending.content_height = view->geometry.height;
889 container_set_geometry_from_content(con);
890}
865 891
866 if (container_is_floating(con)) { 892void view_center_surface(struct sway_view *view) {
867 con->content_width = width; 893 struct sway_container *con = view->container;
868 con->content_height = height; 894 // We always center the current coordinates rather than the next, as the
869 container_set_geometry_from_content(con); 895 // geometry immediately affects the currently active rendering.
870 } else { 896 con->surface_x = fmax(con->current.content_x, con->current.content_x +
871 con->surface_x = con->content_x + (con->content_width - width) / 2; 897 (con->current.content_width - view->geometry.width) / 2);
872 con->surface_y = con->content_y + (con->content_height - height) / 2; 898 con->surface_y = fmax(con->current.content_y, con->current.content_y +
873 con->surface_x = fmax(con->surface_x, con->content_x); 899 (con->current.content_height - view->geometry.height) / 2);
874 con->surface_y = fmax(con->surface_y, con->content_y);
875 }
876} 900}
877 901
878static const struct sway_view_child_impl subsurface_impl; 902static const struct sway_view_child_impl subsurface_impl;
879 903
880static void subsurface_get_root_coords(struct sway_view_child *child, 904static void subsurface_get_view_coords(struct sway_view_child *child,
881 int *root_sx, int *root_sy) { 905 int *sx, int *sy) {
882 struct wlr_surface *surface = child->surface; 906 struct wlr_surface *surface = child->surface;
883 *root_sx = -child->view->geometry.x;
884 *root_sy = -child->view->geometry.y;
885
886 if (child->parent && child->parent->impl && 907 if (child->parent && child->parent->impl &&
887 child->parent->impl->get_root_coords) { 908 child->parent->impl->get_view_coords) {
888 int sx, sy; 909 child->parent->impl->get_view_coords(child->parent, sx, sy);
889 child->parent->impl->get_root_coords(child->parent, &sx, &sy);
890 *root_sx += sx;
891 *root_sy += sy;
892 } else { 910 } else {
893 while (surface && wlr_surface_is_subsurface(surface)) { 911 *sx = *sy = 0;
894 struct wlr_subsurface *subsurface =
895 wlr_subsurface_from_wlr_surface(surface);
896 if (subsurface == NULL) {
897 break;
898 }
899 *root_sx += subsurface->current.x;
900 *root_sy += subsurface->current.y;
901 surface = subsurface->parent;
902 }
903 } 912 }
913 struct wlr_subsurface *subsurface =
914 wlr_subsurface_from_wlr_surface(surface);
915 *sx += subsurface->current.x;
916 *sy += subsurface->current.y;
904} 917}
905 918
906static void subsurface_destroy(struct sway_view_child *child) { 919static void subsurface_destroy(struct sway_view_child *child) {
@@ -914,7 +927,7 @@ static void subsurface_destroy(struct sway_view_child *child) {
914} 927}
915 928
916static const struct sway_view_child_impl subsurface_impl = { 929static const struct sway_view_child_impl subsurface_impl = {
917 .get_root_coords = subsurface_get_root_coords, 930 .get_view_coords = subsurface_get_view_coords,
918 .destroy = subsurface_destroy, 931 .destroy = subsurface_destroy,
919}; 932};
920 933
@@ -968,15 +981,27 @@ static void view_child_subsurface_create(struct sway_view_child *child,
968 view_child_damage(&subsurface->child, true); 981 view_child_damage(&subsurface->child, true);
969} 982}
970 983
984static bool view_child_is_mapped(struct sway_view_child *child) {
985 while (child) {
986 if (!child->mapped) {
987 return false;
988 }
989 child = child->parent;
990 }
991 return true;
992}
993
971static void view_child_damage(struct sway_view_child *child, bool whole) { 994static void view_child_damage(struct sway_view_child *child, bool whole) {
972 if (!child || !child->mapped || !child->view || !child->view->container) { 995 if (!child || !view_child_is_mapped(child) || !child->view || !child->view->container) {
973 return; 996 return;
974 } 997 }
975 int sx, sy; 998 int sx, sy;
976 child->impl->get_root_coords(child, &sx, &sy); 999 child->impl->get_view_coords(child, &sx, &sy);
977 desktop_damage_surface(child->surface, 1000 desktop_damage_surface(child->surface,
978 child->view->container->content_x + sx, 1001 child->view->container->pending.content_x -
979 child->view->container->content_y + sy, whole); 1002 child->view->geometry.x + sx,
1003 child->view->container->pending.content_y -
1004 child->view->geometry.y + sy, whole);
980} 1005}
981 1006
982static void view_child_handle_surface_commit(struct wl_listener *listener, 1007static void view_child_handle_surface_commit(struct wl_listener *listener,
@@ -1004,11 +1029,29 @@ static void view_child_handle_surface_destroy(struct wl_listener *listener,
1004static void view_init_subsurfaces(struct sway_view *view, 1029static void view_init_subsurfaces(struct sway_view *view,
1005 struct wlr_surface *surface) { 1030 struct wlr_surface *surface) {
1006 struct wlr_subsurface *subsurface; 1031 struct wlr_subsurface *subsurface;
1007 wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { 1032 wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
1033 current.link) {
1034 view_subsurface_create(view, subsurface);
1035 }
1036 wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
1037 current.link) {
1008 view_subsurface_create(view, subsurface); 1038 view_subsurface_create(view, subsurface);
1009 } 1039 }
1010} 1040}
1011 1041
1042static void view_child_init_subsurfaces(struct sway_view_child *view_child,
1043 struct wlr_surface *surface) {
1044 struct wlr_subsurface *subsurface;
1045 wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
1046 current.link) {
1047 view_child_subsurface_create(view_child, subsurface);
1048 }
1049 wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
1050 current.link) {
1051 view_child_subsurface_create(view_child, subsurface);
1052 }
1053}
1054
1012static void view_child_handle_surface_map(struct wl_listener *listener, 1055static void view_child_handle_surface_map(struct wl_listener *listener,
1013 void *data) { 1056 void *data) {
1014 struct sway_view_child *child = 1057 struct sway_view_child *child =
@@ -1059,16 +1102,16 @@ void view_child_init(struct sway_view_child *child,
1059 wl_signal_add(&view->events.unmap, &child->view_unmap); 1102 wl_signal_add(&view->events.unmap, &child->view_unmap);
1060 child->view_unmap.notify = view_child_handle_view_unmap; 1103 child->view_unmap.notify = view_child_handle_view_unmap;
1061 1104
1062 struct sway_workspace *workspace = child->view->container->workspace; 1105 struct sway_workspace *workspace = child->view->container->pending.workspace;
1063 if (workspace) { 1106 if (workspace) {
1064 wlr_surface_send_enter(child->surface, workspace->output->wlr_output); 1107 wlr_surface_send_enter(child->surface, workspace->output->wlr_output);
1065 } 1108 }
1066 1109
1067 view_init_subsurfaces(child->view, surface); 1110 view_child_init_subsurfaces(child, surface);
1068} 1111}
1069 1112
1070void view_child_destroy(struct sway_view_child *child) { 1113void view_child_destroy(struct sway_view_child *child) {
1071 if (child->mapped && child->view->container != NULL) { 1114 if (view_child_is_mapped(child) && child->view->container != NULL) {
1072 view_child_damage(child, true); 1115 view_child_damage(child, true);
1073 } 1116 }
1074 1117
@@ -1081,6 +1124,9 @@ void view_child_destroy(struct sway_view_child *child) {
1081 wl_list_for_each_safe(subchild, tmpchild, &child->children, link) { 1124 wl_list_for_each_safe(subchild, tmpchild, &child->children, link) {
1082 wl_list_remove(&subchild->link); 1125 wl_list_remove(&subchild->link);
1083 subchild->parent = NULL; 1126 subchild->parent = NULL;
1127 // The subchild lost its parent link, so it cannot see that the parent
1128 // is unmapped. Unmap it directly.
1129 subchild->mapped = false;
1084 } 1130 }
1085 1131
1086 wl_list_remove(&child->surface_commit.link); 1132 wl_list_remove(&child->surface_commit.link);
@@ -1101,18 +1147,27 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
1101 if (wlr_surface_is_xdg_surface(wlr_surface)) { 1147 if (wlr_surface_is_xdg_surface(wlr_surface)) {
1102 struct wlr_xdg_surface *xdg_surface = 1148 struct wlr_xdg_surface *xdg_surface =
1103 wlr_xdg_surface_from_wlr_surface(wlr_surface); 1149 wlr_xdg_surface_from_wlr_surface(wlr_surface);
1150 if (xdg_surface == NULL) {
1151 return NULL;
1152 }
1104 return view_from_wlr_xdg_surface(xdg_surface); 1153 return view_from_wlr_xdg_surface(xdg_surface);
1105 } 1154 }
1106#if HAVE_XWAYLAND 1155#if HAVE_XWAYLAND
1107 if (wlr_surface_is_xwayland_surface(wlr_surface)) { 1156 if (wlr_surface_is_xwayland_surface(wlr_surface)) {
1108 struct wlr_xwayland_surface *xsurface = 1157 struct wlr_xwayland_surface *xsurface =
1109 wlr_xwayland_surface_from_wlr_surface(wlr_surface); 1158 wlr_xwayland_surface_from_wlr_surface(wlr_surface);
1159 if (xsurface == NULL) {
1160 return NULL;
1161 }
1110 return view_from_wlr_xwayland_surface(xsurface); 1162 return view_from_wlr_xwayland_surface(xsurface);
1111 } 1163 }
1112#endif 1164#endif
1113 if (wlr_surface_is_subsurface(wlr_surface)) { 1165 if (wlr_surface_is_subsurface(wlr_surface)) {
1114 struct wlr_subsurface *subsurface = 1166 struct wlr_subsurface *subsurface =
1115 wlr_subsurface_from_wlr_surface(wlr_surface); 1167 wlr_subsurface_from_wlr_surface(wlr_surface);
1168 if (subsurface == NULL) {
1169 return NULL;
1170 }
1116 return view_from_wlr_surface(subsurface->parent); 1171 return view_from_wlr_surface(subsurface->parent);
1117 } 1172 }
1118 if (wlr_surface_is_layer_surface(wlr_surface)) { 1173 if (wlr_surface_is_layer_surface(wlr_surface)) {
@@ -1225,8 +1280,6 @@ void view_update_title(struct sway_view *view, bool force) {
1225 view->container->title = NULL; 1280 view->container->title = NULL;
1226 view->container->formatted_title = NULL; 1281 view->container->formatted_title = NULL;
1227 } 1282 }
1228 container_calculate_title_height(view->container);
1229 config_update_font_height(false);
1230 1283
1231 // Update title after the global font height is updated 1284 // Update title after the global font height is updated
1232 container_update_title_textures(view->container); 1285 container_update_title_textures(view->container);
@@ -1242,15 +1295,15 @@ bool view_is_visible(struct sway_view *view) {
1242 if (view->container->node.destroying) { 1295 if (view->container->node.destroying) {
1243 return false; 1296 return false;
1244 } 1297 }
1245 struct sway_workspace *workspace = view->container->workspace; 1298 struct sway_workspace *workspace = view->container->pending.workspace;
1246 if (!workspace && view->container->fullscreen_mode != FULLSCREEN_GLOBAL) { 1299 if (!workspace && view->container->pending.fullscreen_mode != FULLSCREEN_GLOBAL) {
1247 bool fs_global_descendant = false; 1300 bool fs_global_descendant = false;
1248 struct sway_container *parent = view->container->parent; 1301 struct sway_container *parent = view->container->pending.parent;
1249 while (parent) { 1302 while (parent) {
1250 if (parent->fullscreen_mode == FULLSCREEN_GLOBAL) { 1303 if (parent->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
1251 fs_global_descendant = true; 1304 fs_global_descendant = true;
1252 } 1305 }
1253 parent = parent->parent; 1306 parent = parent->pending.parent;
1254 } 1307 }
1255 if (!fs_global_descendant) { 1308 if (!fs_global_descendant) {
1256 return false; 1309 return false;
@@ -1268,13 +1321,13 @@ bool view_is_visible(struct sway_view *view) {
1268 enum sway_container_layout layout = container_parent_layout(con); 1321 enum sway_container_layout layout = container_parent_layout(con);
1269 if ((layout == L_TABBED || layout == L_STACKED) 1322 if ((layout == L_TABBED || layout == L_STACKED)
1270 && !container_is_floating(con)) { 1323 && !container_is_floating(con)) {
1271 struct sway_node *parent = con->parent ? 1324 struct sway_node *parent = con->pending.parent ?
1272 &con->parent->node : &con->workspace->node; 1325 &con->pending.parent->node : &con->pending.workspace->node;
1273 if (seat_get_active_tiling_child(seat, parent) != &con->node) { 1326 if (seat_get_active_tiling_child(seat, parent) != &con->node) {
1274 return false; 1327 return false;
1275 } 1328 }
1276 } 1329 }
1277 con = con->parent; 1330 con = con->pending.parent;
1278 } 1331 }
1279 // Check view isn't hidden by another fullscreen view 1332 // Check view isn't hidden by another fullscreen view
1280 struct sway_container *fs = root->fullscreen_global ? 1333 struct sway_container *fs = root->fullscreen_global ?
@@ -1308,7 +1361,7 @@ void view_set_urgent(struct sway_view *view, bool enable) {
1308 ipc_event_window(view->container, "urgent"); 1361 ipc_event_window(view->container, "urgent");
1309 1362
1310 if (!container_is_scratchpad_hidden(view->container)) { 1363 if (!container_is_scratchpad_hidden(view->container)) {
1311 workspace_detect_urgent(view->container->workspace); 1364 workspace_detect_urgent(view->container->pending.workspace);
1312 } 1365 }
1313} 1366}
1314 1367
@@ -1338,11 +1391,11 @@ static void view_save_buffer_iterator(struct wlr_surface *surface,
1338 saved_buffer->buffer = surface->buffer; 1391 saved_buffer->buffer = surface->buffer;
1339 saved_buffer->width = surface->current.width; 1392 saved_buffer->width = surface->current.width;
1340 saved_buffer->height = surface->current.height; 1393 saved_buffer->height = surface->current.height;
1341 saved_buffer->x = sx; 1394 saved_buffer->x = view->container->surface_x + sx;
1342 saved_buffer->y = sy; 1395 saved_buffer->y = view->container->surface_y + sy;
1343 saved_buffer->transform = surface->current.transform; 1396 saved_buffer->transform = surface->current.transform;
1344 wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box); 1397 wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box);
1345 wl_list_insert(&view->saved_buffers, &saved_buffer->link); 1398 wl_list_insert(view->saved_buffers.prev, &saved_buffer->link);
1346 } 1399 }
1347} 1400}
1348 1401
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 921b7d19..8dd7789d 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -48,7 +48,7 @@ struct sway_output *workspace_get_initial_output(const char *name) {
48 if (focus && focus->type == N_WORKSPACE) { 48 if (focus && focus->type == N_WORKSPACE) {
49 return focus->sway_workspace->output; 49 return focus->sway_workspace->output;
50 } else if (focus && focus->type == N_CONTAINER) { 50 } else if (focus && focus->type == N_CONTAINER) {
51 return focus->sway_container->workspace->output; 51 return focus->sway_container->pending.workspace->output;
52 } 52 }
53 // Fallback to the first output or noop output for headless 53 // Fallback to the first output or noop output for headless
54 return root->outputs->length ? root->outputs->items[0] : root->noop_output; 54 return root->outputs->length ? root->outputs->items[0] : root->noop_output;
@@ -222,10 +222,8 @@ static void workspace_name_from_binding(const struct sway_binding * binding,
222 // not a command about workspaces 222 // not a command about workspaces
223 if (strcmp(_target, "next") == 0 || 223 if (strcmp(_target, "next") == 0 ||
224 strcmp(_target, "prev") == 0 || 224 strcmp(_target, "prev") == 0 ||
225 strncmp(_target, "next_on_output", 225 strcmp(_target, "next_on_output") == 0 ||
226 strlen("next_on_output")) == 0 || 226 strcmp(_target, "prev_on_output") == 0 ||
227 strncmp(_target, "prev_on_output",
228 strlen("next_on_output")) == 0 ||
229 strcmp(_target, "number") == 0 || 227 strcmp(_target, "number") == 0 ||
230 strcmp(_target, "back_and_forth") == 0 || 228 strcmp(_target, "back_and_forth") == 0 ||
231 strcmp(_target, "current") == 0) { 229 strcmp(_target, "current") == 0) {
@@ -363,11 +361,11 @@ struct sway_workspace *workspace_by_name(const char *name) {
363 if (current && strcmp(name, "prev") == 0) { 361 if (current && strcmp(name, "prev") == 0) {
364 return workspace_prev(current); 362 return workspace_prev(current);
365 } else if (current && strcmp(name, "prev_on_output") == 0) { 363 } else if (current && strcmp(name, "prev_on_output") == 0) {
366 return workspace_output_prev(current, false); 364 return workspace_output_prev(current);
367 } else if (current && strcmp(name, "next") == 0) { 365 } else if (current && strcmp(name, "next") == 0) {
368 return workspace_next(current); 366 return workspace_next(current);
369 } else if (current && strcmp(name, "next_on_output") == 0) { 367 } else if (current && strcmp(name, "next_on_output") == 0) {
370 return workspace_output_next(current, false); 368 return workspace_output_next(current);
371 } else if (strcmp(name, "current") == 0) { 369 } else if (strcmp(name, "current") == 0) {
372 return current; 370 return current;
373 } else if (strcasecmp(name, "back_and_forth") == 0) { 371 } else if (strcasecmp(name, "back_and_forth") == 0) {
@@ -530,7 +528,7 @@ struct sway_workspace *workspace_next(struct sway_workspace *workspace) {
530 * otherwise the next one is returned. 528 * otherwise the next one is returned.
531 */ 529 */
532static struct sway_workspace *workspace_output_prev_next_impl( 530static struct sway_workspace *workspace_output_prev_next_impl(
533 struct sway_output *output, int dir, bool create) { 531 struct sway_output *output, int dir) {
534 struct sway_seat *seat = input_manager_current_seat(); 532 struct sway_seat *seat = input_manager_current_seat();
535 struct sway_workspace *workspace = seat_get_focused_workspace(seat); 533 struct sway_workspace *workspace = seat_get_focused_workspace(seat);
536 if (!workspace) { 534 if (!workspace) {
@@ -540,46 +538,43 @@ static struct sway_workspace *workspace_output_prev_next_impl(
540 } 538 }
541 539
542 int index = list_find(output->workspaces, workspace); 540 int index = list_find(output->workspaces, workspace);
543 if (!workspace_is_empty(workspace) && create &&
544 (index + dir < 0 || index + dir == output->workspaces->length)) {
545 struct sway_output *output = workspace->output;
546 char *next = workspace_next_name(output->wlr_output->name);
547 workspace_create(output, next);
548 free(next);
549 }
550 size_t new_index = wrap(index + dir, output->workspaces->length); 541 size_t new_index = wrap(index + dir, output->workspaces->length);
551 return output->workspaces->items[new_index]; 542 return output->workspaces->items[new_index];
552} 543}
553 544
554struct sway_workspace *workspace_output_next( 545
555 struct sway_workspace *current, bool create) { 546struct sway_workspace *workspace_output_next(struct sway_workspace *current) {
556 return workspace_output_prev_next_impl(current->output, 1, create); 547 return workspace_output_prev_next_impl(current->output, 1);
557} 548}
558 549
559struct sway_workspace *workspace_output_prev( 550struct sway_workspace *workspace_output_prev(struct sway_workspace *current) {
560 struct sway_workspace *current, bool create) { 551 return workspace_output_prev_next_impl(current->output, -1);
561 return workspace_output_prev_next_impl(current->output, -1, create);
562} 552}
563 553
564bool workspace_switch(struct sway_workspace *workspace, 554struct sway_workspace *workspace_auto_back_and_forth(
565 bool no_auto_back_and_forth) { 555 struct sway_workspace *workspace) {
566 struct sway_seat *seat = input_manager_current_seat(); 556 struct sway_seat *seat = input_manager_current_seat();
567 struct sway_workspace *active_ws = NULL; 557 struct sway_workspace *active_ws = NULL;
568 struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); 558 struct sway_node *focus = seat_get_focus_inactive(seat, &root->node);
569 if (focus && focus->type == N_WORKSPACE) { 559 if (focus && focus->type == N_WORKSPACE) {
570 active_ws = focus->sway_workspace; 560 active_ws = focus->sway_workspace;
571 } else if (focus && focus->type == N_CONTAINER) { 561 } else if (focus && focus->type == N_CONTAINER) {
572 active_ws = focus->sway_container->workspace; 562 active_ws = focus->sway_container->pending.workspace;
573 } 563 }
574 564
575 if (!no_auto_back_and_forth && config->auto_back_and_forth && active_ws 565 if (config->auto_back_and_forth && active_ws && active_ws == workspace &&
576 && active_ws == workspace && seat->prev_workspace_name) { 566 seat->prev_workspace_name) {
577 struct sway_workspace *new_ws = 567 struct sway_workspace *new_ws =
578 workspace_by_name(seat->prev_workspace_name); 568 workspace_by_name(seat->prev_workspace_name);
579 workspace = new_ws ? 569 workspace = new_ws ?
580 new_ws : 570 new_ws :
581 workspace_create(NULL, seat->prev_workspace_name); 571 workspace_create(NULL, seat->prev_workspace_name);
582 } 572 }
573 return workspace;
574}
575
576bool workspace_switch(struct sway_workspace *workspace) {
577 struct sway_seat *seat = input_manager_current_seat();
583 578
584 sway_log(SWAY_DEBUG, "Switching to workspace %p:%s", 579 sway_log(SWAY_DEBUG, "Switching to workspace %p:%s",
585 workspace, workspace->name); 580 workspace, workspace->name);
@@ -736,13 +731,13 @@ struct sway_container *workspace_find_container(struct sway_workspace *ws,
736} 731}
737 732
738static void set_workspace(struct sway_container *container, void *data) { 733static void set_workspace(struct sway_container *container, void *data) {
739 container->workspace = container->parent->workspace; 734 container->pending.workspace = container->pending.parent->pending.workspace;
740} 735}
741 736
742static void workspace_attach_tiling(struct sway_workspace *ws, 737static void workspace_attach_tiling(struct sway_workspace *ws,
743 struct sway_container *con) { 738 struct sway_container *con) {
744 list_add(ws->tiling, con); 739 list_add(ws->tiling, con);
745 con->workspace = ws; 740 con->pending.workspace = ws;
746 container_for_each_child(con, set_workspace, NULL); 741 container_for_each_child(con, set_workspace, NULL);
747 container_handle_fullscreen_reparent(con); 742 container_handle_fullscreen_reparent(con);
748 workspace_update_representation(ws); 743 workspace_update_representation(ws);
@@ -753,7 +748,7 @@ static void workspace_attach_tiling(struct sway_workspace *ws,
753struct sway_container *workspace_wrap_children(struct sway_workspace *ws) { 748struct sway_container *workspace_wrap_children(struct sway_workspace *ws) {
754 struct sway_container *fs = ws->fullscreen; 749 struct sway_container *fs = ws->fullscreen;
755 struct sway_container *middle = container_create(NULL); 750 struct sway_container *middle = container_create(NULL);
756 middle->layout = ws->layout; 751 middle->pending.layout = ws->layout;
757 while (ws->tiling->length) { 752 while (ws->tiling->length) {
758 struct sway_container *child = ws->tiling->items[0]; 753 struct sway_container *child = ws->tiling->items[0];
759 container_detach(child); 754 container_detach(child);
@@ -771,9 +766,9 @@ void workspace_unwrap_children(struct sway_workspace *ws,
771 return; 766 return;
772 } 767 }
773 768
774 ws->layout = wrap->layout; 769 ws->layout = wrap->pending.layout;
775 while (wrap->children->length) { 770 while (wrap->pending.children->length) {
776 struct sway_container *child = wrap->children->items[0]; 771 struct sway_container *child = wrap->pending.children->items[0];
777 container_detach(child); 772 container_detach(child);
778 workspace_add_tiling(ws, child); 773 workspace_add_tiling(ws, child);
779 } 774 }
@@ -793,14 +788,18 @@ void workspace_detach(struct sway_workspace *workspace) {
793 788
794struct sway_container *workspace_add_tiling(struct sway_workspace *workspace, 789struct sway_container *workspace_add_tiling(struct sway_workspace *workspace,
795 struct sway_container *con) { 790 struct sway_container *con) {
796 if (con->workspace) { 791 if (con->pending.workspace) {
792 struct sway_container *old_parent = con->pending.parent;
797 container_detach(con); 793 container_detach(con);
794 if (old_parent) {
795 container_reap_empty(old_parent);
796 }
798 } 797 }
799 if (config->default_layout != L_NONE) { 798 if (config->default_layout != L_NONE) {
800 con = container_split(con, config->default_layout); 799 con = container_split(con, config->default_layout);
801 } 800 }
802 list_add(workspace->tiling, con); 801 list_add(workspace->tiling, con);
803 con->workspace = workspace; 802 con->pending.workspace = workspace;
804 container_for_each_child(con, set_workspace, NULL); 803 container_for_each_child(con, set_workspace, NULL);
805 container_handle_fullscreen_reparent(con); 804 container_handle_fullscreen_reparent(con);
806 workspace_update_representation(workspace); 805 workspace_update_representation(workspace);
@@ -811,11 +810,11 @@ struct sway_container *workspace_add_tiling(struct sway_workspace *workspace,
811 810
812void workspace_add_floating(struct sway_workspace *workspace, 811void workspace_add_floating(struct sway_workspace *workspace,
813 struct sway_container *con) { 812 struct sway_container *con) {
814 if (con->workspace) { 813 if (con->pending.workspace) {
815 container_detach(con); 814 container_detach(con);
816 } 815 }
817 list_add(workspace->floating, con); 816 list_add(workspace->floating, con);
818 con->workspace = workspace; 817 con->pending.workspace = workspace;
819 container_for_each_child(con, set_workspace, NULL); 818 container_for_each_child(con, set_workspace, NULL);
820 container_handle_fullscreen_reparent(con); 819 container_handle_fullscreen_reparent(con);
821 node_set_dirty(&workspace->node); 820 node_set_dirty(&workspace->node);
@@ -825,7 +824,7 @@ void workspace_add_floating(struct sway_workspace *workspace,
825void workspace_insert_tiling_direct(struct sway_workspace *workspace, 824void workspace_insert_tiling_direct(struct sway_workspace *workspace,
826 struct sway_container *con, int index) { 825 struct sway_container *con, int index) {
827 list_insert(workspace->tiling, index, con); 826 list_insert(workspace->tiling, index, con);
828 con->workspace = workspace; 827 con->pending.workspace = workspace;
829 container_for_each_child(con, set_workspace, NULL); 828 container_for_each_child(con, set_workspace, NULL);
830 container_handle_fullscreen_reparent(con); 829 container_handle_fullscreen_reparent(con);
831 workspace_update_representation(workspace); 830 workspace_update_representation(workspace);
@@ -835,7 +834,7 @@ void workspace_insert_tiling_direct(struct sway_workspace *workspace,
835 834
836struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, 835struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace,
837 struct sway_container *con, int index) { 836 struct sway_container *con, int index) {
838 if (con->workspace) { 837 if (con->pending.workspace) {
839 container_detach(con); 838 container_detach(con);
840 } 839 }
841 if (config->default_layout != L_NONE) { 840 if (config->default_layout != L_NONE) {
@@ -905,7 +904,7 @@ struct sway_container *workspace_split(struct sway_workspace *workspace,
905 enum sway_container_layout old_layout = workspace->layout; 904 enum sway_container_layout old_layout = workspace->layout;
906 struct sway_container *middle = workspace_wrap_children(workspace); 905 struct sway_container *middle = workspace_wrap_children(workspace);
907 workspace->layout = layout; 906 workspace->layout = layout;
908 middle->layout = old_layout; 907 middle->pending.layout = old_layout;
909 908
910 struct sway_seat *seat; 909 struct sway_seat *seat;
911 wl_list_for_each(seat, &server.input->seats, link) { 910 wl_list_for_each(seat, &server.input->seats, link) {