summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-06-03 16:35:06 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-06-09 10:08:43 +1000
commit59c94887018bdfa578c4371c4275061ca6e71b3e (patch)
tree62bdaa6ac4777d1fcb292013bddd2043dad7765a
parentMerge pull request #2115 from RedSoxFan/restore-workspaces (diff)
downloadsway-59c94887018bdfa578c4371c4275061ca6e71b3e.tar.gz
sway-59c94887018bdfa578c4371c4275061ca6e71b3e.tar.zst
sway-59c94887018bdfa578c4371c4275061ca6e71b3e.zip
WIP: Atomic layout updates ground work
-rw-r--r--include/sway/desktop/transaction.h56
-rw-r--r--include/sway/output.h2
-rw-r--r--include/sway/tree/arrange.h33
-rw-r--r--include/sway/tree/container.h29
-rw-r--r--include/sway/tree/view.h19
-rw-r--r--sway/desktop/output.c70
-rw-r--r--sway/desktop/transaction.c214
-rw-r--r--sway/desktop/xdg_shell.c29
-rw-r--r--sway/desktop/xdg_shell_v6.c30
-rw-r--r--sway/desktop/xwayland.c33
-rw-r--r--sway/meson.build1
-rw-r--r--sway/tree/arrange.c321
-rw-r--r--sway/tree/container.c11
-rw-r--r--sway/tree/layout.c4
-rw-r--r--sway/tree/view.c98
-rw-r--r--sway/tree/workspace.c6
16 files changed, 690 insertions, 266 deletions
diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h
new file mode 100644
index 00000000..575d28c8
--- /dev/null
+++ b/include/sway/desktop/transaction.h
@@ -0,0 +1,56 @@
1#ifndef _SWAY_TRANSACTION_H
2#define _SWAY_TRANSACTION_H
3#include "sway/tree/container.h"
4
5/**
6 * Transactions enable us to perform atomic layout updates.
7 *
8 * When we want to make adjustments to the layout, we create a transaction.
9 * A transaction contains a list of affected containers and their new state.
10 * A state might contain a new size, or new border settings, or new parent/child
11 * relationships.
12 *
13 * Calling transaction_commit() makes sway notify of all the affected clients
14 * with their new sizes. We then wait for all the views to respond with their
15 * new surface sizes. When all are ready, or when a timeout has passed, we apply
16 * the updates all at the same time.
17 */
18
19struct sway_transaction {
20 struct wl_event_source *timer;
21 list_t *instructions; // struct sway_transaction_instruction *
22 list_t *damage; // struct wlr_box *
23 size_t num_waiting;
24};
25
26/**
27 * Create a new transaction.
28 */
29struct sway_transaction *transaction_create(void);
30
31/**
32 * Add a container's pending state to the transaction.
33 */
34void transaction_add_container(struct sway_transaction *transaction,
35 struct sway_container *container);
36
37/**
38 * Add a box to be damaged when the transaction is applied.
39 * The box should be in layout coordinates.
40 */
41void transaction_add_damage(struct sway_transaction *transaction,
42 struct wlr_box *box);
43
44/**
45 * Submit a transaction to the client views for configuration.
46 */
47void transaction_commit(struct sway_transaction *transaction);
48
49/**
50 * Notify the transaction system that a view is ready for the new layout.
51 *
52 * When all views in the transaction are ready, the layout will be applied.
53 */
54void transaction_notify_view_ready(struct sway_view *view, uint32_t serial);
55
56#endif
diff --git a/include/sway/output.h b/include/sway/output.h
index 70f746dc..e6ca0d02 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -42,6 +42,8 @@ void output_damage_surface(struct sway_output *output, double ox, double oy,
42void output_damage_from_view(struct sway_output *output, 42void output_damage_from_view(struct sway_output *output,
43 struct sway_view *view); 43 struct sway_view *view);
44 44
45void output_damage_box(struct sway_output *output, struct wlr_box *box);
46
45void output_damage_whole_container(struct sway_output *output, 47void output_damage_whole_container(struct sway_output *output,
46 struct sway_container *con); 48 struct sway_container *con);
47 49
diff --git a/include/sway/tree/arrange.h b/include/sway/tree/arrange.h
index ce95cfe9..23cd66dc 100644
--- a/include/sway/tree/arrange.h
+++ b/include/sway/tree/arrange.h
@@ -1,18 +1,33 @@
1#ifndef _SWAY_ARRANGE_H 1#ifndef _SWAY_ARRANGE_H
2#define _SWAY_ARRANGE_H 2#define _SWAY_ARRANGE_H
3#include "sway/desktop/transaction.h"
3 4
4struct sway_container; 5struct sway_container;
5 6
6// Determine the root container's geometry, then iterate to everything below 7/**
7void arrange_root(void); 8 * Arrange layout for all the children of the given container, and add them to
8 9 * the given transaction.
9// Determine the output's geometry, then iterate to everything below 10 *
10void arrange_output(struct sway_container *output); 11 * Use this function if you need to arrange multiple sections of the tree in one
12 * transaction.
13 */
14void arrange_windows(struct sway_container *container,
15 struct sway_transaction *transaction);
11 16
12// Determine the workspace's geometry, then iterate to everything below 17/**
13void arrange_workspace(struct sway_container *workspace); 18 * Arrange layout for the given container and commit the transaction.
19 *
20 * This function is a wrapper around arrange_windows, and handles creating and
21 * committing the transaction for you. Use this function if you're only doing
22 * one arrange operation.
23 */
24void arrange_and_commit(struct sway_container *container);
14 25
15// Arrange layout for all the children of the given workspace/container 26// These functions are temporary and are only here to make everything compile.
16void arrange_children_of(struct sway_container *parent); 27// They are wrappers around arrange_and_commit.
28void arrange_root(void);
29void arrange_output(struct sway_container *container);
30void arrange_workspace(struct sway_container *container);
31void arrange_children_of(struct sway_container *container);
17 32
18#endif 33#endif
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 7ed6aab1..dd5bd47c 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -54,6 +54,28 @@ struct sway_output;
54struct sway_workspace; 54struct sway_workspace;
55struct sway_view; 55struct sway_view;
56 56
57struct sway_container_state {
58 // Container/swayc properties
59 enum sway_container_layout layout;
60 double swayc_x, swayc_y;
61 double swayc_width, swayc_height;
62
63 //struct sway_container *parent;
64 //list_t *children;
65
66 // View properties
67 double view_x, view_y;
68 double view_width, view_height;
69 bool is_fullscreen;
70
71 enum sway_container_border border;
72 int border_thickness;
73 bool border_top;
74 bool border_bottom;
75 bool border_left;
76 bool border_right;
77};
78
57struct sway_container { 79struct sway_container {
58 union { 80 union {
59 // TODO: Encapsulate state for other node types as well like C_CONTAINER 81 // TODO: Encapsulate state for other node types as well like C_CONTAINER
@@ -69,6 +91,8 @@ struct sway_container {
69 */ 91 */
70 size_t id; 92 size_t id;
71 93
94 struct sway_container_state pending;
95
72 char *name; // The view's title (unformatted) 96 char *name; // The view's title (unformatted)
73 char *formatted_title; // The title displayed in the title bar 97 char *formatted_title; // The title displayed in the title bar
74 98
@@ -246,4 +270,9 @@ void container_set_geometry_from_floating_view(struct sway_container *con);
246 */ 270 */
247bool container_is_floating(struct sway_container *container); 271bool container_is_floating(struct sway_container *container);
248 272
273/**
274 * Get a container's box in layout coordinates.
275 */
276struct wlr_box *container_get_box(struct sway_container *container);
277
249#endif 278#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 3df38e2d..f47db567 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -29,8 +29,8 @@ struct sway_view_impl {
29 const char *(*get_string_prop)(struct sway_view *view, 29 const char *(*get_string_prop)(struct sway_view *view,
30 enum sway_view_prop prop); 30 enum sway_view_prop prop);
31 uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop); 31 uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop);
32 void (*configure)(struct sway_view *view, double lx, double ly, int width, 32 uint32_t (*configure)(struct sway_view *view, double lx, double ly,
33 int height); 33 int width, int height);
34 void (*set_activated)(struct sway_view *view, bool activated); 34 void (*set_activated)(struct sway_view *view, bool activated);
35 void (*set_fullscreen)(struct sway_view *view, bool fullscreen); 35 void (*set_fullscreen)(struct sway_view *view, bool fullscreen);
36 bool (*wants_floating)(struct sway_view *view); 36 bool (*wants_floating)(struct sway_view *view);
@@ -70,6 +70,12 @@ struct sway_view {
70 70
71 list_t *executed_criteria; // struct criteria * 71 list_t *executed_criteria; // struct criteria *
72 list_t *marks; // char * 72 list_t *marks; // char *
73 list_t *instructions; // struct sway_transaction_instruction *
74
75 // If saved_texture is set, the main surface of the view will render this
76 // texture instead of its own. This is used while waiting for transactions
77 // to complete.
78 struct wlr_texture *saved_texture;
73 79
74 struct wlr_texture *marks_focused; 80 struct wlr_texture *marks_focused;
75 struct wlr_texture *marks_focused_inactive; 81 struct wlr_texture *marks_focused_inactive;
@@ -103,8 +109,6 @@ struct sway_xdg_shell_v6_view {
103 struct wl_listener map; 109 struct wl_listener map;
104 struct wl_listener unmap; 110 struct wl_listener unmap;
105 struct wl_listener destroy; 111 struct wl_listener destroy;
106
107 int pending_width, pending_height;
108}; 112};
109 113
110struct sway_xdg_shell_view { 114struct sway_xdg_shell_view {
@@ -119,8 +123,6 @@ struct sway_xdg_shell_view {
119 struct wl_listener map; 123 struct wl_listener map;
120 struct wl_listener unmap; 124 struct wl_listener unmap;
121 struct wl_listener destroy; 125 struct wl_listener destroy;
122
123 int pending_width, pending_height;
124}; 126};
125 127
126struct sway_xwayland_view { 128struct sway_xwayland_view {
@@ -138,9 +140,6 @@ struct sway_xwayland_view {
138 struct wl_listener map; 140 struct wl_listener map;
139 struct wl_listener unmap; 141 struct wl_listener unmap;
140 struct wl_listener destroy; 142 struct wl_listener destroy;
141
142 int pending_lx, pending_ly;
143 int pending_width, pending_height;
144}; 143};
145 144
146struct sway_xwayland_unmanaged { 145struct sway_xwayland_unmanaged {
@@ -212,7 +211,7 @@ uint32_t view_get_window_type(struct sway_view *view);
212 211
213const char *view_get_shell(struct sway_view *view); 212const char *view_get_shell(struct sway_view *view);
214 213
215void view_configure(struct sway_view *view, double ox, double oy, int width, 214uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
216 int height); 215 int height);
217 216
218/** 217/**
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 3142bdb4..c5d445a6 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -69,6 +69,7 @@ struct render_data {
69 struct root_geometry root_geo; 69 struct root_geometry root_geo;
70 struct sway_output *output; 70 struct sway_output *output;
71 pixman_region32_t *damage; 71 pixman_region32_t *damage;
72 struct sway_view *view;
72 float alpha; 73 float alpha;
73}; 74};
74 75
@@ -108,6 +109,38 @@ static bool get_surface_box(struct root_geometry *geo,
108 return wlr_box_intersection(&output_box, &rotated_box, &intersection); 109 return wlr_box_intersection(&output_box, &rotated_box, &intersection);
109} 110}
110 111
112static bool get_view_box(struct root_geometry *geo,
113 struct sway_output *output, struct sway_view *view, int sx, int sy,
114 struct wlr_box *surface_box) {
115 int sw = view->width;
116 int sh = view->height;
117
118 double _sx = sx, _sy = sy;
119 rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height,
120 geo->rotation);
121
122 struct wlr_box box = {
123 .x = geo->x + _sx,
124 .y = geo->y + _sy,
125 .width = sw,
126 .height = sh,
127 };
128 if (surface_box != NULL) {
129 memcpy(surface_box, &box, sizeof(struct wlr_box));
130 }
131
132 struct wlr_box rotated_box;
133 wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box);
134
135 struct wlr_box output_box = {
136 .width = output->swayc->width,
137 .height = output->swayc->height,
138 };
139
140 struct wlr_box intersection;
141 return wlr_box_intersection(&output_box, &rotated_box, &intersection);
142}
143
111static void surface_for_each_surface(struct wlr_surface *surface, 144static void surface_for_each_surface(struct wlr_surface *surface,
112 double ox, double oy, struct root_geometry *geo, 145 double ox, double oy, struct root_geometry *geo,
113 wlr_surface_iterator_func_t iterator, void *user_data) { 146 wlr_surface_iterator_func_t iterator, void *user_data) {
@@ -225,13 +258,26 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
225 pixman_region32_t *output_damage = data->damage; 258 pixman_region32_t *output_damage = data->damage;
226 float alpha = data->alpha; 259 float alpha = data->alpha;
227 260
228 if (!wlr_surface_has_buffer(surface)) { 261 struct wlr_texture *texture = NULL;
229 return; 262 struct wlr_box box;
263 bool intersects;
264
265 // If this is the main surface of a view, render the saved_texture instead
266 // if it exists. It exists when we are mid-transaction.
267 if (data->view && data->view->saved_texture &&
268 data->view->surface == surface) {
269 texture = data->view->saved_texture;
270 intersects = get_view_box(&data->root_geo, data->output, data->view,
271 sx, sy, &box);
272 } else {
273 if (!wlr_surface_has_buffer(surface)) {
274 return;
275 }
276 texture = surface->texture;
277 intersects = get_surface_box(&data->root_geo, data->output, surface,
278 sx, sy, &box);
230 } 279 }
231 280
232 struct wlr_box box;
233 bool intersects = get_surface_box(&data->root_geo, data->output, surface,
234 sx, sy, &box);
235 if (!intersects) { 281 if (!intersects) {
236 return; 282 return;
237 } 283 }
@@ -244,8 +290,7 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
244 wlr_matrix_project_box(matrix, &box, transform, rotation, 290 wlr_matrix_project_box(matrix, &box, transform, rotation,
245 wlr_output->transform_matrix); 291 wlr_output->transform_matrix);
246 292
247 render_texture(wlr_output, output_damage, surface->texture, &box, matrix, 293 render_texture(wlr_output, output_damage, texture, &box, matrix, alpha);
248 alpha);
249} 294}
250 295
251static void render_layer(struct sway_output *output, 296static void render_layer(struct sway_output *output,
@@ -315,6 +360,7 @@ static void render_view_surfaces(struct sway_view *view,
315 struct render_data data = { 360 struct render_data data = {
316 .output = output, 361 .output = output,
317 .damage = damage, 362 .damage = damage,
363 .view = view,
318 .alpha = alpha, 364 .alpha = alpha,
319 }; 365 };
320 output_view_for_each_surface( 366 output_view_for_each_surface(
@@ -1134,6 +1180,16 @@ void output_damage_from_view(struct sway_output *output,
1134 output_damage_view(output, view, false); 1180 output_damage_view(output, view, false);
1135} 1181}
1136 1182
1183// Expecting an unscaled box in layout coordinates
1184void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
1185 struct wlr_box box;
1186 memcpy(&box, _box, sizeof(struct wlr_box));
1187 box.x -= output->swayc->x;
1188 box.y -= output->swayc->y;
1189 scale_box(&box, output->wlr_output->scale);
1190 wlr_output_damage_add_box(output->damage, &box);
1191}
1192
1137static void output_damage_whole_container_iterator(struct sway_container *con, 1193static void output_damage_whole_container_iterator(struct sway_container *con,
1138 void *data) { 1194 void *data) {
1139 struct sway_output *output = data; 1195 struct sway_output *output = data;
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
new file mode 100644
index 00000000..69f97e3d
--- /dev/null
+++ b/sway/desktop/transaction.c
@@ -0,0 +1,214 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdbool.h>
3#include <stdlib.h>
4#include <string.h>
5#include <wlr/types/wlr_linux_dmabuf.h>
6#include "sway/debug.h"
7#include "sway/desktop/transaction.h"
8#include "sway/output.h"
9#include "sway/tree/container.h"
10#include "sway/tree/view.h"
11#include "list.h"
12#include "log.h"
13
14/**
15 * How long we should wait for views to respond to the configure before giving
16 * up and applying the transaction anyway.
17 */
18#define TIMEOUT_MS 200
19
20struct sway_transaction_instruction {
21 struct sway_transaction *transaction;
22 struct sway_container *container;
23 struct sway_container_state state;
24 uint32_t serial;
25};
26
27struct sway_transaction *transaction_create() {
28 struct sway_transaction *transaction =
29 calloc(1, sizeof(struct sway_transaction));
30 transaction->instructions = create_list();
31 transaction->damage = create_list();
32 return transaction;
33}
34
35static void transaction_destroy(struct sway_transaction *transaction) {
36 int i;
37 // Free instructions
38 for (i = 0; i < transaction->instructions->length; ++i) {
39 struct sway_transaction_instruction *instruction =
40 transaction->instructions->items[i];
41 if (instruction->container->type == C_VIEW) {
42 struct sway_view *view = instruction->container->sway_view;
43 for (int j = 0; j < view->instructions->length; ++j) {
44 if (view->instructions->items[j] == instruction) {
45 list_del(view->instructions, j);
46 break;
47 }
48 }
49 }
50 free(instruction);
51 }
52 list_free(transaction->instructions);
53
54 // Free damage
55 for (i = 0; i < transaction->damage->length; ++i) {
56 struct wlr_box *box = transaction->damage->items[i];
57 free(box);
58 }
59 list_free(transaction->damage);
60
61 free(transaction);
62}
63
64void transaction_add_container(struct sway_transaction *transaction,
65 struct sway_container *container) {
66 struct sway_transaction_instruction *instruction =
67 calloc(1, sizeof(struct sway_transaction_instruction));
68 instruction->transaction = transaction;
69 instruction->container = container;
70 memcpy(&instruction->state, &container->pending,
71 sizeof(struct sway_container_state));
72 list_add(transaction->instructions, instruction);
73}
74
75void transaction_add_damage(struct sway_transaction *transaction,
76 struct wlr_box *_box) {
77 struct wlr_box *box = calloc(1, sizeof(struct wlr_box));
78 memcpy(box, _box, sizeof(struct wlr_box));
79 list_add(transaction->damage, box);
80}
81
82static void save_view_texture(struct sway_view *view) {
83 wlr_texture_destroy(view->saved_texture);
84 view->saved_texture = NULL;
85
86 // TODO: Copy the texture and store it in view->saved_texture.
87}
88
89static void remove_saved_view_texture(struct sway_view *view) {
90 wlr_texture_destroy(view->saved_texture);
91 view->saved_texture = NULL;
92}
93
94/**
95 * Apply a transaction to the "current" state of the tree.
96 *
97 * This is mostly copying stuff from the pending state into the main swayc
98 * properties, but also includes reparenting and deleting containers.
99 */
100static void transaction_apply(struct sway_transaction *transaction) {
101 int i;
102 for (i = 0; i < transaction->instructions->length; ++i) {
103 struct sway_transaction_instruction *instruction =
104 transaction->instructions->items[i];
105 struct sway_container_state *state = &instruction->state;
106 struct sway_container *container = instruction->container;
107
108 container->layout = state->layout;
109 container->x = state->swayc_x;
110 container->y = state->swayc_y;
111 container->width = state->swayc_width;
112 container->height = state->swayc_height;
113
114 if (container->type == C_VIEW) {
115 struct sway_view *view = container->sway_view;
116 view->x = state->view_x;
117 view->y = state->view_y;
118 view->width = state->view_width;
119 view->height = state->view_height;
120 view->is_fullscreen = state->is_fullscreen;
121 view->border = state->border;
122 view->border_thickness = state->border_thickness;
123 view->border_top = state->border_top;
124 view->border_left = state->border_left;
125 view->border_right = state->border_right;
126 view->border_bottom = state->border_bottom;
127
128 remove_saved_view_texture(view);
129 }
130 }
131
132 // Damage
133 for (i = 0; i < transaction->damage->length; ++i) {
134 struct wlr_box *box = transaction->damage->items[i];
135 for (int j = 0; j < root_container.children->length; ++j) {
136 struct sway_container *output = root_container.children->items[j];
137 output_damage_box(output->sway_output, box);
138 }
139 }
140
141 update_debug_tree();
142}
143
144static int handle_timeout(void *data) {
145 struct sway_transaction *transaction = data;
146 wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting), applying anyway",
147 transaction, transaction->num_waiting);
148 transaction_apply(transaction);
149 transaction_destroy(transaction);
150 return 0;
151}
152
153void transaction_commit(struct sway_transaction *transaction) {
154 wlr_log(L_DEBUG, "Transaction %p committing with %i instructions",
155 transaction, transaction->instructions->length);
156 transaction->num_waiting = 0;
157 for (int i = 0; i < transaction->instructions->length; ++i) {
158 struct sway_transaction_instruction *instruction =
159 transaction->instructions->items[i];
160 if (instruction->container->type == C_VIEW) {
161 struct sway_view *view = instruction->container->sway_view;
162 instruction->serial = view_configure(view,
163 instruction->state.view_x,
164 instruction->state.view_y,
165 instruction->state.view_width,
166 instruction->state.view_height);
167 if (instruction->serial) {
168 save_view_texture(view);
169 list_add(view->instructions, instruction);
170 ++transaction->num_waiting;
171 }
172 }
173 }
174 if (!transaction->num_waiting) {
175 // This can happen if the transaction only contains xwayland views
176 wlr_log(L_DEBUG, "Transaction %p has nothing to wait for, applying",
177 transaction);
178 transaction_apply(transaction);
179 transaction_destroy(transaction);
180 return;
181 }
182
183 // Set up a timer which the views must respond within
184 transaction->timer = wl_event_loop_add_timer(server.wl_event_loop,
185 handle_timeout, transaction);
186 wl_event_source_timer_update(transaction->timer, TIMEOUT_MS);
187}
188
189void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) {
190 // Find the instruction
191 struct sway_transaction_instruction *instruction = NULL;
192 for (int i = 0; i < view->instructions->length; ++i) {
193 struct sway_transaction_instruction *tmp_instruction =
194 view->instructions->items[i];
195 if (tmp_instruction->serial == serial) {
196 instruction = tmp_instruction;
197 list_del(view->instructions, i);
198 break;
199 }
200 }
201 if (!instruction) {
202 // This can happen if the view acknowledges the configure after the
203 // transaction has timed out and applied.
204 return;
205 }
206 // If all views are ready, apply the transaction
207 struct sway_transaction *transaction = instruction->transaction;
208 if (--transaction->num_waiting == 0) {
209 wlr_log(L_DEBUG, "Transaction %p is ready, applying", transaction);
210 wl_event_source_timer_update(transaction->timer, 0);
211 transaction_apply(transaction);
212 transaction_destroy(transaction);
213 }
214}
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index d2b8822c..f43a0a1b 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -5,6 +5,7 @@
5#include <wlr/types/wlr_xdg_shell.h> 5#include <wlr/types/wlr_xdg_shell.h>
6#include <wlr/util/edges.h> 6#include <wlr/util/edges.h>
7#include "log.h" 7#include "log.h"
8#include "sway/desktop/transaction.h"
8#include "sway/input/input-manager.h" 9#include "sway/input/input-manager.h"
9#include "sway/input/seat.h" 10#include "sway/input/seat.h"
10#include "sway/server.h" 11#include "sway/server.h"
@@ -87,18 +88,14 @@ static const char *get_string_prop(struct sway_view *view, enum sway_view_prop p
87 } 88 }
88} 89}
89 90
90static void configure(struct sway_view *view, double lx, double ly, int width, 91static uint32_t configure(struct sway_view *view, double lx, double ly,
91 int height) { 92 int width, int height) {
92 struct sway_xdg_shell_view *xdg_shell_view = 93 struct sway_xdg_shell_view *xdg_shell_view =
93 xdg_shell_view_from_view(view); 94 xdg_shell_view_from_view(view);
94 if (xdg_shell_view == NULL) { 95 if (xdg_shell_view == NULL) {
95 return; 96 return 0;
96 } 97 }
97 98 return wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
98 xdg_shell_view->pending_width = width;
99 xdg_shell_view->pending_height = height;
100 wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
101 view_update_position(view, lx, ly);
102} 99}
103 100
104static void set_activated(struct sway_view *view, bool activated) { 101static void set_activated(struct sway_view *view, bool activated) {
@@ -174,18 +171,12 @@ static void handle_commit(struct wl_listener *listener, void *data) {
174 struct sway_xdg_shell_view *xdg_shell_view = 171 struct sway_xdg_shell_view *xdg_shell_view =
175 wl_container_of(listener, xdg_shell_view, commit); 172 wl_container_of(listener, xdg_shell_view, commit);
176 struct sway_view *view = &xdg_shell_view->view; 173 struct sway_view *view = &xdg_shell_view->view;
177 if (view->swayc && container_is_floating(view->swayc)) { 174 struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
178 int width = view->wlr_xdg_surface->geometry.width; 175
179 int height = view->wlr_xdg_surface->geometry.height; 176 if (view->instructions->length) {
180 if (!width && !height) { 177 transaction_notify_view_ready(view, xdg_surface->configure_serial);
181 width = view->wlr_xdg_surface->surface->current->width;
182 height = view->wlr_xdg_surface->surface->current->height;
183 }
184 view_update_size(view, width, height);
185 } else {
186 view_update_size(view, xdg_shell_view->pending_width,
187 xdg_shell_view->pending_height);
188 } 178 }
179
189 view_update_title(view, false); 180 view_update_title(view, false);
190 view_damage_from(view); 181 view_damage_from(view);
191} 182}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 6ffe334a..bce59174 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -3,6 +3,7 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <wayland-server.h> 4#include <wayland-server.h>
5#include <wlr/types/wlr_xdg_shell_v6.h> 5#include <wlr/types/wlr_xdg_shell_v6.h>
6#include "sway/desktop/transaction.h"
6#include "sway/tree/container.h" 7#include "sway/tree/container.h"
7#include "sway/tree/layout.h" 8#include "sway/tree/layout.h"
8#include "sway/server.h" 9#include "sway/server.h"
@@ -86,18 +87,15 @@ static const char *get_string_prop(struct sway_view *view, enum sway_view_prop p
86 } 87 }
87} 88}
88 89
89static void configure(struct sway_view *view, double lx, double ly, int width, 90static uint32_t configure(struct sway_view *view, double lx, double ly,
90 int height) { 91 int width, int height) {
91 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 92 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
92 xdg_shell_v6_view_from_view(view); 93 xdg_shell_v6_view_from_view(view);
93 if (xdg_shell_v6_view == NULL) { 94 if (xdg_shell_v6_view == NULL) {
94 return; 95 return 0;
95 } 96 }
96 97 return wlr_xdg_toplevel_v6_set_size(
97 xdg_shell_v6_view->pending_width = width; 98 view->wlr_xdg_surface_v6, width, height);
98 xdg_shell_v6_view->pending_height = height;
99 wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height);
100 view_update_position(view, lx, ly);
101} 99}
102 100
103static void set_activated(struct sway_view *view, bool activated) { 101static void set_activated(struct sway_view *view, bool activated) {
@@ -173,18 +171,12 @@ static void handle_commit(struct wl_listener *listener, void *data) {
173 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 171 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
174 wl_container_of(listener, xdg_shell_v6_view, commit); 172 wl_container_of(listener, xdg_shell_v6_view, commit);
175 struct sway_view *view = &xdg_shell_v6_view->view; 173 struct sway_view *view = &xdg_shell_v6_view->view;
176 if (view->swayc && container_is_floating(view->swayc)) { 174 struct wlr_xdg_surface_v6 *xdg_surface_v6 = view->wlr_xdg_surface_v6;
177 int width = view->wlr_xdg_surface_v6->geometry.width; 175
178 int height = view->wlr_xdg_surface_v6->geometry.height; 176 if (view->instructions->length) {
179 if (!width && !height) { 177 transaction_notify_view_ready(view, xdg_surface_v6->configure_serial);
180 width = view->wlr_xdg_surface_v6->surface->current->width;
181 height = view->wlr_xdg_surface_v6->surface->current->height;
182 }
183 view_update_size(view, width, height);
184 } else {
185 view_update_size(view, xdg_shell_v6_view->pending_width,
186 xdg_shell_v6_view->pending_height);
187 } 178 }
179
188 view_update_title(view, false); 180 view_update_title(view, false);
189 view_damage_from(view); 181 view_damage_from(view);
190} 182}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 6447b711..6a3c1b66 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -167,19 +167,18 @@ static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) {
167 } 167 }
168} 168}
169 169
170static void configure(struct sway_view *view, double lx, double ly, int width, 170static uint32_t configure(struct sway_view *view, double lx, double ly, int width,
171 int height) { 171 int height) {
172 struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); 172 struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
173 if (xwayland_view == NULL) { 173 if (xwayland_view == NULL) {
174 return; 174 return 0;
175 } 175 }
176 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; 176 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
177 177
178 xwayland_view->pending_lx = lx;
179 xwayland_view->pending_ly = ly;
180 xwayland_view->pending_width = width;
181 xwayland_view->pending_height = height;
182 wlr_xwayland_surface_configure(xsurface, lx, ly, width, height); 178 wlr_xwayland_surface_configure(xsurface, lx, ly, width, height);
179
180 // xwayland doesn't give us a serial for the configure
181 return 0;
183} 182}
184 183
185static void set_activated(struct sway_view *view, bool activated) { 184static void set_activated(struct sway_view *view, bool activated) {
@@ -250,15 +249,21 @@ static void handle_commit(struct wl_listener *listener, void *data) {
250 wl_container_of(listener, xwayland_view, commit); 249 wl_container_of(listener, xwayland_view, commit);
251 struct sway_view *view = &xwayland_view->view; 250 struct sway_view *view = &xwayland_view->view;
252 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; 251 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
253 if (view->swayc && container_is_floating(view->swayc)) { 252
254 view_update_size(view, xsurface->width, xsurface->height); 253 // Don't allow xwayland views to do resize or reposition themselves if
255 } else { 254 // they're involved in a transaction. Once the transaction has finished
256 view_update_size(view, xwayland_view->pending_width, 255 // they'll apply the next time a commit happens.
257 xwayland_view->pending_height); 256 if (view->instructions->length) {
257 if (view->swayc && container_is_floating(view->swayc)) {
258 view_update_size(view, xsurface->width, xsurface->height);
259 } else {
260 view_update_size(view, view->swayc->pending.swayc_width,
261 view->swayc->pending.swayc_height);
262 }
263 view_update_position(view,
264 view->swayc->pending.view_x, view->swayc->pending.view_y);
265 view_damage_from(view);
258 } 266 }
259 view_update_position(view,
260 xwayland_view->pending_lx, xwayland_view->pending_ly);
261 view_damage_from(view);
262} 267}
263 268
264static void handle_unmap(struct wl_listener *listener, void *data) { 269static void handle_unmap(struct wl_listener *listener, void *data) {
diff --git a/sway/meson.build b/sway/meson.build
index b6bb02a7..5ff62490 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -12,6 +12,7 @@ sway_sources = files(
12 'desktop/desktop.c', 12 'desktop/desktop.c',
13 'desktop/layer_shell.c', 13 'desktop/layer_shell.c',
14 'desktop/output.c', 14 'desktop/output.c',
15 'desktop/transaction.c',
15 'desktop/xdg_shell_v6.c', 16 'desktop/xdg_shell_v6.c',
16 'desktop/xdg_shell.c', 17 'desktop/xdg_shell.c',
17 'desktop/xwayland.c', 18 'desktop/xwayland.c',
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 721b557e..d8b3aec1 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -5,7 +5,6 @@
5#include <string.h> 5#include <string.h>
6#include <wlr/types/wlr_output.h> 6#include <wlr/types/wlr_output.h>
7#include <wlr/types/wlr_output_layout.h> 7#include <wlr/types/wlr_output_layout.h>
8#include "sway/debug.h"
9#include "sway/tree/arrange.h" 8#include "sway/tree/arrange.h"
10#include "sway/tree/container.h" 9#include "sway/tree/container.h"
11#include "sway/tree/layout.h" 10#include "sway/tree/layout.h"
@@ -17,116 +16,56 @@
17 16
18struct sway_container root_container; 17struct sway_container root_container;
19 18
20void arrange_root() {
21 if (config->reloading) {
22 return;
23 }
24 struct wlr_output_layout *output_layout =
25 root_container.sway_root->output_layout;
26 const struct wlr_box *layout_box =
27 wlr_output_layout_get_box(output_layout, NULL);
28 root_container.x = layout_box->x;
29 root_container.y = layout_box->y;
30 root_container.width = layout_box->width;
31 root_container.height = layout_box->height;
32 for (int i = 0; i < root_container.children->length; ++i) {
33 struct sway_container *output = root_container.children->items[i];
34 arrange_output(output);
35 }
36}
37
38void arrange_output(struct sway_container *output) {
39 if (config->reloading) {
40 return;
41 }
42 if (!sway_assert(output->type == C_OUTPUT,
43 "called arrange_output() on non-output container")) {
44 return;
45 }
46 const struct wlr_box *output_box = wlr_output_layout_get_box(
47 root_container.sway_root->output_layout,
48 output->sway_output->wlr_output);
49 output->x = output_box->x;
50 output->y = output_box->y;
51 output->width = output_box->width;
52 output->height = output_box->height;
53 wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f",
54 output->name, output->x, output->y);
55 for (int i = 0; i < output->children->length; ++i) {
56 struct sway_container *workspace = output->children->items[i];
57 arrange_workspace(workspace);
58 }
59 container_damage_whole(output);
60}
61
62void arrange_workspace(struct sway_container *workspace) {
63 if (config->reloading) {
64 return;
65 }
66 if (!sway_assert(workspace->type == C_WORKSPACE,
67 "called arrange_workspace() on non-workspace container")) {
68 return;
69 }
70 struct sway_container *output = workspace->parent;
71 struct wlr_box *area = &output->sway_output->usable_area;
72 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
73 area->width, area->height, area->x, area->y);
74 workspace->width = area->width;
75 workspace->height = area->height;
76 workspace->x = output->x + area->x;
77 workspace->y = output->y + area->y;
78 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
79 workspace->name, workspace->x, workspace->y);
80 arrange_children_of(workspace);
81 container_damage_whole(workspace);
82}
83
84static void apply_horiz_layout(struct sway_container *parent) { 19static void apply_horiz_layout(struct sway_container *parent) {
85 size_t num_children = parent->children->length; 20 size_t num_children = parent->children->length;
86 if (!num_children) { 21 if (!num_children) {
87 return; 22 return;
88 } 23 }
89 size_t parent_offset = 0; 24 size_t parent_offset = 0;
90 if (parent->parent->layout == L_TABBED) { 25 if (parent->parent->pending.layout == L_TABBED) {
91 parent_offset = container_titlebar_height(); 26 parent_offset = container_titlebar_height();
92 } else if (parent->parent->layout == L_STACKED) { 27 } else if (parent->parent->pending.layout == L_STACKED) {
93 parent_offset = 28 parent_offset = container_titlebar_height() *
94 container_titlebar_height() * parent->parent->children->length; 29 parent->parent->children->length;
95 } 30 }
96 size_t parent_height = parent->height - parent_offset; 31 size_t parent_height = parent->pending.swayc_height - parent_offset;
97 32
98 // Calculate total width of children 33 // Calculate total width of children
99 double total_width = 0; 34 double total_width = 0;
100 for (size_t i = 0; i < num_children; ++i) { 35 for (size_t i = 0; i < num_children; ++i) {
101 struct sway_container *child = parent->children->items[i]; 36 struct sway_container *child = parent->children->items[i];
102 if (child->width <= 0) { 37 if (child->pending.swayc_width <= 0) {
103 if (num_children > 1) { 38 if (num_children > 1) {
104 child->width = parent->width / (num_children - 1); 39 child->pending.swayc_width =
40 parent->pending.swayc_width / (num_children - 1);
105 } else { 41 } else {
106 child->width = parent->width; 42 child->pending.swayc_width = parent->pending.swayc_width;
107 } 43 }
108 } 44 }
109 total_width += child->width; 45 total_width += child->pending.swayc_width;
110 } 46 }
111 double scale = parent->width / total_width; 47 double scale = parent->pending.swayc_width / total_width;
112 48
113 // Resize windows 49 // Resize windows
114 wlr_log(L_DEBUG, "Arranging %p horizontally", parent); 50 wlr_log(L_DEBUG, "Arranging %p horizontally", parent);
115 double child_x = parent->x; 51 double child_x = parent->pending.swayc_x;
116 struct sway_container *child;
117 for (size_t i = 0; i < num_children; ++i) { 52 for (size_t i = 0; i < num_children; ++i) {
118 child = parent->children->items[i]; 53 struct sway_container *child = parent->children->items[i];
119 wlr_log(L_DEBUG, 54 wlr_log(L_DEBUG,
120 "Calculating arrangement for %p:%d (will scale %f by %f)", 55 "Calculating arrangement for %p:%d (will scale %f by %f)",
121 child, child->type, child->width, scale); 56 child, child->type, child->pending.swayc_width, scale);
122 child->x = child_x; 57 child->pending.swayc_x = child_x;
123 child->y = parent->y + parent_offset; 58 child->pending.swayc_y = parent->pending.swayc_y + parent_offset;
124 child->width = floor(child->width * scale); 59 child->pending.swayc_width = floor(child->pending.swayc_width * scale);
125 child->height = parent_height; 60 child->pending.swayc_height = parent_height;
126 child_x += child->width; 61 child_x += child->pending.swayc_width;
62
63 // Make last child use remaining width of parent
64 if (i == num_children - 1) {
65 child->pending.swayc_width = parent->pending.swayc_x +
66 parent->pending.swayc_width - child->pending.swayc_x;
67 }
127 } 68 }
128 // Make last child use remaining width of parent
129 child->width = parent->x + parent->width - child->x;
130} 69}
131 70
132static void apply_vert_layout(struct sway_container *parent) { 71static void apply_vert_layout(struct sway_container *parent) {
@@ -135,46 +74,51 @@ static void apply_vert_layout(struct sway_container *parent) {
135 return; 74 return;
136 } 75 }
137 size_t parent_offset = 0; 76 size_t parent_offset = 0;
138 if (parent->parent->layout == L_TABBED) { 77 if (parent->parent->pending.layout == L_TABBED) {
139 parent_offset = container_titlebar_height(); 78 parent_offset = container_titlebar_height();
140 } else if (parent->parent->layout == L_STACKED) { 79 } else if (parent->parent->pending.layout == L_STACKED) {
141 parent_offset = 80 parent_offset =
142 container_titlebar_height() * parent->parent->children->length; 81 container_titlebar_height() * parent->parent->children->length;
143 } 82 }
144 size_t parent_height = parent->height - parent_offset; 83 size_t parent_height = parent->pending.swayc_height - parent_offset;
145 84
146 // Calculate total height of children 85 // Calculate total height of children
147 double total_height = 0; 86 double total_height = 0;
148 for (size_t i = 0; i < num_children; ++i) { 87 for (size_t i = 0; i < num_children; ++i) {
149 struct sway_container *child = parent->children->items[i]; 88 struct sway_container *child = parent->children->items[i];
150 if (child->height <= 0) { 89 if (child->pending.swayc_height <= 0) {
151 if (num_children > 1) { 90 if (num_children > 1) {
152 child->height = parent_height / (num_children - 1); 91 child->pending.swayc_height =
92 parent_height / (num_children - 1);
153 } else { 93 } else {
154 child->height = parent_height; 94 child->pending.swayc_height = parent_height;
155 } 95 }
156 } 96 }
157 total_height += child->height; 97 total_height += child->pending.swayc_height;
158 } 98 }
159 double scale = parent_height / total_height; 99 double scale = parent_height / total_height;
160 100
161 // Resize 101 // Resize
162 wlr_log(L_DEBUG, "Arranging %p vertically", parent); 102 wlr_log(L_DEBUG, "Arranging %p vertically", parent);
163 double child_y = parent->y + parent_offset; 103 double child_y = parent->pending.swayc_y + parent_offset;
164 struct sway_container *child;
165 for (size_t i = 0; i < num_children; ++i) { 104 for (size_t i = 0; i < num_children; ++i) {
166 child = parent->children->items[i]; 105 struct sway_container *child = parent->children->items[i];
167 wlr_log(L_DEBUG, 106 wlr_log(L_DEBUG,
168 "Calculating arrangement for %p:%d (will scale %f by %f)", 107 "Calculating arrangement for %p:%d (will scale %f by %f)",
169 child, child->type, child->height, scale); 108 child, child->type, child->pending.swayc_height, scale);
170 child->x = parent->x; 109 child->pending.swayc_x = parent->pending.swayc_x;
171 child->y = child_y; 110 child->pending.swayc_y = child_y;
172 child->width = parent->width; 111 child->pending.swayc_width = parent->pending.swayc_width;
173 child->height = floor(child->height * scale); 112 child->pending.swayc_height =
174 child_y += child->height; 113 floor(child->pending.swayc_height * scale);
114 child_y += child->pending.swayc_height;
115
116 // Make last child use remaining height of parent
117 if (i == num_children - 1) {
118 child->pending.swayc_height = parent->pending.swayc_y +
119 parent_offset + parent_height - child->pending.swayc_y;
120 }
175 } 121 }
176 // Make last child use remaining height of parent
177 child->height = parent->y + parent_offset + parent_height - child->y;
178} 122}
179 123
180static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { 124static void apply_tabbed_or_stacked_layout(struct sway_container *parent) {
@@ -182,46 +126,33 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) {
182 return; 126 return;
183 } 127 }
184 size_t parent_offset = 0; 128 size_t parent_offset = 0;
185 if (parent->parent->layout == L_TABBED) { 129 if (parent->parent->pending.layout == L_TABBED) {
186 parent_offset = container_titlebar_height(); 130 parent_offset = container_titlebar_height();
187 } else if (parent->parent->layout == L_STACKED) { 131 } else if (parent->parent->pending.layout == L_STACKED) {
188 parent_offset = 132 parent_offset =
189 container_titlebar_height() * parent->parent->children->length; 133 container_titlebar_height() * parent->parent->children->length;
190 } 134 }
191 size_t parent_height = parent->height - parent_offset; 135 size_t parent_height = parent->pending.swayc_height - parent_offset;
192 for (int i = 0; i < parent->children->length; ++i) { 136 for (int i = 0; i < parent->children->length; ++i) {
193 struct sway_container *child = parent->children->items[i]; 137 struct sway_container *child = parent->children->items[i];
194 child->x = parent->x; 138 child->pending.swayc_x = parent->pending.swayc_x;
195 child->y = parent->y + parent_offset; 139 child->pending.swayc_y = parent->pending.swayc_y + parent_offset;
196 child->width = parent->width; 140 child->pending.swayc_width = parent->pending.swayc_width;
197 child->height = parent_height; 141 child->pending.swayc_height = parent_height;
198 } 142 }
199} 143}
200 144
201void arrange_children_of(struct sway_container *parent) { 145static void _arrange_children_of(struct sway_container *parent,
146 struct sway_transaction *transaction) {
202 if (config->reloading) { 147 if (config->reloading) {
203 return; 148 return;
204 } 149 }
205 if (!sway_assert(parent->type == C_WORKSPACE || parent->type == C_CONTAINER,
206 "container is a %s", container_type_to_str(parent->type))) {
207 return;
208 }
209
210 struct sway_container *workspace = parent;
211 if (workspace->type != C_WORKSPACE) {
212 workspace = container_parent(workspace, C_WORKSPACE);
213 }
214 if (workspace->sway_workspace->fullscreen) {
215 // Just arrange the fullscreen view and jump out
216 view_autoconfigure(workspace->sway_workspace->fullscreen);
217 return;
218 }
219
220 wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, 150 wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent,
221 parent->name, parent->width, parent->height, parent->x, parent->y); 151 parent->name, parent->pending.swayc_width, parent->pending.swayc_height,
152 parent->pending.swayc_x, parent->pending.swayc_y);
222 153
223 // Calculate x, y, width and height of children 154 // Calculate x, y, width and height of children
224 switch (parent->layout) { 155 switch (parent->pending.layout) {
225 case L_HORIZ: 156 case L_HORIZ:
226 apply_horiz_layout(parent); 157 apply_horiz_layout(parent);
227 break; 158 break;
@@ -232,33 +163,135 @@ void arrange_children_of(struct sway_container *parent) {
232 case L_STACKED: 163 case L_STACKED:
233 apply_tabbed_or_stacked_layout(parent); 164 apply_tabbed_or_stacked_layout(parent);
234 break; 165 break;
235 default: 166 case L_NONE:
236 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
237 apply_horiz_layout(parent); 167 apply_horiz_layout(parent);
238 break; 168 break;
169 case L_FLOATING:
170 sway_assert(false, "Didn't expect to see floating here");
239 } 171 }
240 172
241 // Apply x, y, width and height to children and recurse if needed 173 // Recurse into child containers
242 for (int i = 0; i < parent->children->length; ++i) { 174 for (int i = 0; i < parent->children->length; ++i) {
243 struct sway_container *child = parent->children->items[i]; 175 struct sway_container *child = parent->children->items[i];
244 if (child->type == C_VIEW) { 176 if (child->type == C_VIEW) {
245 view_autoconfigure(child->sway_view); 177 view_autoconfigure(child->sway_view);
246 } else { 178 } else {
247 arrange_children_of(child); 179 _arrange_children_of(child, transaction);
248 } 180 }
181 transaction_add_container(transaction, child);
249 } 182 }
183}
250 184
251 // If container is a workspace, process floating containers too 185static void _arrange_workspace(struct sway_container *workspace,
252 if (parent->type == C_WORKSPACE) { 186 struct sway_transaction *transaction) {
253 struct sway_workspace *ws = workspace->sway_workspace; 187 if (config->reloading) {
254 for (int i = 0; i < ws->floating->children->length; ++i) { 188 return;
255 struct sway_container *child = ws->floating->children->items[i]; 189 }
256 if (child->type != C_VIEW) { 190 struct sway_container *output = workspace->parent;
257 arrange_children_of(child); 191 struct wlr_box *area = &output->sway_output->usable_area;
258 } 192 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
259 } 193 area->width, area->height, area->x, area->y);
194 workspace->pending.swayc_width = area->width;
195 workspace->pending.swayc_height = area->height;
196 workspace->pending.swayc_x = output->x + area->x;
197 workspace->pending.swayc_y = output->y + area->y;
198 transaction_add_container(transaction, workspace);
199 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
200 workspace->pending.swayc_x, workspace->pending.swayc_y);
201 _arrange_children_of(workspace, transaction);
202}
203
204static void _arrange_output(struct sway_container *output,
205 struct sway_transaction *transaction) {
206 if (config->reloading) {
207 return;
208 }
209 const struct wlr_box *output_box = wlr_output_layout_get_box(
210 root_container.sway_root->output_layout,
211 output->sway_output->wlr_output);
212 output->x = output_box->x;
213 output->y = output_box->y;
214 output->width = output_box->width;
215 output->height = output_box->height;
216 output->pending.swayc_x = output_box->x;
217 output->pending.swayc_y = output_box->y;
218 output->pending.swayc_width = output_box->width;
219 output->pending.swayc_height = output_box->height;
220 transaction_add_container(transaction, output);
221 wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f",
222 output->name, output->pending.swayc_x, output->pending.swayc_y);
223 for (int i = 0; i < output->children->length; ++i) {
224 struct sway_container *workspace = output->children->items[i];
225 _arrange_workspace(workspace, transaction);
226 }
227}
228
229static void _arrange_root(struct sway_transaction *transaction) {
230 if (config->reloading) {
231 return;
260 } 232 }
233 struct wlr_output_layout *output_layout =
234 root_container.sway_root->output_layout;
235 const struct wlr_box *layout_box =
236 wlr_output_layout_get_box(output_layout, NULL);
237 root_container.x = layout_box->x;
238 root_container.y = layout_box->y;
239 root_container.width = layout_box->width;
240 root_container.height = layout_box->height;
241 root_container.pending.swayc_x = layout_box->x;
242 root_container.pending.swayc_y = layout_box->y;
243 root_container.pending.swayc_width = layout_box->width;
244 root_container.pending.swayc_height = layout_box->height;
245 transaction_add_container(transaction, &root_container);
246 for (int i = 0; i < root_container.children->length; ++i) {
247 struct sway_container *output = root_container.children->items[i];
248 _arrange_output(output, transaction);
249 }
250}
251
252void arrange_windows(struct sway_container *container,
253 struct sway_transaction *transaction) {
254 switch (container->type) {
255 case C_ROOT:
256 _arrange_root(transaction);
257 break;
258 case C_OUTPUT:
259 _arrange_output(container, transaction);
260 break;
261 case C_WORKSPACE:
262 _arrange_workspace(container, transaction);
263 break;
264 case C_CONTAINER:
265 _arrange_children_of(container, transaction);
266 transaction_add_container(transaction, container);
267 break;
268 case C_VIEW:
269 break;
270 case C_TYPES:
271 break;
272 }
273 transaction_add_damage(transaction, container_get_box(container));
274}
275
276void arrange_and_commit(struct sway_container *container) {
277 struct sway_transaction *transaction = transaction_create();
278 arrange_windows(container, transaction);
279 transaction_commit(transaction);
280}
281
282// These functions are only temporary
283void arrange_root() {
284 arrange_and_commit(&root_container);
285}
286
287void arrange_output(struct sway_container *container) {
288 arrange_and_commit(container);
289}
290
291void arrange_workspace(struct sway_container *container) {
292 arrange_and_commit(container);
293}
261 294
262 container_damage_whole(parent); 295void arrange_children_of(struct sway_container *container) {
263 update_debug_tree(); 296 arrange_and_commit(container);
264} 297}
diff --git a/sway/tree/container.c b/sway/tree/container.c
index cd2c083c..e6956f5c 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -116,6 +116,7 @@ struct sway_container *container_create(enum sway_container_type type) {
116 116
117 if (type != C_VIEW) { 117 if (type != C_VIEW) {
118 c->children = create_list(); 118 c->children = create_list();
119 //c->pending.children = create_list();
119 } 120 }
120 121
121 wl_signal_init(&c->events.destroy); 122 wl_signal_init(&c->events.destroy);
@@ -162,6 +163,7 @@ static void _container_destroy(struct sway_container *cont) {
162 wlr_texture_destroy(cont->title_urgent); 163 wlr_texture_destroy(cont->title_urgent);
163 164
164 list_free(cont->children); 165 list_free(cont->children);
166 //list_free(cont->pending.children);
165 cont->children = NULL; 167 cont->children = NULL;
166 free(cont); 168 free(cont);
167} 169}
@@ -971,3 +973,12 @@ bool container_is_floating(struct sway_container *container) {
971 } 973 }
972 return container->parent == workspace->sway_workspace->floating; 974 return container->parent == workspace->sway_workspace->floating;
973} 975}
976
977struct wlr_box *container_get_box(struct sway_container *container) {
978 struct wlr_box *box = calloc(1, sizeof(struct wlr_box));
979 box->x = container->x;
980 box->y = container->y;
981 box->width = container->width;
982 box->height = container->height;
983 return box;
984}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 6d4cd088..3bba049a 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -915,10 +915,10 @@ void container_recursive_resize(struct sway_container *container,
915 bool layout_match = true; 915 bool layout_match = true;
916 wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); 916 wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount);
917 if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { 917 if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) {
918 container->width += amount; 918 container->pending.swayc_width += amount;
919 layout_match = container->layout == L_HORIZ; 919 layout_match = container->layout == L_HORIZ;
920 } else if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) { 920 } else if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) {
921 container->height += amount; 921 container->pending.swayc_height += amount;
922 layout_match = container->layout == L_VERT; 922 layout_match = container->layout == L_VERT;
923 } 923 }
924 if (container->children) { 924 if (container->children) {
diff --git a/sway/tree/view.c b/sway/tree/view.c
index c9c82405..40fe2740 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -25,6 +25,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,
25 view->impl = impl; 25 view->impl = impl;
26 view->executed_criteria = create_list(); 26 view->executed_criteria = create_list();
27 view->marks = create_list(); 27 view->marks = create_list();
28 view->instructions = create_list();
28 wl_signal_init(&view->events.unmap); 29 wl_signal_init(&view->events.unmap);
29} 30}
30 31
@@ -37,6 +38,11 @@ void view_destroy(struct sway_view *view) {
37 view_unmap(view); 38 view_unmap(view);
38 } 39 }
39 40
41 if (!sway_assert(view->instructions->length == 0,
42 "Tried to destroy view with pending instructions")) {
43 return;
44 }
45
40 list_free(view->executed_criteria); 46 list_free(view->executed_criteria);
41 47
42 for (int i = 0; i < view->marks->length; ++i) { 48 for (int i = 0; i < view->marks->length; ++i) {
@@ -44,6 +50,8 @@ void view_destroy(struct sway_view *view) {
44 } 50 }
45 list_free(view->marks); 51 list_free(view->marks);
46 52
53 list_free(view->instructions);
54
47 wlr_texture_destroy(view->marks_focused); 55 wlr_texture_destroy(view->marks_focused);
48 wlr_texture_destroy(view->marks_focused_inactive); 56 wlr_texture_destroy(view->marks_focused_inactive);
49 wlr_texture_destroy(view->marks_unfocused); 57 wlr_texture_destroy(view->marks_unfocused);
@@ -119,11 +127,12 @@ const char *view_get_shell(struct sway_view *view) {
119 return "unknown"; 127 return "unknown";
120} 128}
121 129
122void view_configure(struct sway_view *view, double lx, double ly, int width, 130uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
123 int height) { 131 int height) {
124 if (view->impl->configure) { 132 if (view->impl->configure) {
125 view->impl->configure(view, lx, ly, width, height); 133 return view->impl->configure(view, lx, ly, width, height);
126 } 134 }
135 return 0;
127} 136}
128 137
129static void view_autoconfigure_floating(struct sway_view *view) { 138static void view_autoconfigure_floating(struct sway_view *view) {
@@ -178,21 +187,23 @@ void view_autoconfigure(struct sway_view *view) {
178 } 187 }
179 } 188 }
180 189
181 view->border_top = view->border_bottom = true; 190 struct sway_container_state *state = &view->swayc->pending;
182 view->border_left = view->border_right = true; 191
192 state->border_top = state->border_bottom = true;
193 state->border_left = state->border_right = true;
183 if (config->hide_edge_borders == E_BOTH 194 if (config->hide_edge_borders == E_BOTH
184 || config->hide_edge_borders == E_VERTICAL 195 || config->hide_edge_borders == E_VERTICAL
185 || (config->hide_edge_borders == E_SMART && !other_views)) { 196 || (config->hide_edge_borders == E_SMART && !other_views)) {
186 view->border_left = view->swayc->x != ws->x; 197 state->border_left = state->swayc_x != ws->x;
187 int right_x = view->swayc->x + view->swayc->width; 198 int right_x = state->swayc_x + state->swayc_width;
188 view->border_right = right_x != ws->x + ws->width; 199 state->border_right = right_x != ws->x + ws->width;
189 } 200 }
190 if (config->hide_edge_borders == E_BOTH 201 if (config->hide_edge_borders == E_BOTH
191 || config->hide_edge_borders == E_HORIZONTAL 202 || config->hide_edge_borders == E_HORIZONTAL
192 || (config->hide_edge_borders == E_SMART && !other_views)) { 203 || (config->hide_edge_borders == E_SMART && !other_views)) {
193 view->border_top = view->swayc->y != ws->y; 204 state->border_top = state->swayc_y != ws->y;
194 int bottom_y = view->swayc->y + view->swayc->height; 205 int bottom_y = state->swayc_y + state->swayc_height;
195 view->border_bottom = bottom_y != ws->y + ws->height; 206 state->border_bottom = bottom_y != ws->y + ws->height;
196 } 207 }
197 208
198 double x, y, width, height; 209 double x, y, width, height;
@@ -202,53 +213,54 @@ void view_autoconfigure(struct sway_view *view) {
202 // In a tabbed or stacked container, the swayc's y is the top of the title 213 // In a tabbed or stacked container, the swayc's y is the top of the title
203 // area. We have to offset the surface y by the height of the title bar, and 214 // area. We have to offset the surface y by the height of the title bar, and
204 // disable any top border because we'll always have the title bar. 215 // disable any top border because we'll always have the title bar.
205 if (view->swayc->parent->layout == L_TABBED) { 216 if (view->swayc->parent->pending.layout == L_TABBED) {
206 y_offset = container_titlebar_height(); 217 y_offset = container_titlebar_height();
207 view->border_top = false; 218 state->border_top = false;
208 } else if (view->swayc->parent->layout == L_STACKED) { 219 } else if (view->swayc->parent->pending.layout == L_STACKED) {
209 y_offset = container_titlebar_height() 220 y_offset = container_titlebar_height()
210 * view->swayc->parent->children->length; 221 * view->swayc->parent->children->length;
211 view->border_top = false; 222 view->border_top = false;
212 } 223 }
213 224
214 switch (view->border) { 225 switch (state->border) {
215 case B_NONE: 226 case B_NONE:
216 x = view->swayc->x; 227 x = state->swayc_x;
217 y = view->swayc->y + y_offset; 228 y = state->swayc_y + y_offset;
218 width = view->swayc->width; 229 width = state->swayc_width;
219 height = view->swayc->height - y_offset; 230 height = state->swayc_height - y_offset;
220 break; 231 break;
221 case B_PIXEL: 232 case B_PIXEL:
222 x = view->swayc->x + view->border_thickness * view->border_left; 233 x = state->swayc_x + state->border_thickness * state->border_left;
223 y = view->swayc->y + view->border_thickness * view->border_top + y_offset; 234 y = state->swayc_y + state->border_thickness * state->border_top + y_offset;
224 width = view->swayc->width 235 width = state->swayc_width
225 - view->border_thickness * view->border_left 236 - state->border_thickness * state->border_left
226 - view->border_thickness * view->border_right; 237 - state->border_thickness * state->border_right;
227 height = view->swayc->height - y_offset 238 height = state->swayc_height - y_offset
228 - view->border_thickness * view->border_top 239 - state->border_thickness * state->border_top
229 - view->border_thickness * view->border_bottom; 240 - state->border_thickness * state->border_bottom;
230 break; 241 break;
231 case B_NORMAL: 242 case B_NORMAL:
232 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border 243 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border
233 x = view->swayc->x + view->border_thickness * view->border_left; 244 x = state->swayc_x + state->border_thickness * state->border_left;
234 width = view->swayc->width 245 width = state->swayc_width
235 - view->border_thickness * view->border_left 246 - state->border_thickness * state->border_left
236 - view->border_thickness * view->border_right; 247 - state->border_thickness * state->border_right;
237 if (y_offset) { 248 if (y_offset) {
238 y = view->swayc->y + y_offset; 249 y = state->swayc_y + y_offset;
239 height = view->swayc->height - y_offset 250 height = state->swayc_height - y_offset
240 - view->border_thickness * view->border_bottom; 251 - state->border_thickness * state->border_bottom;
241 } else { 252 } else {
242 y = view->swayc->y + container_titlebar_height(); 253 y = state->swayc_y + container_titlebar_height();
243 height = view->swayc->height - container_titlebar_height() 254 height = state->swayc_height - container_titlebar_height()
244 - view->border_thickness * view->border_bottom; 255 - state->border_thickness * state->border_bottom;
245 } 256 }
246 break; 257 break;
247 } 258 }
248 259
249 view->x = x; 260 state->view_x = x;
250 view->y = y; 261 state->view_y = y;
251 view_configure(view, x, y, width, height); 262 state->view_width = width;
263 state->view_height = height;
252} 264}
253 265
254void view_set_activated(struct sway_view *view, bool activated) { 266void view_set_activated(struct sway_view *view, bool activated) {
@@ -307,8 +319,8 @@ void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) {
307 view_configure(view, view->saved_x, view->saved_y, 319 view_configure(view, view->saved_x, view->saved_y,
308 view->saved_width, view->saved_height); 320 view->saved_width, view->saved_height);
309 } else { 321 } else {
310 view->swayc->width = view->swayc->saved_width; 322 view->swayc->width = view->swayc->saved_width;
311 view->swayc->height = view->swayc->saved_height; 323 view->swayc->height = view->swayc->saved_height;
312 view_autoconfigure(view); 324 view_autoconfigure(view);
313 } 325 }
314 } 326 }
@@ -496,6 +508,8 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
496 view->swayc = cont; 508 view->swayc = cont;
497 view->border = config->border; 509 view->border = config->border;
498 view->border_thickness = config->border_thickness; 510 view->border_thickness = config->border_thickness;
511 view->swayc->pending.border = config->border;
512 view->swayc->pending.border_thickness = config->border_thickness;
499 513
500 view_init_subsurfaces(view, wlr_surface); 514 view_init_subsurfaces(view, wlr_surface);
501 wl_signal_add(&wlr_surface->events.new_subsurface, 515 wl_signal_add(&wlr_surface->events.new_subsurface,
@@ -963,7 +977,7 @@ bool view_is_visible(struct sway_view *view) {
963 } 977 }
964 // Check the workspace is visible 978 // Check the workspace is visible
965 if (!is_sticky) { 979 if (!is_sticky) {
966 return workspace_is_visible(workspace); 980 return workspace_is_visible(workspace);
967 } 981 }
968 return true; 982 return true;
969} 983}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 9ba210fd..ad581a96 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -60,6 +60,12 @@ struct sway_container *workspace_create(struct sway_container *output,
60 workspace->prev_layout = L_NONE; 60 workspace->prev_layout = L_NONE;
61 workspace->layout = container_get_default_layout(output); 61 workspace->layout = container_get_default_layout(output);
62 62
63 workspace->pending.swayc_x = workspace->x;
64 workspace->pending.swayc_y = workspace->y;
65 workspace->pending.swayc_width = workspace->width;
66 workspace->pending.swayc_height = workspace->height;
67 workspace->pending.layout = workspace->layout;
68
63 struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); 69 struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace));
64 if (!swayws) { 70 if (!swayws) {
65 return NULL; 71 return NULL;