From: Alexandros Frantzis alexandros.frantzis@collabora.com
Pointer confinement may only be enabled by the compositor if the pointer enters the confine region. If the region is small (as in many mouselook cases) it's very likely that this will never happen and the pointer will remained unconfined.
To allow mouselook to work more reliably, prefer to lock the pointer if the confine area is smaller than the client area and the cursor is not visible. --- dlls/winewayland.drv/wayland_pointer.c | 74 +++++++++++++++++++++++--- dlls/winewayland.drv/waylanddrv.h | 1 + 2 files changed, 68 insertions(+), 7 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index 1e256b0defb..388e7dcb0cd 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -39,6 +39,7 @@ enum wayland_pointer_constraint { WAYLAND_POINTER_CONSTRAINT_NONE = 0, WAYLAND_POINTER_CONSTRAINT_CONFINE, + WAYLAND_POINTER_CONSTRAINT_MAYBE_LOCK, };
static HWND wayland_pointer_get_focused_hwnd(void) @@ -344,6 +345,11 @@ void wayland_pointer_deinit(void) zwp_confined_pointer_v1_destroy(pointer->zwp_confined_pointer_v1); pointer->zwp_confined_pointer_v1 = NULL; } + if (pointer->zwp_locked_pointer_v1) + { + zwp_locked_pointer_v1_destroy(pointer->zwp_locked_pointer_v1); + pointer->zwp_locked_pointer_v1 = NULL; + } if (pointer->zwp_relative_pointer_v1) { zwp_relative_pointer_v1_destroy(pointer->zwp_relative_pointer_v1); @@ -702,7 +708,8 @@ static enum wayland_pointer_constraint wayland_surface_calc_constraint( struct wayland_surface *surface, const RECT *clip, RECT *confine) { - RECT vscreen_rect, window_clip; + RECT vscreen_rect, window_clip, tmp; + enum wayland_pointer_constraint constraint;
/* Get individual system metrics to get coords in thread dpi * (NtUserGetVirtualScreenRect would return values in system dpi). */ @@ -739,6 +746,15 @@ static enum wayland_pointer_constraint wayland_surface_calc_constraint( return WAYLAND_POINTER_CONSTRAINT_NONE; }
+ /* If the confine rect is smaller than the client area prefer to + * lock the pointer if possible, to make the constraint easy + * to enable. */ + intersect_rect(&tmp, &window_clip, &surface->window.client_rect); + if (EqualRect(&tmp, &surface->window.client_rect)) + constraint = WAYLAND_POINTER_CONSTRAINT_CONFINE; + else + constraint = WAYLAND_POINTER_CONSTRAINT_MAYBE_LOCK; + OffsetRect(&window_clip, -surface->window.rect.left, -surface->window.rect.top); @@ -749,7 +765,7 @@ static enum wayland_pointer_constraint wayland_surface_calc_constraint( window_clip.right, window_clip.bottom, (int *)&confine->right, (int *)&confine->bottom);
- return WAYLAND_POINTER_CONSTRAINT_CONFINE; + return constraint; }
/*********************************************************************** @@ -767,6 +783,33 @@ static void wayland_pointer_update_constraint(enum wayland_pointer_constraint co struct wayland_pointer *pointer = &process_wayland.pointer; BOOL needs_relative;
+ /* Do not lock the pointer if the cursor is visible. */ + if (constraint == WAYLAND_POINTER_CONSTRAINT_MAYBE_LOCK && + pointer->cursor.wl_surface) + { + constraint = WAYLAND_POINTER_CONSTRAINT_CONFINE; + } + + if (constraint != WAYLAND_POINTER_CONSTRAINT_CONFINE && + pointer->zwp_confined_pointer_v1) + { + TRACE("Unconfining from hwnd=%p\n", pointer->constraint_hwnd); + zwp_confined_pointer_v1_destroy(pointer->zwp_confined_pointer_v1); + pointer->zwp_confined_pointer_v1 = NULL; + if (constraint == WAYLAND_POINTER_CONSTRAINT_NONE) + pointer->constraint_hwnd = NULL; + } + + if (constraint != WAYLAND_POINTER_CONSTRAINT_MAYBE_LOCK && + pointer->zwp_locked_pointer_v1) + { + TRACE("Unlocking from hwnd=%p\n", pointer->constraint_hwnd); + zwp_locked_pointer_v1_destroy(pointer->zwp_locked_pointer_v1); + pointer->zwp_locked_pointer_v1 = NULL; + if (constraint == WAYLAND_POINTER_CONSTRAINT_NONE) + pointer->constraint_hwnd = NULL; + } + if (constraint == WAYLAND_POINTER_CONSTRAINT_CONFINE) { HWND hwnd; @@ -809,12 +852,29 @@ static void wayland_pointer_update_constraint(enum wayland_pointer_constraint co
wl_region_destroy(region); } - else if (pointer->zwp_confined_pointer_v1) + else if (constraint == WAYLAND_POINTER_CONSTRAINT_MAYBE_LOCK) { - TRACE("Unconfining from hwnd=%p\n", pointer->constraint_hwnd); - zwp_confined_pointer_v1_destroy(pointer->zwp_confined_pointer_v1); - pointer->zwp_confined_pointer_v1 = NULL; - pointer->constraint_hwnd = NULL; + HWND hwnd; + + assert(wl_surface); + assert(confine_rect); + + hwnd = wl_surface_get_user_data(wl_surface); + + if (!pointer->zwp_locked_pointer_v1 || pointer->constraint_hwnd != hwnd) + { + if (pointer->zwp_locked_pointer_v1) + zwp_locked_pointer_v1_destroy(pointer->zwp_locked_pointer_v1); + pointer->zwp_locked_pointer_v1 = + zwp_pointer_constraints_v1_lock_pointer( + process_wayland.zwp_pointer_constraints_v1, + wl_surface, + pointer->wl_pointer, + NULL, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + pointer->constraint_hwnd = hwnd; + TRACE("Locking to hwnd=%p\n", pointer->constraint_hwnd); + } }
needs_relative = !pointer->cursor.wl_surface && diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 8a8a4fe798b..c6db31369b2 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -92,6 +92,7 @@ struct wayland_pointer { struct wl_pointer *wl_pointer; struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1; + struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1; struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1; HWND focused_hwnd; HWND constraint_hwnd;