wclient_wl: fix cross-surface motion/release during implicit grab
When a popup menu is opened during a button-held drag, the compositor changes pointer focus to the popup surface as the pointer enters it. But pointer_handle_motion always delivered events to the originally grabbed view (wlc_ptr_grab), never hit-testing inside the popup. This meant wpopupbutton.c received motion events targeted at the main button view with coordinates relative to that view, not the menu. Fix: in both pointer_handle_motion and pointer_handle_button (release), check whether the grab target is within the currently focused toplevel. If not (the pointer entered a different surface), use wlc_hit_test against wlc_ptr_focused to find the correct child view with proper local coordinates. Also enable enter/leave synthesis during grabs when target changes, so child views receive proper WME_ENTER/WME_LEAVE as the pointer moves between them across the cross-surface boundary.
This commit is contained in:
parent
d2c9a59344
commit
a63c97638d
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue