From d70c84b5717dafd922f434b022873b7f1b276543 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 28 Jun 2026 17:19:13 +0200 Subject: [PATCH] scene: intersect visible area with output layout in update_node_update_outputs() A node can have a visible area outside the output layout bounds. In that case, it will not pass the overlap check. For instance, with a single output, a 100x100 px weston-simple-shm would stop animating when moving it close to an edge and leaving less than a ~30x30 px square visible. Fix this by intersecting the node's visible region with the output layout region so that the 10% overlap target is always reachable. Switch to a strict comparison in case visible_area is zero. --- types/scene/wlr_scene.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 7e4a81004..1c8a8d781 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -417,7 +417,21 @@ static void update_node_update_outputs(struct wlr_scene_node *node, uint64_t active_outputs = 0; if (!pixman_region32_empty(&node->visible)) { - uint32_t visible_area = region_area(&node->visible); + struct wlr_scene_output *scene_output; + + // Compute the region covered by all outputs, then intersect with the + // node's visible region + pixman_region32_t visible; + pixman_region32_init(&visible); + wl_list_for_each(scene_output, outputs, link) { + int width, height; + wlr_output_effective_resolution(scene_output->output, &width, &height); + pixman_region32_union_rect(&visible, &visible, + scene_output->x, scene_output->y, width, height); + } + pixman_region32_intersect(&visible, &visible, &node->visible); + uint32_t visible_area = region_area(&visible); + pixman_region32_fini(&visible); // let's update the outputs in two steps: // - the primary outputs @@ -425,7 +439,6 @@ static void update_node_update_outputs(struct wlr_scene_node *node, // This ensures that the enter/leave signals can rely on the primary output // to have a reasonable value. Otherwise, they may get a value that's in // the middle of a calculation. - struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, outputs, link) { if (scene_output == ignore) { continue; @@ -449,9 +462,9 @@ static void update_node_update_outputs(struct wlr_scene_node *node, uint32_t overlap = region_area(&intersection); pixman_region32_fini(&intersection); - // If the overlap accounts for less than 10% of the visible node area, + // If the overlap accounts for 10% of the visible node area or less, // ignore this output - if (overlap >= 0.1 * visible_area) { + if (overlap > 0.1 * visible_area) { if (overlap >= largest_overlap) { largest_overlap = overlap; scene_buffer->primary_output = scene_output;