sdl2-compat: update from latest SDL2 and SDL3 branches (7955a)

From 7955aa322fef34e61661ca0e43ac917b8fd7466f Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Fri, 10 Nov 2023 03:51:40 +0300
Subject: [PATCH] update from latest SDL2 and SDL3 branches

---
 CMakeLists.txt                   |   1 +
 src/sdl3_include_wrapper.h       |  80 +++++++++++
 test/testautomation_subsystems.c | 239 +++++++++++++++++++++++++++++++
 test/testautomation_suites.h     |   2 +
 test/testsprite2.c               |  33 ++++-
 5 files changed, 348 insertions(+), 7 deletions(-)
 create mode 100644 test/testautomation_subsystems.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index edeb3d4..290c09a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -515,6 +515,7 @@ if(SDL2COMPAT_TESTS)
       "test/testautomation_math.c"
       "test/testautomation_rect.c"
       "test/testautomation_stdlib.c"
+      "test/testautomation_subsystems.c"
       "test/testautomation_timer.c"
       "test/testautomation_clipboard.c"
       "test/testautomation_joystick.c"
diff --git a/src/sdl3_include_wrapper.h b/src/sdl3_include_wrapper.h
index c034d7e..f80ff39 100644
--- a/src/sdl3_include_wrapper.h
+++ b/src/sdl3_include_wrapper.h
@@ -948,6 +948,22 @@
 #define SDL_SetPropertyWithCleanup IGNORE_THIS_VERSION_OF_SDL_SetPropertyWithCleanup
 #define SDL_SetX11EventHook IGNORE_THIS_VERSION_OF_SDL_SetX11EventHook
 #define SDL_GetGlobalProperties IGNORE_THIS_VERSION_OF_SDL_GetGlobalProperties
+#define SDL_OpenVideoCapture IGNORE_THIS_VERSION_OF_SDL_OpenVideoCapture
+#define SDL_SetVideoCaptureSpec IGNORE_THIS_VERSION_OF_SDL_SetVideoCaptureSpec
+#define SDL_OpenVideoCaptureWithSpec IGNORE_THIS_VERSION_OF_SDL_OpenVideoCaptureWithSpec
+#define SDL_GetVideoCaptureDeviceName IGNORE_THIS_VERSION_OF_SDL_GetVideoCaptureDeviceName
+#define SDL_GetVideoCaptureSpec IGNORE_THIS_VERSION_OF_SDL_GetVideoCaptureSpec
+#define SDL_GetVideoCaptureFormat IGNORE_THIS_VERSION_OF_SDL_GetVideoCaptureFormat
+#define SDL_GetNumVideoCaptureFormats IGNORE_THIS_VERSION_OF_SDL_GetNumVideoCaptureFormats
+#define SDL_GetVideoCaptureFrameSize IGNORE_THIS_VERSION_OF_SDL_GetVideoCaptureFrameSize
+#define SDL_GetNumVideoCaptureFrameSizes IGNORE_THIS_VERSION_OF_SDL_GetNumVideoCaptureFrameSizes
+#define SDL_GetVideoCaptureStatus IGNORE_THIS_VERSION_OF_SDL_GetVideoCaptureStatus
+#define SDL_StartVideoCapture IGNORE_THIS_VERSION_OF_SDL_StartVideoCapture
+#define SDL_AcquireVideoCaptureFrame IGNORE_THIS_VERSION_OF_SDL_AcquireVideoCaptureFrame
+#define SDL_ReleaseVideoCaptureFrame IGNORE_THIS_VERSION_OF_SDL_ReleaseVideoCaptureFrame
+#define SDL_StopVideoCapture IGNORE_THIS_VERSION_OF_SDL_StopVideoCapture
+#define SDL_CloseVideoCapture IGNORE_THIS_VERSION_OF_SDL_CloseVideoCapture
+#define SDL_GetVideoCaptureDevices IGNORE_THIS_VERSION_OF_SDL_GetVideoCaptureDevices
 
 
 #define SDL_FUNCTION_POINTER_IS_VOID_POINTER 1
@@ -4656,6 +4672,70 @@
 #undef SDL_GetGlobalProperties
 #endif
 
