Skip to content

Commit 794ff28

Browse files
committed
Added support for using XTest to warp the mouse
1 parent fae324d commit 794ff28

10 files changed

+159
-6
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ dep_option(SDL_X11_XRANDR "Enable Xrandr support" "${SDL_X11_XRANDR_DEF
357357
dep_option(SDL_X11_XSCRNSAVER "Enable Xscrnsaver support" ON SDL_X11 OFF)
358358
dep_option(SDL_X11_XSHAPE "Enable XShape support" ON SDL_X11 OFF)
359359
dep_option(SDL_X11_XSYNC "Enable Xsync support" ON SDL_X11 OFF)
360+
dep_option(SDL_X11_XTEST "Enable XTest support" ON SDL_X11 OFF)
360361
dep_option(SDL_WAYLAND "Use Wayland video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
361362
dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND;SDL_DEPS_SHARED" OFF)
362363
dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF)

cmake/sdlchecks.cmake

+13-1
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,11 @@ macro(CheckX11)
274274
set(Xrandr_PKG_CONFIG_SPEC xrandr)
275275
set(Xrender_PKG_CONFIG_SPEC xrender)
276276
set(Xss_PKG_CONFIG_SPEC xscrnsaver)
277+
set(Xtst_PKG_CONFIG_SPEC xtst)
277278

278279
find_package(X11)
279280

280-
foreach(_LIB X11 Xext Xcursor Xi Xfixes Xrandr Xrender Xss)
281+
foreach(_LIB X11 Xext Xcursor Xi Xfixes Xrandr Xrender Xss Xtst)
281282
get_filename_component(_libdir "${X11_${_LIB}_LIB}" DIRECTORY)
282283
FindLibraryAndSONAME("${_LIB}" LIBDIRS ${_libdir})
283284
endforeach()
@@ -310,6 +311,7 @@ macro(CheckX11)
310311
find_file(HAVE_XSYNC_H NAMES "X11/extensions/sync.h" HINTS "${X11_INCLUDEDIR}")
311312
find_file(HAVE_XSS_H NAMES "X11/extensions/scrnsaver.h" HINTS "${X11_INCLUDEDIR}")
312313
find_file(HAVE_XSHAPE_H NAMES "X11/extensions/shape.h" HINTS "${X11_INCLUDEDIR}")
314+
find_file(HAVE_XTEST_H NAMES "X11/extensions/XTest.h" HINTS "${X11_INCLUDEDIR}")
313315
find_file(HAVE_XDBE_H NAMES "X11/extensions/Xdbe.h" HINTS "${X11_INCLUDEDIR}")
314316
find_file(HAVE_XEXT_H NAMES "X11/extensions/Xext.h" HINTS "${X11_INCLUDEDIR}")
315317

@@ -472,6 +474,16 @@ macro(CheckX11)
472474
set(SDL_VIDEO_DRIVER_X11_XSHAPE 1)
473475
set(HAVE_X11_XSHAPE TRUE)
474476
endif()
477+
478+
if(SDL_X11_XTEST AND HAVE_XTEST_H AND XTST_LIB)
479+
if(HAVE_X11_SHARED)
480+
set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST "\"${XTST_LIB_SONAME}\"")
481+
else()
482+
sdl_link_dependency(xtst LIBS X11::Xtst CMAKE_MODULE X11 PKG_CONFIG_SPECS ${Xtst_PKG_CONFIG_SPEC})
483+
endif()
484+
set(SDL_VIDEO_DRIVER_X11_XTEST 1)
485+
set(HAVE_X11_XTEST TRUE)
486+
endif()
475487
endif()
476488
endif()
477489
if(NOT HAVE_X11)

docs/README-linux.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Ubuntu 18.04, all available features enabled:
1717
sudo apt-get install build-essential git make \
1818
pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
1919
libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
20-
libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
20+
libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev \
2121
libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
2222
libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev
2323

@@ -46,7 +46,7 @@ openSUSE Tumbleweed:
4646
libgbm-devel pipewire-devel libpulse-devel sndio-devel Mesa-libEGL-devel
4747

4848
Arch:
49-
sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols
49+
sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss libxtst mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols
5050

5151

5252
Joystick does not work

