From f175c2f592c764362ce31e05e568dbfffced0d93 Mon Sep 17 00:00:00 2001 From: Lu YaNing Date: Tue, 13 Jan 2026 20:43:36 +0800 Subject: [PATCH] seat/pointer: add wl_pointer.warp event support Add support for the wl_pointer.warp event from Wayland protocol version 11. https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/340 This allows the compositor to notify clients when the pointer position has changed due to surface movement or compositor action, rather than input device motion. This is useful for tracking cursor position across surface boundaries and dynamic repositioning. --- backend/wayland/pointer.c | 17 +++++++++++++++++ include/wlr/types/wlr_pointer.h | 6 +++++- include/wlr/types/wlr_seat.h | 9 +++++++++ types/seat/wlr_seat.c | 2 +- types/seat/wlr_seat_pointer.c | 22 ++++++++++++++++++++++ 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/backend/wayland/pointer.c b/backend/wayland/pointer.c index b61e32cd0..8ee79c079 100644 --- a/backend/wayland/pointer.c +++ b/backend/wayland/pointer.c @@ -211,6 +211,22 @@ static void pointer_handle_axis_relative_direction(void *data, pointer->axis_relative_direction = direction; } +static void pointer_handle_warp(void *data, struct wl_pointer *wl_pointer, + wl_fixed_t sx, wl_fixed_t sy) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_warp_event event = { + .pointer = &pointer->wlr_pointer, + .sx = wl_fixed_to_double(sx), + .sy = wl_fixed_to_double(sy), + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.warp, &event); +} + static const struct wl_pointer_listener pointer_listener = { .enter = pointer_handle_enter, .leave = pointer_handle_leave, @@ -223,6 +239,7 @@ static const struct wl_pointer_listener pointer_listener = { .axis_discrete = pointer_handle_axis_discrete, .axis_value120 = pointer_handle_axis_value120, .axis_relative_direction = pointer_handle_axis_relative_direction, + .warp = pointer_handle_warp, }; static void gesture_swipe_begin(void *data, diff --git a/include/wlr/types/wlr_pointer.h b/include/wlr/types/wlr_pointer.h index 756ffa1f6..eaa669ed5 100644 --- a/include/wlr/types/wlr_pointer.h +++ b/include/wlr/types/wlr_pointer.h @@ -34,6 +34,7 @@ struct wlr_pointer { struct wl_signal button; // struct wlr_pointer_button_event struct wl_signal axis; // struct wlr_pointer_axis_event struct wl_signal frame; + struct wl_signal warp; // struct wlr_pointer_warp_event struct wl_signal swipe_begin; // struct wlr_pointer_swipe_begin_event struct wl_signal swipe_update; // struct wlr_pointer_swipe_update_event @@ -82,7 +83,10 @@ struct wlr_pointer_axis_event { double delta; int32_t delta_discrete; }; - +struct wlr_pointer_warp_event { + struct wlr_pointer *pointer; + double sx, sy; +}; struct wlr_pointer_swipe_begin_event { struct wlr_pointer *pointer; uint32_t time_msec; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 670b4458b..84bfb5150 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -432,6 +432,15 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time_msec, */ void wlr_seat_pointer_send_frame(struct wlr_seat *wlr_seat); +/** + * Send a warp event to the surface with pointer focus. This notifies the client + * that the pointer location has changed due to surface movement or compositor + * action, rather than input device motion. Coordinates are surface-local. + * This function does not respect pointer grabs. + */ +void wlr_seat_pointer_send_warp(struct wlr_seat *wlr_seat, + double sx, double sy); + /** * Notify the seat of a pointer enter event to the given surface and request it * to be the focused surface for the pointer. Pass surface-local coordinates diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index 015a57b52..dd7db8c66 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -11,7 +11,7 @@ #include "types/wlr_seat.h" #include "util/global.h" -#define SEAT_VERSION 9 +#define SEAT_VERSION 11 static void seat_handle_get_pointer(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 41729dcd9..6e69e658a 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -410,6 +410,28 @@ void wlr_seat_pointer_send_frame(struct wlr_seat *wlr_seat) { } } +void wlr_seat_pointer_send_warp(struct wlr_seat *wlr_seat, + double sx, double sy) { + struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client; + if (client == NULL) { + return; + } + + struct wl_resource *resource; + wl_resource_for_each(resource, &client->pointers) { + if (wlr_seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + + uint32_t version = wl_resource_get_version(resource); + if (version >= 11) { // WL_POINTER_WARP_SINCE_VERSION + wl_pointer_send_warp(resource, + wl_fixed_from_double(sx), + wl_fixed_from_double(sy)); + } + } +} + void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat, struct wlr_seat_pointer_grab *grab) { assert(wlr_seat);