WINGs/wclient_wl: implement implicit pointer grab for drag operations
On X11, a button press creates an implicit pointer grab — all subsequent motion and release events go to the window that received the press, even if the pointer moves outside it. This is essential for scroller knob dragging, window resize handles, etc. Implement the same for Wayland client: on button press, record the target view as wlc_ptr_grab. Motion events during the grab are delivered to the grabbed view with coordinates translated relative to it. On button release, deliver to the grabbed view and clear the grab. Enter/leave synthesis is suppressed during grabs.
This commit is contained in:
parent
d6767530e4
commit
7efede0274
|
|
@ -544,6 +544,7 @@ 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;
|
||||
static W_View *wlc_ptr_grab; /* implicit grab: deliver events here while button held */
|
||||
|
||||
/*
|
||||
* Hit-test: find the deepest child view at (x,y) relative to the toplevel,
|
||||
|
|
@ -640,10 +641,24 @@ pointer_handle_motion(void *data, struct wl_pointer *p, uint32_t time,
|
|||
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);
|
||||
W_View *target;
|
||||
|
||||
/* During implicit grab (button held), deliver to grabbed view */
|
||||
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;
|
||||
}
|
||||
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 (target != wlc_ptr_child_focus) {
|
||||
if (!wlc_ptr_grab && target != wlc_ptr_child_focus) {
|
||||
if (wlc_ptr_child_focus) {
|
||||
WMEvent lev;
|
||||
memset(&lev, 0, sizeof(lev));
|
||||
|
|
@ -717,7 +732,28 @@ pointer_handle_button(void *data, struct wl_pointer *p, uint32_t serial,
|
|||
? WME_BUTTON_PRESS : WME_BUTTON_RELEASE;
|
||||
|
||||
int lx, ly;
|
||||
W_View *target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly);
|
||||
W_View *target;
|
||||
|
||||
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
wlc_ptr_grab = NULL;
|
||||
}
|
||||
|
||||
ev.window = target ? target->window : wlc_ptr_focused->view->window;
|
||||
ev.u.button.window = ev.window;
|
||||
|
|
|
|||
Loading…
Reference in New Issue