fix: non-responsive WINGs widgets on Wayland (overlapping sibling views + cascade compositing)

This commit is contained in:
Window Maker 2026-05-30 15:29:04 +02:00
parent 6e902db869
commit 86f7510a13
1 changed files with 59 additions and 4 deletions

View File

@ -531,6 +531,52 @@ static void wl_redisplay(void *vctx, W_View *view)
0, 0, 0, 0,
view->pos.x, view->pos.y, cw, ch);
}
/* Cascade: composite all the way up to the toplevel.
*
* When wl_redisplay is called directly (depth==1, e.g. from
* W_RedisplayView for a slider widget), only the IMMEDIATE
* parent's backing is updated above. The toplevel's backing
* (shared-memory wl_buffer) remains STALE, so the subsequent
* wl_surface.commit shows the old content — widget visual
* updates are invisible.
*
* By continuing the composite up the tree here we propagate
* the child's pixel change all the way to the toplevel before
* the commit below. We skip the cascade when depth > 1
* (recursive call during a full parent→child redisplay)
* because the parent will composite all siblings in order
* and the depth-1 invocation will handle the cascade once. */
if (wl_redisplay_depth == 1) {
W_View *v = view->parent;
while (v->parent && !v->flags.topLevel) {
pixman_image_t *v_src = W_GetViewBacking(v->window);
pixman_image_t *v_dst = W_GetViewBacking(v->parent->window);
if (v_src && v_dst) {
int v_sw = pixman_image_get_width(v_src);
int v_sh = pixman_image_get_height(v_src);
int v_dw = pixman_image_get_width(v_dst);
int v_dh = pixman_image_get_height(v_dst);
if (v_sw < 1 || v_sh < 1 || v_dw < 1 || v_dh < 1) {
fprintf(stderr, "wl_redisplay cascade: skip zero backing (%p src=%dx%d dst=%dx%d)\n",
(void*)v, v_sw, v_sh, v_dw, v_dh);
v = v->parent;
continue;
}
int v_cw = v_sw < (int)v->size.width ? v_sw : (int)v->size.width;
int v_ch = v_sh < (int)v->size.height ? v_sh : (int)v->size.height;
if (v->pos.x + v_cw > v_dw) v_cw = v_dw - v->pos.x;
if (v->pos.y + v_ch > v_dh) v_ch = v_dh - v->pos.y;
if (v_cw < 0) v_cw = 0;
if (v_ch < 0) v_ch = 0;
if (v_cw > 0 && v_ch > 0 && v->pos.x >= 0 && v->pos.y >= 0)
pixman_image_composite32(PIXMAN_OP_OVER, v_src, NULL, v_dst,
0, 0, 0, 0,
v->pos.x, v->pos.y, v_cw, v_ch);
}
v = v->parent;
}
}
}
/* Notify WM backend to commit the top-level view's backing buffer */
@ -546,23 +592,32 @@ static void wl_redisplay(void *vctx, W_View *view)
wl_redisplay_depth--;
}
/* Find the deepest child view at (x, y) relative to the given view. */
/* Find the deepest child view at (x, y) relative to the given view.
* When multiple children overlap the same point, prefer the one that
* has children (or deeper descendents) over a leaf view, so that
* widgets nested inside a sibling that overlaps a parent container
* are found correctly on Wayland where subwindows are absent. */
W_View *W_FindViewAtPoint(W_View *parent, int x, int y)
{
if (!parent) return NULL;
W_View *best = NULL;
W_View *child = parent->childrenList;
while (child) {
if (child->flags.mapped && child->flags.realized &&
x >= child->pos.x && x < child->pos.x + child->size.width &&
y >= child->pos.y && y < child->pos.y + child->size.height) {
/* Recurse into this child with local coordinates */
W_View *deeper = W_FindViewAtPoint(child,
x - child->pos.x, y - child->pos.y);
return deeper ? deeper : child;
if (deeper)
return deeper;
if (!best)
best = child;
/* Keep looking — a later sibling at the same coords
* may have deeper children. */
}
child = child->nextSister;
}
return NULL;
return best;
}
static WMPoint wl_get_screen_position(void *vctx, W_View *view)