From 644efae8988426cc61b4b58bc018ff73387ba149 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 11 Feb 2025 13:02:28 -0800
Subject: [PATCH] Implemented SDL2_SYSWMEVENT
Fixes https://github.com/libsdl-org/sdl2-compat/issues/274
---
src/dynapi/SDL_dynapi_procs.h | 2 +-
src/sdl2_compat.c | 164 +++++++++++++++++++++++-----------
src/sdl2_compat.h | 33 ++++++-
src/sdl2_protos.h | 2 +-
src/sdl3_syms.h | 1 +
5 files changed, 147 insertions(+), 55 deletions(-)
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 3e045d97..023964f0 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -495,7 +495,7 @@ SDL_DYNAPI_PROC(int,SDL_LowerBlit,(SDL2_Surface *a, SDL_Rect *b, SDL2_Surface *c
SDL_DYNAPI_PROC(int,SDL_SoftStretch,(SDL2_Surface *a, const SDL_Rect *b, SDL2_Surface *c, const SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_UpperBlitScaled,(SDL2_Surface *a, const SDL_Rect *b, SDL2_Surface *c, SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_LowerBlitScaled,(SDL2_Surface *a, SDL_Rect *b, SDL2_Surface *c, SDL_Rect *d),(a,b,c,d),return)
-SDL_DYNAPI_PROC(SDL2_bool,SDL_GetWindowWMInfo,(SDL_Window *a, SDL_SysWMinfo *b),(a,b),return)
+SDL_DYNAPI_PROC(SDL2_bool,SDL_GetWindowWMInfo,(SDL_Window *a, SDL2_SysWMinfo *b),(a,b),return)
SDL_DYNAPI_PROC(const char*,SDL_GetThreadName,(SDL_Thread *a),(a),return)
SDL_DYNAPI_PROC(unsigned long,SDL_ThreadID,(void),(),return)
SDL_DYNAPI_PROC(unsigned long,SDL_GetThreadID,(SDL_Thread *a),(a),return)
diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index 02686d03..51e5da51 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -100,7 +100,7 @@ This breaks the build when creating SDL_ ## DisableScreenSaver
#include <unistd.h> /* for readlink() */
#endif
-#if defined(__unix__) || defined(__APPLE__)
+#if defined(SDL_PLATFORM_UNIX) || defined(__APPLE__)
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
@@ -386,7 +386,7 @@ static char loaderror[256];
return false; /* didn't find it anywhere reasonable. :( */
}
-#elif defined(__unix__)
+#elif defined(SDL_PLATFORM_UNIX)
#include <dlfcn.h>
#define SDL3_LIBNAME "libSDL3.so.0"
static void *Loaded_SDL3 = NULL;
@@ -1543,12 +1543,6 @@ Event3to2(const SDL_Event *event3, SDL2_Event *event2)
SDL_Renderer *renderer;
SDL_Event cvtevent3;
-#if 0
- if (event3->type == SDL_SYSWMEVENT) {
- return SDL2_FALSE; /* !!! FIXME: figure out what to do with this. */
- }
-#endif
-
/* currently everything _mostly_ matches up between SDL2 and SDL3, but this might
drift more as SDL3 development continues. */
@@ -1720,12 +1714,6 @@ Event3to2(const SDL_Event *event3, SDL2_Event *event2)
static SDL_Event *
Event2to3(const SDL2_Event *event2, SDL_Event *event3)
{
-#if 0
- if (event2->type == SDL_SYSWMEVENT) {
- return SDL2_FALSE; /* !!! FIXME: figure out what to do with this. */
- }
-#endif
-
/* currently everything _mostly_ matches up between SDL2 and SDL3, but this might
drift more as SDL3 development continues. */
@@ -3693,7 +3681,7 @@ SDL_GetTicks64(void)
return SDL3_GetTicks();
}
-SDL_DECLSPEC SDL2_bool SDLCALL SDL_GetWindowWMInfo(SDL_Window *window, SDL_SysWMinfo *info)
+SDL_DECLSPEC SDL2_bool SDLCALL SDL_GetWindowWMInfo(SDL_Window *window, SDL2_SysWMinfo *info)
{
const char *driver = SDL3_GetCurrentVideoDriver();
SDL_PropertiesID props;
@@ -3740,9 +3728,9 @@ SDL_DECLSPEC SDL2_bool SDLCALL SDL_GetWindowWMInfo(SDL_Window *window, SDL_SysWM
(Uint32)info->version.patch);
/* Before 2.0.6, it was possible to build an SDL with Wayland support
- * (SDL_SysWMinfo will be large enough to hold Wayland info), but build
+ * (SDL2_SysWMinfo will be large enough to hold Wayland info), but build
* your app against SDL headers that didn't have Wayland support
- * (SDL_SysWMinfo could be smaller than Wayland needs. This would lead
+ * (SDL2_SysWMinfo could be smaller than Wayland needs). This would lead
* to an app properly using SDL_GetWindowWMInfo() but we'd accidentally
* overflow memory on the stack or heap. To protect against this, we've
* padded out the struct unconditionally in the headers and Wayland will
@@ -5636,9 +5624,25 @@ static void PostInitSubsystem(SDL_InitFlags new_flags)
++timer_init;
}
+ /* Gamepads imply the joystick subsystem */
+ if (new_flags & SDL_INIT_GAMEPAD) {
+ new_flags |= SDL_INIT_JOYSTICK;
+ }
+
+ /* Some subsystems imply the events subsystem */
+ if (new_flags & (SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)) {
+ new_flags |= SDL_INIT_EVENTS;
+ }
+
/* If the subsystem failed to initialize, mask out the flag for it */
new_flags &= SDL_WasInit(new_flags);
+ if (new_flags & SDL_INIT_EVENTS) {
+ (void)SDL_EventState(SDL_EVENT_TEXT_INPUT, SDL2_DISABLE);
+ (void)SDL_EventState(SDL_EVENT_TEXT_EDITING, SDL2_DISABLE);
+ (void)SDL_EventState(SDL2_SYSWMEVENT, SDL2_DISABLE);
+ }
+
if (new_flags & SDL_INIT_VIDEO) {
/* default SDL2 GL attributes */
SDL_GL_SetAttribute(SDL2_GL_RED_SIZE, 3);
@@ -5658,7 +5662,7 @@ static void PostInitSubsystem(SDL_InitFlags new_flags)
}
/* enumerate joysticks and haptics to build device list */
- if (new_flags & (SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) {
+ if (new_flags & SDL_INIT_JOYSTICK) {
SDL_NumJoysticks();
}
if (new_flags & SDL_INIT_HAPTIC) {
@@ -7856,7 +7860,13 @@ SDL_JoystickSetPlayerIndex(SDL_Joystick *joystick, int player_index)
SDL_DECLSPEC void SDLCALL
SDL_StartTextInput(void)
{
- SDL_Window **windows = SDL3_GetWindows(NULL);
+ SDL_Window **windows;
+
+ /* First, enable text events */
+ (void)SDL_EventState(SDL_EVENT_TEXT_INPUT, SDL2_ENABLE);
+ (void)SDL_EventState(SDL_EVENT_TEXT_EDITING, SDL2_ENABLE);
+
+ windows = SDL3_GetWindows(NULL);
if (windows) {
int i;
SDL_PropertiesID props = SDL3_CreateProperties();
@@ -7877,20 +7887,7 @@ SDL_StartTextInput(void)
SDL_DECLSPEC SDL2_bool SDLCALL
SDL_IsTextInputActive(void)
{
- SDL2_bool result = SDL2_FALSE;
- SDL_Window **windows = SDL3_GetWindows(NULL);
- if (windows) {
- int i;
-
- for (i = 0; windows[i]; ++i) {
- if (SDL3_TextInputActive(windows[i])) {
- result = SDL2_TRUE;
- break;
- }
- }
- SDL3_free(windows);
- }
- return result;
+ return SDL3_EventEnabled(SDL_EVENT_TEXT_INPUT) ? SDL2_TRUE : SDL2_FALSE;
}
SDL_DECLSPEC void SDLCALL
@@ -7905,6 +7902,10 @@ SDL_StopTextInput(void)
}
SDL3_free(windows);
}
+
+ /* Finally disable text events */
+ (void)SDL_EventState(SDL_EVENT_TEXT_INPUT, SDL2_DISABLE);
+ (void)SDL_EventState(SDL_EVENT_TEXT_EDITING, SDL2_DISABLE);
}
SDL_DECLSPEC void SDLCALL
@@ -8721,14 +8722,93 @@ SDL_JoystickGetGUIDString(SDL_GUID guid, char *pszGUID, int cbGUID)
SDL3_GUIDToString(guid, pszGUID, cbGUID);
}
+#ifdef SDL_PLATFORM_WINDOWS
+static SDL2_WindowsMessageHook g_WindowsMessageHook = NULL;
+static void *g_WindowsMessageHookData = NULL;
+
+static bool SDLCALL SDL3to2_WindowsMessageHook(void *userdata, MSG *msg)
+{
+ if (g_WindowsMessageHook) {
+ g_WindowsMessageHook(g_WindowsMessageHookData, msg->hwnd, msg->message, msg->wParam, msg->lParam);
+ }
+ if (SDL3_EventEnabled(SDL2_SYSWMEVENT)) {
+ SDL2_Event event;
+
+ SDL2_SysWMmsg wmmsg;
+ SDL_GetVersion(&wmmsg.version);
+ wmmsg.subsystem = SDL2_SYSWM_WINDOWS;
+ wmmsg.msg.win.hwnd = msg->hwnd;
+ wmmsg.msg.win.msg = msg->message;
+ wmmsg.msg.win.wParam = msg->wParam;
+ wmmsg.msg.win.lParam = msg->lParam;
+
+ SDL3_zero(event);
+ event.type = SDL2_SYSWMEVENT;
+ event.syswm.msg = &wmmsg;
+ SDL_PushEvent(&event);
+ }
+ return true;
+}
+
+SDL_DECLSPEC void SDLCALL
+SDL_SetWindowsMessageHook(SDL2_WindowsMessageHook callback, void *userdata)
+{
+ SDL_WindowsMessageHook callback3;
+ if (callback || SDL3_EventEnabled(SDL2_SYSWMEVENT)) {
+ callback3 = SDL3to2_WindowsMessageHook;
+ } else {
+ callback3 = NULL;
+ }
+ g_WindowsMessageHook = callback;
+ g_WindowsMessageHookData = userdata;
+ SDL3_SetWindowsMessageHook(callback3, NULL);
+}
+#endif /* SDL_PLATFORM_WINDOWS */
+
+#ifdef SDL_PLATFORM_UNIX
+static bool SDLCALL SDL2COMPAT_X11EventHook(void *userdata, XEvent *xevent)
+{
+ SDL2_Event event;
+
+ SDL2_SysWMmsg wmmsg;
+ SDL_GetVersion(&wmmsg.version);
+ wmmsg.subsystem = SDL2_SYSWM_X11;
+ wmmsg.msg.x11.event = *xevent;
+
+ SDL3_zero(event);
+ event.type = SDL2_SYSWMEVENT;
+ event.syswm.msg = &wmmsg;
+ SDL_PushEvent(&event);
+ return true;
+}
+#endif /* SDL_PLATFORM_UNIX */
+
/* SDL3 split this into getter/setter functions. */
SDL_DECLSPEC Uint8 SDLCALL
SDL_EventState(Uint32 type, int state)
{
const int retval = SDL3_EventEnabled(type) ? SDL2_ENABLE : SDL2_DISABLE;
if (state == SDL2_ENABLE) {
+ if (type == SDL2_SYSWMEVENT) {
+#ifdef SDL_PLATFORM_WINDOWS
+ SDL3_SetWindowsMessageHook(SDL3to2_WindowsMessageHook, NULL);
+#endif
+#ifdef SDL_PLATFORM_UNIX
+ SDL3_SetX11EventHook(SDL2COMPAT_X11EventHook, NULL);
+#endif
+ }
SDL3_SetEventEnabled(type, true);
} else if (state == SDL2_DISABLE) {
+ if (type == SDL2_SYSWMEVENT) {
+#ifdef SDL_PLATFORM_WINDOWS
+ if (!g_WindowsMessageHook) {
+ SDL_SetWindowsMessageHook(NULL, NULL);
+ }
+#endif
+#ifdef SDL_PLATFORM_UNIX
+ SDL3_SetX11EventHook(NULL, NULL);
+#endif
+ }
SDL3_SetEventEnabled(type, false);
}
return retval;
@@ -10302,24 +10382,6 @@ SDL_UnloadObject(void *lib)
}
-#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
-static SDL2_WindowsMessageHook g_WindowsMessageHook = NULL;
-
-static bool SDLCALL SDL3to2_WindowsMessageHook(void *userdata, MSG *msg)
-{
- g_WindowsMessageHook(userdata, msg->hwnd, msg->message, msg->wParam, msg->lParam);
- return true;
-}
-
-SDL_DECLSPEC void SDLCALL
-SDL_SetWindowsMessageHook(SDL2_WindowsMessageHook callback, void *userdata)
-{
- SDL_WindowsMessageHook callback3 = (callback != NULL) ? SDL3to2_WindowsMessageHook : NULL;
- g_WindowsMessageHook = callback;
- SDL3_SetWindowsMessageHook(callback3, userdata);
-}
-#endif
-
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
SDL_DECLSPEC int SDLCALL
SDL_Direct3D9GetAdapterIndex(int displayIndex)
diff --git a/src/sdl2_compat.h b/src/sdl2_compat.h
index 9a8561f4..c4df737c 100644
--- a/src/sdl2_compat.h
+++ b/src/sdl2_compat.h
@@ -674,6 +674,7 @@ typedef struct SDL2_Keysym
/* These values are reserved in SDL3's SDL_EventType enum to help sdl2-compat. */
#define SDL2_DISPLAYEVENT 0x150
#define SDL2_WINDOWEVENT 0x200
+#define SDL2_SYSWMEVENT 0x201
typedef enum SDL2_WindowEventID
{
@@ -1274,7 +1275,35 @@ typedef struct _NSWindow NSWindow;
typedef struct _UIWindow UIWindow;
#endif
-typedef struct SDL_SysWMinfo
+#ifdef SDL_PLATFORM_UNIX
+#include <X11/Xlib.h>
+#endif
+
+typedef struct SDL2_SysWMmsg
+{
+ SDL2_version version;
+ SDL2_SYSWM_TYPE subsystem;
+ union
+ {
+#ifdef SDL_PLATFORM_WINDOWS
+ struct {
+ HWND hwnd; /**< The window for the message */
+ UINT msg; /**< The type of message */
+ WPARAM wParam; /**< WORD message parameter */
+ LPARAM lParam; /**< LONG message parameter */
+ } win;
+#endif
+#ifdef SDL_PLATFORM_UNIX
+ struct {
+ XEvent event;
+ } x11;
+#endif
+ /* Can't have an empty union */
+ int dummy;
+ } msg;
+} SDL2_SysWMmsg;
+
+typedef struct SDL2_SysWMinfo
{
SDL2_version version;
SDL2_SYSWM_TYPE subsystem;
@@ -1349,7 +1378,7 @@ typedef struct SDL_SysWMinfo
/* Be careful not to overflow this if you add a new target! */
Uint8 dummy[64];
} info;
-} SDL_SysWMinfo;
+} SDL2_SysWMinfo;
#define SDL_NONSHAPEABLE_WINDOW -1
diff --git a/src/sdl2_protos.h b/src/sdl2_protos.h
index 0630cc20..3664afb9 100644
--- a/src/sdl2_protos.h
+++ b/src/sdl2_protos.h
@@ -493,7 +493,7 @@ SDL2_PROTO(int,LowerBlit,(SDL2_Surface *a, SDL_Rect *b, SDL2_Surface *c, SDL_Rec
SDL2_PROTO(int,SoftStretch,(SDL2_Surface *a, const SDL_Rect *b, SDL2_Surface *c, const SDL_Rect *d))
SDL2_PROTO(int,UpperBlitScaled,(SDL2_Surface *a, const SDL_Rect *b, SDL2_Surface *c, SDL_Rect *d))
SDL2_PROTO(int,LowerBlitScaled,(SDL2_Surface *a, SDL_Rect *b, SDL2_Surface *c, SDL_Rect *d))
-SDL2_PROTO(SDL2_bool,GetWindowWMInfo,(SDL_Window *a, SDL_SysWMinfo *b))
+SDL2_PROTO(SDL2_bool,GetWindowWMInfo,(SDL_Window *a, SDL2_SysWMinfo *b))
SDL2_PROTO(const char*,GetThreadName,(SDL_Thread *a))
SDL2_PROTO(unsigned long,ThreadID,(void))
SDL2_PROTO(unsigned long,GetThreadID,(SDL_Thread *a))
diff --git a/src/sdl3_syms.h b/src/sdl3_syms.h
index 16a9ba06..a9fcf9eb 100644
--- a/src/sdl3_syms.h
+++ b/src/sdl3_syms.h
@@ -671,6 +671,7 @@ SDL3_SYM(bool,SetWindowResizable,(SDL_Window *a, bool b),(a,b),return)
SDL3_SYM(bool,SetWindowShape,(SDL_Window *a, SDL_Surface *b),(a,b),return)
SDL3_SYM(bool,SetWindowSize,(SDL_Window *a, int b, int c),(a,b,c),return)
SDL3_SYM(bool,SetWindowTitle,(SDL_Window *a, const char *b),(a,b),return)
+SDL3_SYM(void,SetX11EventHook,(SDL_X11EventHook a, void *b),(a,b),return)
SDL3_SYM(bool,ShowCursor,(void),(),return)
SDL3_SYM_PASSTHROUGH_RETCODE(bool,ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,b),return)
SDL3_SYM_PASSTHROUGH_RETCODE(bool,ShowSimpleMessageBox,(Uint32 a, const char *b, const char *c, SDL_Window *d),(a,b,c,d),return)