+#ifdef SDL_OpenVideoCapture
+#undef SDL_OpenVideoCapture
+#endif
+
+#ifdef SDL_SetVideoCaptureSpec
+#undef SDL_SetVideoCaptureSpec
+#endif
+
+#ifdef SDL_OpenVideoCaptureWithSpec
+#undef SDL_OpenVideoCaptureWithSpec
+#endif
+
+#ifdef SDL_GetVideoCaptureDeviceName
+#undef SDL_GetVideoCaptureDeviceName
+#endif
+
+#ifdef SDL_GetVideoCaptureSpec
+#undef SDL_GetVideoCaptureSpec
+#endif
+
+#ifdef SDL_GetVideoCaptureFormat
+#undef SDL_GetVideoCaptureFormat
+#endif
+
+#ifdef SDL_GetNumVideoCaptureFormats
+#undef SDL_GetNumVideoCaptureFormats
+#endif
+
+#ifdef SDL_GetVideoCaptureFrameSize
+#undef SDL_GetVideoCaptureFrameSize
+#endif
+
+#ifdef SDL_GetNumVideoCaptureFrameSizes
+#undef SDL_GetNumVideoCaptureFrameSizes
+#endif
+
+#ifdef SDL_GetVideoCaptureStatus
+#undef SDL_GetVideoCaptureStatus
+#endif
+
+#ifdef SDL_StartVideoCapture
+#undef SDL_StartVideoCapture
+#endif
+
+#ifdef SDL_AcquireVideoCaptureFrame
+#undef SDL_AcquireVideoCaptureFrame
+#endif
+
+#ifdef SDL_ReleaseVideoCaptureFrame
+#undef SDL_ReleaseVideoCaptureFrame
+#endif
+
+#ifdef SDL_StopVideoCapture
+#undef SDL_StopVideoCapture
+#endif
+
+#ifdef SDL_CloseVideoCapture
+#undef SDL_CloseVideoCapture
+#endif
+
+#ifdef SDL_GetVideoCaptureDevices
+#undef SDL_GetVideoCaptureDevices
+#endif
+
 /* undefine these macros too: */
 /* redefine as SDL3_xxx, if needed. */
 
