From 235e4870af091ea7e3814ee2dbdb8e2ec627aaf0 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Thu, 9 Oct 2025 09:48:22 -0400
Subject: [PATCH] wayland: Special-case relative warp mode to deliver
accelerated relative motion
The Wayland backend lacks pointer warp functionality, so special-case the relative warp mode hint to deliver accelerated relative motion deltas, which is ultimately what the client wants by enabling this hint.
---
src/events/SDL_mouse.c | 9 +++++++++
src/video/wayland/SDL_waylandevents.c | 23 ++++++++++++++---------
src/video/wayland/SDL_waylandmouse.c | 3 +++
src/video/wayland/SDL_waylandvideo.h | 1 +
4 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index a9a89f63d82b1..3eec659ede5e5 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -1121,6 +1121,15 @@ int SDL_WarpMouseGlobal(int x, int y)
static SDL_bool ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
{
+#ifdef SDL_VIDEO_DRIVER_WAYLAND
+ SDL_VideoDevice *vid = SDL_GetVideoDevice();
+
+ /* Wayland can't warp the mouse, but uses this hint internally to deliver accelerated motion */
+ if (SDL_strcmp(vid->name, "wayland") == 0) {
+ return SDL_FALSE;
+ }
+#endif
+
if (!mouse->WarpMouse) {
/* Need this functionality for relative mode warp implementation */
return SDL_FALSE;
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 496bb5e8feba6..189798a91e21e 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -2681,23 +2681,28 @@ static void relative_pointer_handle_relative_motion(void *data,
struct SDL_WaylandInput *input = data;
SDL_VideoData *d = input->display;
SDL_WindowData *window = input->pointer_focus;
- double dx_unaccel;
- double dy_unaccel;
double dx;
double dy;
+ double dx_mod;
+ double dy_mod;
- dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
- dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
+ if (!d->relative_mode_accelerated) {
+ dx = wl_fixed_to_double(dx_unaccel_w);
+ dy = wl_fixed_to_double(dy_unaccel_w);
+ } else {
+ dx = wl_fixed_to_double(dx_w) * (window ? window->pointer_scale_x : 1.0);
+ dy = wl_fixed_to_double(dy_w) * (window ? window->pointer_scale_y : 1.0);
+ }
/* Add left over fraction from last event. */
- dx_unaccel += input->dx_frac;
- dy_unaccel += input->dy_frac;
+ dx += input->dx_frac;
+ dy += input->dy_frac;
- input->dx_frac = modf(dx_unaccel, &dx);
- input->dy_frac = modf(dy_unaccel, &dy);
+ input->dx_frac = modf(dx, &dx_mod);
+ input->dy_frac = modf(dy, &dy_mod);
if (input->pointer_focus && d->relative_mouse_mode) {
- SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
+ SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx_mod, (int)dy_mod);
}
}
diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c
index bf1bf9b8d36a1..89fb301d18abc 100644
--- a/src/video/wayland/SDL_waylandmouse.c
+++ b/src/video/wayland/SDL_waylandmouse.c
@@ -537,6 +537,9 @@ static int Wayland_SetRelativeMouseMode(SDL_bool enabled)
SDL_VideoData *data = (SDL_VideoData *)vd->driverdata;
if (enabled) {
+ /* Clients use relative warp mode to get accelerated motion deltas, which Wayland delivers internally. */
+ data->relative_mode_accelerated = SDL_GetHintBoolean(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, SDL_FALSE);
+
/* Disable mouse warp emulation if it's enabled. */
if (data->input->relative_mode_override) {
data->input->relative_mode_override = SDL_FALSE;
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index 13e9b35ee8ea4..c8464f397ae41 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -101,6 +101,7 @@ typedef struct
char *classname;
int relative_mouse_mode;
+ int relative_mode_accelerated;
SDL_bool egl_transparency_enabled;
} SDL_VideoData;