fix: WINGs widget clicks on Wayland (child view hit-testing)
On Wayland, all WINGs child widgets composite into a single scene_buf for the toplevel dialog. Clicks always arrived with the toplevel window ID, so WMHandleEvent delivered them to the toplevel view which has no ButtonPressMask handler. Child widget handlers never fired. Fix: add W_FindViewAtPoint() to walk the view tree and find the deepest mapped child at click coordinates. In handle_pointer_button, resolve the child view for WINGs surfaces and pass it as the direct target to W_WL_EnqueueEvent. WMHandleEvent then delivers directly to the widget.
This commit is contained in:
parent
68d4301b9f
commit
ee8489e3a1
|
|
@ -328,6 +328,25 @@ static void wl_redisplay(void *vctx, W_View *view)
|
|||
W_ViewCommitBackingFn((unsigned long)top->window);
|
||||
}
|
||||
|
||||
/* Find the deepest child view at (x, y) relative to the given view. */
|
||||
W_View *W_FindViewAtPoint(W_View *parent, int x, int y)
|
||||
{
|
||||
if (!parent) return 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;
|
||||
}
|
||||
child = child->nextSister;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static WMPoint wl_get_screen_position(void *vctx, W_View *view)
|
||||
{
|
||||
W_Screen *scr = (W_Screen *)vctx;
|
||||
|
|
|
|||
|
|
@ -5248,7 +5248,20 @@ handle_pointer_button(struct wl_listener *listener, void *data)
|
|||
case 0x112: wev.u.button.button = 2; break;
|
||||
default: wev.u.button.button = (ev->button - 0x110) + 1; break;
|
||||
}
|
||||
W_WL_EnqueueEvent(wmscr, &wev, NULL);
|
||||
/* For WINGs views, resolve the child widget at click coordinates */
|
||||
struct W_View *target = NULL;
|
||||
if (fb && fb->id >= 0x20000000) {
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
extern struct W_View *W_FindViewAtPoint(struct W_View *parent, int x, int y);
|
||||
W_View *toplevel = W_GetViewForWindow((unsigned long)fb->id);
|
||||
if (toplevel) {
|
||||
target = W_FindViewAtPoint(toplevel,
|
||||
wev.u.button.x, wev.u.button.y);
|
||||
if (!target)
|
||||
target = toplevel;
|
||||
}
|
||||
}
|
||||
W_WL_EnqueueEvent(wmscr, &wev, target);
|
||||
}
|
||||
|
||||
wlr_seat_pointer_notify_button(wl_state.seat, ev->time_msec,
|
||||
|
|
|
|||
Loading…
Reference in New Issue