diff --git a/WINGs/wview_wl.c b/WINGs/wview_wl.c index 0b65190..133c5db 100644 --- a/WINGs/wview_wl.c +++ b/WINGs/wview_wl.c @@ -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)