aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/arrange.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/arrange.c')
-rw-r--r--sway/tree/arrange.c338
1 files changed, 177 insertions, 161 deletions
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 53c95820..582b2891 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,6 @@
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
47 const struct wlr_box *output_box = wlr_output_layout_get_box(
48 root_container.sway_root->output_layout,
49 output->sway_output->wlr_output);
50 output->x = output_box->x;
51 output->y = output_box->y;
52 output->width = output_box->width;
53 output->height = output_box->height;
54 wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f",
55 output->name, output->x, output->y);
56
57 for (int i = 0; i < output->children->length; ++i) {
58 struct sway_container *workspace = output->children->items[i];
59 arrange_workspace(workspace);
60 }
61 container_damage_whole(output);
62}
63
64void arrange_workspace(struct sway_container *workspace) {
65 if (config->reloading) {
66 return;
67 }
68 if (!sway_assert(workspace->type == C_WORKSPACE,
69 "called arrange_workspace() on non-workspace container")) {
70 return;
71 }
72
73 struct sway_container *output = workspace->parent;
74 struct wlr_box *area = &output->sway_output->usable_area;
75 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
76 area->width, area->height, area->x, area->y);
77
78 remove_gaps(workspace);
79
80 workspace->width = area->width;
81 workspace->height = area->height;
82 workspace->x = output->x + area->x;
83 workspace->y = output->y + area->y;
84
85 add_gaps(workspace);
86
87 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
88 workspace->name, workspace->x, workspace->y);
89 arrange_children_of(workspace);
90}
91
92void remove_gaps(struct sway_container *c) {
93 if (c->current_gaps == 0) {
94 wlr_log(L_DEBUG, "Removing gaps: not gapped: %p", c);
95 return;
96 }
97
98 c->width += c->current_gaps * 2;
99 c->height += c->current_gaps * 2;
100 c->x -= c->current_gaps;
101 c->y -= c->current_gaps;
102
103 c->current_gaps = 0;
104
105 wlr_log(L_DEBUG, "Removing gaps %p", c);
106}
107
108void add_gaps(struct sway_container *c) {
109 if (c->current_gaps > 0 || c->type == C_CONTAINER) {
110 wlr_log(L_DEBUG, "Not adding gaps: %p", c);
111 return;
112 }
113
114 if (c->type == C_WORKSPACE &&
115 !(config->edge_gaps || (config->smart_gaps && c->children->length > 1))) {
116 return;
117 }
118
119 double gaps = c->has_gaps ? c->gaps_inner : config->gaps_inner;
120
121 c->x += gaps;
122 c->y += gaps;
123 c->width -= 2 * gaps;
124 c->height -= 2 * gaps;
125 c->current_gaps = gaps;
126
127 wlr_log(L_DEBUG, "Adding gaps: %p", c);
128}
129
130static void apply_horiz_layout(struct sway_container *parent) { 19static void apply_horiz_layout(struct sway_container *parent) {
131 size_t num_children = parent->children->length; 20 size_t num_children = parent->children->length;
132 if (!num_children) { 21 if (!num_children) {
@@ -136,8 +25,8 @@ static void apply_horiz_layout(struct sway_container *parent) {
136 if (parent->parent->layout == L_TABBED) { 25 if (parent->parent->layout == L_TABBED) {
137 parent_offset = container_titlebar_height(); 26 parent_offset = container_titlebar_height();
138 } else if (parent->parent->layout == L_STACKED) { 27 } else if (parent->parent->layout == L_STACKED) {
139 parent_offset = 28 parent_offset = container_titlebar_height() *
140 container_titlebar_height() * parent->parent->children->length; 29 parent->parent->children->length;
141 } 30 }
142 size_t parent_height = parent->height - parent_offset; 31 size_t parent_height = parent->height - parent_offset;
143 32
@@ -145,7 +34,6 @@ static void apply_horiz_layout(struct sway_container *parent) {
145 double total_width = 0; 34 double total_width = 0;
146 for (size_t i = 0; i < num_children; ++i) { 35 for (size_t i = 0; i < num_children; ++i) {
147 struct sway_container *child = parent->children->items[i]; 36 struct sway_container *child = parent->children->items[i];
148
149 if (child->width <= 0) { 37 if (child->width <= 0) {
150 if (num_children > 1) { 38 if (num_children > 1) {
151 child->width = parent->width / (num_children - 1); 39 child->width = parent->width / (num_children - 1);
@@ -161,25 +49,21 @@ static void apply_horiz_layout(struct sway_container *parent) {
161 // Resize windows 49 // Resize windows
162 wlr_log(L_DEBUG, "Arranging %p horizontally", parent); 50 wlr_log(L_DEBUG, "Arranging %p horizontally", parent);
163 double child_x = parent->x; 51 double child_x = parent->x;
164 struct sway_container *child;
165 for (size_t i = 0; i < num_children; ++i) { 52 for (size_t i = 0; i < num_children; ++i) {
166 child = parent->children->items[i]; 53 struct sway_container *child = parent->children->items[i];
167 wlr_log(L_DEBUG, 54 wlr_log(L_DEBUG,
168 "Calculating arrangement for %p:%d (will scale %f by %f)", 55 "Calculating arrangement for %p:%d (will scale %f by %f)",
169 child, child->type, child->width, scale); 56 child, child->type, child->width, scale);
170 child->x = child_x; 57 child->x = child_x;
171 child->y = parent->y + parent_offset; 58 child->y = parent->y + parent_offset;
59 child->width = floor(child->width * scale);
172 child->height = parent_height; 60 child->height = parent_height;
61 child_x += child->width;
173 62
63 // Make last child use remaining width of parent
174 if (i == num_children - 1) { 64 if (i == num_children - 1) {
175 // Make last child use remaining width of parent
176 child->width = parent->x + parent->width - child->x; 65 child->width = parent->x + parent->width - child->x;
177 } else {
178 child->width = floor(child->width * scale);
179 } 66 }
180
181 child_x += child->width;
182
183 add_gaps(child); 67 add_gaps(child);
184 } 68 }
185} 69}
@@ -202,7 +86,6 @@ static void apply_vert_layout(struct sway_container *parent) {
202 double total_height = 0; 86 double total_height = 0;
203 for (size_t i = 0; i < num_children; ++i) { 87 for (size_t i = 0; i < num_children; ++i) {
204 struct sway_container *child = parent->children->items[i]; 88 struct sway_container *child = parent->children->items[i];
205
206 if (child->height <= 0) { 89 if (child->height <= 0) {
207 if (num_children > 1) { 90 if (num_children > 1) {
208 child->height = parent_height / (num_children - 1); 91 child->height = parent_height / (num_children - 1);
@@ -218,25 +101,22 @@ static void apply_vert_layout(struct sway_container *parent) {
218 // Resize 101 // Resize
219 wlr_log(L_DEBUG, "Arranging %p vertically", parent); 102 wlr_log(L_DEBUG, "Arranging %p vertically", parent);
220 double child_y = parent->y + parent_offset; 103 double child_y = parent->y + parent_offset;
221 struct sway_container *child;
222 for (size_t i = 0; i < num_children; ++i) { 104 for (size_t i = 0; i < num_children; ++i) {
223 child = parent->children->items[i]; 105 struct sway_container *child = parent->children->items[i];
224 wlr_log(L_DEBUG, 106 wlr_log(L_DEBUG,
225 "Calculating arrangement for %p:%d (will scale %f by %f)", 107 "Calculating arrangement for %p:%d (will scale %f by %f)",
226 child, child->type, child->height, scale); 108 child, child->type, child->height, scale);
227 child->x = parent->x; 109 child->x = parent->x;
228 child->y = child_y; 110 child->y = child_y;
229 child->width = parent->width; 111 child->width = parent->width;
112 child->height = floor(child->height * scale);
113 child_y += child->height;
230 114
115 // Make last child use remaining height of parent
231 if (i == num_children - 1) { 116 if (i == num_children - 1) {
232 // Make last child use remaining height of parent 117 child->height =
233 child->height = parent->y + parent_offset + parent_height - child->y; 118 parent->y + parent_offset + parent_height - child->y;
234 } else {
235 child->height = floor(child->height * scale);
236 } 119 }
237
238 child_y += child->height;
239
240 add_gaps(child); 120 add_gaps(child);
241 } 121 }
242} 122}
@@ -264,26 +144,41 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) {
264 } 144 }
265} 145}
266 146
267void arrange_children_of(struct sway_container *parent) { 147/**
268 if (config->reloading) { 148 * If a container has been deleted from the pending tree state, we must add it
269 return; 149 * to the transaction so it can be freed afterwards. To do this, we iterate the
270 } 150 * server's destroying_containers list and add all of them. We may add more than
271 if (!sway_assert(parent->type == C_WORKSPACE || parent->type == C_CONTAINER, 151 * what we need to, but this is easy and has no negative consequences.
272 "container is a %s", container_type_to_str(parent->type))) { 152 */
273 return; 153static void add_deleted_containers(struct sway_transaction *transaction) {
154 for (int i = 0; i < server.destroying_containers->length; ++i) {
155 struct sway_container *child = server.destroying_containers->items[i];
156 transaction_add_container(transaction, child);
274 } 157 }
158}
275 159
276 struct sway_container *workspace = parent; 160static void arrange_children_of(struct sway_container *parent,
277 if (workspace->type != C_WORKSPACE) { 161 struct sway_transaction *transaction);
278 workspace = container_parent(workspace, C_WORKSPACE); 162
163static void arrange_floating(struct sway_container *floating,
164 struct sway_transaction *transaction) {
165 for (int i = 0; i < floating->children->length; ++i) {
166 struct sway_container *floater = floating->children->items[i];
167 if (floater->type == C_VIEW) {
168 view_autoconfigure(floater->sway_view);
169 } else {
170 arrange_children_of(floater, transaction);
171 }
172 transaction_add_container(transaction, floater);
279 } 173 }
174 transaction_add_container(transaction, floating);
175}
280 176
281 if (workspace->sway_workspace->fullscreen) { 177static void arrange_children_of(struct sway_container *parent,
282 // Just arrange the fullscreen view and jump out 178 struct sway_transaction *transaction) {
283 view_autoconfigure(workspace->sway_workspace->fullscreen); 179 if (config->reloading) {
284 return; 180 return;
285 } 181 }
286
287 wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, 182 wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent,
288 parent->name, parent->width, parent->height, parent->x, parent->y); 183 parent->name, parent->width, parent->height, parent->x, parent->y);
289 184
@@ -299,13 +194,15 @@ void arrange_children_of(struct sway_container *parent) {
299 case L_STACKED: 194 case L_STACKED:
300 apply_tabbed_or_stacked_layout(parent); 195 apply_tabbed_or_stacked_layout(parent);
301 break; 196 break;
302 default: 197 case L_NONE:
303 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
304 apply_horiz_layout(parent); 198 apply_horiz_layout(parent);
305 break; 199 break;
200 case L_FLOATING:
201 arrange_floating(parent, transaction);
202 break;
306 } 203 }
307 204
308 // Apply x, y, width and height to children and recurse if needed 205 // Recurse into child containers
309 for (int i = 0; i < parent->children->length; ++i) { 206 for (int i = 0; i < parent->children->length; ++i) {
310 struct sway_container *child = parent->children->items[i]; 207 struct sway_container *child = parent->children->items[i];
311 if (parent->has_gaps && !child->has_gaps) { 208 if (parent->has_gaps && !child->has_gaps) {
@@ -316,21 +213,140 @@ void arrange_children_of(struct sway_container *parent) {
316 if (child->type == C_VIEW) { 213 if (child->type == C_VIEW) {
317 view_autoconfigure(child->sway_view); 214 view_autoconfigure(child->sway_view);
318 } else { 215 } else {
319 arrange_children_of(child); 216 arrange_children_of(child, transaction);
320 } 217 }
218 transaction_add_container(transaction, child);
321 } 219 }
220}
322 221
323 // If container is a workspace, process floating containers too 222static void arrange_workspace(struct sway_container *workspace,
324 if (parent->type == C_WORKSPACE) { 223 struct sway_transaction *transaction) {
325 struct sway_workspace *ws = workspace->sway_workspace; 224 if (config->reloading) {
326 for (int i = 0; i < ws->floating->children->length; ++i) { 225 return;
327 struct sway_container *child = ws->floating->children->items[i]; 226 }
328 if (child->type != C_VIEW) { 227 struct sway_container *output = workspace->parent;
329 arrange_children_of(child); 228 struct wlr_box *area = &output->sway_output->usable_area;
330 } 229 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
331 } 230 area->width, area->height, area->x, area->y);
231 remove_gaps(workspace);
232 workspace->width = area->width;
233 workspace->height = area->height;
234 workspace->x = output->x + area->x;
235 workspace->y = output->y + area->y;
236 add_gaps(workspace);
237 transaction_add_container(transaction, workspace);
238 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
239 workspace->x, workspace->y);
240 arrange_floating(workspace->sway_workspace->floating, transaction);
241 arrange_children_of(workspace, transaction);
242}
243
244static void arrange_output(struct sway_container *output,
245 struct sway_transaction *transaction) {
246 if (config->reloading) {
247 return;
248 }
249 const struct wlr_box *output_box = wlr_output_layout_get_box(
250 root_container.sway_root->output_layout,
251 output->sway_output->wlr_output);
252 output->x = output_box->x;
253 output->y = output_box->y;
254 output->width = output_box->width;
255 output->height = output_box->height;
256 transaction_add_container(transaction, output);
257 wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f",
258 output->name, output->x, output->y);
259 for (int i = 0; i < output->children->length; ++i) {
260 struct sway_container *workspace = output->children->items[i];
261 arrange_workspace(workspace, transaction);
262 }
263}
264
265static void arrange_root(struct sway_transaction *transaction) {
266 if (config->reloading) {
267 return;
268 }
269 struct wlr_output_layout *output_layout =
270 root_container.sway_root->output_layout;
271 const struct wlr_box *layout_box =
272 wlr_output_layout_get_box(output_layout, NULL);
273 root_container.x = layout_box->x;
274 root_container.y = layout_box->y;
275 root_container.width = layout_box->width;
276 root_container.height = layout_box->height;
277 transaction_add_container(transaction, &root_container);
278 for (int i = 0; i < root_container.children->length; ++i) {
279 struct sway_container *output = root_container.children->items[i];
280 arrange_output(output, transaction);
281 }
282}
283
284void arrange_windows(struct sway_container *container,
285 struct sway_transaction *transaction) {
286 switch (container->type) {
287 case C_ROOT:
288 arrange_root(transaction);
289 break;
290 case C_OUTPUT:
291 arrange_output(container, transaction);
292 break;
293 case C_WORKSPACE:
294 arrange_workspace(container, transaction);
295 break;
296 case C_CONTAINER:
297 arrange_children_of(container, transaction);
298 transaction_add_container(transaction, container);
299 break;
300 case C_VIEW:
301 view_autoconfigure(container->sway_view);
302 transaction_add_container(transaction, container);
303 break;
304 case C_TYPES:
305 break;
306 }
307 add_deleted_containers(transaction);
308}
309
310void arrange_and_commit(struct sway_container *container) {
311 struct sway_transaction *transaction = transaction_create();
312 arrange_windows(container, transaction);
313 transaction_commit(transaction);
314}
315
316void remove_gaps(struct sway_container *c) {
317 if (c->current_gaps == 0) {
318 wlr_log(L_DEBUG, "Removing gaps: not gapped: %p", c);
319 return;
332 } 320 }
333 321
334 container_damage_whole(parent); 322 c->width += c->current_gaps * 2;
335 update_debug_tree(); 323 c->height += c->current_gaps * 2;
324 c->x -= c->current_gaps;
325 c->y -= c->current_gaps;
326
327 c->current_gaps = 0;
328
329 wlr_log(L_DEBUG, "Removing gaps %p", c);
330}
331
332void add_gaps(struct sway_container *c) {
333 if (c->current_gaps > 0 || c->type == C_CONTAINER) {
334 wlr_log(L_DEBUG, "Not adding gaps: %p", c);
335 return;
336 }
337
338 if (c->type == C_WORKSPACE &&
339 !(config->edge_gaps || (config->smart_gaps && c->children->length > 1))) {
340 return;
341 }
342
343 double gaps = c->has_gaps ? c->gaps_inner : config->gaps_inner;
344
345 c->x += gaps;
346 c->y += gaps;
347 c->width -= 2 * gaps;
348 c->height -= 2 * gaps;
349 c->current_gaps = gaps;
350
351 wlr_log(L_DEBUG, "Adding gaps: %p", c);
336} 352}