summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFurkan Sahin <furkan-dev@proton.me>2025-03-12 16:35:41 +0100
committerFurkan Sahin <furkan-dev@proton.me>2025-03-12 16:35:41 +0100
commitfaed8484c4e2cf9171b5fff1e4a449bcfc8f9930 (patch)
treeaefae9c2e9a8bc4f77fc60a51e612e7828bbff07
parentc5cd4061854d51adc458a112ff16f015d8b48f73 (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;
}
}