aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenny Levinsen <kl@kl.wtf>2025-03-12 16:35:41 +0100
committerAlexander Orzechowski <alex@ozal.ski>2025-03-21 21:08:04 -0400
commitc2d6aff64c1e265c8f1d95b780b54193defae18a (patch)
treeaefae9c2e9a8bc4f77fc60a51e612e7828bbff07
parent4b185a0fe0031455d5ceab1eda2b9d9ffe0c81de (diff)
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.
-rw-r--r--sway/desktop/transaction.c27
-rw-r--r--sway/tree/arrange.c18
2 files changed, 33 insertions, 12 deletions
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index 52c03b18..16ce8e2e 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -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");
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 2b95a6dc..faf54d02 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -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;
}
}