From b5715546c0a995d69cbdaffe663adbeb9a2228c2 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 24 Jun 2021 15:24:07 -0400
Subject: [PATCH] Implemented SDL_syswm API.
---
include/SDL/SDL_config.h | 9 ++-
include/SDL/SDL_syswm.h | 9 +--
src/SDL12_compat.c | 166 +++++++++++++++++++++++++++++++++++----
src/SDL20_syms.h | 3 +
test/testwm.c | 46 +++++++++++
5 files changed, 208 insertions(+), 25 deletions(-)
diff --git a/include/SDL/SDL_config.h b/include/SDL/SDL_config.h
index 6ab8c87..dac480d 100644
--- a/include/SDL/SDL_config.h
+++ b/include/SDL/SDL_config.h
@@ -163,6 +163,13 @@ stage, though. Send patches if your platform lacks something. */
#define HAVE_SETJMP 1
#endif
-/* Don't define any of the SDL backend, under the assumption checking for these against the headers won't work anyhow. */
+/* Don't define most of the SDL backends, under the assumption checking for these against the headers won't work anyhow.
+ The exception is the X11 backend; you need its define to know if you can use its syswm interface. */
+
+# if defined(__unix__) && !defined(__APPLE__) && defined(__has_include)
+# if __has_include(<X11/Xlib.h>)
+# define SDL_VIDEO_DRIVER_X11 1
+# endif
+# endif
#endif /* _SDL_config_h */
diff --git a/include/SDL/SDL_syswm.h b/include/SDL/SDL_syswm.h
index b6b0c9e..65666da 100644
--- a/include/SDL/SDL_syswm.h
+++ b/include/SDL/SDL_syswm.h
@@ -32,14 +32,7 @@ real SDL-1.2 available to you. */
#ifndef SDL_PROTOTYPES_ONLY
-# if defined(__unix__) && !defined(__APPLE__) && defined(__has_include)
-# if __has_include(<X11/Xlib.h>)
-# define SDL12_COMPAT_SUPPORT_SYSWM_X11 1
-# endif
-# endif
-
-# if defined(SDL12_COMPAT_SUPPORT_SYSWM_X11)
-# undef SDL12_COMPAT_SUPPORT_SYSWM_X11
+# if defined(SDL_VIDEO_DRIVER_X11)
# include <X11/Xlib.h>
# include <X11/Xatom.h>
diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index bf812fc..a849b83 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -36,7 +36,13 @@
#include <stdarg.h>
#include <limits.h>
-#ifndef _WIN32
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+#else
#include <stdio.h> /* fprintf(), etc. */
#include <stdlib.h> /* for abort() */
#include <string.h>
@@ -566,6 +572,54 @@ typedef struct SDL12_keysym
#define SDL12_RELEASED 0
#define SDL12_PRESSED 1
+#if defined(SDL_VIDEO_DRIVER_X11) /* SDL_VIDEO_DRIVER_X11 refers to the SDL2 headers. */
+typedef enum SDL_SYSWM_TYPE /* this is only used for 1.2 X11 syswm */
+{
+ SDL12_SYSWM_X11
+} SDL12_SYSWM_TYPE;
+#endif
+
+typedef struct SDL12_SysWMmsg
+{
+ SDL_version version;
+#if defined(_WIN32)
+ HWND hwnd;
+ UINT msg;
+ WPARAM wParam;
+ LPARAM lParam;
+#elif defined(SDL_VIDEO_DRIVER_X11)
+ SDL12_SYSWM_TYPE subsystem;
+ union { XEvent xevent; } event;
+#else
+ int data; /* unused at the moment. */
+#endif
+} SDL12_SysWMmsg;
+
+typedef struct SDL12_SysWMinfo
+{
+ SDL_version version;
+#if defined(_WIN32)
+ HWND window;
+ HGLRC hglrc;
+#elif defined(SDL_VIDEO_DRIVER_X11)
+ SDL12_SYSWM_TYPE subsystem;
+ union {
+ struct {
+ Display *display;
+ Window window;
+ void (*lock_func)(void);
+ void (*unlock_func)(void);
+ Window fswindow;
+ Window wmwindow;
+ Display *gfxdisplay;
+ } x11;
+ } info;
+#else
+ int data; /* unused at the moment. */
+#endif
+} SDL12_SysWMinfo;
+
+
typedef enum
{
SDL12_NOEVENT = 0,
@@ -690,7 +744,7 @@ typedef struct
typedef struct
{
Uint8 type;
- void *msg;
+ SDL12_SysWMmsg *msg;
} SDL12_SysWMEvent;
typedef union
@@ -863,6 +917,7 @@ static char *WindowIconTitle = NULL;
static SDL_Surface *VideoIcon20 = NULL;
static int EnabledUnicode = 0;
static int VideoDisplayIndex = 0;
+static SDL_bool SupportSysWM = SDL_FALSE;
static SDL_bool CDRomInit = SDL_FALSE;
static char *CDRomPath = NULL;
static SDL12_CD *CDRomDevice = NULL;
@@ -889,11 +944,11 @@ static GLuint OpenGLLogicalScalingMultisampleDepth = 0;
static GLuint OpenGLCurrentReadFBO = 0;
static GLuint OpenGLCurrentDrawFBO = 0;
-
/* !!! FIXME: need a mutex for the event queue. */
#define SDL12_MAXEVENTS 128
typedef struct EventQueueType
{
+ SDL12_SysWMmsg syswm_msg; /* save space for a copy of this in case we use it. */
SDL12_Event event12;
struct EventQueueType *next;
} EventQueueType;
@@ -909,10 +964,6 @@ static SDL12_Event PendingKeydownEvent;
/* Obviously we can't use SDL_LoadObject() to load SDL2. :) */
static char loaderror[256];
#if defined(_WIN32)
- #ifndef WIN32_LEAN_AND_MEAN
- #define WIN32_LEAN_AND_MEAN 1
- #endif
- #include <windows.h>
#define DIRSEP "\\"
#define SDL20_LIBNAME "SDL2.dll"
/* require SDL2 >= 2.0.12 for SDL_CreateThread binary compatibility */
@@ -1021,7 +1072,6 @@ static char loaderror[256];
#define DIRSEP "/"
#endif
-
static void *
LoadSDL20Symbol(const char *fn, int *okay)
{
@@ -1193,6 +1243,7 @@ SDL_UnregisterApp(void)
}
#endif
+
DECLSPEC const SDL_version * SDLCALL
SDL_Linked_Version(void)
{
@@ -1671,7 +1722,17 @@ Init12Video(void)
SDL20_memset(&PendingKeydownEvent, 0, sizeof(SDL12_Event));
SDL20_memset(EventStates, SDL_ENABLE, sizeof (EventStates)); /* on by default */
+
EventStates[SDL12_SYSWMEVENT] = SDL_IGNORE; /* off by default. */
+ SDL20_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
+
+#if defined(SDL_VIDEO_DRIVER_WINDOWS)
+ SupportSysWM = (SDL20_strcmp(driver, "windows") == 0) ? SDL_TRUE : SDL_FALSE;
+#elif defined(SDL_VIDEO_DRIVER_X11)
+ SupportSysWM = (SDL20_strcmp(driver, "x11") == 0) ? SDL_TRUE : SDL_FALSE;
+#else
+ SupportSysWM = SDL_FALSE;
+#endif
SDL20_AddEventWatch(EventFilter20to12, NULL);
@@ -1975,6 +2036,11 @@ SDL_PushEvent(SDL12_Event *event12)
SDL20_memcpy(&item->event12, event12, sizeof (SDL12_Event));
+ if (event12->type == SDL12_SYSWMEVENT) { /* make a copy of the data here */
+ SDL20_memcpy(&item->syswm_msg, event12->syswm.msg, sizeof (SDL12_SysWMmsg));
+ item->event12.syswm.msg = &item->syswm_msg;
+ }
+
return 0;
}
@@ -2074,6 +2140,9 @@ SDL_EventState(Uint8 type, int state)
if (state != SDL_QUERY) {
EventStates[type] = state;
+ if ((type == SDL12_SYSWMEVENT) && SupportSysWM) { /* we only enable syswm in SDL2 if it makes sense. */
+ SDL20_EventState(SDL_SYSWMEVENT, state);
+ }
}
if (state == SDL_IGNORE) { /* drop existing events of this type. */
while (SDL_PeepEvents(&e, 1, SDL_GETEVENT, (1<<type))) {
@@ -2840,6 +2909,7 @@ static int SDLCALL
EventFilter20to12(void *data, SDL_Event *event20)
{
SDL12_Event event12;
+ SDL12_SysWMmsg msg;
SDL_assert(data == NULL); /* currently unused. */
@@ -2921,8 +2991,29 @@ EventFilter20to12(void *data, SDL_Event *event20)
}
break;
- /* !!! FIXME: this is sort of a mess to convert. */
- case SDL_SYSWMEVENT: FIXME("write me"); return 1;
+ case SDL_SYSWMEVENT:
+ if (!SupportSysWM) {
+ return 1;
+ }
+
+ #if defined(SDL_VIDEO_DRIVER_WINDOWS)
+ SDL_assert(event20->syswm.msg->subsystem == SDL_SYSWM_WINDOWS);
+ msg.hwnd = event20->syswm.msg->hwnd;
+ msg.msg = event20->syswm.msg->msg;
+ msg.wParam = event20->syswm.msg->wParam;
+ msg.lParam = event20->syswm.msg->lParam;
+ #elif defined(SDL_VIDEO_DRIVER_X11)
+ SDL_assert(event20->syswm.msg->subsystem == SDL_SYSWM_X11);
+ msg.subsystem = SDL12_SYSWM_X11;
+ SDL20_memcpy(&msg.event.xevent, &event20->syswm.msg->msg.x11.event, sizeof (XEvent));
+ #else
+ SDL_assert(!"should have been caught by !SupportsSysWM test");
+ #endif
+
+ SDL20_memcpy(&msg.version, SDL_Linked_Version(), sizeof (msg.version));
+ event12.type = SDL12_SYSWMEVENT;
+ event12.syswm.msg = &msg; /* this is stack-allocated, but we copy and update the pointer later. */
+ break;
case SDL_KEYUP:
if (event20->key.repeat) {
@@ -5243,14 +5334,57 @@ SDL_SetColors(SDL12_Surface *surface12, const SDL_Color * colors, int firstcolor
return SDL_SetPalette(surface12, SDL12_LOGPAL | SDL12_PHYSPAL, colors, firstcolor, ncolors);
}
+
+#if defined(SDL_VIDEO_DRIVER_X11)
+/* In 1.2, these would lock the event thread (if you _used_ the event thread), and call XSync(SDL_Display, False) before unlocking */
+static void x11_lock_display(void) {}
+static void x11_unlock_display(void) {}
+#endif
+
DECLSPEC int SDLCALL
-SDL_GetWMInfo(SDL_SysWMinfo * info)
+SDL_GetWMInfo(SDL12_SysWMinfo *info12)
{
- /*return SDL20_GetWindowWMInfo(VideoWindow20, info);*/
- FIXME("write me");
- (void)info;
- SDL20_Unsupported();
- return 0; /* some programs only test against 0, not -1 */
+ SDL_SysWMinfo info20;
+
+ if (info12->version.major > 1) {
+ SDL20_SetError("Requested version is unsupported");
+ return 0; /* some programs only test against 0, not -1 */
+ } else if (!SupportSysWM) {
+ SDL20_SetError("No SysWM support available");
+ return 0; /* some programs only test against 0, not -1 */
+ }
+
+ SDL_zero(info20);
+ SDL_VERSION(&info20.version);
+ if (!SDL20_GetWindowWMInfo(VideoWindow20, &info20)) {
+ return 0; /* some programs only test against 0, not -1 */
+ }
+
+#if defined(SDL_VIDEO_DRIVER_WINDOWS)
+ SDL_assert(info20.subsystem == SDL_SYSWM_WINDOWS);
+ info12->window = info20.win.window;
+ if (SDL_VERSIONNUM(info12->version.major, info12->version.minor, info12->version.patch) >= SDL_VERSIONNUM(1, 2, 5)) {
+ info12->hglrc = (HGLRC) VideoGLContext20;
+ }
+#elif defined(SDL_VIDEO_DRIVER_X11)
+ SDL_assert(info20.subsystem == SDL_SYSWM_X11);
+ info12->subsystem = SDL12_SYSWM_X11;
+ info12->info.x11.display = info20.info.x11.display;
+ info12->info.x11.window = info20.info.x11.window;
+ if (SDL_VERSIONNUM(info12->version.major, info12->version.minor, info12->version.patch) >= SDL_VERSIONNUM(1, 0, 2)) {
+ info12->info.x11.fswindow = 0; /* these don't exist in SDL2. */
+ info12->info.x11.wmwindow = 0;
+ }
+ if (SDL_VERSIONNUM(info12->version.major, info12->version.minor, info12->version.patch) >= SDL_VERSIONNUM(1, 2, 12)) {
+ info12->info.x11.gfxdisplay = info20.info.x11.display; /* shrug */
+ }
+ info12->info.x11.lock_func = x11_lock_display; /* just no-ops for now */
+ info12->info.x11.unlock_func = x11_unlock_display;
+#else
+ info12->data = 0; /* shrug */
+#endif
+
+ return 1;
}
DECLSPEC SDL12_Overlay * SDLCALL
diff --git a/src/SDL20_syms.h b/src/SDL20_syms.h
index 0937d8a..36ca624 100644
--- a/src/SDL20_syms.h
+++ b/src/SDL20_syms.h
@@ -70,6 +70,9 @@ SDL20_SYM(void,PumpEvents,(void),(),)
SDL20_SYM(void,SetEventFilter,(SDL_EventFilter a, void *b),(a,b),)
SDL20_SYM(void,AddEventWatch,(SDL_EventFilter a, void *b),(a,b),)
SDL20_SYM(void,DelEventWatch,(SDL_EventFilter a, void *b),(a,b),)
+SDL20_SYM(Uint8,EventState,(Uint32 a, int b),(a,b),return)
+
+SDL20_SYM(SDL_bool,GetWindowWMInfo,(SDL_Window *a, SDL_SysWMinfo *b),(a,b),)
SDL20_SYM(int,GetNumDisplayModes,(int a),(a),return)
SDL20_SYM(int,GetDisplayMode,(int a, int b, SDL_DisplayMode *c),(a,b,c),return)
diff --git a/test/testwm.c b/test/testwm.c
index 9c3c050..00d53d1 100644
--- a/test/testwm.c
+++ b/test/testwm.c
@@ -5,8 +5,14 @@
#include <stdlib.h>
#include <string.h>
+#define TEST_SYSWM 0
+
#include "SDL.h"
+#ifdef TEST_SYSWM
+#include "SDL_syswm.h"
+#endif
+
/* Is the cursor visible? */
static int visible = 1;
@@ -318,6 +324,18 @@ int SDLCALL FilterEvents(const SDL_Event *event)
printf("Quit demanded\n");
return(1);
+ case SDL_SYSWMEVENT:
+ #ifdef TEST_SYSWM
+ #ifdef _WIN32
+ printf("Windows syswm event: hwnd=%X msg=%X wparam=%X lparam=%X\n", (unsigned int) (size_t) event->syswm.msg->hwnd, (unsigned int) (size_t) event->syswm.msg->msg, (unsigned int) (size_t) event->syswm.msg->wparam, (unsigned int) (size_t) event->syswm.msg->lparam);
+ #elif defined(SDL_VIDEO_DRIVER_X11)
+ printf("X11 syswm event: %d\n", event->syswm.msg->event.xevent.type);
+ #else
+ printf("Generic syswm event: data=%d\n", event->syswm.msg->data);
+ #endif
+ #endif
+ return(1);
+
/* This will never happen because events queued directly
to the event queue are not filtered.
*/
@@ -413,6 +431,34 @@ int main(int argc, char *argv[])
quit(1);
}
+#ifdef TEST_SYSWM
+ {
+ SDL_SysWMinfo syswm_info;
+ SDL_VERSION(&syswm_info.version);
+ if (SDL_GetWMInfo(&syswm_info) != 1) {
+ printf("Failed to get syswm info: %s\n", SDL_GetError());
+ } else {
+ #ifdef _WIN32
+ printf("Windows syswm info: hwnd=%X hglrc=%X\n",
+ (unsigned int) (size_t) syswm_info.hwnd,
+ (unsigned int) (size_t) syswm_info.hglrc);
+ #elif defined(SDL_VIDEO_DRIVER_X11)
+ printf("X11 syswm info: display=%p window=%X lock_func=%p unlock_func=%p fswindow=%X wmwindow=%X gfxdisplay=%p\n",
+ syswm_info.info.x11.display,
+ (unsigned int) (size_t) syswm_info.info.x11.window,
+ syswm_info.info.x11.lock_func,
+ syswm_info.info.x11.unlock_func,
+ (unsigned int) (size_t) syswm_info.info.x11.fswindow,
+ (unsigned int) (size_t) syswm_info.info.x11.wmwindow,
+ syswm_info.info.x11.gfxdisplay);
+ #else
+ printf("Generic syswm info: data=%X hglrc=%X\n", syswm_info.data);
+ #endif
+ }
+ }
+ SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
+#endif
+
/* Set an event filter that discards everything but QUIT */
SDL_SetEventFilter(FilterEvents);