From 24243f9c38d29ee5d19e23655e62029966fe74c5 Mon Sep 17 00:00:00 2001 From: "James N. Hart" Date: Wed, 18 Mar 2026 21:46:22 -0600 Subject: [PATCH] Clamp dimensions to non-negative before wlr_scene_rect_set_size During cross-output tiling drags, computed box dimensions can become negative due to coordinate transforms and thickness subtractions. This triggers the assertion in wlr_scene_rect_set_size() which requires width >= 0 && height >= 0, crashing the compositor. Clamp dimensions to zero in three locations: - resize_box() in seatop_move_tiling.c for the WLR_EDGE_NONE case - update_indicator() in seatop_move_tiling.c as a safety net - arrange_container() in transaction.c for border width (matching the existing vert_border_height clamping from 62fd8c4d) - update_rect_list() in container.c for pixman region boxes This is the same class of bug fixed by 62fd8c4d (height clamping) and partially addressed by c2d6aff6 (too-many-containers guards). --- sway/desktop/transaction.c | 7 ++++--- sway/input/seatop_move_tiling.c | 6 +++++- sway/tree/container.c | 6 +++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 325a30226..b88f41728 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -435,9 +435,10 @@ static void arrange_container(struct sway_container *con, int border_left = con->current.border_left ? border_width : 0; int border_right = con->current.border_right ? border_width : 0; int vert_border_height = MAX(0, height - border_top - border_bottom); + int horiz_border_width = MAX(0, width); - wlr_scene_rect_set_size(con->border.top, width, border_top); - wlr_scene_rect_set_size(con->border.bottom, width, border_bottom); + wlr_scene_rect_set_size(con->border.top, horiz_border_width, border_top); + wlr_scene_rect_set_size(con->border.bottom, horiz_border_width, border_bottom); wlr_scene_rect_set_size(con->border.left, border_left, vert_border_height); wlr_scene_rect_set_size(con->border.right, @@ -449,7 +450,7 @@ static void arrange_container(struct sway_container *con, wlr_scene_node_set_position(&con->border.left->node, 0, border_top); wlr_scene_node_set_position(&con->border.right->node, - width - border_right, border_top); + horiz_border_width - border_right, border_top); // make sure to reparent, it's possible that the client just came out of // fullscreen mode where the parent of the surface is not the container diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index c525b77a9..d82091108 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -81,6 +81,8 @@ static void resize_box(struct wlr_box *box, enum wlr_edges edge, box->y += thickness; box->width -= thickness * 2; box->height -= thickness * 2; + if (box->width < 0) box->width = 0; + if (box->height < 0) box->height = 0; break; } } @@ -154,7 +156,9 @@ static bool split_titlebar(struct sway_node *node, struct sway_container *avoid, static void update_indicator(struct seatop_move_tiling_event *e, struct wlr_box *box) { wlr_scene_node_set_position(&e->indicator_rect->node, box->x, box->y); - wlr_scene_rect_set_size(e->indicator_rect, box->width, box->height); + wlr_scene_rect_set_size(e->indicator_rect, + box->width > 0 ? box->width : 0, + box->height > 0 ? box->height : 0); } static void handle_motion_postthreshold(struct sway_seat *seat) { diff --git a/sway/tree/container.c b/sway/tree/container.c index 0385d7c17..efc3ef55a 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -335,7 +335,11 @@ static void update_rect_list(struct wlr_scene_tree *tree, pixman_region32_t *reg if (i < len) { const pixman_box32_t *box = &rects[i++]; wlr_scene_node_set_position(&rect->node, box->x1, box->y1); - wlr_scene_rect_set_size(rect, box->x2 - box->x1, box->y2 - box->y1); + int rect_width = box->x2 - box->x1; + int rect_height = box->y2 - box->y1; + wlr_scene_rect_set_size(rect, + rect_width > 0 ? rect_width : 0, + rect_height > 0 ? rect_height : 0); } } }