From d43ceae0813fa557ac41a2a1ebd5c0a961746586 Mon Sep 17 00:00:00 2001 From: lkn Date: Sun, 7 Jun 2026 13:33:19 +0200 Subject: [PATCH] wclient_wl: hit-test child views on pointer enter/leave during drag pointer_handle_enter always sent WME_ENTER to the toplevel root view with _view_target=NULL, so child views (e.g. menuView) never received proper WME_ENTER with correct local coordinates when the pointer entered the popup surface during a held drag. Fix: hit-test against the newly-focused toplevel on enter, find the deepest child at the pointer position, and deliver WME_ENTER to that child view with proper local coordinates and _view_target set. Also fix pointer_handle_leave to deliver WME_LEAVE to the deepest child (via wlc_ptr_child_focus) instead of the toplevel root view, matching the enter side. --- WINGs/wclient_wl.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/WINGs/wclient_wl.c b/WINGs/wclient_wl.c index 78f86a0..260e0ac 100644 --- a/WINGs/wclient_wl.c +++ b/WINGs/wclient_wl.c @@ -711,18 +711,27 @@ pointer_handle_enter(void *data, struct wl_pointer *p, uint32_t serial, wlc_ptr_y = wl_fixed_to_double(sy); if (!wlc_ptr_focused) return; + /* Hit-test to find the deepest child view at the enter point, + * consistent with motion handling. This ensures popup child views + * (e.g. menuView) receive proper WME_ENTER with correct local + * coordinates during drag-selection. */ + int hit_lx, hit_ly; + W_View *hit = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, + (int)wlc_ptr_y, &hit_lx, &hit_ly); + wlc_ptr_child_focus = hit; + WMEvent ev; memset(&ev, 0, sizeof(ev)); ev.type = WME_ENTER; - ev.window = wlc_ptr_focused->view->window; + ev.window = hit ? hit->window : wlc_ptr_focused->view->window; ev.u.crossing.window = ev.window; - ev.u.crossing.x = (int)wlc_ptr_x; - ev.u.crossing.y = (int)wlc_ptr_y; + ev.u.crossing.x = hit_lx; + ev.u.crossing.y = hit_ly; ev.u.crossing.x_root = (int)wlc_ptr_x; ev.u.crossing.y_root = (int)wlc_ptr_y; ev.u.crossing.mode = WM_NOTIFY_NORMAL; ev.u.crossing.detail = WM_NOTIFY_ANCESTOR; - W_WL_EnqueueEvent(ctx->scr, &ev, NULL); + W_WL_EnqueueEvent(ctx->scr, &ev, hit); } static void @@ -736,11 +745,15 @@ pointer_handle_leave(void *data, struct wl_pointer *p, uint32_t serial, WMEvent ev; memset(&ev, 0, sizeof(ev)); ev.type = WME_LEAVE; - ev.window = wlc_ptr_focused->view->window; + /* Deliver leave to the deepest child that was under the pointer, + * consistent with the child that received the matching enter. */ + ev.window = wlc_ptr_child_focus + ? wlc_ptr_child_focus->window + : wlc_ptr_focused->view->window; ev.u.crossing.window = ev.window; ev.u.crossing.mode = WM_NOTIFY_NORMAL; ev.u.crossing.detail = WM_NOTIFY_ANCESTOR; - W_WL_EnqueueEvent(ctx->scr, &ev, NULL); + W_WL_EnqueueEvent(ctx->scr, &ev, wlc_ptr_child_focus); wlc_ptr_focused = NULL; wlc_ptr_child_focus = NULL; }