diff options
Diffstat (limited to 'sway/tree')
-rw-r--r-- | sway/tree/arrange.c | 70 | ||||
-rw-r--r-- | sway/tree/container.c | 622 | ||||
-rw-r--r-- | sway/tree/node.c | 18 | ||||
-rw-r--r-- | sway/tree/output.c | 14 | ||||
-rw-r--r-- | sway/tree/root.c | 33 | ||||
-rw-r--r-- | sway/tree/view.c | 363 | ||||
-rw-r--r-- | sway/tree/workspace.c | 77 |
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 | ||
152 | struct sway_container *container_find_child(struct sway_container *container, | 154 | struct 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 | ||
313 | struct sway_container *view_container_at(struct sway_node *parent, | 315 | static 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 | |||
338 | static 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, | |||
408 | void container_for_each_child(struct sway_container *container, | 433 | void 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 | ||
445 | struct 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 | |||
420 | bool container_has_ancestor(struct sway_container *descendant, | 467 | bool 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 | ||
449 | static void update_title_texture(struct sway_container *con, | 496 | static 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 | ||
561 | static 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 | |||
517 | void container_update_title_textures(struct sway_container *container) { | 579 | void 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 | ||
529 | void 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 | ||
597 | void container_update_representation(struct sway_container *con) { | 644 | void 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 | ||
678 | void container_floating_resize_and_center(struct sway_container *con) { | 724 | void 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 | ||
724 | void container_floating_set_default_size(struct sway_container *con) { | 770 | void 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 | ||
850 | bool container_is_floating(struct sway_container *container) { | 917 | bool 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 | |||
928 | bool 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 | ||
861 | void container_get_box(struct sway_container *container, struct wlr_box *box) { | 939 | void 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 | */ |
871 | void container_floating_translate(struct sway_container *con, | 949 | void 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 | */ |
895 | struct sway_output *container_floating_find_output(struct sway_container *con) { | 973 | struct 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 | ||
960 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | 1038 | static 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 | ||
975 | static void set_fullscreen_iterator(struct sway_container *con, void *data) { | 1053 | static 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 | ||
989 | static void container_fullscreen_workspace(struct sway_container *con) { | 1066 | static 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 | ||
1025 | static void container_fullscreen_global(struct sway_container *con) { | 1100 | static 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 | ||
1053 | void container_fullscreen_disable(struct sway_container *con) { | 1126 | void 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 | ||
1107 | void container_set_fullscreen(struct sway_container *con, | 1178 | void 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 | ||
1138 | struct sway_container *container_toplevel_ancestor( | 1209 | struct 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 | ||
1151 | bool container_is_fullscreen_or_child(struct sway_container *container) { | 1222 | bool 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 | ||
1228 | enum sway_container_layout container_parent_layout(struct sway_container *con) { | 1299 | enum 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 | ||
1246 | list_t *container_get_siblings(struct sway_container *container) { | 1317 | list_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 | ||
1259 | int container_sibling_index(struct sway_container *child) { | 1330 | int 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 | ||
1270 | void container_handle_fullscreen_reparent(struct sway_container *con) { | 1341 | void 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 | ||
1283 | static void set_workspace(struct sway_container *container, void *data) { | 1354 | static 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 | ||
1287 | void container_insert_child(struct sway_container *parent, | 1358 | void 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 | ||
1300 | void container_add_sibling(struct sway_container *fixed, | 1371 | void 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 | ||
1315 | void container_add_child(struct sway_container *parent, | 1386 | void 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 | ||
1334 | void container_detach(struct sway_container *child) { | 1401 | void 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 | ||
1365 | void container_replace(struct sway_container *container, | 1432 | void 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) { | |||
1608 | void container_raise_floating(struct sway_container *con) { | 1644 | void 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 | ||
1617 | bool container_is_scratchpad_hidden(struct sway_container *con) { | 1653 | bool 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 | ||
1621 | bool container_is_scratchpad_hidden_or_child(struct sway_container *con) { | 1657 | bool 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 | ||
1626 | bool container_is_sticky(struct sway_container *con) { | 1662 | bool container_is_sticky(struct sway_container *con) { |
@@ -1648,39 +1684,39 @@ static bool is_parallel(enum sway_container_layout first, | |||
1648 | static bool container_is_squashable(struct sway_container *con, | 1684 | static 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 | ||
1657 | static void container_squash_children(struct sway_container *con) { | 1693 | static 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 | ||
1664 | int container_squash(struct sway_container *con) { | 1700 | int 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) { | |||
75 | struct sway_output *node_get_output(struct sway_node *node) { | 75 | struct 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) { | |||
91 | enum sway_container_layout node_get_layout(struct sway_node *node) { | 91 | enum 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) { | |||
131 | list_t *node_get_children(struct sway_node *node) { | 131 | list_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 | ||
144 | bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) { | 144 | bool 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 | ||
157 | static void disable_fullscreen(struct sway_container *con, void *data) { | 157 | static 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) { | |||
163 | void root_scratchpad_hide(struct sway_container *con) { | 163 | void 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 | ||
231 | static bool gaps_to_edge(struct sway_view *view) { | 232 | static 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 | ||
236 | void view_autoconfigure(struct sway_view *view) { | 237 | void 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 | ||
353 | void view_set_activated(struct sway_view *view, bool activated) { | 355 | void 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 | ||
363 | void view_request_activate(struct sway_view *view) { | 365 | void 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) { | |||
401 | void view_update_csd_from_client(struct sway_view *view, bool enabled) { | 403 | void 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, | |||
465 | static void view_init_subsurfaces(struct sway_view *view, | 467 | static void view_init_subsurfaces(struct sway_view *view, |
466 | struct wlr_surface *surface); | 468 | struct wlr_surface *surface); |
467 | 469 | ||
470 | static void view_child_init_subsurfaces(struct sway_view_child *view_child, | ||
471 | struct wlr_surface *surface); | ||
472 | |||
468 | static void view_handle_surface_new_subsurface(struct wl_listener *listener, | 473 | static 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 | ||
640 | static void handle_foreign_fullscreen_request( | 651 | static 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 | ||
667 | static void handle_foreign_close_request( | 691 | static 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 | ||
863 | void view_update_size(struct sway_view *view, int width, int height) { | 885 | void 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)) { | 892 | void 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 | ||
878 | static const struct sway_view_child_impl subsurface_impl; | 902 | static const struct sway_view_child_impl subsurface_impl; |
879 | 903 | ||
880 | static void subsurface_get_root_coords(struct sway_view_child *child, | 904 | static 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 | ||
906 | static void subsurface_destroy(struct sway_view_child *child) { | 919 | static 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 | ||
916 | static const struct sway_view_child_impl subsurface_impl = { | 929 | static 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 | ||
984 | static 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 | |||
971 | static void view_child_damage(struct sway_view_child *child, bool whole) { | 994 | static 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 | ||
982 | static void view_child_handle_surface_commit(struct wl_listener *listener, | 1007 | static 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, | |||
1004 | static void view_init_subsurfaces(struct sway_view *view, | 1029 | static 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 | ||
1042 | static 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 | |||
1012 | static void view_child_handle_surface_map(struct wl_listener *listener, | 1055 | static 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 | ||
1070 | void view_child_destroy(struct sway_view_child *child) { | 1113 | void 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 | */ |
532 | static struct sway_workspace *workspace_output_prev_next_impl( | 530 | static 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 | ||
554 | struct sway_workspace *workspace_output_next( | 545 | |
555 | struct sway_workspace *current, bool create) { | 546 | struct 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 | ||
559 | struct sway_workspace *workspace_output_prev( | 550 | struct 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 | ||
564 | bool workspace_switch(struct sway_workspace *workspace, | 554 | struct 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 | |||
576 | bool 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 | ||
738 | static void set_workspace(struct sway_container *container, void *data) { | 733 | static 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 | ||
742 | static void workspace_attach_tiling(struct sway_workspace *ws, | 737 | static 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, | |||
753 | struct sway_container *workspace_wrap_children(struct sway_workspace *ws) { | 748 | struct 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 | ||
794 | struct sway_container *workspace_add_tiling(struct sway_workspace *workspace, | 789 | struct 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 | ||
812 | void workspace_add_floating(struct sway_workspace *workspace, | 811 | void 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, | |||
825 | void workspace_insert_tiling_direct(struct sway_workspace *workspace, | 824 | void 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 | ||
836 | struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, | 835 | struct 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) { |