From: Zakaria Habri <zakaria.habri@gmail.com> The existing implementation abuses zwp_locked_pointer_v1's set_cursor_position_hint side effect: it briefly locks the pointer, sets the hint, then unlocks. The compositor clamps the position hint to locked-surface bounds, so warps targeted outside that area are silently dropped, and the lock/unlock cycle has subtle side effects. wp_pointer_warp_v1 (staging in wayland-protocols 1.45) provides a direct primitive that does not require pointer locking. When the compositor advertises the global and we have a recent enter serial, prefer it; otherwise fall back to the existing workaround. --- dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/pointer-warp-v1.xml | 72 ++++++++++++++++++++++++ dlls/winewayland.drv/wayland.c | 5 ++ dlls/winewayland.drv/wayland_pointer.c | 16 +++++- dlls/winewayland.drv/waylanddrv.h | 2 + 5 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 dlls/winewayland.drv/pointer-warp-v1.xml diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 1f1b2ccf8af..cbc49823cd6 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -12,6 +12,7 @@ SOURCES = \ dllmain.c \ opengl.c \ pointer-constraints-unstable-v1.xml \ + pointer-warp-v1.xml \ relative-pointer-unstable-v1.xml \ text-input-unstable-v3.xml \ viewporter.xml \ diff --git a/dlls/winewayland.drv/pointer-warp-v1.xml b/dlls/winewayland.drv/pointer-warp-v1.xml new file mode 100644 index 00000000000..158dad83c5d --- /dev/null +++ b/dlls/winewayland.drv/pointer-warp-v1.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="pointer_warp_v1"> + <copyright> + Copyright © 2024 Neal Gompa + Copyright © 2024 Xaver Hugl + Copyright © 2024 Matthias Klumpp + Copyright © 2024 Vlad Zahorodnii + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + </copyright> + + <interface name="wp_pointer_warp_v1" version="1"> + <description summary="reposition the pointer to a location on a surface"> + This global interface allows applications to request the pointer to be + moved to a position relative to a wl_surface. + + Note that if the desired behavior is to constrain the pointer to an area + or lock it to a position, this protocol does not provide a reliable way + to do that. The pointer constraint and pointer lock protocols should be + used for those use cases instead. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the warp manager"> + Destroy the pointer warp manager. + </description> + </request> + + <request name="warp_pointer"> + <description summary="reposition the pointer"> + Request the compositor to move the pointer to a surface-local position. + Whether or not the compositor honors the request is implementation defined, + but it should + - honor it if the surface has pointer focus, including + when it has an implicit pointer grab + - reject it if the enter serial is incorrect + - reject it if the requested position is outside of the surface + + Note that the enter serial is valid for any surface of the client, + and does not have to be from the surface the pointer is warped to. + + </description> + <arg name="surface" type="object" interface="wl_surface" + summary="surface to position the pointer on"/> + <arg name="pointer" type="object" interface="wl_pointer" + summary="the pointer that should be repositioned"/> + <arg name="x" type="fixed"/> + <arg name="y" type="fixed"/> + <arg name="serial" type="uint" summary="serial number of the enter event"/> + </request> + </interface> +</protocol> diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index b164210adf0..b3d6b3c89e7 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -200,6 +200,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, wl_registry_bind(registry, id, &wp_cursor_shape_manager_v1_interface, version < 2 ? version : 2); } + else if (strcmp(interface, "wp_pointer_warp_v1") == 0) + { + process_wayland.wp_pointer_warp_v1 = + wl_registry_bind(registry, id, &wp_pointer_warp_v1_interface, 1); + } } static void registry_handle_global_remove(void *data, struct wl_registry *registry, diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index fb93407088a..fa7bb54b160 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -1070,7 +1070,21 @@ BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset) pthread_mutex_lock(&pointer->mutex); if (wl_surface && pointer->pending_warp) { - wayland_pointer_update_constraint(wl_surface, NULL, FALSE, TRUE); + if (process_wayland.wp_pointer_warp_v1) + { + wp_pointer_warp_v1_warp_pointer(process_wayland.wp_pointer_warp_v1, + wl_surface, + pointer->wl_pointer, + wl_fixed_from_int(warp_x), + wl_fixed_from_int(warp_y), + pointer->enter_serial); + TRACE("warp_pointer hwnd=%p wayland_xy=%d,%d screen_xy=%d,%d\n", + hwnd, warp_x, warp_y, cursor_pos.x, cursor_pos.y); + } + else + { + wayland_pointer_update_constraint(wl_surface, NULL, FALSE, TRUE); + } pointer->pending_warp = FALSE; } diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 110db8ba0c4..5f4bd6a7cf6 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -38,6 +38,7 @@ #include "xdg-shell-client-protocol.h" #include "wlr-data-control-unstable-v1-client-protocol.h" #include "xdg-toplevel-icon-v1-client-protocol.h" +#include "pointer-warp-v1-client-protocol.h" #include "windef.h" #include "winbase.h" @@ -178,6 +179,7 @@ struct wayland struct wl_data_device_manager *wl_data_device_manager; struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1; struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1; + struct wp_pointer_warp_v1 *wp_pointer_warp_v1; struct wayland_seat seat; struct wayland_keyboard keyboard; struct wayland_pointer pointer; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10830