WINGs/wview_wl,wclient_wl: fix rendering and input for child views

Rendering: wl_map only triggered wl_redisplay for topLevel views.
Non-toplevel views (buttons, frames, labels) were mapped but never
painted. Now wl_map calls wl_redisplay for any realized view.
wl_redisplay already recurses into children, so wl_map_subviews is
simplified to just set mapped flags then redisplay the parent.

Input: pointer events were delivered to the toplevel view because
Wayland has a single surface per window (unlike X11 where each widget
has its own window). Added hit-testing via W_FindViewAtPoint to route
button press/release and motion events to the correct child view.
Also synthesizes enter/leave events as the pointer moves between
child views (needed for button highlight on hover).
This commit is contained in:
Window Maker 2026-05-24 15:49:05 +02:00
parent c70fec7f56
commit 50096c7487
2 changed files with 77 additions and 37 deletions

View File

@ -509,6 +509,34 @@ static uint32_t wlc_ptr_focus_serial;
static WLClientToplevel *wlc_ptr_focused;
static unsigned int wlc_ptr_button_state;
static unsigned int wlc_ptr_mods;
static W_View *wlc_ptr_child_focus;
/*
* Hit-test: find the deepest child view at (x,y) relative to the toplevel,
* and compute local coordinates within that view.
*/
extern W_View *W_FindViewAtPoint(W_View *parent, int x, int y);
static W_View *
wlc_hit_test(WLClientToplevel *top, int x, int y, int *lx, int *ly)
{
if (!top || !top->view) return NULL;
W_View *hit = W_FindViewAtPoint(top->view, x, y);
if (!hit) {
*lx = x;
*ly = y;
return top->view;
}
/* Compute local coords by walking up from hit to toplevel */
int ox = 0, oy = 0;
for (W_View *v = hit; v && v != top->view; v = v->parent) {
ox += v->pos.x;
oy += v->pos.y;
}
*lx = x - ox;
*ly = y - oy;
return hit;
}
static WLClientToplevel *
wlc_top_for_surface(struct wl_surface *surf)
@ -564,6 +592,7 @@ pointer_handle_leave(void *data, struct wl_pointer *p, uint32_t serial,
ev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
W_WL_EnqueueEvent(ctx->scr, &ev, NULL);
wlc_ptr_focused = NULL;
wlc_ptr_child_focus = NULL;
}
static void
@ -576,18 +605,48 @@ pointer_handle_motion(void *data, struct wl_pointer *p, uint32_t time,
wlc_ptr_y = wl_fixed_to_double(sy);
if (!wlc_ptr_focused) return;
int lx, ly;
W_View *target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly);
/* Synthesize enter/leave when pointer moves between child views */
if (target != wlc_ptr_child_focus) {
if (wlc_ptr_child_focus) {
WMEvent lev;
memset(&lev, 0, sizeof(lev));
lev.type = WME_LEAVE;
lev.window = wlc_ptr_child_focus->window;
lev.u.crossing.window = lev.window;
lev.u.crossing.mode = WM_NOTIFY_NORMAL;
lev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
W_WL_EnqueueEvent(ctx->scr, &lev, wlc_ptr_child_focus);
}
wlc_ptr_child_focus = target;
if (target) {
WMEvent eev;
memset(&eev, 0, sizeof(eev));
eev.type = WME_ENTER;
eev.window = target->window;
eev.u.crossing.window = eev.window;
eev.u.crossing.x = lx;
eev.u.crossing.y = ly;
eev.u.crossing.mode = WM_NOTIFY_NORMAL;
eev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
W_WL_EnqueueEvent(ctx->scr, &eev, target);
}
}
WMEvent ev;
memset(&ev, 0, sizeof(ev));
ev.type = WME_MOTION;
ev.window = wlc_ptr_focused->view->window;
ev.window = target ? target->window : wlc_ptr_focused->view->window;
ev.u.motion.window = ev.window;
ev.u.motion.time = time;
ev.u.motion.x = (int)wlc_ptr_x;
ev.u.motion.y = (int)wlc_ptr_y;
ev.u.motion.x = lx;
ev.u.motion.y = ly;
ev.u.motion.x_root = (int)wlc_ptr_x;
ev.u.motion.y_root = (int)wlc_ptr_y;
ev.u.motion.state = wlc_ptr_button_state | wlc_ptr_mods;
W_WL_EnqueueEvent(ctx->scr, &ev, NULL);
W_WL_EnqueueEvent(ctx->scr, &ev, target);
}
static void
@ -622,16 +681,20 @@ pointer_handle_button(void *data, struct wl_pointer *p, uint32_t serial,
memset(&ev, 0, sizeof(ev));
ev.type = (state == WL_POINTER_BUTTON_STATE_PRESSED)
? WME_BUTTON_PRESS : WME_BUTTON_RELEASE;
ev.window = wlc_ptr_focused->view->window;
int lx, ly;
W_View *target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly);
ev.window = target ? target->window : wlc_ptr_focused->view->window;
ev.u.button.window = ev.window;
ev.u.button.button = wmb;
ev.u.button.state = wlc_ptr_button_state | wlc_ptr_mods;
ev.u.button.time = time;
ev.u.button.x = (int)wlc_ptr_x;
ev.u.button.y = (int)wlc_ptr_y;
ev.u.button.x = lx;
ev.u.button.y = ly;
ev.u.button.x_root = (int)wlc_ptr_x;
ev.u.button.y_root = (int)wlc_ptr_y;
W_WL_EnqueueEvent(ctx->scr, &ev, NULL);
W_WL_EnqueueEvent(ctx->scr, &ev, target);
}
static void

View File

@ -265,20 +265,8 @@ static void wl_map(void *vctx, W_View *view)
{
(void)vctx;
view->flags.mapped = 1;
if (view->flags.topLevel && view->flags.realized) {
if (view->flags.realized) {
wl_redisplay(vctx, view);
wl_map_subviews(vctx, view);
/* Re-composite top-level after children have drawn into it */
if (view->parent) {
pixman_image_t *src = (pixman_image_t *)W_GetViewBacking(view->window);
pixman_image_t *dst = (pixman_image_t *)W_GetViewBacking(view->parent->window);
if (src && dst) {
pixman_image_composite32(PIXMAN_OP_OVER, src, NULL, dst,
0, 0, 0, 0,
view->pos.x, view->pos.y,
view->size.width, view->size.height);
}
}
}
}
@ -288,25 +276,14 @@ static void wl_map_subviews(void *vctx, W_View *view)
while (child) {
if (child->flags.realized) {
child->flags.mapped = 1;
wl_redisplay(vctx, child);
/* Recurse into grandchildren */
if (child->childrenList)
wl_map_subviews(vctx, child);
/* Re-composite child after grandchildren have drawn into it */
pixman_image_t *src = (pixman_image_t *)W_GetViewBacking(child->window);
pixman_image_t *dst = (pixman_image_t *)W_GetViewBacking(view->window);
if (src && dst) {
pixman_image_composite32(PIXMAN_OP_OVER, src, NULL, dst,
0, 0, 0, 0,
child->pos.x, child->pos.y,
child->size.width, child->size.height);
}
} else {
if (child->childrenList)
wl_map_subviews(vctx, child);
}
if (child->childrenList)
wl_map_subviews(vctx, child);
child = child->nextSister;
}
/* Redisplay the parent which will recurse into all now-mapped children */
if (view->flags.mapped)
wl_redisplay(vctx, view);
}
static void wl_move(void *vctx, W_View *view, int x, int y)