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 | 59 +++++++++++++++++++++++--- dlls/winewayland.drv/wayland_surface.c | 14 +++++- dlls/winewayland.drv/waylanddrv.h | 2 + 3 files changed, 68 insertions(+), 7 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index fdae170e529..741ebfc750d 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -338,6 +338,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); @@ -698,6 +703,33 @@ void wayland_pointer_update_constraint(enum wayland_pointer_constraint constrain 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; @@ -740,12 +772,29 @@ void wayland_pointer_update_constraint(enum wayland_pointer_constraint constrain
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/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 7b42da1f738..6a75bce9a6b 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -910,7 +910,8 @@ void wayland_surface_ensure_contents(struct wayland_surface *surface) 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). */ @@ -947,6 +948,15 @@ enum wayland_pointer_constraint wayland_surface_calc_constraint(struct wayland_s 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); @@ -957,5 +967,5 @@ enum wayland_pointer_constraint wayland_surface_calc_constraint(struct wayland_s window_clip.right, window_clip.bottom, (int *)&confine->right, (int *)&confine->bottom);
- return WAYLAND_POINTER_CONSTRAINT_CONFINE; + return constraint; } diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index b1a178d92b1..48cfd56bd9e 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -75,6 +75,7 @@ enum wayland_pointer_constraint { WAYLAND_POINTER_CONSTRAINT_NONE = 0, WAYLAND_POINTER_CONSTRAINT_CONFINE, + WAYLAND_POINTER_CONSTRAINT_MAYBE_LOCK };
struct wayland_keyboard @@ -98,6 +99,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;