Skip to content

Commit 6565d1e

Browse files
committed
Avoid crashing on too many containers
If far too many containers are created, they can become so small that their size calculations come out negative, leading to crashes on asserts. Instead, set a lower bound for sizes and disable the container entirely if it goes below it, giving whatever space it used to the last container. The splits are not recalculated, so currently the effect is that if all containers have the same width fraction, they keep getting narrower until at some point they all round to zero and the last container will be given all the available space. A better behavior would have been if the additional container did not contribute to size and fraction calculations at all, but it's an extreme edge-case, anything is better than crashing, and this is easier to implement.
1 parent 61cc08c commit 6565d1e

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

sway/desktop/transaction.c

+18-9
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,9 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
312312
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height);
313313
wlr_scene_node_reparent(&child->scene_tree->node, content);
314314

315-
if (activated) {
316-
arrange_container(child, width, height - title_bar_height,
317-
title_bar_height == 0, 0);
315+
height -= title_bar_height;
316+
if (activated && width > 0 && height > 0) {
317+
arrange_container(child, width, height, title_bar_height == 0, 0);
318318
} else {
319319
disable_container(child);
320320
}
@@ -341,9 +341,9 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
341341
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height);
342342
wlr_scene_node_reparent(&child->scene_tree->node, content);
343343

344-
if (activated) {
345-
arrange_container(child, width, height - title_height,
346-
title_bar_height == 0, 0);
344+
height -= title_bar_height;
345+
if (activated && width > 0 && height > 0) {
346+
arrange_container(child, width, height, title_bar_height == 0, 0);
347347
} else {
348348
disable_container(child);
349349
}
@@ -359,8 +359,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
359359
wlr_scene_node_set_enabled(&child->border.tree->node, true);
360360
wlr_scene_node_set_position(&child->scene_tree->node, 0, off);
361361
wlr_scene_node_reparent(&child->scene_tree->node, content);
362-
arrange_container(child, width, cheight, true, gaps);
363-
off += cheight + gaps;
362+
if (width > 0 && cheight > 0) {
363+
arrange_container(child, width, cheight, true, gaps);
364+
off += cheight + gaps;
365+
} else {
366+
disable_container(child);
367+
}
364368
}
365369
} else if (layout == L_HORIZ) {
366370
int off = 0;
@@ -372,7 +376,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
372376
wlr_scene_node_set_position(&child->scene_tree->node, off, 0);
373377
wlr_scene_node_reparent(&child->scene_tree->node, content);
374378
arrange_container(child, cwidth, height, true, gaps);
375-
off += cwidth + gaps;
379+
if (cwidth > 0 && height > 0) {
380+
arrange_container(child, cwidth, height, true, gaps);
381+
off += cwidth + gaps;
382+
} else {
383+
disable_container(child);
384+
}
376385
}
377386
} else {
378387
sway_assert(false, "unreachable");

sway/tree/arrange.c

+15-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
2929
}
3030
}
3131

32-
// Calculate each height fraction
32+
// Calculate each width fraction
3333
double total_width_fraction = 0;
3434
for (int i = 0; i < children->length; ++i) {
3535
struct sway_container *child = children->items[i];
@@ -82,12 +82,18 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
8282
child->pending.y = parent->y;
8383
child->pending.width = round(child->width_fraction * child_total_width);
8484
child->pending.height = parent->height;
85-
child_x += child->pending.width + inner_gap;
8685

8786
// Make last child use remaining width of parent
8887
if (i == children->length - 1) {
8988
child->pending.width = parent->x + parent->width - child->pending.x;
9089
}
90+
91+
// Arbitrary lower bound for window size
92+
if (child->pending.width < 10 || child->pending.height < 10) {
93+
child->pending.width = 0;
94+
child->pending.height = 0;
95+
}
96+
child_x += child->pending.width + inner_gap;
9197
}
9298
}
9399

@@ -161,12 +167,18 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) {
161167
child->pending.y = child_y;
162168
child->pending.width = parent->width;
163169
child->pending.height = round(child->height_fraction * child_total_height);
164-
child_y += child->pending.height + inner_gap;
165170

166171
// Make last child use remaining height of parent
167172
if (i == children->length - 1) {
168173
child->pending.height = parent->y + parent->height - child->pending.y;
169174
}
175+
176+
// Arbitrary lower bound for window size
177+
if (child->pending.width < 10 || child->pending.height < 10) {
178+
child->pending.width = 0;
179+
child->pending.height = 0;
180+
}
181+
child_y += child->pending.height + inner_gap;
170182
}
171183
}
172184

0 commit comments

Comments
 (0)