include/build_config/SDL_build_config.h.cmake

+2
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@
390390
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2@
391391
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR@
392392
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS @SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS@
393+
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST @SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST@
393394
#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM 1
394395
#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1
395396
#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR 1
@@ -401,6 +402,7 @@
401402
#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1
402403
#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE 1
403404
#cmakedefine SDL_VIDEO_DRIVER_X11_XSYNC 1
405+
#cmakedefine SDL_VIDEO_DRIVER_X11_XTEST 1
404406
#cmakedefine SDL_VIDEO_DRIVER_QNX 1
405407

406408
#cmakedefine SDL_VIDEO_RENDER_D3D 1

src/video/x11/SDL_x11dyn.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ typedef struct
5656
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
5757
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS NULL
5858
#endif
59+
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST
60+
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST NULL
61+
#endif
5962

6063
static x11dynlib x11libs[] = {
6164
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC },
@@ -64,7 +67,8 @@ static x11dynlib x11libs[] = {
6467
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 },
6568
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES },
6669
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR },
67-
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS }
70+
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS },
71+
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST }
6872
};
6973

7074
static void *X11_GetSym(const char *fnname, int *pHasModule)

src/video/x11/SDL_x11mouse.c

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "SDL_x11video.h"
2727
#include "SDL_x11mouse.h"
2828
#include "SDL_x11xinput2.h"
29+
#include "SDL_x11xtest.h"
2930
#include "../SDL_video_c.h"
3031
#include "../../events/SDL_mouse_c.h"
3132

@@ -367,6 +368,10 @@ static bool X11_WarpMouse(SDL_Window *window, float x, float y)
367368
{
368369
SDL_WindowData *data = window->internal;
369370

371+
if (X11_WarpMouseXTest(SDL_GetVideoDevice(), window, x, y)) {
372+
return true;
373+
}
374+
370375
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
371376
// If we have no barrier, we need to warp
372377
if (data->pointer_barrier_active == false) {
@@ -380,6 +385,10 @@ static bool X11_WarpMouse(SDL_Window *window, float x, float y)
380385

381386
static bool X11_WarpMouseGlobal(float x, float y)
382387
{
388+
if (X11_WarpMouseXTest(SDL_GetVideoDevice(), NULL, x, y)) {
389+
return true;
390+
}
391+
383392
X11_WarpMouseInternal(DefaultRootWindow(GetDisplay()), x, y);
384393
return true;
385394
}

src/video/x11/SDL_x11sym.h

+6
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ SDL_X11_SYM(Status, XSyncDestroyCounter, (Display* a, XSyncCounter b), (a, b), r
182182
SDL_X11_SYM(Status, XSyncSetCounter, (Display* a, XSyncCounter b, XSyncValue c), (a, b, c), return)
183183
#endif
184184

185+
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
186+
SDL_X11_MODULE(XTEST)
187+
SDL_X11_SYM(Status, XTestQueryExtension, (Display* a, int* b, int* c), (a, b, c), return)
188+
SDL_X11_SYM(int, XTestFakeMotionEvent, (Display* a, int b, int c, int d, unsigned long e), (a, b, c, d, e), return)
189+
#endif
190+
185191
#ifdef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
186192
SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b),(a,b),return)
187193
SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b),(a,b),)

src/video/x11/SDL_x11video.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "SDL_x11messagebox.h"
4040
#include "SDL_x11shape.h"
4141
#include "SDL_x11xsync.h"
42+
#include "SDL_x11xtest.h"
4243

4344
#ifdef SDL_VIDEO_OPENGL_EGL
4445
#include "SDL_x11opengles.h"
@@ -443,13 +444,17 @@ static bool X11_VideoInit(SDL_VideoDevice *_this)
443444

444445
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
445446
X11_InitXfixes(_this);
446-
#endif // SDL_VIDEO_DRIVER_X11_XFIXES
447+
#endif
447448

448449
X11_InitXsettings(_this);
449450

450451
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
451452
X11_InitXsync(_this);
452-
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
453+
#endif
454+
455+
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
456+
X11_InitXTest(_this);
457+
#endif
453458

