SDL: Windows default to fullscreen desktop mode if they don't pick an explicit video mode

From 6b137579eaa4ff47c936e72ced73939bc69daa62 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 31 Jan 2023 21:23:14 -0800
Subject: [PATCH] Windows default to fullscreen desktop mode if they don't pick
 an explicit video mode

Rather than iterating over display modes using an index, there is a new function SDL_GetFullscreenDisplayModes() to get the list of available fullscreen modes on a display.
{
    SDL_DisplayID display = SDL_GetPrimaryDisplay();
    int num_modes = 0;
    SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &num_modes);
    if (modes) {
        for (i = 0; i < num_modes; ++i) {
            SDL_DisplayMode *mode = modes[i];
            SDL_Log("Display %" SDL_PRIu32 " mode %d:  %dx%d@%gHz, %d%% scale\n",
                    display, i, mode->pixel_w, mode->pixel_h, mode->refresh_rate, (int)(mode->display_scale * 100.0f));
        }
        SDL_free(modes);
    }
}

SDL_GetDesktopDisplayMode() and SDL_GetCurrentDisplayMode() return pointers to display modes rather than filling in application memory.

Windows now have an explicit fullscreen mode that is set, using SDL_SetWindowFullscreenMode(). The fullscreen mode for a window can be queried with SDL_GetWindowFullscreenMode(), which returns a pointer to the mode, or NULL if the window will be fullscreen desktop. SDL_SetWindowFullscreen() just takes a boolean value, setting the correct fullscreen state based on the selected mode.
---
 build-scripts/SDL_migration.cocci          |  15 +
 docs/README-migration.md                   |  33 +-
 docs/README-winrt.md                       |   9 +-
 include/SDL3/SDL_oldnames.h                |   6 +
 include/SDL3/SDL_test_common.h             |   4 +-
 include/SDL3/SDL_video.h                   | 154 ++--
 src/dynapi/SDL_dynapi.sym                  |   9 +-
 src/dynapi/SDL_dynapi_overrides.h          |   9 +-
 src/dynapi/SDL_dynapi_procs.h              |  15 +-
 src/events/SDL_windowevents.c              |   4 +-
 src/render/SDL_render.c                    |   7 +-
 src/render/direct3d/SDL_render_d3d.c       |  27 +-
 src/test/SDL_test_common.c                 | 156 ++--
 src/video/SDL_sysvideo.h                   |  17 +-
 src/video/SDL_video.c                      | 936 ++++++++++-----------
 src/video/android/SDL_androidvideo.c       |  20 +-
 src/video/cocoa/SDL_cocoamodes.m           |  32 +-
 src/video/cocoa/SDL_cocoaopengl.m          |   2 +-
 src/video/dummy/SDL_nullvideo.c            |   2 -
 src/video/emscripten/SDL_emscriptenvideo.c |   2 -
 src/video/haiku/SDL_bmodes.cc              |   2 +-
 src/video/kmsdrm/SDL_kmsdrmvideo.c         |  39 +-
 src/video/n3ds/SDL_n3dsvideo.c             |  17 +-
 src/video/ngage/SDL_ngagevideo.cpp         |  10 -
 src/video/offscreen/SDL_offscreenvideo.c   |   2 -
 src/video/psp/SDL_pspvideo.c               |  28 +-
 src/video/raspberry/SDL_rpivideo.c         |  14 -
 src/video/riscos/SDL_riscosframebuffer.c   |  10 +-
 src/video/riscos/SDL_riscosmodes.c         |   2 +-
 src/video/uikit/SDL_uikitmodes.m           |  48 +-
 src/video/uikit/SDL_uikitwindow.m          |  16 +-
 src/video/vita/SDL_vitavideo.c             |  16 +-
 src/video/vivante/SDL_vivantevideo.c       |  14 -
 src/video/wayland/SDL_waylandopengles.c    |   5 +-
 src/video/wayland/SDL_waylandvideo.c       |  39 +-
 src/video/wayland/SDL_waylandwindow.c      |  19 +-
 src/video/windows/SDL_windowsevents.c      |   4 +-
 src/video/windows/SDL_windowsmodes.c       |   9 +-
 src/video/winrt/SDL_winrtvideo.cpp         |  11 +-
 src/video/x11/SDL_x11messagebox.c          |   5 +-
 src/video/x11/SDL_x11modes.c               |  28 +-
 src/video/x11/SDL_x11video.c               |   3 +-
 test/testautomation_video.c                | 135 +--
 test/testdisplayinfo.c                     |  34 +-
 test/testgl.c                              |   8 +-
 test/testgles.c                            |  10 +-
 test/testgles2.c                           |  10 +-
 test/testgles2_sdf.c                       |  10 +-
 test/testvulkan.c                          |   8 +-
 test/testwm.c                              |  27 +-
 50 files changed, 914 insertions(+), 1128 deletions(-)

