diff --git a/WINGs/wclient_wl.c b/WINGs/wclient_wl.c index 508805d..78f86a0 100644 --- a/WINGs/wclient_wl.c +++ b/WINGs/wclient_wl.c @@ -758,22 +758,39 @@ pointer_handle_motion(void *data, struct wl_pointer *p, uint32_t time, int lx, ly; W_View *target; - /* During implicit grab (button held), deliver to grabbed view */ + /* During implicit grab (button held), deliver to grabbed view. + * If the pointer has entered a different toplevel surface (e.g. a + * popup menu opened during the drag), hit-test against the focused + * surface instead so motion events reach the correct child view + * (e.g. menuView) with proper local coordinates. */ if (wlc_ptr_grab) { - target = wlc_ptr_grab; - int ox = 0, oy = 0; - for (W_View *v = target; v && v != wlc_ptr_focused->view; v = v->parent) { - ox += v->pos.x; - oy += v->pos.y; + /* Check if grab target is within the currently focused toplevel */ + int grab_in_focused = 0; + for (W_View *v = wlc_ptr_grab; v; v = v->parent) { + if (v == wlc_ptr_focused->view) { + grab_in_focused = 1; + break; + } + } + if (grab_in_focused) { + target = wlc_ptr_grab; + int ox = 0, oy = 0; + for (W_View *v = target; v && v != wlc_ptr_focused->view; v = v->parent) { + ox += v->pos.x; + oy += v->pos.y; + } + lx = (int)wlc_ptr_x - ox; + ly = (int)wlc_ptr_y - oy; + } else { + /* Pointer entered a different toplevel — hit-test there */ + target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly); } - lx = (int)wlc_ptr_x - ox; - ly = (int)wlc_ptr_y - oy; } else { 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 (!wlc_ptr_grab && target != wlc_ptr_child_focus) { + if (target != wlc_ptr_child_focus) { if (wlc_ptr_child_focus) { WMEvent lev; memset(&lev, 0, sizeof(lev)); @@ -859,17 +876,29 @@ pointer_handle_button(void *data, struct wl_pointer *p, uint32_t serial, target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly); wlc_ptr_grab = target; } else { - /* Deliver release to the grabbed view */ + /* Deliver release to the grabbed view. If the pointer has moved + * to a different toplevel (e.g. popup menu), hit-test there. */ target = wlc_ptr_grab; if (target) { - /* Compute local coords relative to grabbed view */ - int ox = 0, oy = 0; - for (W_View *v = target; v && v != wlc_ptr_focused->view; v = v->parent) { - ox += v->pos.x; - oy += v->pos.y; + int grab_in_focused = 0; + for (W_View *v = target; v; v = v->parent) { + if (v == wlc_ptr_focused->view) { + grab_in_focused = 1; + break; + } + } + if (grab_in_focused) { + int ox = 0, oy = 0; + for (W_View *v = target; v && v != wlc_ptr_focused->view; v = v->parent) { + ox += v->pos.x; + oy += v->pos.y; + } + lx = (int)wlc_ptr_x - ox; + ly = (int)wlc_ptr_y - oy; + } else { + /* Release on a different surface — hit-test there */ + target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly); } - lx = (int)wlc_ptr_x - ox; - ly = (int)wlc_ptr_y - oy; } else { target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly); }