diff --git a/test/testautomation_subsystems.c b/test/testautomation_subsystems.c
new file mode 100644
index 0000000..d25edee
--- /dev/null
+++ b/test/testautomation_subsystems.c
@@ -0,0 +1,239 @@
+/**
+ * Subsystem test suite
+ */
+
+#include "SDL.h"
+#include "SDL_test.h"
+
+/* ================= Test Case Implementation ================== */
+
+/* Fixture */
+
+static void subsystemsSetUp(void *arg)
+{
+    /* Reset each one of the SDL subsystems */
+    /* CHECKME: can we use SDL_Quit here, or this will break the flow of tests? */
+    SDL_Quit();
+    /* Alternate variant without SDL_Quit:
+        while (SDL_WasInit(SDL_INIT_EVERYTHING) != 0) {
+            SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
+        }
+    */
+    SDLTest_AssertPass("Reset all subsystems before subsystems test");
+    SDLTest_AssertCheck(SDL_WasInit(SDL_INIT_EVERYTHING) == 0, "Check result from SDL_WasInit(SDL_INIT_EVERYTHING)");
+}
+
+static void subsystemsTearDown(void *arg)
+{
+    /* Reset each one of the SDL subsystems */
+    SDL_Quit();
+
+    SDLTest_AssertPass("Cleanup of subsystems test completed");
+}
+
+/* Test case functions */
+
+/**
+ * \brief Inits and Quits particular subsystem, checking its Init status.
+ *
+ * \sa SDL_InitSubSystem
+ * \sa SDL_QuitSubSystem
+ *
+ */
+static int subsystems_referenceCount()
+{
+    const int system = SDL_INIT_VIDEO;
+    int result;
+    /* Ensure that we start with a non-initialized subsystem. */
+    SDLTest_AssertCheck(SDL_WasInit(system) == 0, "Check result from SDL_WasInit(0x%x)", system);
+
+    /* Init subsystem once, and quit once */
+    SDL_InitSubSystem(system);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(0x%x)", system);
+    result = SDL_WasInit(system);
+    SDLTest_AssertCheck(result == system, "Check result from SDL_WasInit(0x%x), expected: 0x%x, got: 0x%x", system, system, result);
+
+    SDL_QuitSubSystem(system);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(0x%x)", system);
+    result = SDL_WasInit(system);
+    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(0x%x), expected: 0, got: 0x%x", system, result);
+
+    /* Init subsystem number of times, then decrement reference count until it's disposed of. */
+    SDL_InitSubSystem(system);
+    SDL_InitSubSystem(system);
+    SDL_InitSubSystem(system);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(0x%x) x3 times", system);
+    result = SDL_WasInit(system);
+    SDLTest_AssertCheck(result == system, "Check result from SDL_WasInit(0x%x), expected: 0x%x, got: 0x%x", system, system, result);
+
+    SDL_QuitSubSystem(system);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(0x%x) x1", system);
+    result = SDL_WasInit(system);
+    SDLTest_AssertCheck(result == system, "Check result from SDL_WasInit(0x%x), expected: 0x%x, got: 0x%x", system, system, result);
+    SDL_QuitSubSystem(system);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(0x%x) x2", system);
+    result = SDL_WasInit(system);
+    SDLTest_AssertCheck(result == system, "Check result from SDL_WasInit(0x%x), expected: 0x%x, got: 0x%x", system, system, result);
+    SDL_QuitSubSystem(system);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(0x%x) x3", system);
+    result = SDL_WasInit(system);
+    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(0x%x), expected: 0, got: 0x%x", system, result);
+
+    return TEST_COMPLETED;
+}
+
+/**
+ * \brief Inits and Quits subsystems that have another as dependency;
+ *        check that the dependency is not removed before the last of its dependents.
+ *
+ * \sa SDL_InitSubSystem
+ * \sa SDL_QuitSubSystem
+ *
+ */
+static int subsystems_dependRefCountInitAllQuitByOne()
+{
+    int result;
+    /* Ensure that we start with reset subsystems. */
+    SDLTest_AssertCheck(SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS) == 0,
+                        "Check result from SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS)");
+
+    /* Following should init SDL_INIT_EVENTS and give it +3 ref counts. */
+    SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
+
+    /* Quit systems one by one. */
+    SDL_QuitSubSystem(SDL_INIT_VIDEO);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_VIDEO)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
+    SDL_QuitSubSystem(SDL_INIT_AUDIO);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
+    SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_JOYSTICK)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0, got: 0x%x", result);
+
+    return TEST_COMPLETED;
+}
+
+/**
+ * \brief Inits and Quits subsystems that have another as dependency;
+ *        check that the dependency is not removed before the last of its dependents.
+ *
+ * \sa SDL_InitSubSystem
+ * \sa SDL_QuitSubSystem
+ *
+ */
+static int subsystems_dependRefCountInitByOneQuitAll()
+{
+    int result;
+    /* Ensure that we start with reset subsystems. */
+    SDLTest_AssertCheck(SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS) == 0,
+                        "Check result from SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS)");
+
+    /* Following should init SDL_INIT_EVENTS and give it +3 ref counts. */
+    SDL_InitSubSystem(SDL_INIT_VIDEO);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_VIDEO)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
+    SDL_InitSubSystem(SDL_INIT_AUDIO);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_AUDIO)");
+    SDL_InitSubSystem(SDL_INIT_JOYSTICK);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_JOYSTICK)");
+
+    /* Quit systems all at once. */
+    SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0, got: 0x%x", result);
+
+    return TEST_COMPLETED;
+}
+
+/**
+ * \brief Inits and Quits subsystems that have another as dependency,
+ *        but also inits that dependency explicitly, giving it extra ref count.
+ *        Check that the dependency is not removed before the last reference is gone.
+ *
+ * \sa SDL_InitSubSystem
+ * \sa SDL_QuitSubSystem
+ *
+ */
+static int subsystems_dependRefCountWithExtraInit()
+{
+    int result;
+    /* Ensure that we start with reset subsystems. */
+    SDLTest_AssertCheck(SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS) == 0,
+                        "Check result from SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS)");
+
+    /* Init EVENTS explicitly, +1 ref count. */
+    SDL_InitSubSystem(SDL_INIT_EVENTS);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_EVENTS)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
+    /* Following should init SDL_INIT_EVENTS and give it +3 ref counts. */
+    SDL_InitSubSystem(SDL_INIT_VIDEO);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_VIDEO)");
+    SDL_InitSubSystem(SDL_INIT_AUDIO);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_AUDIO)");
+    SDL_InitSubSystem(SDL_INIT_JOYSTICK);
+    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_JOYSTICK)");
+
+    /* Quit EVENTS explicitly, -1 ref count. */
+    SDL_QuitSubSystem(SDL_INIT_EVENTS);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_EVENTS)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
+
+    /* Quit systems one by one. */
+    SDL_QuitSubSystem(SDL_INIT_VIDEO);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_VIDEO)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
+    SDL_QuitSubSystem(SDL_INIT_AUDIO);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
+    SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_JOYSTICK)");
+    result = SDL_WasInit(SDL_INIT_EVENTS);
+    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0, got: 0x%x", result);
+
+    return TEST_COMPLETED;
+}
+
+/* ================= Test References ================== */
+
+/* Subsystems test cases */
+static const SDLTest_TestCaseReference subsystemsTest1 = {
+    (SDLTest_TestCaseFp)subsystems_referenceCount, "subsystems_referenceCount", "Makes sure that subsystem stays until number of quits matches inits.", TEST_ENABLED
+};
+
+static const SDLTest_TestCaseReference subsystemsTest2 = {
+    (SDLTest_TestCaseFp)subsystems_dependRefCountInitAllQuitByOne, "subsystems_dependRefCountInitAllQuitByOne", "Check reference count of subsystem dependencies.", TEST_ENABLED
+};
+
+static const SDLTest_TestCaseReference subsystemsTest3 = {
+    (SDLTest_TestCaseFp)subsystems_dependRefCountInitByOneQuitAll, "subsystems_dependRefCountInitByOneQuitAll", "Check reference count of subsystem dependencies.", TEST_ENABLED
+};
+
+static const SDLTest_TestCaseReference subsystemsTest4 = {
+    (SDLTest_TestCaseFp)subsystems_dependRefCountWithExtraInit, "subsystems_dependRefCountWithExtraInit", "Check reference count of subsystem dependencies.", TEST_ENABLED
+};
+
+/* Sequence of Events test cases */
+static const SDLTest_TestCaseReference *subsystemsTests[] = {
+    &subsystemsTest1, &subsystemsTest2, &subsystemsTest3, &subsystemsTest4, NULL
+};
+
+/* Events test suite (global) */
+SDLTest_TestSuiteReference subsystemsTestSuite = {
+    "Subsystems",
+    subsystemsSetUp,
+    subsystemsTests,
+    subsystemsTearDown
+};
diff --git a/test/testautomation_suites.h b/test/testautomation_suites.h
index 6fdcd83..24909db 100644
--- a/test/testautomation_suites.h
+++ b/test/testautomation_suites.h
@@ -26,6 +26,7 @@ extern SDLTest_TestSuiteReference renderTestSuite;
 extern SDLTest_TestSuiteReference rwopsTestSuite;
 extern SDLTest_TestSuiteReference sdltestTestSuite;
 extern SDLTest_TestSuiteReference stdlibTestSuite;