diff --git a/build-scripts/SDL_migration.cocci b/build-scripts/SDL_migration.cocci
index feaf0c9b0816..40546b9af004 100644
--- a/build-scripts/SDL_migration.cocci
+++ b/build-scripts/SDL_migration.cocci
@@ -2359,3 +2359,18 @@ SDL_DisplayMode e;
 - SDL_GetWindowDisplayIndex
 + SDL_GetDisplayForWindow
   (...)
+@@
+@@
+- SDL_SetWindowDisplayMode
++ SDL_SetWindowFullscreenMode
+  (...)
+@@
+@@
+- SDL_GetWindowDisplayMode
++ SDL_GetWindowFullscreenMode
+  (...)
+@@
+@@
+- SDL_GetClosestDisplayMode
++ SDL_GetClosestFullscreenDisplayMode
+  (...)
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 57ea7ede1da1..32a7bb3f8afd 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -962,7 +962,7 @@ Rather than iterating over displays using display index, there is a new function
 ```c
 {
     if (SDL_InitSubSystem(SDL_INIT_VIDEO) == 0) {
-        int i, num_displays;
+        int i, num_displays = 0;
         SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
         if (displays) {
             for (i = 0; i < num_displays; ++i) {
@@ -988,6 +988,29 @@ SDL_DisplayMode now includes the pixel size, the screen size and the relationshi
 
 The refresh rate in SDL_DisplayMode is now a float.
 
+Rather than iterating over display modes using an index, there is a new function SDL_GetFullscreenDisplayModes() to get the list of available fullscreen modes on a display.
+```c
+{
+    SDL_DisplayID display = SDL_GetPrimaryDisplay();
+    int num_modes = 0;
+    SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &num_modes);
+    if (modes) {
+        for (i = 0; i < num_modes; ++i) {
+            SDL_DisplayMode *mode = modes[i];
+            SDL_Log("Display %" SDL_PRIu32 " mode %d:  %dx%d@%gHz, %d%% scale\n",
+                    display, i, mode->pixel_w, mode->pixel_h, mode->refresh_rate, (int)(mode->display_scale * 100.0f));
+        }
+        SDL_free(modes);
+    }
+}
+```
+
+SDL_GetDesktopDisplayMode() and SDL_GetCurrentDisplayMode() return pointers to display modes rather than filling in application memory.
+
+Windows now have an explicit fullscreen mode that is set, using SDL_SetWindowFullscreenMode(). The fullscreen mode for a window can be queried with SDL_GetWindowFullscreenMode(), which returns a pointer to the mode, or NULL if the window will be fullscreen desktop. SDL_SetWindowFullscreen() just takes a boolean value, setting the correct fullscreen state based on the selected mode.
+
+SDL_WINDOW_FULLSCREEN has been renamed SDL_WINDOW_FULLSCREEN_EXCLUSIVE, and SDL_WINDOW_FULLSCREEN_DESKTOP no longer includes the old SDL_WINDOW_FULLSCREEN flag. You can use `(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_MASK) != 0` if you want to check for either state.
+
 SDL_SetWindowBrightness and SDL_SetWindowGammaRamp have been removed from the API, because they interact poorly with modern operating systems and aren't able to limit their effects to the SDL window.
 
 Programs which have access to shaders can implement more robust versions of those functions using custom shader code rendered as a post-process effect.
@@ -1003,18 +1026,22 @@ SDL_GL_GetSwapInterval() takes the interval as an output parameter and returns 0
 SDL_GL_GetDrawableSize() has been removed. SDL_GetWindowSizeInPixels() can be used in its place.
 
 The following functions have been renamed:
+* SDL_GetClosestDisplayMode() => SDL_GetClosestFullscreenDisplayMode()
 * SDL_GetDisplayDPI() => SDL_GetDisplayPhysicalDPI()
 * SDL_GetPointDisplayIndex() => SDL_GetDisplayForPoint()
 * SDL_GetRectDisplayIndex() => SDL_GetDisplayForRect()
 * SDL_GetWindowDisplayIndex() => SDL_GetDisplayForWindow()
+* SDL_GetWindowDisplayMode() => SDL_GetWindowFullscreenMode()
+* SDL_SetWindowDisplayMode() => SDL_SetWindowFullscreenMode()
 
 The following functions have been removed:
+* SDL_GetClosestFullscreenDisplayMode()
+* SDL_GetDisplayMode()
+* SDL_GetNumDisplayModes() - replaced with SDL_GetFullscreenDisplayModes()
 * SDL_GetNumVideoDisplays() - replaced with SDL_GetDisplays()
 
 SDL_Window id type is named SDL_WindowID
 
-SDL_WINDOW_FULLSCREEN has been renamed SDL_WINDOW_FULLSCREEN_EXCLUSIVE, and SDL_WINDOW_FULLSCREEN_DESKTOP no longer includes the old SDL_WINDOW_FULLSCREEN flag. You can use `(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_MASK) != 0` if you want to check for either state.
-
 The following symbols have been renamed:
 * SDL_WINDOW_INPUT_GRABBED => SDL_WINDOW_MOUSE_GRABBED
 
diff --git a/docs/README-winrt.md b/docs/README-winrt.md
index 7d26fbf5d71e..f8c2e812fcbf 100644
--- a/docs/README-winrt.md
+++ b/docs/README-winrt.md
@@ -333,17 +333,14 @@ your project, and open the file in Visual C++'s text editor.
     
 int main(int argc, char **argv)
 {
-    SDL_DisplayMode mode;
-    SDL_Window * window = NULL;
-    SDL_Renderer * renderer = NULL;
+    SDL_Window *window = NULL;
+    SDL_Renderer *renderer = NULL;
     SDL_Event evt;
     SDL_bool keep_going = SDL_TRUE;
   
     if (SDL_Init(SDL_INIT_VIDEO) != 0) {
         return 1;
-    } else if (SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay(), &mode) != 0) {
-        return 1;
-    } else if (SDL_CreateWindowAndRenderer(mode.w, mode.h, SDL_WINDOW_FULLSCREEN_EXCLUSIVE, &window, &renderer) != 0) {
+    } else if (SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP, &window, &renderer) != 0) {
         return 1;
     }
     
diff --git a/include/SDL3/SDL_oldnames.h b/include/SDL3/SDL_oldnames.h
index f84b8e0df3e3..80d73537a33a 100644
--- a/include/SDL3/SDL_oldnames.h
+++ b/include/SDL3/SDL_oldnames.h
@@ -412,10 +412,13 @@
 #define SDL_GetTicks64 SDL_GetTicks
 
 /* ##SDL_video.h */
+#define SDL_GetClosestDisplayMode SDL_GetClosestFullscreenDisplayMode
 #define SDL_GetDisplayDPI SDL_GetDisplayPhysicalDPI
 #define SDL_GetPointDisplayIndex SDL_GetDisplayForPoint
 #define SDL_GetRectDisplayIndex SDL_GetDisplayForRect
 #define SDL_GetWindowDisplayIndex SDL_GetDisplayForWindow
+#define SDL_GetWindowDisplayMode SDL_GetWindowFullscreenMode
+#define SDL_SetWindowDisplayMode SDL_SetWindowFullscreenMode
 #define SDL_WINDOW_FULLSCREEN SDL_WINDOW_FULLSCREEN_EXCLUSIVE
 #define SDL_WINDOW_INPUT_GRABBED SDL_WINDOW_MOUSE_GRABBED
 
@@ -795,10 +798,13 @@
 #define SDL_GetTicks64 SDL_GetTicks64_renamed_SDL_GetTicks
 
 /* ##SDL_video.h */
+#define SDL_GetClosestDisplayMode SDL_GetClosestDisplayMode_renamed_SDL_GetClosestFullscreenDisplayMode
 #define SDL_GetDisplayDPI SDL_GetDisplayDPI_renamed_SDL_GetDisplayPhysicalDPI
 #define SDL_GetPointDisplayIndex SDL_GetPointDisplayIndex_renamed_SDL_GetDisplayForPoint
 #define SDL_GetRectDisplayIndex SDL_GetRectDisplayIndex_renamed_SDL_GetDisplayForRect
 #define SDL_GetWindowDisplayIndex SDL_GetWindowDisplayIndex_renamed_SDL_GetDisplayForWindow
+#define SDL_GetWindowDisplayMode SDL_GetWindowDisplayMode_renamed_SDL_GetWindowFullscreenMode
+#define SDL_SetWindowDisplayMode SDL_SetWindowDisplayMode_renamed_SDL_SetWindowFullscreenMode
 #define SDL_WINDOW_FULLSCREEN SDL_WINDOW_FULLSCREEN_renamed_SDL_WINDOW_FULLSCREEN_EXCLUSIVE
 #define SDL_WINDOW_INPUT_GRABBED SDL_WINDOW_INPUT_GRABBED_renamed_SDL_WINDOW_MOUSE_GRABBED
 
diff --git a/include/SDL3/SDL_test_common.h b/include/SDL3/SDL_test_common.h
index 0dc4df3b70bd..50a612c34d51 100644
--- a/include/SDL3/SDL_test_common.h
+++ b/include/SDL3/SDL_test_common.h
@@ -61,7 +61,8 @@ typedef struct
 
     /* Video info */
     const char *videodriver;
-    int display;
+    int display_index;
+    SDL_DisplayID displayID;
     const char *window_title;
     const char *window_icon;
     Uint32 window_flags;
@@ -79,6 +80,7 @@ typedef struct
     float scale;
     int depth;
     float refresh_rate;
+    SDL_DisplayMode fullscreen_mode;
     int num_windows;
     SDL_Window **windows;
 
diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h
index 05c0c9ae90b7..fa1c73d6c457 100644
--- a/include/SDL3/SDL_video.h
+++ b/include/SDL3/SDL_video.h
@@ -43,19 +43,29 @@ extern "C" {
 typedef Uint32 SDL_DisplayID;
 typedef Uint32 SDL_WindowID;
 
+/**
+ *  \brief The flags on a display mode
+ */
+typedef enum
+{
+    SDL_DISPLAYMODE_DESKTOP         = 0x00000001,   /**< The display uses this as the desktop mode */
+    SDL_DISPLAYMODE_CURRENT         = 0x00000002,   /**< The display is currently using this mode */
+
+} SDL_DisplayModeFlags;
+
 /**
  *  \brief  The structure that defines a display mode
  *
- *  \sa SDL_GetNumDisplayModes()
- *  \sa SDL_GetDisplayMode()
+ *  \sa SDL_GetFullscreenDisplayModes()
  *  \sa SDL_GetDesktopDisplayMode()
  *  \sa SDL_GetCurrentDisplayMode()
- *  \sa SDL_GetClosestDisplayMode()
- *  \sa SDL_SetWindowDisplayMode()
- *  \sa SDL_GetWindowDisplayMode()
+ *  \sa SDL_SetWindowFullscreenMode()
+ *  \sa SDL_GetWindowFullscreenMode()
  */
 typedef struct
 {
+    SDL_DisplayID displayID;    /**< the display this mode is associated with */
+    Uint32 flags;               /**< whether this mode is the current mode or a desktop mode */
     Uint32 format;              /**< pixel format */
     int pixel_w;                /**< width in pixels (used for creating back buffers) */
     int pixel_h;                /**< height in pixels (used for creating back buffers) */
@@ -422,44 +432,53 @@ extern DECLSPEC int SDLCALL SDL_GetDisplayPhysicalDPI(SDL_DisplayID displayID, f
 extern DECLSPEC SDL_DisplayOrientation SDLCALL SDL_GetDisplayOrientation(SDL_DisplayID displayID);
 
 /**
- * Get the number of available display modes.
+ * Get a list of fullscreen display modes available on a display.
+ *
+ * The display modes are sorted in this priority:
+ * - screen_w -> largest to smallest
+ * - screen_h -> largest to smallest
+ * - pixel_w -> largest to smallest
+ * - pixel_h -> largest to smallest
+ * - bits per pixel -> more colors to fewer colors
+ * - packed pixel layout -> largest to smallest
+ * - refresh rate -> highest to lowest
  *
  * \param displayID the instance ID of the display to query
- * \returns a number >= 1 on success or a negative error code on failure; call
- *          SDL_GetError() for more information.
+ * \param count a pointer filled in with the number of displays returned
+ * \returns a NULL terminated array of display mode pointers which should be freed
+ *          with SDL_free(), or NULL on error; call SDL_GetError() for more
+ *          details.
  *
  * \since This function is available since SDL 3.0.0.
  *
- * \sa SDL_GetDisplayMode
  * \sa SDL_GetDisplays
  */
-extern DECLSPEC int SDLCALL SDL_GetNumDisplayModes(SDL_DisplayID displayID);
+extern DECLSPEC const SDL_DisplayMode **SDLCALL SDL_GetFullscreenDisplayModes(SDL_DisplayID displayID, int *count);
 
 /**
- * Get information about a specific display mode.
- *
- * The display modes are sorted in this priority:
+ * Get the closest match to the requested display mode.
  *
- * - screen_w -> largest to smallest
- * - screen_h -> largest to smallest
- * - pixel_w -> largest to smallest
- * - pixel_h -> largest to smallest
- * - bits per pixel -> more colors to fewer colors
- * - packed pixel layout -> largest to smallest
- * - refresh rate -> highest to lowest
+ * The available display modes are scanned and `closest` is filled in with the
+ * closest mode matching the requested mode and returned. The mode format and
+ * refresh rate default to the desktop mode if they are set to 0. The modes
+ * are scanned with size being first priority, format being second priority,
+ * and finally checking the refresh rate. If all the available modes are too
+ * small, then NULL is returned.
  *
  * \param displayID the instance ID of the display to query
- * \param modeIndex the index of the display mode to query
- * \param mode an SDL_DisplayMode structure filled in with the mode at
- *             `modeIndex`
- * \returns 0 on success or a negative error code on failure; call
- *          SDL_GetError() for more information.
+ * \param w the width in pixels of the desired display mode
+ * \param h the height in pixels of the desired display mode
+ * \param refresh_rate the refresh rate of the desired display mode, or 0.0f for the desktop refresh rate
+ * \returns a pointer to the closest display mode equal to or larger than the desired mode, or NULL on error; call SDL_GetError() for more information.
+ * \returns the passed in value `closest` or NULL if no matching video mode
+ *          was available; call SDL_GetError() for more information.
  *
  * \since This function is available since SDL 3.0.0.
  *
- * \sa SDL_GetNumDisplayModes
+ * \sa SDL_GetDisplays
+ * \sa SDL_GetFullscreenDisplayModes
  */
-extern DECLSPEC int SDLCALL SDL_GetDisplayMode(SDL_DisplayID displayID, int modeIndex, SDL_DisplayMode *mode);
+extern DECLSPEC const SDL_DisplayMode *SDLCALL SDL_GetClosestFullscreenDisplayMode(SDL_DisplayID displayID, int w, int h, float refresh_rate);
 
 /**
  * Get information about the desktop's display mode.
@@ -470,18 +489,15 @@ extern DECLSPEC int SDLCALL SDL_GetDisplayMode(SDL_DisplayID displayID, int mode
  * display mode.
  *
  * \param displayID the instance ID of the display to query
- * \param mode an SDL_DisplayMode structure filled in with the current display
- *             mode
- * \returns 0 on success or a negative error code on failure; call
+ * \returns a pointer to the desktop display mode or NULL on error; call
  *          SDL_GetError() for more information.
  *
  * \since This function is available since SDL 3.0.0.
  *
  * \sa SDL_GetCurrentDisplayMode
- * \sa SDL_GetDisplayMode
- * \sa SDL_SetWindowDisplayMode
+ * \sa SDL_GetDisplays
  */
-extern DECLSPEC int SDLCALL SDL_GetDesktopDisplayMode(SDL_DisplayID displayID, SDL_DisplayMode *mode);
+extern DECLSPEC const SDL_DisplayMode *SDLCALL SDL_GetDesktopDisplayMode(SDL_DisplayID displayID);
 
 /**
  * Get information about the current display mode.
@@ -492,44 +508,15 @@ extern DECLSPEC int SDLCALL SDL_GetDesktopDisplayMode(SDL_DisplayID displayID, S
  * display mode.
  *
  * \param displayID the instance ID of the display to query
- * \param mode an SDL_DisplayMode structure filled in with the current display
- *             mode
- * \returns 0 on success or a negative error code on failure; call
+ * \returns a pointer to the desktop display mode or NULL on error; call
  *          SDL_GetError() for more information.
  *
  * \since This function is available since SDL 3.0.0.
  *
  * \sa SDL_GetDesktopDisplayMode
- * \sa SDL_GetDisplayMode
  * \sa SDL_GetDisplays
- * \sa SDL_SetWindowDisplayMode
- */
-extern DECLSPEC int SDLCALL SDL_GetCurrentDisplayMode(SDL_DisplayID displayID, SDL_DisplayMode *mode);
-
-/**
- * Get the closest match to the requested display mode.
- *
- * The available display modes are scanned and `closest` is filled in with the
- * closest mode matching the requested mode and returned. The mode format and
- * refresh rate default to the desktop mode if they are set to 0. The modes
- * are scanned with size being first priority, format being second priority,
- * and finally checking the refresh rate. If all the available modes are too
- * small, then NULL is returned.
- *
- * \param displayID the instance ID of the display to query
- * \param mode an SDL_DisplayMode structure containing the desired display
- *             mode, should be zero initialized
- * \param closest an SDL_DisplayMode structure filled in with the closest
- *                match of the available display modes
- * \returns the passed in value `closest` or NULL if no matching video mode
- *          was available; call SDL_GetError() for more information.
- *
- * \since This function is available since SDL 3.0.0.
- *
- * \sa SDL_GetDisplayMode
- * \sa SDL_GetNumDisplayModes
  */
-extern DECLSPEC SDL_DisplayMode *SDLCALL SDL_GetClosestDisplayMode(SDL_DisplayID displayID, const SDL_DisplayMode *mode, SDL_DisplayMode *closest);
+extern DECLSPEC const SDL_DisplayMode *SDLCALL SDL_GetCurrentDisplayMode(SDL_DisplayID displayID);
 
 /**
  * Get the display containing a point
@@ -576,41 +563,36 @@ extern DECLSPEC SDL_DisplayID SDLCALL SDL_GetDisplayForRect(const SDL_Rect *rect
 extern DECLSPEC SDL_DisplayID SDLCALL SDL_GetDisplayForWindow(SDL_Window *window);
 
 /**
- * Set the display mode to use when a window is visible at fullscreen.
+ * Set the display mode to use when a window is visible and fullscreen.
  *
  * This only affects the display mode used when the window is fullscreen. To
  * change the window size when the window is not fullscreen, use
  * SDL_SetWindowSize().
  *
  * \param window the window to affect
- * \param mode the SDL_DisplayMode structure representing the mode to use, or
- *             NULL to use the window's dimensions and the desktop's format
- *             and refresh rate
+ * \param mode a pointer to the display mode to use, which can be NULL for desktop mode, or one of the fullscreen modes returned by SDL_GetFullscreenDisplayModes().
  * \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_GetWindowDisplayMode
+ * \sa SDL_GetWindowFullscreenMode
  * \sa SDL_SetWindowFullscreen
  */
-extern DECLSPEC int SDLCALL SDL_SetWindowDisplayMode(SDL_Window *window, const SDL_DisplayMode *mode);
+extern DECLSPEC int SDLCALL SDL_SetWindowFullscreenMode(SDL_Window *window, const SDL_DisplayMode *mode);
 
 /**
  * Query the display mode to use when a window is visible at fullscreen.
  *
  * \param window the window to query
- * \param mode an SDL_DisplayMode structure filled in with the fullscreen
- *             display mode
- * \returns 0 on success or a negative error code on failure; call
- *          SDL_GetError() for more information.
+ * \returns a pointer to the fullscreen mode to use or NULL for desktop mode
  *
  * \since This function is available since SDL 3.0.0.
  *
- * \sa SDL_SetWindowDisplayMode
+ * \sa SDL_SetWindowFullscreenMode
  * \sa SDL_SetWindowFullscreen
  */
-extern DECLSPEC int SDLCALL SDL_GetWindowDisplayMode(SDL_Window *window, SDL_DisplayMode *mode);
+extern DECLSPEC const SDL_DisplayMode *SDLCALL SDL_GetWindowFullscreenMode(SDL_Window *window);
 
 /**
  * Get the raw ICC profile data for the screen the window is currently on.
@@ -879,8 +861,8 @@ extern DECLSPEC void SDLCALL SDL_GetWindowPosition(SDL_Window *window, int *x, i
  * The window size in screen coordinates may differ from the size in pixels if
  * the window is on a high density display (one with an OS scaling factor).
  *
- * Fullscreen windows automatically match the size of the display mode, and
- * you should use SDL_SetWindowDisplayMode() to change their size.
+ * This only affects the size of the window when not in fullscreen mode. To change
+ * the fullscreen mode of a window, use SDL_SetWindowFullscreenMode()
  *
  * \param window the window to change
  * \param w the width of the window, must be > 0
@@ -889,7 +871,7 @@ extern DECLSPEC void SDLCALL SDL_GetWindowPosition(SDL_Window *window, int *x, i
  * \since This function is available since SDL 3.0.0.
  *
  * \sa SDL_GetWindowSize
- * \sa SDL_SetWindowDisplayMode
+ * \sa SDL_SetWindowFullscreenMode
  */
 extern DECLSPEC void SDLCALL SDL_SetWindowSize(SDL_Window *window, int w, int h);
 
@@ -1152,22 +1134,20 @@ extern DECLSPEC void SDLCALL SDL_RestoreWindow(SDL_Window *window);
 /**
  * Set a window's fullscreen state.
  *
- * `flags` may be `SDL_WINDOW_FULLSCREEN_EXCLUSIVE`, for "real" fullscreen
- * with a videomode change; `SDL_WINDOW_FULLSCREEN_DESKTOP` for "fake"
- * fullscreen that takes the size of the desktop; and 0 for windowed mode.
+ * By default a window in fullscreen state uses fullscreen desktop mode,
+ * but a specific display mode can be set using SDL_SetWindowFullscreenMode().
  *
  * \param window the window to change
- * \param flags `SDL_WINDOW_FULLSCREEN_EXCLUSIVE`,
- *              `SDL_WINDOW_FULLSCREEN_DESKTOP` or 0
+ * \param fullscreen SDL_TRUE for fullscreen mode, SDL_FALSE for windowed mode
  * \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_GetWindowDisplayMode
- * \sa SDL_SetWindowDisplayMode
+ * \sa SDL_GetWindowFullscreenMode
+ * \sa SDL_SetWindowFullscreenMode
  */
-extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_Window *window, Uint32 flags);
+extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_Window *window, SDL_bool fullscreen);
 
 /**
  * Get the SDL surface associated with the window.
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 22bbb40275c7..8547bde20180 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -153,7 +153,6 @@ SDL3_0.0.0 {
     SDL_GetCPUCacheLineSize;
     SDL_GetCPUCount;
     SDL_GetClipboardText;
-    SDL_GetClosestDisplayMode;
     SDL_GetCurrentAudioDriver;
     SDL_GetCurrentDisplayMode;
     SDL_GetCurrentVideoDriver;
@@ -166,7 +165,6 @@ SDL3_0.0.0 {
     SDL_GetDisplayPhysicalDPI;
     SDL_GetDisplayForPoint;
     SDL_GetDisplayForRect;
-    SDL_GetDisplayMode;
     SDL_GetDisplayName;
     SDL_GetDisplayOrientation;
     SDL_GetDisplayUsableBounds;
@@ -260,7 +258,6 @@ SDL3_0.0.0 {
     SDL_GetNumAllocations;
     SDL_GetNumAudioDevices;
     SDL_GetNumAudioDrivers;
-    SDL_GetNumDisplayModes;
     SDL_GetNumGamepadMappings;
     SDL_GetNumJoystickAxes;
     SDL_GetNumJoystickButtons;
@@ -348,7 +345,7 @@ SDL3_0.0.0 {
     SDL_GetWindowBordersSize;
     SDL_GetWindowData;
     SDL_GetDisplayForWindow;
-    SDL_GetWindowDisplayMode;
+    SDL_GetWindowFullscreenMode;
     SDL_GetWindowFlags;
     SDL_GetWindowFromID;
     SDL_GetWindowGrab;
@@ -613,7 +610,7 @@ SDL3_0.0.0 {
     SDL_SetWindowAlwaysOnTop;
     SDL_SetWindowBordered;
     SDL_SetWindowData;
-    SDL_SetWindowDisplayMode;
+    SDL_SetWindowFullscreenMode;
     SDL_SetWindowFullscreen;
     SDL_SetWindowGrab;
     SDL_SetWindowHitTest;
@@ -840,6 +837,8 @@ SDL3_0.0.0 {
     SDL_ConvertAudioSamples;
     SDL_GetDisplays;
     SDL_GetPrimaryDisplay;
+    SDL_GetFullscreenDisplayModes;
+    SDL_GetClosestFullscreenDisplayMode;
     # extra symbols go here (don't modify this line)
   local: *;
 };
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 2f2c0c46637f..92d4019f95f7 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -178,7 +178,6 @@
 #define SDL_GetCPUCacheLineSize SDL_GetCPUCacheLineSize_REAL
 #define SDL_GetCPUCount SDL_GetCPUCount_REAL
 #define SDL_GetClipboardText SDL_GetClipboardText_REAL
-#define SDL_GetClosestDisplayMode SDL_GetClosestDisplayMode_REAL
 #define SDL_GetCurrentAudioDriver SDL_GetCurrentAudioDriver_REAL
 #define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_REAL
 #define SDL_GetCurrentVideoDriver SDL_GetCurrentVideoDriver_REAL
@@ -191,7 +190,6 @@
 #define SDL_GetDisplayPhysicalDPI SDL_GetDisplayPhysicalDPI_REAL
 #define SDL_GetDisplayForPoint SDL_GetDisplayForPoint_REAL
 #define SDL_GetDisplayForRect SDL_GetDisplayForRect_REAL
-#define SDL_GetDisplayMode SDL_GetDisplayMode_REAL
 #define SDL_GetDisplayName SDL_GetDisplayName_REAL
 #define SDL_GetDisplayOrientation SDL_GetDisplayOrientation_REAL
 #define SDL_GetDisplayUsableBounds SDL_GetDisplayUsableBounds_REAL
@@ -285,7 +283,6 @@
 #define SDL_GetNumAllocations SDL_GetNumAllocations_REAL
 #define SDL_GetNumAudioDevices SDL_GetNumAudioDevices_REAL
 #define SDL_GetNumAudioDrivers SDL_GetNumAudioDrivers_REAL
-#define SDL_GetNumDisplayModes SDL_GetNumDisplayModes_REAL
 #define SDL_GetNumGamepadMappings SDL_GetNumGamepadMappings_REAL
 #define SDL_GetNumJoystickAxes SDL_GetNumJoystickAxes_REAL
 #define SDL_GetNumJoystickButtons SDL_GetNumJoystickButtons_REAL
@@ -373,7 +370,7 @@
 #define SDL_GetWindowBordersSize SDL_GetWindowBordersSize_REAL
 #define SDL_GetWindowData SDL_GetWindowData_REAL
 #define SDL_GetDisplayForWindow SDL_GetDisplayForWindow_REAL
-#define SDL_GetWindowDisplayMode SDL_GetWindowDisplayMode_REAL
+#define SDL_GetWindowFullscreenMode SDL_GetWindowFullscreenMode_REAL
 #define SDL_GetWindowFlags SDL_GetWindowFlags_REAL
 #define SDL_GetWindowFromID SDL_GetWindowFromID_REAL
 #define SDL_GetWindowGrab SDL_GetWindowGrab_REAL
@@ -638,7 +635,7 @@
 #define SDL_SetWindowAlwaysOnTop SDL_SetWindowAlwaysOnTop_REAL
 #define SDL_SetWindowBordered SDL_SetWindowBordered_REAL
 #define SDL_SetWindowData SDL_SetWindowData_REAL
-#define SDL_SetWindowDisplayMode SDL_SetWindowDisplayMode_REAL
+#define SDL_SetWindowFullscreenMode SDL_SetWindowFullscreenMode_REAL
 #define SDL_SetWindowFullscreen SDL_SetWindowFullscreen_REAL
 #define SDL_SetWindowGrab SDL_SetWindowGrab_REAL
 #define SDL_SetWindowHitTest SDL_SetWindowHitTest_REAL
@@ -867,3 +864,5 @@
 #define SDL_ConvertAudioSamples SDL_ConvertAudioSamples_REAL
 #define SDL_GetDisplays SDL_GetDisplays_REAL
 #define SDL_GetPrimaryDisplay SDL_GetPrimaryDisplay_REAL
+#define SDL_GetFullscreenDisplayModes SDL_GetFullscreenDisplayModes_REAL
+#define SDL_GetClosestFullscreenDisplayMode SDL_GetClosestFullscreenDisplayMode_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 74214a85b0cf..1363f552d664 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -252,20 +252,18 @@ SDL_DYNAPI_PROC(char*,SDL_GetBasePath,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetCPUCacheLineSize,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetCPUCount,(void),(),return)
 SDL_DYNAPI_PROC(char*,SDL_GetClipboardText,(void),(),return)
-SDL_DYNAPI_PROC(SDL_DisplayMode*,SDL_GetClosestDisplayMode,(SDL_DisplayID a, const SDL_DisplayMode *b, SDL_DisplayMode *c),(a,b,c),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetCurrentAudioDriver,(void),(),return)
-SDL_DYNAPI_PROC(int,SDL_GetCurrentDisplayMode,(SDL_DisplayID a, SDL_DisplayMode *b),(a,b),return)
+SDL_DYNAPI_PROC(const SDL_DisplayMode*,SDL_GetCurrentDisplayMode,(SDL_DisplayID a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetCurrentVideoDriver,(void),(),return)
 SDL_DYNAPI_PROC(SDL_Cursor*,SDL_GetCursor,(void),(),return)
 SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetDefaultAssertionHandler,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetDefaultAudioInfo,(char **a, SDL_AudioSpec *b, int c),(a,b,c),return)
 SDL_DYNAPI_PROC(SDL_Cursor*,SDL_GetDefaultCursor,(void),(),return)
-SDL_DYNAPI_PROC(int,SDL_GetDesktopDisplayMode,(SDL_DisplayID a, SDL_DisplayMode *b),(a,b),return)
+SDL_DYNAPI_PROC(const SDL_DisplayMode*,SDL_GetDesktopDisplayMode,(SDL_DisplayID a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetDisplayBounds,(SDL_DisplayID a, SDL_Rect *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_GetDisplayPhysicalDPI,(SDL_DisplayID a, float *b, float *c, float *d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(SDL_DisplayID,SDL_GetDisplayForPoint,(const SDL_Point *a),(a),return)
 SDL_DYNAPI_PROC(SDL_DisplayID,SDL_GetDisplayForRect,(const SDL_Rect *a),(a),return)
-SDL_DYNAPI_PROC(int,SDL_GetDisplayMode,(SDL_DisplayID a, int b, SDL_DisplayMode *c),(a,b,c),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetDisplayName,(SDL_DisplayID a),(a),return)
 SDL_DYNAPI_PROC(SDL_DisplayOrientation,SDL_GetDisplayOrientation,(SDL_DisplayID a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetDisplayUsableBounds,(SDL_DisplayID a, SDL_Rect *b),(a,b),return)
@@ -359,7 +357,6 @@ SDL_DYNAPI_PROC(Uint32,SDL_GetMouseState,(float *a, float *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumAllocations,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumAudioDevices,(int a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumAudioDrivers,(void),(),return)
-SDL_DYNAPI_PR

(Patch may be truncated, please check the link at the top of this post.)