wayland: Implement the pointer warp protocol

The pointer warp protocol allows us to warp the pointer to a different position on
the surface, without any hacks like locking and unlocking the pointer.
This commit is contained in:
Xaver Hugl
2024-09-22 18:49:27 +02:00
committed by Frank Praznik
parent 558a89fdb6
commit ec1297199e
4 changed files with 119 additions and 30 deletions

View File

@@ -38,6 +38,7 @@
#include "cursor-shape-v1-client-protocol.h"
#include "pointer-constraints-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "pointer-warp-v1-client-protocol.h"
#include "../../SDL_hints_c.h"
@@ -832,43 +833,50 @@ void Wayland_SeatWarpMouse(SDL_WaylandSeat *seat, SDL_WindowData *window, float
SDL_VideoData *d = vd->internal;
if (seat->pointer.wl_pointer) {
bool toggle_lock = !seat->pointer.locked_pointer;
bool update_grabs = false;
if (d->wp_pointer_warp_v1) {
// It's a protocol error to warp the pointer outside of the surface, so clamp the position.
const wl_fixed_t f_x = wl_fixed_from_double(SDL_clamp(x / window->pointer_scale.x, 0, window->current.logical_width));
const wl_fixed_t f_y = wl_fixed_from_double(SDL_clamp(y / window->pointer_scale.y, 0, window->current.logical_height));
wp_pointer_warp_v1_warp_pointer(d->wp_pointer_warp_v1, window->surface, seat->pointer.wl_pointer, f_x, f_y, seat->pointer.enter_serial);
} else {
bool toggle_lock = !seat->pointer.locked_pointer;
bool update_grabs = false;
/* The pointer confinement protocol allows setting a hint to warp the pointer,
* but only when the pointer is locked.
*
* Lock the pointer, set the position hint, unlock, and hope for the best.
*/
if (toggle_lock) {
if (seat->pointer.confined_pointer) {
zwp_confined_pointer_v1_destroy(seat->pointer.confined_pointer);
seat->pointer.confined_pointer = NULL;
update_grabs = true;
/* The pointer confinement protocol allows setting a hint to warp the pointer,
* but only when the pointer is locked.
*
* Lock the pointer, set the position hint, unlock, and hope for the best.
*/
if (toggle_lock) {
if (seat->pointer.confined_pointer) {
zwp_confined_pointer_v1_destroy(seat->pointer.confined_pointer);
seat->pointer.confined_pointer = NULL;
update_grabs = true;
}
seat->pointer.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints, window->surface,
seat->pointer.wl_pointer, NULL,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT);
}
seat->pointer.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints, window->surface,
seat->pointer.wl_pointer, NULL,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT);
}
const wl_fixed_t f_x = wl_fixed_from_double(x / window->pointer_scale.x);
const wl_fixed_t f_y = wl_fixed_from_double(y / window->pointer_scale.y);
zwp_locked_pointer_v1_set_cursor_position_hint(seat->pointer.locked_pointer, f_x, f_y);
wl_surface_commit(window->surface);
const wl_fixed_t f_x = wl_fixed_from_double(x / window->pointer_scale.x);
const wl_fixed_t f_y = wl_fixed_from_double(y / window->pointer_scale.y);
zwp_locked_pointer_v1_set_cursor_position_hint(seat->pointer.locked_pointer, f_x, f_y);
wl_surface_commit(window->surface);
if (toggle_lock) {
zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer);
seat->pointer.locked_pointer = NULL;
if (toggle_lock) {
zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer);
seat->pointer.locked_pointer = NULL;
if (update_grabs) {
Wayland_SeatUpdatePointerGrab(seat);
if (update_grabs) {
Wayland_SeatUpdatePointerGrab(seat);
}
}
}
/* NOTE: There is a pending warp event under discussion that should replace this when available.
* https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/340
*/
SDL_SendMouseMotion(0, window->sdlwindow, seat->pointer.sdl_id, false, x, y);
/* NOTE: There is a pending warp event under discussion that should replace this when available.
* https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/340
*/
SDL_SendMouseMotion(0, window->sdlwindow, seat->pointer.sdl_id, false, x, y);
}
}
}

View File

@@ -66,6 +66,7 @@
#include "xdg-shell-client-protocol.h"
#include "xdg-toplevel-icon-v1-client-protocol.h"
#include "color-management-v1-client-protocol.h"
#include "pointer-warp-v1-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@@ -1311,6 +1312,8 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
} else if (SDL_strcmp(interface, "wp_color_manager_v1") == 0) {
d->wp_color_manager_v1 = wl_registry_bind(d->registry, id, &wp_color_manager_v1_interface, 1);
Wayland_InitColorManager(d);
} else if (SDL_strcmp(interface, "wp_pointer_warp_v1") == 0) {
d->wp_pointer_warp_v1 = wl_registry_bind(d->registry, id, &wp_pointer_warp_v1_interface, 1);
}
}
@@ -1620,6 +1623,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
data->wp_color_manager_v1 = NULL;
}
if (data->wp_pointer_warp_v1) {
wp_pointer_warp_v1_destroy(data->wp_pointer_warp_v1);
data->wp_pointer_warp_v1 = NULL;
}
if (data->compositor) {
wl_compositor_destroy(data->compositor);
data->compositor = NULL;

View File

@@ -65,6 +65,7 @@ struct SDL_VideoData
} shell;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct wp_pointer_warp_v1 *wp_pointer_warp_v1;
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
struct wl_data_device_manager *data_device_manager;
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;