+extern SDLTest_TestSuiteReference subsystemsTestSuite;
 extern SDLTest_TestSuiteReference surfaceTestSuite;
 extern SDLTest_TestSuiteReference syswmTestSuite;
 extern SDLTest_TestSuiteReference timerTestSuite;
@@ -54,6 +55,7 @@ SDLTest_TestSuiteReference *testSuites[] = {
     &syswmTestSuite,
     &timerTestSuite,
     &videoTestSuite,
+    &subsystemsTestSuite, /* run last, not interfere with other test enviroment */
     NULL
 };
 
diff --git a/test/testsprite2.c b/test/testsprite2.c
index 89037fd..01c6148 100644
--- a/test/testsprite2.c
+++ b/test/testsprite2.c
@@ -392,22 +392,30 @@ void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite)
     SDL_RenderPresent(renderer);
 }
 
-void loop()
+static void MoveAllSprites()
 {
-    Uint32 now;
     int i;
-    SDL_Event event;
 
-    /* Check for events */
-    while (SDL_PollEvent(&event)) {
-        SDLTest_CommonEvent(state, &event, &done);
-    }
     for (i = 0; i < state->num_windows; ++i) {
         if (state->windows[i] == NULL) {
             continue;
         }
         MoveSprites(state->renderers[i], sprites[i]);
     }
+}
+
+void loop()
+{
+    Uint32 now;
+    SDL_Event event;
+
+    /* Check for events */
+    while (SDL_PollEvent(&event)) {
+        SDLTest_CommonEvent(state, &event, &done);
+    }
+
+    MoveAllSprites();
+
 #ifdef __EMSCRIPTEN__
     if (done) {
         emscripten_cancel_main_loop();
@@ -426,6 +434,14 @@ void loop()
     }
 }
 
+static int SDLCALL ExposeEventWatcher(void *userdata, SDL_Event *event)
+{
+    if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_EXPOSED) {
+        MoveAllSprites();
+    }
+    return 0;
+}
+
 int main(int argc, char *argv[])
 {
     int i;
@@ -568,6 +584,9 @@ int main(int argc, char *argv[])
         }
     }
 
+    /* Add an event watcher to redraw from within modal window resize/move loops */
+    SDL_AddEventWatch(ExposeEventWatcher, NULL);
+
     /* Main render loop */
     frames = 0;
     next_fps_check = SDL_GetTicks() + fps_check_delay;