If a surface is being clipped and hides the cursor, drawing its own one, winewayland constrains using a pointer lock and enables Wayland relative motion. If the application decides to stop drawing its own cursor and make the cursor visible, winewayland will disable relative motion and pointer lock, and enable pointer confinement. The user will perceive a pointer jump from the win32/application drawn cursor to where the Wayland pointer is after being unlocked and an absolute motion event is received, because they were desynchronized due to the Wayland one being locked in place.
The pointer constraints protocol says this:
If the client is drawing its own cursor, it should update the position hint to the position of its own cursor. A compositor may use this information to warp the pointer upon unlock in order to avoid pointer jumps.
So, right before unlocking, make a request for the compositor to warp the pointer to the win32 position on pointer unlock.
-- v4: winewayland: Update locked pointer position hint.
From: Attila Fidan dev@print0.net
This may be used by the compositor to warp the Wayland pointer to where the win32 cursor is upon unlock, if it's within surface bounds. --- dlls/winewayland.drv/wayland_pointer.c | 30 ++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index c20ba170285..52aaa337aac 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -885,27 +885,53 @@ void WAYLAND_SetCursor(HWND hwnd, HCURSOR hcursor) BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset) { struct wayland_pointer *pointer = &process_wayland.pointer; + HWND hwnd; struct wl_surface *wl_surface = NULL; struct wayland_surface *surface = NULL; struct wayland_win_data *data; BOOL covers_vscreen = FALSE; RECT confine_rect; + POINT cursor_pos; + int warp_x, warp_y;
TRACE("clip=%s reset=%d\n", wine_dbgstr_rect(clip), reset);
- if (!(data = wayland_win_data_get(NtUserGetForegroundWindow()))) return FALSE; + NtUserGetCursorPos(&cursor_pos); + hwnd = NtUserGetForegroundWindow(); + + if (!(data = wayland_win_data_get(hwnd))) return FALSE; if ((surface = data->wayland_surface)) { wl_surface = surface->wl_surface; if (clip) wayland_surface_calc_confine(surface, clip, &confine_rect); covers_vscreen = wayland_surface_client_covers_vscreen(surface); + wayland_surface_coords_from_window(surface, + cursor_pos.x - surface->window.rect.left, + cursor_pos.y - surface->window.rect.top, + &warp_x, &warp_y); } wayland_win_data_release(data);
+ pthread_mutex_lock(&pointer->mutex); + if (wl_surface && hwnd == pointer->constraint_hwnd && pointer->zwp_locked_pointer_v1) + { + zwp_locked_pointer_v1_set_cursor_position_hint( + pointer->zwp_locked_pointer_v1, + wl_fixed_from_int(warp_x), + wl_fixed_from_int(warp_y)); + pthread_mutex_unlock(&pointer->mutex); + + data = wayland_win_data_get(hwnd); + wl_surface_commit(wl_surface); + wayland_win_data_release(data); + TRACE("position hint hwnd=%p wayland_xy=%d,%d screen_xy=%d,%d\n", + hwnd, warp_x, warp_y, (int)cursor_pos.x, (int)cursor_pos.y); + pthread_mutex_lock(&pointer->mutex); + } + /* Since we are running in the context of the foreground thread we know * that the wl_surface of the foreground HWND will not be invalidated, * so we can access it without having the win data lock. */ - pthread_mutex_lock(&pointer->mutex); wayland_pointer_update_constraint(wl_surface, (clip && wl_surface) ? &confine_rect : NULL, covers_vscreen);
On Tue Feb 25 15:00:14 2025 +0000, Attila Fidan wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/7352/diffs?diff_id=160261&start_sha=dd8f47585bff4ac9b303d39af3bd0fb2e9e87e4b#ed873a9226289213ee847a41e40cf5b866d6cd6d_57_49)
Right, I think I used this function directly in the relative motion handler at first but it's not needed.
On Tue Feb 25 15:00:14 2025 +0000, Attila Fidan wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/7352/diffs?diff_id=160261&start_sha=dd8f47585bff4ac9b303d39af3bd0fb2e9e87e4b#ed873a9226289213ee847a41e40cf5b866d6cd6d_332_275)
I dropped this as I don't really care about the position on user-triggered unlock.
This merge request was approved by Alexandros Frantzis.