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.
This commit is contained in:
Kenny Levinsen 2025-03-12 16:35:41 +01:00 committed by Alexander Orzechowski
parent 4b185a0fe0
commit c2d6aff64c
2 changed files with 33 additions and 12 deletions

View file

@ -312,9 +312,9 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height);
wlr_scene_node_reparent(&child->scene_tree->node, content);
if (activated) {
arrange_container(child, width, height - title_bar_height,
title_bar_height == 0, 0);
height -= title_bar_height;
if (activated && width > 0 && height > 0) {
arrange_container(child, width, height, title_bar_height == 0, 0);
} else {
disable_container(child);
}
@ -341,9 +341,9 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height);
wlr_scene_node_reparent(&child->scene_tree->node, content);
if (activated) {
arrange_container(child, width, height - title_height,
title_bar_height == 0, 0);
height -= title_bar_height;
if (activated && width > 0 && height > 0) {
arrange_container(child, width, height, title_bar_height == 0, 0);
} else {
disable_container(child);
}
@ -359,8 +359,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
wlr_scene_node_set_enabled(&child->border.tree->node, true);
wlr_scene_node_set_position(&child->scene_tree->node, 0, off);
wlr_scene_node_reparent(&child->scene_tree->node, content);
arrange_container(child, width, cheight, true, gaps);
off += cheight + gaps;
if (width > 0 && cheight > 0) {
arrange_container(child, width, cheight, true, gaps);
off += cheight + gaps;
} else {
disable_container(child);
}
}
} else if (layout == L_HORIZ) {
int off = 0;
@ -372,7 +376,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
wlr_scene_node_set_position(&child->scene_tree->node, off, 0);
wlr_scene_node_reparent(&child->scene_tree->node, content);
arrange_container(child, cwidth, height, true, gaps);
off += cwidth + gaps;
if (cwidth > 0 && height > 0) {
arrange_container(child, cwidth, height, true, gaps);
off += cwidth + gaps;
} else {
disable_container(child);
}
}
} else {
sway_assert(false, "unreachable");

View file

@ -29,7 +29,7 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
}
}
// Calculate each height fraction
// Calculate each width fraction
double total_width_fraction = 0;
for (int i = 0; i < children->length; ++i) {
struct sway_container *child = children->items[i];
@ -82,12 +82,18 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
child->pending.y = parent->y;
child->pending.width = round(child->width_fraction * child_total_width);
child->pending.height = parent->height;
child_x += child->pending.width + inner_gap;
// Make last child use remaining width of parent
if (i == children->length - 1) {
child->pending.width = parent->x + parent->width - child->pending.x;
}
// Arbitrary lower bound for window size
if (child->pending.width < 10 || child->pending.height < 10) {
child->pending.width = 0;
child->pending.height = 0;
}
child_x += child->pending.width + inner_gap;
}
}
@ -161,12 +167,18 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) {
child->pending.y = child_y;
child->pending.width = parent->width;
child->pending.height = round(child->height_fraction * child_total_height);
child_y += child->pending.height + inner_gap;
// Make last child use remaining height of parent
if (i == children->length - 1) {
child->pending.height = parent->y + parent->height - child->pending.y;
}
// Arbitrary lower bound for window size
if (child->pending.width < 10 || child->pending.height < 10) {
child->pending.width = 0;
child->pending.height = 0;
}
child_y += child->pending.height + inner_gap;
}
}