SDL: Remove SDL_VideoInit / Quit. Prefer SDL_SubSytemInit / Quit (#6913)

From aa0053141bfc60e4940ca2724dbd94639dd4fc7b Mon Sep 17 00:00:00 2001
From: Sylvain Becker <[EMAIL REDACTED]>
Date: Tue, 27 Dec 2022 14:42:48 +0100
Subject: [PATCH] Remove SDL_VideoInit / Quit. Prefer SDL_SubSytemInit / Quit
 (#6913)

---
 WhatsNew.txt                      |  2 ++
 docs/README-migration.md          | 10 ++++++
 include/SDL3/SDL_init.h           | 13 -------
 include/SDL3/SDL_video.h          | 42 ----------------------
 src/SDL.c                         |  1 +
 src/dynapi/SDL_dynapi.sym         |  2 --
 src/dynapi/SDL_dynapi_overrides.h |  2 --
 src/dynapi/SDL_dynapi_procs.h     |  2 --
 src/test/SDL_test_common.c        |  5 +--
 src/video/SDL_video.c             |  1 +
 src/video/SDL_video_c.h           | 58 +++++++++++++++++++++++++++++++
 test/testnative.c                 |  4 +--
 test/testoffscreen.c              |  3 +-
 test/testshape.c                  | 14 ++++----
 14 files changed, 86 insertions(+), 73 deletions(-)
 create mode 100644 src/video/SDL_video_c.h

diff --git a/WhatsNew.txt b/WhatsNew.txt
index dbabf200fb15..fa08c7d090e8 100644
--- a/WhatsNew.txt
+++ b/WhatsNew.txt
@@ -40,6 +40,8 @@ General:
     * SDL_SensorGetDataWithTimestamp()
     * SDL_SetWindowBrightness()
     * SDL_SetWindowGammaRamp()
+    * SDL_VideoInit()
+    * SDL_VideoQuit()
 * Removed the following hints from the API, see docs/README-migration.md for details:
     * SDL_HINT_IDLE_TIMER_DISABLED
     * SDL_HINT_VIDEO_X11_FORCE_EGL
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 498bac603757..cf61744d0d7e 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -455,3 +455,13 @@ Programs which have access to shaders can implement more robust versions of thos
 Removed 'SDL_GL_CONTEXT_EGL' from OpenGL configuration attributes
 You can instead use 'SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);'
 
+SDL_VideoInit() and SDL_VideoQuit() have been removed. Instead you can call SDL_InitSubSytem() and SDL_QuitSubSytem() with SDL_INIT_VIDEO, which will properly refcount the subsystems. You can choose a specific audio driver using SDL_VIDEO_DRIVER hint.
+
+
+
+
+
+
+
+
+
diff --git a/include/SDL3/SDL_init.h b/include/SDL3/SDL_init.h
index e05bc58b3ce2..a1d76253aa0c 100644
--- a/include/SDL3/SDL_init.h
+++ b/include/SDL3/SDL_init.h
@@ -129,13 +129,6 @@ extern DECLSPEC int SDLCALL SDL_InitSubSystem(Uint32 flags);
 /**
  * Shut down specific SDL subsystems.
  *
- * If you start a subsystem using a call to that subsystem's init function
- * (for example SDL_VideoInit()) instead of SDL_Init() or SDL_InitSubSystem(),
- * SDL_QuitSubSystem() and SDL_WasInit() will not work. You will need to use
- * that subsystem's quit function (SDL_VideoQuit()) directly instead. But
- * generally, you should not be using those functions directly anyhow; use
- * SDL_Init() instead.
- *
  * You still need to call SDL_Quit() even if you close all open subsystems
  * with SDL_QuitSubSystem().
  *
@@ -171,12 +164,6 @@ extern DECLSPEC Uint32 SDLCALL SDL_WasInit(Uint32 flags);
  * initialized subsystem with SDL_QuitSubSystem(). It is safe to call this
  * function even in the case of errors in initialization.
  *
- * If you start a subsystem using a call to that subsystem's init function
- * (for example SDL_VideoInit()) instead of SDL_Init() or SDL_InitSubSystem(),
- * then you must use that subsystem's quit function (SDL_VideoQuit()) to shut
- * it down before calling SDL_Quit(). But generally, you should not be using
- * those functions directly anyhow; use SDL_Init() instead.
- *
  * You can use this function with atexit() to ensure that it is run when your
  * application is shutdown, but it is not wise to do this from a library or
  * other dynamically loaded code.
diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h
index 7a55d5b46066..06ff3dcb09d8 100644
--- a/include/SDL3/SDL_video.h
+++ b/include/SDL3/SDL_video.h
@@ -281,48 +281,6 @@ extern DECLSPEC int SDLCALL SDL_GetNumVideoDrivers(void);
  */
 extern DECLSPEC const char *SDLCALL SDL_GetVideoDriver(int index);
 
-/**
- * Initialize the video subsystem, optionally specifying a video driver.
- *
- * This function initializes the video subsystem, setting up a connection to
- * the window manager, etc, and determines the available display modes and
- * pixel formats, but does not initialize a window or graphics mode.
- *
- * If you use this function and you haven't used the SDL_INIT_VIDEO flag with
- * either SDL_Init() or SDL_InitSubSystem(), you should call SDL_VideoQuit()
- * before calling SDL_Quit().
- *
- * It is safe to call this function multiple times. SDL_VideoInit() will call
- * SDL_VideoQuit() itself if the video subsystem has already been initialized.
- *
- * You can use SDL_GetNumVideoDrivers() and SDL_GetVideoDriver() to find a
- * specific `driver_name`.
- *
- * \param driver_name the name of a video driver to initialize, or NULL for
- *                    the default driver
- * \returns 0 on success or a negative error code on failure; call
- *          SDL_GetError() for more information.
- *
- * \since This function is available since SDL 3.0.0.
- *
- * \sa SDL_GetNumVideoDrivers
- * \sa SDL_GetVideoDriver
- * \sa SDL_InitSubSystem
- * \sa SDL_VideoQuit
- */
-extern DECLSPEC int SDLCALL SDL_VideoInit(const char *driver_name);
-
-/**
- * Shut down the video subsystem, if initialized with SDL_VideoInit().
- *
- * This function closes all windows, and restores the original video mode.
- *
- * \since This function is available since SDL 3.0.0.
- *
- * \sa SDL_VideoInit
- */
-extern DECLSPEC void SDLCALL SDL_VideoQuit(void);
-
 /**
  * Get the name of the currently initialized video driver.
  *
diff --git a/src/SDL.c b/src/SDL.c
index bf427dc5d01c..fe89de4ac173 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -38,6 +38,7 @@
 #include "SDL_assert_c.h"
 #include "SDL_log_c.h"
 #include "audio/SDL_audio_c.h"
+#include "video/SDL_video_c.h"
 #include "events/SDL_events_c.h"
 #include "haptic/SDL_haptic_c.h"
 #include "joystick/SDL_joystick_c.h"
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index b2af247048db..7613f24928b5 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -524,8 +524,6 @@ SDL3_0.0.0 {
     SDL_GetPrefPath;
     SDL_GetNumVideoDrivers;
     SDL_GetVideoDriver;
-    SDL_VideoInit;
-    SDL_VideoQuit;
     SDL_GetCurrentVideoDriver;
     SDL_GetNumVideoDisplays;
     SDL_GetDisplayName;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 16b70cf2a16a..f94b3e31bac9 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -475,8 +475,6 @@
 #define SDL_GetRevision SDL_GetRevision_REAL
 #define SDL_GetNumVideoDrivers SDL_GetNumVideoDrivers_REAL
 #define SDL_GetVideoDriver SDL_GetVideoDriver_REAL
-#define SDL_VideoInit SDL_VideoInit_REAL
-#define SDL_VideoQuit SDL_VideoQuit_REAL
 #define SDL_GetCurrentVideoDriver SDL_GetCurrentVideoDriver_REAL
 #define SDL_GetNumVideoDisplays SDL_GetNumVideoDisplays_REAL
 #define SDL_GetDisplayName SDL_GetDisplayName_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 95225cb4615c..b2b3e0620aa0 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -502,8 +502,6 @@ SDL_DYNAPI_PROC(void,SDL_GetVersion,(SDL_version *a),(a),)
 SDL_DYNAPI_PROC(const char*,SDL_GetRevision,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumVideoDrivers,(void),(),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetVideoDriver,(int a),(a),return)
-SDL_DYNAPI_PROC(int,SDL_VideoInit,(const char *a),(a),return)
-SDL_DYNAPI_PROC(void,SDL_VideoQuit,(void),(),)
 SDL_DYNAPI_PROC(const char*,SDL_GetCurrentVideoDriver,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumVideoDisplays,(void),(),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetDisplayName,(int a),(a),return)
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index 2e6490c1bc78..fa144ec26721 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -1071,7 +1071,8 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
                 SDL_Log("%s\n", text);
             }
         }
-        if (SDL_VideoInit(state->videodriver) < 0) {
+        SDL_SetHint("SDL_VIDEO_DRIVER", state->videodriver);
+        if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
             SDL_Log("Couldn't initialize video driver: %s\n",
                     SDL_GetError());
             return SDL_FALSE;
@@ -2161,7 +2162,7 @@ void SDLTest_CommonQuit(SDLTest_CommonState *state)
         SDL_free(state->renderers);
     }
     if (state->flags & SDL_INIT_VIDEO) {
-        SDL_VideoQuit();
+        SDL_QuitSubSystem(SDL_INIT_VIDEO);
     }
     if (state->flags & SDL_INIT_AUDIO) {
         SDL_QuitSubSystem(SDL_INIT_AUDIO);
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 87cce71dd84f..8f5bf4bfe889 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -27,6 +27,7 @@
 #include "SDL_blit.h"
 #include "SDL_pixels_c.h"
 #include "SDL_rect_c.h"
+#include "SDL_video_c.h"
 #include "../events/SDL_events_c.h"
 #include "../timer/SDL_timer_c.h"
 
diff --git a/src/video/SDL_video_c.h b/src/video/SDL_video_c.h
new file mode 100644
index 000000000000..887f38ef3e7f
--- /dev/null
+++ b/src/video/SDL_video_c.h
@@ -0,0 +1,58 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_video_c_h_
+#define SDL_video_c_h_
+
+#include "SDL_internal.h"
+
+/**
+ * Initialize the video subsystem, optionally specifying a video driver.
+ *
+ * This function initializes the video subsystem, setting up a connection to
+ * the window manager, etc, and determines the available display modes and
+ * pixel formats, but does not initialize a window or graphics mode.
+ *
+ * If you use this function and you haven't used the SDL_INIT_VIDEO flag with
+ * either SDL_Init() or SDL_InitSubSystem(), you should call SDL_VideoQuit()
+ * before calling SDL_Quit().
+ *
+ * It is safe to call this function multiple times. SDL_VideoInit() will call
+ * SDL_VideoQuit() itself if the video subsystem has already been initialized.
+ *
+ * You can use SDL_GetNumVideoDrivers() and SDL_GetVideoDriver() to find a
+ * specific `driver_name`.
+ *
+ * \param driver_name the name of a video driver to initialize, or NULL for
+ *                    the default driver
+ * \returns 0 on success or a negative error code on failure; call
+ *          SDL_GetError() for more information.
+ */
+extern int SDL_VideoInit(const char *driver_name);
+
+/**
+ * Shut down the video subsystem, if initialized with SDL_VideoInit().
+ *
+ * This function closes all windows, and restores the original video mode.
+ */
+extern void SDL_VideoQuit(void);
+
+#endif /* SDL_video_c_h_ */
diff --git a/test/testnative.c b/test/testnative.c
index 41df7b41a0ce..bc6d70b872ed 100644
--- a/test/testnative.c
+++ b/test/testnative.c
@@ -44,7 +44,7 @@ static SDL_Rect *positions, *velocities;
 static void
 quit(int rc)
 {
-    SDL_VideoQuit();
+    SDL_Quit();
     if (native_window != NULL && factory != NULL) {
         factory->DestroyNativeWindow(native_window);
     }
@@ -103,7 +103,7 @@ int main(int argc, char *argv[])
     /* Enable standard application logging */
     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
 
-    if (SDL_VideoInit(NULL) < 0) {
+    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL video: %s\n",
                      SDL_GetError());
         exit(1);
diff --git a/test/testoffscreen.c b/test/testoffscreen.c
index a1f0bd4fd5b1..bfbeb3285573 100644
--- a/test/testoffscreen.c
+++ b/test/testoffscreen.c
@@ -102,7 +102,8 @@ int main(int argc, char *argv[])
     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
 
     /* Force the offscreen renderer, if it cannot be created then fail out */
-    if (SDL_VideoInit("offscreen") < 0) {
+    SDL_SetHint("SDL_VIDEO_DRIVER", "offscreen");
+    if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
         SDL_Log("Couldn't initialize the offscreen video driver: %s\n",
                 SDL_GetError());
         return SDL_FALSE;
diff --git a/test/testshape.c b/test/testshape.c
index 7adbefae7b84..415d6d21d9dc 100644
--- a/test/testshape.c
+++ b/test/testshape.c
@@ -63,7 +63,7 @@ int main(int argc, char **argv)
         exit(-1);
     }
 
-    if (SDL_VideoInit(NULL) == -1) {
+    if (SDL_Init(SDL_INIT_VIDEO) == -1) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not initialize SDL video.");
         exit(-2);
     }
@@ -85,7 +85,7 @@ int main(int argc, char **argv)
                 SDL_FreeSurface(pictures[j].surface);
             }
             SDL_free(pictures);
-            SDL_VideoQuit();
+            SDL_Quit();
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not load surface from named bitmap file: %s", argv[i + 1]);
             exit(-3);
         }
@@ -110,7 +110,7 @@ int main(int argc, char **argv)
             SDL_FreeSurface(pictures[i].surface);
         }
         SDL_free(pictures);
-        SDL_VideoQuit();
+        SDL_Quit();
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create shaped window for SDL_Shape.");
         exit(-4);
     }
@@ -121,7 +121,7 @@ int main(int argc, char **argv)
             SDL_FreeSurface(pictures[i].surface);
         }
         SDL_free(pictures);
-        SDL_VideoQuit();
+        SDL_Quit();
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create rendering context for SDL_Shape window.");
         exit(-5);
     }
@@ -143,7 +143,7 @@ int main(int argc, char **argv)
             SDL_free(pictures);
             SDL_DestroyRenderer(renderer);
             SDL_DestroyWindow(window);
-            SDL_VideoQuit();
+            SDL_Quit();
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create texture for SDL_shape.");
             exit(-6);
         }
@@ -201,8 +201,8 @@ int main(int argc, char **argv)
         SDL_FreeSurface(pictures[i].surface);
     }
     SDL_free(pictures);
-    /* Call SDL_VideoQuit() before quitting. */
-    SDL_VideoQuit();
+    /* Call SDL_Quit() before quitting. */
+    SDL_Quit();
 
     return 0;
 }