454459
#ifndef X_HAVE_UTF8_STRING
455460
#warning X server does not support UTF8_STRING, a feature introduced in 2000! This is likely to become a hard error in a future libSDL3.

src/video/x11/SDL_x11xtest.c

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
Simple DirectMedia Layer
3+
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4+
5+
This software is provided 'as-is', without any express or implied
6+
warranty. In no event will the authors be held liable for any damages
7+
arising from the use of this software.
8+
9+
Permission is granted to anyone to use this software for any purpose,
10+
including commercial applications, and to alter it and redistribute it
11+
freely, subject to the following restrictions:
12+
13+
1. The origin of this software must not be misrepresented; you must not
14+
claim that you wrote the original software. If you use this software
15+
in a product, an acknowledgment in the product documentation would be
16+
appreciated but is not required.
17+
2. Altered source versions must be plainly marked as such, and must not be
18+
misrepresented as being the original software.
19+
3. This notice may not be removed or altered from any source distribution.
20+
*/
21+
22+
#include "SDL_internal.h"
23+
24+
#if defined(SDL_VIDEO_DRIVER_X11)
25+
26+
#include "SDL_x11video.h"
27+
#include "SDL_x11xtest.h"
28+
29+
static bool xtest_initialized = false;
30+
31+
void X11_InitXTest(SDL_VideoDevice *_this)
32+
{
33+
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
34+
Display *display = _this->internal->display;
35+
int event, error;
36+
int opcode;
37+
38+
if (!SDL_X11_HAVE_XTEST ||
39+
!X11_XQueryExtension(display, "XTEST", &opcode, &event, &error)) {
40+
return;
41+
}
42+
43+
xtest_initialized = true;
44+
#endif
45+
}
46+
47+
bool X11_XTestIsInitialized(void)
48+
{
49+
return xtest_initialized;
50+
}
51+
52+
bool X11_WarpMouseXTest(SDL_VideoDevice *_this, SDL_Window *window, float x, float y)
53+
{
54+
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
55+
if (!X11_XTestIsInitialized()) {
56+
return false;
57+
}
58+
59+
Display *display = _this->internal->display;
60+
SDL_DisplayData *displaydata = window ? SDL_GetDisplayDriverDataForWindow(window) : SDL_GetDisplayDriverData(SDL_GetPrimaryDisplay());
61+
if (!displaydata) {
62+
return false;
63+
}
64+
65+
int motion_x = (int)SDL_roundf(x);
66+
int motion_y = (int)SDL_roundf(y);
67+
if (window) {
68+
motion_x += window->x;
69+
motion_y += window->y;
70+
}
71+
72+
if (!X11_XTestFakeMotionEvent(display, displaydata->screen, motion_x, motion_y, CurrentTime)) {
73+
return false;
74+
}
75+
X11_XSync(display, False);
76+
77+
return true;
78+
#else
79+
return false;
80+
#endif
81+
}
82+
83+
#endif // SDL_VIDEO_DRIVER_X11

src/video/x11/SDL_x11xtest.h

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Simple DirectMedia Layer
3+
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4+
5+
This software is provided 'as-is', without any express or implied
6+
warranty. In no event will the authors be held liable for any damages
7+
arising from the use of this software.
8+
9+
Permission is granted to anyone to use this software for any purpose,
10+
including commercial applications, and to alter it and redistribute it
11+
freely, subject to the following restrictions:
12+
13+
1. The origin of this software must not be misrepresented; you must not
14+
claim that you wrote the original software. If you use this software
15+
in a product, an acknowledgment in the product documentation would be
16+
appreciated but is not required.
17+
2. Altered source versions must be plainly marked as such, and must not be
18+
misrepresented as being the original software.
19+
3. This notice may not be removed or altered from any source distribution.
20+
*/
21+
22+
#include "SDL_internal.h"
23+
24+
#ifndef SDL_x11xtest_h_
25+
#define SDL_x11xtest_h_
26+
27+
extern void X11_InitXTest(SDL_VideoDevice *_this);
28+
extern bool X11_XTestIsInitialized(void);
29+
extern bool X11_WarpMouseXTest(SDL_VideoDevice *_this, SDL_Window *window, float x, float y);
30+
31+
#endif // SDL_x11xtest_h_

0 commit comments

Comments
 (0)