Преглед на файлове

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.
Sam Lantinga преди 2 години
родител
ревизия
6b137579ea
променени са 50 файла, в които са добавени 914 реда и са изтрити 1128 реда
  1. 15 0
      build-scripts/SDL_migration.cocci
  2. 30 3
      docs/README-migration.md
  3. 3 6
      docs/README-winrt.md
  4. 6 0
      include/SDL3/SDL_oldnames.h
  5. 3 1
      include/SDL3/SDL_test_common.h
  6. 67 87
      include/SDL3/SDL_video.h
  7. 4 5
      src/dynapi/SDL_dynapi.sym
  8. 4 5
      src/dynapi/SDL_dynapi_overrides.h
  9. 7 8
      src/dynapi/SDL_dynapi_procs.h
  10. 2 2
      src/events/SDL_windowevents.c
  11. 4 3
      src/render/SDL_render.c
  12. 14 13
      src/render/direct3d/SDL_render_d3d.c
  13. 85 71
      src/test/SDL_test_common.c
  14. 8 9
      src/video/SDL_sysvideo.h
  15. 432 504
      src/video/SDL_video.c
  16. 2 18
      src/video/android/SDL_androidvideo.c
  17. 6 26
      src/video/cocoa/SDL_cocoamodes.m
  18. 1 1
      src/video/cocoa/SDL_cocoaopengl.m
  19. 0 2
      src/video/dummy/SDL_nullvideo.c
  20. 0 2
      src/video/emscripten/SDL_emscriptenvideo.c
  21. 1 1
      src/video/haiku/SDL_bmodes.cc
  22. 16 23
      src/video/kmsdrm/SDL_kmsdrmvideo.c
  23. 5 12
      src/video/n3ds/SDL_n3dsvideo.c
  24. 0 10
      src/video/ngage/SDL_ngagevideo.cpp
  25. 0 2
      src/video/offscreen/SDL_offscreenvideo.c
  26. 16 12
      src/video/psp/SDL_pspvideo.c
  27. 0 14
      src/video/raspberry/SDL_rpivideo.c
  28. 5 5
      src/video/riscos/SDL_riscosframebuffer.c
  29. 1 1
      src/video/riscos/SDL_riscosmodes.c
  30. 25 23
      src/video/uikit/SDL_uikitmodes.m
  31. 2 14
      src/video/uikit/SDL_uikitwindow.m
  32. 3 13
      src/video/vita/SDL_vitavideo.c
  33. 0 14
      src/video/vivante/SDL_vivantevideo.c
  34. 2 3
      src/video/wayland/SDL_waylandopengles.c
  35. 19 20
      src/video/wayland/SDL_waylandvideo.c
  36. 8 11
      src/video/wayland/SDL_waylandwindow.c
  37. 2 2
      src/video/windows/SDL_windowsevents.c
  38. 3 6
      src/video/windows/SDL_windowsmodes.c
  39. 2 9
      src/video/winrt/SDL_winrtvideo.cpp
  40. 3 2
      src/video/x11/SDL_x11messagebox.c
  41. 6 22
      src/video/x11/SDL_x11modes.c
  42. 1 2
      src/video/x11/SDL_x11video.c
  43. 43 92
      test/testautomation_video.c
  44. 17 17
      test/testdisplayinfo.c
  45. 5 3
      test/testgl.c
  46. 6 4
      test/testgles.c
  47. 6 4
      test/testgles2.c
  48. 6 4
      test/testgles2_sdf.c
  49. 5 3
      test/testvulkan.c
  50. 13 14
      test/testwm.c

+ 15 - 0
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
+  (...)

+ 30 - 3
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
 

+ 3 - 6
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;
     }
     

+ 6 - 0
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
 

+ 3 - 1
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;
 

+ 67 - 87
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.

+ 4 - 5
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: *;
 };

+ 4 - 5
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

+ 7 - 8
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_PROC(int,SDL_GetNumDisplayModes,(SDL_DisplayID a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumGamepadMappings,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumJoystickAxes,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumJoystickButtons,(SDL_Joystick *a),(a),return)
@@ -445,7 +442,7 @@ SDL_DYNAPI_PROC(const char*,SDL_GetVideoDriver,(int a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetWindowBordersSize,(SDL_Window *a, int *b, int *c, int *d, int *e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(void*,SDL_GetWindowData,(SDL_Window *a, const char *b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_DisplayID,SDL_GetDisplayForWindow,(SDL_Window *a),(a),return)
-SDL_DYNAPI_PROC(int,SDL_GetWindowDisplayMode,(SDL_Window *a, SDL_DisplayMode *b),(a,b),return)
+SDL_DYNAPI_PROC(const SDL_DisplayMode*,SDL_GetWindowFullscreenMode,(SDL_Window *a),(a),return)
 SDL_DYNAPI_PROC(Uint32,SDL_GetWindowFlags,(SDL_Window *a),(a),return)
 SDL_DYNAPI_PROC(SDL_Window*,SDL_GetWindowFromID,(Uint32 a),(a),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_GetWindowGrab,(SDL_Window *a),(a),return)
@@ -693,8 +690,8 @@ SDL_DYNAPI_PROC(int,SDL_SetThreadPriority,(SDL_ThreadPriority a),(a),return)
 SDL_DYNAPI_PROC(void,SDL_SetWindowAlwaysOnTop,(SDL_Window *a, SDL_bool b),(a,b),)
 SDL_DYNAPI_PROC(void,SDL_SetWindowBordered,(SDL_Window *a, SDL_bool b),(a,b),)
 SDL_DYNAPI_PROC(void*,SDL_SetWindowData,(SDL_Window *a, const char *b, void *c),(a,b,c),return)
-SDL_DYNAPI_PROC(int,SDL_SetWindowDisplayMode,(SDL_Window *a, const SDL_DisplayMode *b),(a,b),return)
-SDL_DYNAPI_PROC(int,SDL_SetWindowFullscreen,(SDL_Window *a, Uint32 b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_SetWindowFullscreenMode,(SDL_Window *a, const SDL_DisplayMode *b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_SetWindowFullscreen,(SDL_Window *a, SDL_bool b),(a,b),return)
 SDL_DYNAPI_PROC(void,SDL_SetWindowGrab,(SDL_Window *a, SDL_bool b),(a,b),)
 SDL_DYNAPI_PROC(int,SDL_SetWindowHitTest,(SDL_Window *a, SDL_HitTest b, void *c),(a,b,c),return)
 SDL_DYNAPI_PROC(void,SDL_SetWindowIcon,(SDL_Window *a, SDL_Surface *b),(a,b),)
@@ -912,3 +909,5 @@ SDL_DYNAPI_PROC(void,SDL_aligned_free,(void *a),(a),)
 SDL_DYNAPI_PROC(int,SDL_ConvertAudioSamples,(SDL_AudioFormat a, Uint8 b, int c, int d, Uint8 *e, SDL_AudioFormat f, Uint8 g, int h, int *i, Uint8 **j),(a,b,c,d,e,f,g,h,i,j),return)
 SDL_DYNAPI_PROC(SDL_DisplayID*,SDL_GetDisplays,(int *a),(a),return)
 SDL_DYNAPI_PROC(SDL_DisplayID,SDL_GetPrimaryDisplay,(void),(),return)
+SDL_DYNAPI_PROC(const SDL_DisplayMode**,SDL_GetFullscreenDisplayModes,(SDL_DisplayID a, int *b),(a,b),return)
+SDL_DYNAPI_PROC(const SDL_DisplayMode*,SDL_GetClosestFullscreenDisplayMode,(SDL_DisplayID a, int b, int c, float d),(a,b,c,d),return)

+ 2 - 2
src/events/SDL_windowevents.c

@@ -141,10 +141,10 @@ int SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent,
         window->flags &= ~SDL_WINDOW_INPUT_FOCUS;
         break;
     case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
-        if (data1 == 0 || (SDL_DisplayID)data1 == window->displayID) {
+        if (data1 == 0 || (SDL_DisplayID)data1 == window->last_displayID) {
             return 0;
         }
-        window->displayID = (SDL_DisplayID)data1;
+        window->last_displayID = (SDL_DisplayID)data1;
         break;
     default:
         break;

+ 4 - 3
src/render/SDL_render.c

@@ -916,15 +916,16 @@ static SDL_RenderLineMethod SDL_GetRenderLineMethod()
 static void SDL_CalculateSimulatedVSyncInterval(SDL_Renderer *renderer, SDL_Window *window)
 {
     SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode *mode;
     float refresh_rate;
     int num, den;
 
     if (displayID == 0) {
         displayID = SDL_GetPrimaryDisplay();
     }
-    if (SDL_GetDesktopDisplayMode(displayID, &mode) == 0 && mode.refresh_rate > 0.0f) {
-        refresh_rate = mode.refresh_rate;
+    mode = SDL_GetDesktopDisplayMode(displayID);
+    if (mode && mode->refresh_rate > 0.0f) {
+        refresh_rate = mode->refresh_rate;
     } else {
         /* Pick a good default refresh rate */
         refresh_rate = 60.0f;

+ 14 - 13
src/render/direct3d/SDL_render_d3d.c

@@ -289,17 +289,18 @@ static int D3D_ActivateRenderer(SDL_Renderer *renderer)
     if (data->updateSize) {
         SDL_Window *window = renderer->window;
         int w, h;
-        Uint32 window_flags = SDL_GetWindowFlags(window);
+        const SDL_DisplayMode *fullscreen_mode = NULL;
 
         SDL_GetWindowSizeInPixels(window, &w, &h);
         data->pparams.BackBufferWidth = w;
         data->pparams.BackBufferHeight = h;
-        if ((window_flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
-            SDL_DisplayMode fullscreen_mode;
-            SDL_GetWindowDisplayMode(window, &fullscreen_mode);
+        if ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
+            fullscreen_mode = SDL_GetWindowFullscreenMode(window);
+        }
+        if (fullscreen_mode) {
             data->pparams.Windowed = FALSE;
-            data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
-            data->pparams.FullScreen_RefreshRateInHz = (UINT)SDL_ceilf(fullscreen_mode.refresh_rate);
+            data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode->format);
+            data->pparams.FullScreen_RefreshRateInHz = (UINT)SDL_ceilf(fullscreen_mode->refresh_rate);
         } else {
             data->pparams.Windowed = TRUE;
             data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
@@ -1554,10 +1555,9 @@ D3D_CreateRenderer(SDL_Window *window, Uint32 flags)
     IDirect3DSwapChain9 *chain;
     D3DCAPS9 caps;
     DWORD device_flags;
-    Uint32 window_flags;
     int w, h;
-    SDL_DisplayMode fullscreen_mode;
     SDL_DisplayID displayID;
+    const SDL_DisplayMode *fullscreen_mode = NULL;
 
     if (SDL_GetWindowWMInfo(window, &windowinfo, SDL_SYSWM_CURRENT_VERSION) < 0 ||
         windowinfo.subsystem != SDL_SYSWM_WINDOWS) {
@@ -1612,9 +1612,10 @@ D3D_CreateRenderer(SDL_Window *window, Uint32 flags)
     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
     renderer->driverdata = data;
 
-    window_flags = SDL_GetWindowFlags(window);
     SDL_GetWindowSizeInPixels(window, &w, &h);
-    SDL_GetWindowDisplayMode(window, &fullscreen_mode);
+    if ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
+        fullscreen_mode = SDL_GetWindowFullscreenMode(window);
+    }
 
     SDL_zero(pparams);
     pparams.hDeviceWindow = windowinfo.info.win.window;
@@ -1623,10 +1624,10 @@ D3D_CreateRenderer(SDL_Window *window, Uint32 flags)
     pparams.BackBufferCount = 1;
     pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
 
-    if ((window_flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
+    if (fullscreen_mode) {
         pparams.Windowed = FALSE;
-        pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
-        pparams.FullScreen_RefreshRateInHz = (UINT)SDL_ceilf(fullscreen_mode.refresh_rate);
+        pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode->format);
+        pparams.FullScreen_RefreshRateInHz = (UINT)SDL_ceilf(fullscreen_mode->refresh_rate);
     } else {
         pparams.Windowed = TRUE;
         pparams.BackBufferFormat = D3DFMT_UNKNOWN;

+ 85 - 71
src/test/SDL_test_common.c

@@ -218,15 +218,7 @@ int SDLTest_CommonArg(SDLTest_CommonState *state, int index)
         if (!argv[index]) {
             return -1;
         }
-        state->display = SDL_atoi(argv[index]);
-        if (SDL_WINDOWPOS_ISUNDEFINED(state->window_x)) {
-            state->window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->display);
-            state->window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->display);
-        }
-        if (SDL_WINDOWPOS_ISCENTERED(state->window_x)) {
-            state->window_x = SDL_WINDOWPOS_CENTERED_DISPLAY(state->display);
-            state->window_y = SDL_WINDOWPOS_CENTERED_DISPLAY(state->display);
-        }
+        state->display_index = SDL_atoi(argv[index]);
         return 2;
     }
     if (SDL_strcasecmp(argv[index], "--metal-window") == 0) {
@@ -1036,7 +1028,7 @@ SDL_bool
 SDLTest_CommonInit(SDLTest_CommonState *state)
 {
     int i, j, m, n, w, h;
-    SDL_DisplayMode fullscreen_mode;
+    const SDL_DisplayMode *fullscreen_mode;
     char text[1024];
 
     if (state->flags & SDL_INIT_VIDEO) {
@@ -1103,7 +1095,8 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
             SDL_Rect bounds, usablebounds;
             float hdpi = 0;
             float vdpi = 0;
-            SDL_DisplayMode mode;
+            const SDL_DisplayMode **modes;
+            const SDL_DisplayMode *mode;
             int bpp;
             Uint32 Rmask, Gmask, Bmask, Amask;
 #if SDL_VIDEO_DRIVER_WINDOWS
@@ -1128,12 +1121,12 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
                 SDL_Log("Usable bounds: %dx%d at %d,%d\n", usablebounds.w, usablebounds.h, usablebounds.x, usablebounds.y);
                 SDL_Log("DPI: %gx%g\n", hdpi, vdpi);
 
-                SDL_GetDesktopDisplayMode(displayID, &mode);
-                SDL_GetMasksForPixelFormatEnum(mode.format, &bpp, &Rmask, &Gmask,
+                mode = SDL_GetDesktopDisplayMode(displayID);
+                SDL_GetMasksForPixelFormatEnum(mode->format, &bpp, &Rmask, &Gmask,
                                            &Bmask, &Amask);
-                SDL_Log("  Current mode: %dx%d@%gHz, %d%% scale, %d bits-per-pixel (%s)\n",
-                        mode.pixel_w, mode.pixel_h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), bpp,
-                        SDL_GetPixelFormatName(mode.format));
+                SDL_Log("  Desktop mode: %dx%d@%gHz, %d%% scale, %d bits-per-pixel (%s)\n",
+                        mode->pixel_w, mode->pixel_h, mode->refresh_rate, (int)(mode->display_scale * 100.0f), bpp,
+                        SDL_GetPixelFormatName(mode->format));
                 if (Rmask || Gmask || Bmask) {
                     SDL_Log("      Red Mask   = 0x%.8" SDL_PRIx32 "\n", Rmask);
                     SDL_Log("      Green Mask = 0x%.8" SDL_PRIx32 "\n", Gmask);
@@ -1144,18 +1137,18 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
                 }
 
                 /* Print available fullscreen video modes */
-                m = SDL_GetNumDisplayModes(displayID);
+                modes = SDL_GetFullscreenDisplayModes(displayID, &m);
                 if (m == 0) {
                     SDL_Log("No available fullscreen video modes\n");
                 } else {
                     SDL_Log("  Fullscreen video modes:\n");
                     for (j = 0; j < m; ++j) {
-                        SDL_GetDisplayMode(displayID, j, &mode);
-                        SDL_GetMasksForPixelFormatEnum(mode.format, &bpp, &Rmask,
+                        mode = modes[j];
+                        SDL_GetMasksForPixelFormatEnum(mode->format, &bpp, &Rmask,
                                                    &Gmask, &Bmask, &Amask);
                         SDL_Log("    Mode %d: %dx%d@%gHz, %d%% scale, %d bits-per-pixel (%s)\n",
-                                j, mode.pixel_w, mode.pixel_h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), bpp,
-                                SDL_GetPixelFormatName(mode.format));
+                                j, mode->pixel_w, mode->pixel_h, mode->refresh_rate, (int)(mode->display_scale * 100.0f), bpp,
+                                SDL_GetPixelFormatName(mode->format));
                         if (Rmask || Gmask || Bmask) {
                             SDL_Log("        Red Mask   = 0x%.8" SDL_PRIx32 "\n",
                                     Rmask);
@@ -1169,6 +1162,7 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
                         }
                     }
                 }
+                SDL_free(modes);
 
 #if SDL_VIDEO_DRIVER_WINDOWS && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
                 /* Print the D3D9 adapter index */
@@ -1195,25 +1189,28 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
             }
         }
 
-        SDL_zero(fullscreen_mode);
-        switch (state->depth) {
-        case 8:
-            fullscreen_mode.format = SDL_PIXELFORMAT_INDEX8;
-            break;
-        case 15:
-            fullscreen_mode.format = SDL_PIXELFORMAT_RGB555;
-            break;
-        case 16:
-            fullscreen_mode.format = SDL_PIXELFORMAT_RGB565;
-            break;
-        case 24:
-            fullscreen_mode.format = SDL_PIXELFORMAT_RGB24;
-            break;
-        default:
-            fullscreen_mode.format = SDL_PIXELFORMAT_RGB888;
-            break;
+        state->displayID = SDL_GetPrimaryDisplay();
+        if (state->display_index > 0) {
+            SDL_DisplayID *displays = SDL_GetDisplays(&n);
+            if (state->display_index < n) {
+                state->displayID = displays[state->display_index];
+            }
+            SDL_free(displays);
+
+            if (SDL_WINDOWPOS_ISUNDEFINED(state->window_x)) {
+                state->window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->displayID);
+                state->window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->displayID);
+            }
+            if (SDL_WINDOWPOS_ISCENTERED(state->window_x)) {
+                state->window_x = SDL_WINDOWPOS_CENTERED_DISPLAY(state->displayID);
+                state->window_y = SDL_WINDOWPOS_CENTERED_DISPLAY(state->displayID);
+            }
+        }
+
+        fullscreen_mode = SDL_GetClosestFullscreenDisplayMode(state->displayID, state->window_w, state->window_h, state->refresh_rate);
+        if (fullscreen_mode) {
+            SDL_memcpy(&state->fullscreen_mode, fullscreen_mode, sizeof(state->fullscreen_mode));
         }
-        fullscreen_mode.refresh_rate = state->refresh_rate;
 
         state->windows =
             (SDL_Window **)SDL_calloc(state->num_windows,
@@ -1239,14 +1236,7 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
 
             /* !!! FIXME: hack to make --usable-bounds work for now. */
             if ((r.x == -1) && (r.y == -1) && (r.w == -1) && (r.h == -1)) {
-                int num_displays;
-                SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
-                if (displays && state->display < num_displays) {
-                    SDL_GetDisplayUsableBounds(displays[state->display], &r);
-                } else {
-                    SDL_GetDisplayUsableBounds(SDL_GetPrimaryDisplay(), &r);
-                }
-                SDL_free(displays);
+                SDL_GetDisplayUsableBounds(state->displayID, &r);
             }
 
             if (state->num_windows > 1) {
@@ -1275,10 +1265,13 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
                 state->window_w = w;
                 state->window_h = h;
             }
-            if (SDL_SetWindowDisplayMode(state->windows[i], &fullscreen_mode) < 0) {
-                SDL_Log("Can't set up fullscreen display mode: %s\n",
-                        SDL_GetError());
-                return SDL_FALSE;
+            if ((state->window_flags & SDL_WINDOW_FULLSCREEN_MASK) != 0) {
+                if ((state->window_flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
+                    SDL_SetWindowFullscreenMode(state->windows[i], &state->fullscreen_mode);
+                } else {
+                    SDL_SetWindowFullscreenMode(state->windows[i], NULL);
+                }
+                SDL_SetWindowFullscreen(state->windows[i], SDL_TRUE);
             }
 
             /* Add resize/drag areas for windows that are borderless and resizable */
@@ -1728,12 +1721,13 @@ static void SDLTest_ScreenShot(SDL_Renderer *renderer)
     }
 }
 
-static void FullscreenTo(int index, int windowId)
+static void FullscreenTo(SDLTest_CommonState *state, int index, int windowId)
 {
     int num_displays;
     SDL_DisplayID *displays;
     SDL_Window *window;
     Uint32 flags;
+    const SDL_DisplayMode *mode;
     struct SDL_Rect rect = { 0, 0, 0, 0 };
 
     displays = SDL_GetDisplays(&num_displays);
@@ -1744,12 +1738,27 @@ static void FullscreenTo(int index, int windowId)
 
             flags = SDL_GetWindowFlags(window);
             if ((flags & SDL_WINDOW_FULLSCREEN_MASK) != 0) {
-                SDL_SetWindowFullscreen(window, 0);
+                SDL_SetWindowFullscreen(window, SDL_FALSE);
                 SDL_Delay(15);
             }
 
-            SDL_SetWindowPosition(window, rect.x, rect.y);
-            SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_EXCLUSIVE);
+            mode = SDL_GetWindowFullscreenMode(window);
+            if (mode) {
+                /* Try to set the existing mode on the new display */
+                SDL_DisplayMode new_mode;
+
+                SDL_memcpy(&new_mode, mode, sizeof(new_mode));
+                new_mode.displayID = displays[index];
+                if (SDL_SetWindowFullscreenMode(window, &new_mode) < 0) {
+                    /* Try again with a default mode */
+                    mode = SDL_GetClosestFullscreenDisplayMode(displays[index], state->window_w, state->window_h, state->refresh_rate);
+                    SDL_SetWindowFullscreenMode(window, mode);
+                }
+            }
+            if (!mode) {
+                SDL_SetWindowPosition(window, rect.x, rect.y);
+            }
+            SDL_SetWindowFullscreen(window, SDL_TRUE);
         }
     }
     SDL_free(displays);
@@ -2043,9 +2052,9 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
                 if (window) {
                     Uint32 flags = SDL_GetWindowFlags(window);
                     if ((flags & SDL_WINDOW_FULLSCREEN_MASK) != 0) {
-                        SDL_SetWindowFullscreen(window, 0);
+                        SDL_SetWindowFullscreen(window, SDL_FALSE);
                     } else {
-                        SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_EXCLUSIVE);
+                        SDL_SetWindowFullscreen(window, SDL_TRUE);
                     }
                 }
             } else if (withAlt) {
@@ -2054,9 +2063,10 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
                 if (window) {
                     Uint32 flags = SDL_GetWindowFlags(window);
                     if ((flags & SDL_WINDOW_FULLSCREEN_MASK) != 0) {
-                        SDL_SetWindowFullscreen(window, 0);
+                        SDL_SetWindowFullscreen(window, SDL_FALSE);
                     } else {
-                        SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
+                        SDL_SetWindowFullscreenMode(window, NULL);
+                        SDL_SetWindowFullscreen(window, SDL_TRUE);
                     }
                 }
             } else if (withShift) {
@@ -2065,10 +2075,11 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
                 if (window) {
                     Uint32 flags = SDL_GetWindowFlags(window);
                     if ((flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) {
-                        SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_EXCLUSIVE);
+                        SDL_SetWindowFullscreenMode(window, &state->fullscreen_mode);
                     } else {
-                        SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
+                        SDL_SetWindowFullscreenMode(window, NULL);
                     }
+                    SDL_SetWindowFullscreen(window, SDL_TRUE);
                 }
             }
 
@@ -2105,12 +2116,12 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
             break;
         case SDLK_1:
             if (withControl) {
-                FullscreenTo(0, event->key.windowID);
+                FullscreenTo(state, 0, event->key.windowID);
             }
             break;
         case SDLK_2:
             if (withControl) {
-                FullscreenTo(1, event->key.windowID);
+                FullscreenTo(state, 1, event->key.windowID);
             }
             break;
         case SDLK_ESCAPE:
@@ -2192,7 +2203,7 @@ void SDLTest_CommonDrawWindowInfo(SDL_Renderer *renderer, SDL_Window *window, fl
     int x, y, w, h;
     float fx, fy;
     SDL_Rect rect;
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode *mode;
     float ddpi, hdpi, vdpi;
     float scaleX, scaleY;
     Uint32 flags;
@@ -2271,9 +2282,10 @@ void SDLTest_CommonDrawWindowInfo(SDL_Renderer *renderer, SDL_Window *window, fl
     SDLTest_DrawString(renderer, 0.0f, textY, text);
     textY += lineHeight;
 
-    if (0 == SDL_GetWindowDisplayMode(window, &mode)) {
-        (void)SDL_snprintf(text, sizeof text, "SDL_GetWindowDisplayMode: %dx%d@%gHz %d%% scale, (%s)",
-                           mode.pixel_w, mode.pixel_h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), SDL_GetPixelFormatName(mode.format));
+    mode = SDL_GetWindowFullscreenMode(window);
+    if (mode) {
+        (void)SDL_snprintf(text, sizeof text, "SDL_GetWindowFullscreenMode: %dx%d@%gHz %d%% scale, (%s)",
+                           mode->pixel_w, mode->pixel_h, mode->refresh_rate, (int)(mode->display_scale * 100.0f), SDL_GetPixelFormatName(mode->format));
         SDLTest_DrawString(renderer, 0.0f, textY, text);
         textY += lineHeight;
     }
@@ -2301,16 +2313,18 @@ void SDLTest_CommonDrawWindowInfo(SDL_Renderer *renderer, SDL_Window *window, fl
         textY += lineHeight;
     }
 
-    if (0 == SDL_GetCurrentDisplayMode(windowDisplayID, &mode)) {
+    mode = SDL_GetCurrentDisplayMode(windowDisplayID);
+    if (mode) {
         (void)SDL_snprintf(text, sizeof text, "SDL_GetCurrentDisplayMode: %dx%d@%gHz %d%% scale, (%s)",
-                           mode.pixel_w, mode.pixel_h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), SDL_GetPixelFormatName(mode.format));
+                           mode->pixel_w, mode->pixel_h, mode->refresh_rate, (int)(mode->display_scale * 100.0f), SDL_GetPixelFormatName(mode->format));
         SDLTest_DrawString(renderer, 0.0f, textY, text);
         textY += lineHeight;
     }
 
-    if (0 == SDL_GetDesktopDisplayMode(windowDisplayID, &mode)) {
+    mode = SDL_GetDesktopDisplayMode(windowDisplayID);
+    if (mode) {
         (void)SDL_snprintf(text, sizeof text, "SDL_GetDesktopDisplayMode: %dx%d@%gHz %d%% scale, (%s)",
-                           mode.pixel_w, mode.pixel_h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), SDL_GetPixelFormatName(mode.format));
+                           mode->pixel_w, mode->pixel_h, mode->refresh_rate, (int)(mode->display_scale * 100.0f), SDL_GetPixelFormatName(mode->format));
         SDLTest_DrawString(renderer, 0.0f, textY, text);
         textY += lineHeight;
     }

+ 8 - 9
src/video/SDL_sysvideo.h

@@ -107,7 +107,7 @@ struct SDL_Window
     int last_pixel_w, last_pixel_h;
     Uint32 flags;
     Uint32 last_fullscreen_flags;
-    SDL_DisplayID displayID;
+    SDL_DisplayID last_displayID;
 
     /* Stored position and size for windowed mode */
     SDL_Rect windowed;
@@ -150,11 +150,10 @@ struct SDL_VideoDisplay
 {
     SDL_DisplayID id;
     char *name;
-    int max_display_modes;
-    int num_display_modes;
-    SDL_DisplayMode *display_modes;
+    int max_fullscreen_modes;
+    int num_fullscreen_modes;
+    SDL_DisplayMode *fullscreen_modes;
     SDL_DisplayMode desktop_mode;
-    SDL_DisplayMode current_mode;
     SDL_DisplayOrientation orientation;
 
     SDL_Window *fullscreen_window;
@@ -505,11 +504,11 @@ extern SDL_VideoDevice *SDL_GetVideoDevice(void);
 extern SDL_bool SDL_IsVideoContextExternal(void);
 extern SDL_DisplayID SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode);
 extern SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event);
-extern void SDL_DelVideoDisplay(SDL_DisplayID display);
-extern SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
-extern void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
+extern void SDL_DelVideoDisplay(SDL_DisplayID display, SDL_bool send_event);
+extern SDL_bool SDL_AddFullscreenDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
+extern void SDL_ResetFullscreenDisplayModes(SDL_VideoDisplay *display);
 extern void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
-extern void SDL_ResetDisplayModes(SDL_VideoDisplay *display);
+extern void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
 extern SDL_VideoDisplay *SDL_GetVideoDisplay(SDL_DisplayID display);
 extern SDL_VideoDisplay *SDL_GetVideoDisplayForWindow(SDL_Window *window);
 extern int SDL_GetDisplayIndex(SDL_DisplayID displayID);

+ 432 - 504
src/video/SDL_video.c

@@ -374,9 +374,7 @@ static int SDLCALL cmpmodes(const void *A, const void *B)
 {
     const SDL_DisplayMode *a = (const SDL_DisplayMode *)A;
     const SDL_DisplayMode *b = (const SDL_DisplayMode *)B;
-    if (a == b) {
-        return 0;
-    } else if (a->screen_w != b->screen_w) {
+    if (a->screen_w != b->screen_w) {
         return b->screen_w - a->screen_w;
     } else if (a->screen_h != b->screen_h) {
         return b->screen_h - a->screen_h;
@@ -622,43 +620,40 @@ SDL_DisplayID SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode)
 
     SDL_zero(display);
     if (desktop_mode) {
-        display.desktop_mode = *desktop_mode;
-        SDL_FinalizeDisplayMode(&display.desktop_mode);
+        SDL_memcpy(&display.desktop_mode, desktop_mode, sizeof(display.desktop_mode));
     }
-    display.current_mode = display.desktop_mode;
-
     return SDL_AddVideoDisplay(&display, SDL_FALSE);
 }
 
 SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event)
 {
-    SDL_VideoDisplay *displays;
+    SDL_VideoDisplay *displays, *new_display;
     SDL_DisplayID id = 0;
-    int index;
 
     displays = (SDL_VideoDisplay *)SDL_realloc(_this->displays, (_this->num_displays + 1) * sizeof(*displays));
     if (displays) {
-        id = _this->next_object_id++;
-        index = _this->num_displays++;
-        displays[index] = *display;
-        displays[index].id = id;
-        displays[index].device = _this;
         _this->displays = displays;
+        id = _this->next_object_id++;
+        new_display = &displays[_this->num_displays++];
 
+        SDL_memcpy(new_display, display, sizeof(*new_display));
+        new_display->id = id;
+        new_display->device = _this;
         if (display->name) {
-            displays[index].name = SDL_strdup(display->name);
+            new_display->name = SDL_strdup(display->name);
         } else {
             char name[32];
 
-            SDL_itoa(index, name, 10);
-            displays[index].name = SDL_strdup(name);
+            SDL_itoa(id, name, 10);
+            new_display->name = SDL_strdup(name);
         }
 
-        SDL_FinalizeDisplayMode(&displays[index].desktop_mode);
-        SDL_FinalizeDisplayMode(&displays[index].current_mode);
+        new_display->desktop_mode.displayID = id;
+        new_display->desktop_mode.flags = (SDL_DISPLAYMODE_DESKTOP | SDL_DISPLAYMODE_CURRENT);
+        SDL_FinalizeDisplayMode(&new_display->desktop_mode);
 
         if (send_event) {
-            SDL_SendDisplayEvent(&_this->displays[index], SDL_EVENT_DISPLAY_CONNECTED, 0);
+            SDL_SendDisplayEvent(new_display, SDL_EVENT_DISPLAY_CONNECTED, 0);
         }
     } else {
         SDL_OutOfMemory();
@@ -666,7 +661,7 @@ SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send
     return id;
 }
 
-void SDL_DelVideoDisplay(SDL_DisplayID displayID)
+void SDL_DelVideoDisplay(SDL_DisplayID displayID, SDL_bool send_event)
 {
     SDL_VideoDisplay *display;
     int display_index = SDL_GetDisplayIndex(displayID);
@@ -676,11 +671,17 @@ void SDL_DelVideoDisplay(SDL_DisplayID displayID)
 
     display = &_this->displays[display_index];
 
-    SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_DISCONNECTED, 0);
-
-    if (display->driverdata) {
-        SDL_free(display->driverdata);
+    if (send_event) {
+        SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_DISCONNECTED, 0);
     }
+
+    SDL_free(display->name);
+    SDL_ResetFullscreenDisplayModes(display);
+    SDL_free(display->desktop_mode.driverdata);
+    display->desktop_mode.driverdata = NULL;
+    SDL_free(display->driverdata);
+    display->driverdata = NULL;
+
     if (display_index < (_this->num_displays - 1)) {
         SDL_memmove(&_this->displays[display_index], &_this->displays[display_index + 1], (_this->num_displays - display_index - 1) * sizeof(_this->displays[display_index]));
     }
@@ -781,6 +782,7 @@ const char *SDL_GetDisplayName(SDL_DisplayID displayID)
 int SDL_GetDisplayBounds(SDL_DisplayID displayID, SDL_Rect *rect)
 {
     SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID);
+    const SDL_DisplayMode *mode;
 
     CHECK_DISPLAY_MAGIC(display, -1);
 
@@ -802,8 +804,14 @@ int SDL_GetDisplayBounds(SDL_DisplayID displayID, SDL_Rect *rect)
         SDL_GetDisplayBounds(_this->displays[SDL_GetDisplayIndex(displayID) - 1].id, rect);
         rect->x += rect->w;
     }
-    rect->w = display->current_mode.screen_w;
-    rect->h = display->current_mode.screen_h;
+    mode = SDL_GetCurrentDisplayMode(displayID);
+    if (mode) {
+        rect->w = mode->screen_w;
+        rect->h = mode->screen_h;
+    } else {
+        rect->w = 0;
+        rect->h = 0;
+    }
     return 0;
 }
 
@@ -863,314 +871,295 @@ SDL_DisplayOrientation SDL_GetDisplayOrientation(SDL_DisplayID displayID)
     return display->orientation;
 }
 
-SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
+static const SDL_DisplayMode *SDL_GetFullscreenModeMatch(const SDL_DisplayMode *mode)
+{
+    const SDL_DisplayMode **modes;
+    SDL_DisplayMode fullscreen_mode;
+
+    if (mode->screen_w <= 0 || mode->screen_h <= 0) {
+        /* Use the desktop mode */
+        return NULL;
+    }
+
+    SDL_memcpy(&fullscreen_mode, mode, sizeof(fullscreen_mode));
+    if (fullscreen_mode.displayID == 0) {
+        fullscreen_mode.displayID = SDL_GetPrimaryDisplay();
+    }
+    SDL_FinalizeDisplayMode(&fullscreen_mode);
+
+    mode = NULL;
+
+    modes = SDL_GetFullscreenDisplayModes(fullscreen_mode.displayID, NULL);
+    if (modes) {
+        int i;
+
+        /* Search for an exact match */
+        if (!mode) {
+            for (i = 0; modes[i]; ++i) {
+                if (SDL_memcmp(&fullscreen_mode, modes[i], sizeof(fullscreen_mode)) == 0) {
+                    mode = modes[i];
+                    break;
+                }
+            }
+        }
+
+        /* Search for a mode with the same characteristics */
+        if (!mode) {
+            for (i = 0; modes[i]; ++i) {
+                if (cmpmodes(&fullscreen_mode, modes[i]) == 0) {
+                    mode = modes[i];
+                    break;
+                }
+            }
+        }
+
+        SDL_free(modes);
+    }
+    return mode;
+}
+
+SDL_bool SDL_AddFullscreenDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
 {
     SDL_DisplayMode *modes;
+    SDL_DisplayMode new_mode;
     int i, nmodes;
 
+    /* Finalize the mode for the display */
+    SDL_memcpy(&new_mode, mode, sizeof(new_mode));
+    new_mode.displayID = display->id;
+    SDL_FinalizeDisplayMode(&new_mode);
+
+    if ((new_mode.flags & SDL_DISPLAYMODE_CURRENT) != 0) {
+        display->desktop_mode.flags &= ~SDL_DISPLAYMODE_CURRENT;
+        for (i = 0; i < display->num_fullscreen_modes; ++i) {
+            display->fullscreen_modes[i].flags &= ~SDL_DISPLAYMODE_CURRENT;
+        }
+    }
+
     /* Make sure we don't already have the mode in the list */
-    modes = display->display_modes;
-    nmodes = display->num_display_modes;
+    modes = display->fullscreen_modes;
+    nmodes = display->num_fullscreen_modes;
     for (i = 0; i < nmodes; ++i) {
-        if (cmpmodes(mode, &modes[i]) == 0) {
+        if (cmpmodes(&new_mode, &modes[i]) == 0) {
+            /* If the new mode is current, make sure we save that */
+            if ((new_mode.flags & SDL_DISPLAYMODE_CURRENT) != 0) {
+                SDL_memcpy(&modes[i], &new_mode, sizeof(modes[i]));
+            }
             return SDL_FALSE;
         }
     }
 
     /* Go ahead and add the new mode */
-    if (nmodes == display->max_display_modes) {
-        modes = SDL_realloc(modes, (display->max_display_modes + 32) * sizeof(*modes));
+    if (nmodes == display->max_fullscreen_modes) {
+        modes = (SDL_DisplayMode *)SDL_realloc(modes, (display->max_fullscreen_modes + 32) * sizeof(*modes));
         if (modes == NULL) {
             return SDL_FALSE;
         }
-        display->display_modes = modes;
-        display->max_display_modes += 32;
+        display->fullscreen_modes = modes;
+        display->max_fullscreen_modes += 32;
     }
-    modes[nmodes] = *mode;
-    SDL_FinalizeDisplayMode(&modes[nmodes]);
-    display->num_display_modes++;
+    SDL_memcpy(&modes[display->num_fullscreen_modes++], &new_mode, sizeof(new_mode));
 
     /* Re-sort video modes */
-    SDL_qsort(display->display_modes, display->num_display_modes,
+    SDL_qsort(display->fullscreen_modes, display->num_fullscreen_modes,
               sizeof(SDL_DisplayMode), cmpmodes);
 
     return SDL_TRUE;
 }
 
-void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
-{
-    SDL_memcpy(&display->current_mode, mode, sizeof(*mode));
-    SDL_FinalizeDisplayMode(&display->current_mode);
-}
-
-void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
-{
-    SDL_memcpy(&display->desktop_mode, mode, sizeof(*mode));
-    SDL_FinalizeDisplayMode(&display->desktop_mode);
-}
-
-void SDL_ResetDisplayModes(SDL_VideoDisplay *display)
+void SDL_ResetFullscreenDisplayModes(SDL_VideoDisplay *display)
 {
     int i;
 
-    for (i = display->num_display_modes; i--;) {
-        SDL_free(display->display_modes[i].driverdata);
-        display->display_modes[i].driverdata = NULL;
+    for (i = display->num_fullscreen_modes; i--;) {
+        SDL_free(display->fullscreen_modes[i].driverdata);
+        display->fullscreen_modes[i].driverdata = NULL;
     }
-    SDL_free(display->display_modes);
-    display->display_modes = NULL;
-    display->num_display_modes = 0;
-    display->max_display_modes = 0;
+    SDL_free(display->fullscreen_modes);
+    display->fullscreen_modes = NULL;
+    display->num_fullscreen_modes = 0;
+    display->max_fullscreen_modes = 0;
 }
 
-static int SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay *display)
-{
-    if (!display->num_display_modes && _this->GetDisplayModes) {
-        _this->GetDisplayModes(_this, display);
-        SDL_qsort(display->display_modes, display->num_display_modes,
-                  sizeof(SDL_DisplayMode), cmpmodes);
-    }
-    return display->num_display_modes;
-}
-
-int SDL_GetNumDisplayModes(SDL_DisplayID displayID)
-{
-    SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID);
-
-    CHECK_DISPLAY_MAGIC(display, -1);
-
-    return SDL_GetNumDisplayModesForDisplay(display);
-}
-
-int SDL_GetDisplayMode(SDL_DisplayID displayID, int index, SDL_DisplayMode *mode)
+const SDL_DisplayMode **SDL_GetFullscreenDisplayModes(SDL_DisplayID displayID, int *count)
 {
+    int i;
+    const SDL_DisplayMode **modes;
     SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID);
 
-    CHECK_DISPLAY_MAGIC(display, -1);
-
-    if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
-        return SDL_SetError("index must be in the range of 0 - %d", SDL_GetNumDisplayModesForDisplay(display) - 1);
-    }
-    if (mode) {
-        *mode = display->display_modes[index];
+    if (count) {
+        *count = 0;
     }
-    return 0;
-}
-
-int SDL_GetDesktopDisplayMode(SDL_DisplayID displayID, SDL_DisplayMode *mode)
-{
-    SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID);
 
-    CHECK_DISPLAY_MAGIC(display, -1);
+    CHECK_DISPLAY_MAGIC(display, NULL);
 
-    if (mode) {
-        *mode = display->desktop_mode;
+    if (display->num_fullscreen_modes == 0 && _this->GetDisplayModes) {
+        _this->GetDisplayModes(_this, display);
     }
-    return 0;
-}
 
-int SDL_GetCurrentDisplayMode(SDL_DisplayID displayID, SDL_DisplayMode *mode)
-{
-    SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID);
+    modes = (const SDL_DisplayMode **)SDL_malloc((display->num_fullscreen_modes + 1) * sizeof(*modes));
+    if (modes) {
+        if (count) {
+            *count = display->num_fullscreen_modes;
+        }
 
-    CHECK_DISPLAY_MAGIC(display, -1);
+        for (i = 0; i < display->num_fullscreen_modes; ++i) {
+            modes[i] = &display->fullscreen_modes[i];
+        }
+        modes[i] = NULL;
+    } else {
+        if (count) {
+            *count = 0;
+        }
 
-    if (mode) {
-        *mode = display->current_mode;
+        SDL_OutOfMemory();
     }
-    return 0;
+    return modes;
 }
 
-static SDL_DisplayMode *SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay *display,
-                                                            const SDL_DisplayMode *mode,
-                                                            SDL_DisplayMode *closest)
+const SDL_DisplayMode *SDL_GetClosestFullscreenDisplayMode(SDL_DisplayID displayID, int w, int h, float refresh_rate)
 {
-    Uint32 target_format;
-    float target_refresh_rate;
+    const SDL_DisplayMode **modes;
+    const SDL_DisplayMode *mode, *closest = NULL;
+    float aspect_ratio;
     int i;
-    SDL_DisplayMode requested_mode;
-    SDL_DisplayMode *current, *match;
-
-    if (mode == NULL || closest == NULL) {
-        SDL_InvalidParamError("mode/closest");
-        return NULL;
-    }
 
-    /* Make sure all the fields are filled out in the requested mode */
-    requested_mode = *mode;
-    SDL_FinalizeDisplayMode(&requested_mode);
-    mode = &requested_mode;
-
-    /* Default to the desktop format */
-    if (mode->format) {
-        target_format = mode->format;
+    if (h > 0) {
+        aspect_ratio = (float)w / h;
     } else {
-        target_format = display->desktop_mode.format;
+        aspect_ratio = 1.0f;
     }
 
-    /* Default to the desktop refresh rate */
-    if (mode->refresh_rate > 0.0f) {
-        target_refresh_rate = mode->refresh_rate;
-    } else {
-        target_refresh_rate = display->desktop_mode.refresh_rate;
+    if (!refresh_rate) {
+        mode = SDL_GetDesktopDisplayMode(displayID);
+        if (mode) {
+            refresh_rate = mode->refresh_rate;
+        }
     }
 
-    match = NULL;
-    for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
-        current = &display->display_modes[i];
+    modes = SDL_GetFullscreenDisplayModes(displayID, NULL);
+    if (modes) {
+        for (i = 0; modes[i]; ++i) {
+            mode = modes[i];
 
-        if (current->pixel_w && (current->pixel_w < mode->pixel_w)) {
-            /* Out of sorted modes large enough here */
-            break;
-        }
-        if (current->pixel_h && (current->pixel_h < mode->pixel_h)) {
-            if (current->pixel_w && (current->pixel_w == mode->pixel_w)) {
+            if (w > mode->pixel_w) {
                 /* Out of sorted modes large enough here */
                 break;
             }
-            /* Wider, but not tall enough, due to a different
-               aspect ratio. This mode must be skipped, but closer
-               modes may still follow. */
-            continue;
-        }
-        if (match == NULL || current->pixel_w < match->pixel_w || current->pixel_h < match->pixel_h) {
-            match = current;
-            continue;
-        }
-        if (current->format != match->format) {
-            /* Sorted highest depth to lowest */
-            if (current->format == target_format ||
-                (SDL_BITSPERPIXEL(current->format) >=
-                     SDL_BITSPERPIXEL(target_format) &&
-                 SDL_PIXELTYPE(current->format) ==
-                     SDL_PIXELTYPE(target_format))) {
-                match = current;
-            }
-            continue;
-        }
-        if (current->refresh_rate != match->refresh_rate) {
-            /* Sorted highest refresh to lowest */
-            if (current->refresh_rate >= target_refresh_rate) {
-                match = current;
+            if (h > mode->pixel_h) {
+                /* Wider, but not tall enough, due to a different aspect ratio.
+                 * This mode must be skipped, but closer modes may still follow */
                 continue;
             }
-        }
-    }
+            if (closest) {
+                float current_aspect_ratio = (float)mode->pixel_w / mode->pixel_h;
+                float closest_aspect_ratio = (float)closest->pixel_w / closest->pixel_h;
+                if (SDL_fabsf(aspect_ratio - closest_aspect_ratio) < SDL_fabsf(aspect_ratio - current_aspect_ratio)) {
+                    /* The mode we already found has a better aspect ratio match */
+                    continue;
+                }
 
-    if (match) {
-        SDL_zerop(closest);
-        if (match->format) {
-            closest->format = match->format;
-        } else {
-            closest->format = mode->format;
-        }
-        if (match->screen_w && match->screen_h) {
-            closest->screen_w = match->screen_w;
-            closest->screen_h = match->screen_h;
-        } else {
-            closest->screen_w = mode->screen_w;
-            closest->screen_h = mode->screen_h;
-        }
-        if (match->pixel_w && match->pixel_h) {
-            closest->pixel_w = match->pixel_w;
-            closest->pixel_h = match->pixel_h;
-        } else {
-            closest->pixel_w = mode->pixel_w;
-            closest->pixel_h = mode->pixel_h;
-        }
-        if (match->refresh_rate > 0.0f) {
-            closest->refresh_rate = match->refresh_rate;
-        } else {
-            closest->refresh_rate = mode->refresh_rate;
-        }
-        closest->driverdata = match->driverdata;
+                if (mode->refresh_rate < refresh_rate) {
+                    /* We already found a mode and the new mode doesn't meet our
+                     * refresh rate target */
+                    continue;
+                }
+            }
 
-        /* Pick some reasonable defaults if the app and driver don't care */
-        if (!closest->format) {
-            closest->format = SDL_PIXELFORMAT_RGB888;
-        }
-        if (!closest->screen_w) {
-            closest->screen_w = 640;
-        }
-        if (!closest->screen_h) {
-            closest->screen_h = 480;
+            closest = mode;
         }
-        SDL_FinalizeDisplayMode(closest);
-        return closest;
+        SDL_free(modes);
     }
-    return NULL;
+    return closest;
 }
 
-SDL_DisplayMode *SDL_GetClosestDisplayMode(SDL_DisplayID displayID, const SDL_DisplayMode *mode, SDL_DisplayMode *closest)
+void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
+{
+    SDL_memcpy(&display->desktop_mode, mode, sizeof(*mode));
+    display->desktop_mode.displayID = display->id;
+    display->desktop_mode.flags = (SDL_DISPLAYMODE_DESKTOP | SDL_DISPLAYMODE_CURRENT);
+    SDL_FinalizeDisplayMode(&display->desktop_mode);
+}
+
+const SDL_DisplayMode *SDL_GetDesktopDisplayMode(SDL_DisplayID displayID)
 {
     SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID);
 
     CHECK_DISPLAY_MAGIC(display, NULL);
 
-    return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
+    return &display->desktop_mode;
 }
 
-static int SDL_SetDisplayModeForDisplay(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
+void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
 {
-    SDL_DisplayMode display_mode;
-    SDL_DisplayMode current_mode;
-    int result;
+    int i;
 
-    /* Mode switching set as emulated via driver quirk flag, nothing to do and cannot fail. */
-    if (ModeSwitchingEmulated(_this)) {
-        return 0;
+    if (mode == &display->desktop_mode) {
+        display->desktop_mode.flags |= SDL_DISPLAYMODE_CURRENT;
+    } else {
+        display->desktop_mode.flags &= ~SDL_DISPLAYMODE_CURRENT;
     }
 
-    if (mode) {
-        display_mode = *mode;
-
-        /* Default to the current mode */
-        if (!display_mode.format) {
-            display_mode.format = display->current_mode.format;
-        }
-        if (!display_mode.pixel_w) {
-            display_mode.pixel_w = display->current_mode.pixel_w;
-        }
-        if (!display_mode.pixel_h) {
-            display_mode.pixel_h = display->current_mode.pixel_h;
-        }
-        if (!display_mode.screen_w) {
-            display_mode.screen_w = display->current_mode.screen_w;
-        }
-        if (!display_mode.screen_h) {
-            display_mode.screen_h = display->current_mode.screen_h;
-        }
-        if (display_mode.refresh_rate == 0.0f) {
-            display_mode.refresh_rate = display->current_mode.refresh_rate;
+    for (i = 0; i < display->num_fullscreen_modes; ++i) {
+        if (mode == &display->fullscreen_modes[i]) {
+            display->fullscreen_modes[i].flags |= SDL_DISPLAYMODE_CURRENT;
+        } else {
+            display->fullscreen_modes[i].flags &= ~SDL_DISPLAYMODE_CURRENT;
         }
+    }
+    SDL_assert((mode->flags & SDL_DISPLAYMODE_CURRENT) != 0);
+}
 
-        /* Get a good video mode, the closest one possible */
-        if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
-            return SDL_SetError("No video mode large enough for %dx%d (%dx%d)",
-                                display_mode.pixel_w, display_mode.pixel_h,
-                                display_mode.screen_w, display_mode.screen_h);
+const SDL_DisplayMode *SDL_GetCurrentDisplayMode(SDL_DisplayID displayID)
+{
+    SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID);
+    const SDL_DisplayMode **modes;
+    const SDL_DisplayMode *current_mode = NULL;
+
+    CHECK_DISPLAY_MAGIC(display, NULL);
+
+    modes = SDL_GetFullscreenDisplayModes(displayID, NULL);
+    if (modes) {
+        int i;
+
+        for (i = 0; modes[i]; ++i) {
+            if ((modes[i]->flags & SDL_DISPLAYMODE_CURRENT) != 0) {
+                current_mode = modes[i];
+                break;
+            }
         }
-    } else {
-        display_mode = display->desktop_mode;
+        SDL_free(modes);
+    }
+    if (current_mode == NULL) {
+        current_mode = &display->desktop_mode;
+    }
+    return current_mode;
+}
+
+static int SDL_SetDisplayModeForDisplay(SDL_VideoDisplay *display, SDL_DisplayMode *mode)
+{
+    if (!mode) {
+        mode = &display->desktop_mode;
     }
 
-    /* See if there's anything left to do */
-    current_mode = display->current_mode;
-    if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
+    if ((mode->flags & SDL_DISPLAYMODE_CURRENT) != 0) {
         return 0;
     }
 
     /* Actually change the display mode */
-    if (!_this->SetDisplayMode) {
-        return SDL_SetError("SDL video driver doesn't support changing display mode");
-    }
-    _this->setting_display_mode = SDL_TRUE;
-    result = _this->SetDisplayMode(_this, display, &display_mode);
-    _this->setting_display_mode = SDL_FALSE;
-    if (result < 0) {
-        return -1;
+    if (_this->SetDisplayMode) {
+        int result;
+
+        _this->setting_display_mode = SDL_TRUE;
+        result = _this->SetDisplayMode(_this, display, mode);
+        _this->setting_display_mode = SDL_FALSE;
+        if (result < 0) {
+            return -1;
+        }
     }
-    SDL_SetCurrentDisplayMode(display, &display_mode);
+
+    SDL_SetCurrentDisplayMode(display, mode);
+
     return 0;
 }
 
@@ -1273,27 +1262,38 @@ SDL_DisplayID SDL_GetDisplayForWindow(SDL_Window *window)
         displayID = _this->GetDisplayForWindow(_this, window);
     }
 
-    /* A backend implementation may fail to get a display index for the window
+    /* A backend implementation may fail to get a display for the window
      * (for example if the window is off-screen), but other code may expect it
      * to succeed in that situation, so we fall back to a generic position-
      * based implementation in that case. */
+    if (!displayID && (window->flags & SDL_WINDOW_FULLSCREEN_MASK) != 0) {
+        displayID = window->fullscreen_mode.displayID;
+    }
     if (!displayID) {
-        displayID = SDL_GetDisplayForWindowCoordinate(window->x);
+        displayID = SDL_GetDisplayForWindowCoordinate(window->windowed.x);
     }
     if (!displayID) {
-        displayID = SDL_GetDisplayForWindowCoordinate(window->y);
+        displayID = SDL_GetDisplayForWindowCoordinate(window->windowed.y);
     }
     if (!displayID) {
-        int i, display_index;
-
         displayID = GetDisplayForRect(window->x, window->y, window->w, window->h);
         if (!displayID) {
             /* Use the primary display for a window if we can't find it anywhere else */
             displayID = SDL_GetPrimaryDisplay();
         }
-        display_index = SDL_GetDisplayIndex(displayID);
+    }
+    return displayID;
+}
+
+void SDL_CheckWindowDisplayChanged(SDL_Window *window)
+{
+    SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
+
+    if (displayID != window->last_displayID) {
+        int i, display_index;
 
-        /* Find the display containing the window if fullscreen */
+        /* Sanity check our fullscreen windows */
+        display_index = SDL_GetDisplayIndex(displayID);
         for (i = 0; i < _this->num_displays; ++i) {
             SDL_VideoDisplay *display = &_this->displays[i];
 
@@ -1316,90 +1316,14 @@ SDL_DisplayID SDL_GetDisplayForWindow(SDL_Window *window)
                 break;
             }
         }
-    }
-
-    return displayID;
-}
-
-int SDL_SetWindowDisplayMode(SDL_Window *window, const SDL_DisplayMode *mode)
-{
-    CHECK_WINDOW_MAGIC(window, -1);
-
-    if (mode) {
-        window->fullscreen_mode = *mode;
-    } else {
-        SDL_zero(window->fullscreen_mode);
-    }
-
-    if (SDL_WINDOW_FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
-        SDL_DisplayMode fullscreen_mode;
-        if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) {
-            if (SDL_SetDisplayModeForDisplay(SDL_GetVideoDisplayForWindow(window), &fullscreen_mode) == 0) {
-#ifndef __ANDROID__
-                /* Android may not resize the window to exactly what our fullscreen mode is, especially on
-                 * windowed Android environments like the Chromebook or Samsung DeX.  Given this, we shouldn't
-                 * use fullscreen_mode.screen_w and fullscreen_mode.screen_h, but rather get our current native size.  As such,
-                 * Android's SetWindowFullscreen will generate the window event for us with the proper final size.
-                 */
-                SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, fullscreen_mode.screen_w, fullscreen_mode.screen_h);
-#endif /* !__ANDROID__ */
-            }
-        }
-    }
-    return 0;
-}
-
-int SDL_GetWindowDisplayMode(SDL_Window *window, SDL_DisplayMode *mode)
-{
-    SDL_VideoDisplay *display;
-
-    CHECK_WINDOW_MAGIC(window, -1);
 
-    if (mode == NULL) {
-        return SDL_InvalidParamError("mode");
+        SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DISPLAY_CHANGED, (int)displayID, 0);
     }
-
-    display = SDL_GetVideoDisplayForWindow(window);
-
-    /* if in desktop size mode, just return the size of the desktop */
-    if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) {
-        *mode = display->desktop_mode;
-    } else {
-        SDL_DisplayMode fullscreen_mode;
-
-        fullscreen_mode = window->fullscreen_mode;
-        if (!fullscreen_mode.screen_w) {
-            fullscreen_mode.screen_w = window->windowed.w;
-        }
-        if (!fullscreen_mode.screen_h) {
-            fullscreen_mode.screen_h = window->windowed.h;
-        }
-        if (SDL_GetClosestDisplayModeForDisplay(display, &fullscreen_mode, mode) == NULL) {
-            SDL_zerop(mode);
-            return SDL_SetError("Couldn't find display mode match");
-        }
-    }
-    return 0;
 }
 
-void *SDL_GetWindowICCProfile(SDL_Window *window, size_t *size)
-{
-    if (!_this->GetWindowICCProfile) {
-        SDL_Unsupported();
-        return NULL;
-    }
-    return _this->GetWindowICCProfile(_this, window, size);
-}
-
-Uint32 SDL_GetWindowPixelFormat(SDL_Window *window)
-{
-    SDL_VideoDisplay *display;
-
-    CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
-
-    display = SDL_GetVideoDisplayForWindow(window);
-    return display->current_mode.format;
-}
+#if __WINRT__
+extern Uint32 WINRT_DetectWindowFlags(SDL_Window *window);
+#endif
 
 static void SDL_RestoreMousePosition(SDL_Window *window)
 {
@@ -1411,15 +1335,10 @@ static void SDL_RestoreMousePosition(SDL_Window *window)
     }
 }
 
-#if __WINRT__
-extern Uint32 WINRT_DetectWindowFlags(SDL_Window *window);
-#endif
-
 static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen)
 {
     SDL_VideoDisplay *display;
-    SDL_Window *other;
-    int retval = 0;
+    SDL_DisplayMode *mode;
 
     CHECK_WINDOW_MAGIC(window, -1);
 
@@ -1428,6 +1347,18 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen)
         return 0;
     }
 
+    display = SDL_GetVideoDisplayForWindow(window);
+
+    mode = NULL;
+    if (fullscreen && (window->flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
+        mode = (SDL_DisplayMode *)SDL_GetWindowFullscreenMode(window);
+        if (!mode || mode->displayID != display->id) {
+            /* Couldn't find a matching mode, pop out of fullscreen mode */
+            window->flags &= ~SDL_WINDOW_FULLSCREEN_EXCLUSIVE;
+            fullscreen = SDL_FALSE;
+        }
+    }
+
 #if defined(__MACOS__) && defined(SDL_VIDEO_DRIVER_COCOA)
     /* if the window is going away and no resolution change is necessary,
        do nothing, or else we may trigger an ugly double-transition
@@ -1488,108 +1419,143 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen)
     }
 #endif
 
-    display = SDL_GetVideoDisplayForWindow(window);
-
     if (fullscreen) {
+        int mode_w = 0, mode_h = 0;
+        SDL_bool resized = SDL_FALSE;
+
         /* Hide any other fullscreen windows */
         if (display->fullscreen_window &&
             display->fullscreen_window != window) {
             SDL_MinimizeWindow(display->fullscreen_window);
         }
-    }
 
-    /* See if anything needs to be done now */
-    if ((display->fullscreen_window == window) == fullscreen) {
-        if ((window->last_fullscreen_flags & SDL_WINDOW_FULLSCREEN_MASK) == (window->flags & SDL_WINDOW_FULLSCREEN_MASK)) {
-            return 0;
+        if (SDL_SetDisplayModeForDisplay(display, mode) < 0) {
+            return -1;
         }
-    }
+        if (_this->SetWindowFullscreen) {
+            _this->SetWindowFullscreen(_this, window, display, SDL_TRUE);
+        }
+        display->fullscreen_window = window;
 
-    /* See if there are any fullscreen windows */
-    for (other = _this->windows; other; other = other->next) {
-        SDL_bool setDisplayMode = SDL_FALSE;
+#if defined(__ANDROID__)
+        /* Android may not resize the window to exactly what our fullscreen mode is,
+         * especially on windowed Android environments like the Chromebook or Samsung DeX.
+         * Given this, we shouldn't use the mode size. As such, Android's SetWindowFullscreen
+         * will generate the window event for us with the proper final size.
+         */
+#elif defined(__WIN32__)
+        /* This is also unnecessary on Win32 (WIN_SetWindowFullscreen calls SetWindowPos,
+         * WM_WINDOWPOSCHANGED will send SDL_EVENT_WINDOW_RESIZED).
+         */
+#else
+        if (mode) {
+            mode_w = mode->screen_w;
+            mode_h = mode->screen_h;
+        } else {
+            mode_w = display->desktop_mode.screen_w;
+            mode_h = display->desktop_mode.screen_h;
+        }
+        if (window->w != mode_w || window->h != mode_h) {
+            resized = SDL_TRUE;
+        }
+#endif
+        if (resized) {
+            SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, mode_w, mode_h);
+        } else {
+            SDL_OnWindowResized(window);
+        }
+
+        /* Restore the cursor position */
+        SDL_RestoreMousePosition(window);
+
+    } else {
 
-        if (other == window) {
-            setDisplayMode = fullscreen;
-        } else if (SDL_WINDOW_FULLSCREEN_VISIBLE(other) &&
-                   SDL_GetVideoDisplayForWindow(other) == display) {
-            setDisplayMode = SDL_TRUE;
+        if (display->fullscreen_window == window) {
+            /* Restore the desktop mode */
+            SDL_SetDisplayModeForDisplay(display, NULL);
+        }
+
+        if (_this->SetWindowFullscreen) {
+            _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
+        }
+        if (display->fullscreen_window == window) {
+            display->fullscreen_window = NULL;
         }
 
-        if (setDisplayMode) {
-            SDL_DisplayMode fullscreen_mode;
+        SDL_OnWindowResized(window);
 
-            SDL_zero(fullscreen_mode);
+        /* Restore the cursor position */
+        SDL_RestoreMousePosition(window);
+    }
 
-            if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
-                SDL_bool resized = SDL_TRUE;
+    window->last_fullscreen_flags = window->flags;
 
-                if (other->w == fullscreen_mode.screen_w && other->h == fullscreen_mode.screen_h) {
-                    resized = SDL_FALSE;
-                }
+    return 0;
+}
 
-                /* only do the mode change if we want exclusive fullscreen */
-                if ((window->flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
-                    if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
-                        return -1;
-                    }
-                } else {
-                    if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
-                        return -1;
-                    }
-                }
+int SDL_SetWindowFullscreenMode(SDL_Window *window, const SDL_DisplayMode *mode)
+{
+    CHECK_WINDOW_MAGIC(window, -1);
 
-                if (_this->SetWindowFullscreen) {
-                    _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
-                }
-                display->fullscreen_window = other;
-
-                /* Generate a mode change event here */
-                if (resized) {
-#if !defined(__ANDROID__) && !defined(__WIN32__)
-                    /* Android may not resize the window to exactly what our fullscreen mode is, especially on
-                     * windowed Android environments like the Chromebook or Samsung DeX.  Given this, we shouldn't
-                     * use fullscreen_mode.w and fullscreen_mode.h, but rather get our current native size.  As such,
-                     * Android's SetWindowFullscreen will generate the window event for us with the proper final size.
-                     */
-
-                    /* This is also unnecessary on Win32 (WIN_SetWindowFullscreen calls SetWindowPos,
-                     * WM_WINDOWPOSCHANGED will send SDL_EVENT_WINDOW_RESIZED).
-                     */
-                    SDL_SendWindowEvent(other, SDL_EVENT_WINDOW_RESIZED,
-                                        fullscreen_mode.screen_w, fullscreen_mode.screen_h);
-#endif
-                } else {
-                    SDL_OnWindowResized(other);
-                }
+    if (mode) {
+        if (!SDL_GetFullscreenModeMatch(mode)) {
+            return SDL_SetError("Invalid fullscreen display mode");
+        }
 
-                SDL_RestoreMousePosition(other);
+        /* Save the mode so we can look up the closest match later */
+        SDL_memcpy(&window->fullscreen_mode, mode, sizeof(window->fullscreen_mode));
 
-                window->last_fullscreen_flags = window->flags;
-                return 0;
-            } else {
-                /* Failed to find a matching mode, return an error after restoring windowed mode. */
-                retval = -1;
-            }
+        if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) {
+            window->flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP;
+            window->flags |= SDL_WINDOW_FULLSCREEN_EXCLUSIVE;
+        }
+    } else {
+        SDL_zero(window->fullscreen_mode);
+
+        if ((window->flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
+            window->flags &= ~SDL_WINDOW_FULLSCREEN_EXCLUSIVE;
+            window->flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
         }
     }
 
-    /* Nope, restore the desktop mode */
-    SDL_SetDisplayModeForDisplay(display, NULL);
+    if (SDL_WINDOW_FULLSCREEN_VISIBLE(window)) {
+        SDL_UpdateFullscreenMode(window, SDL_TRUE);
+    } else {
+        SDL_CheckWindowDisplayChanged(window);
+    }
+    return 0;
+}
 
-    if (_this->SetWindowFullscreen) {
-        _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
+const SDL_DisplayMode *SDL_GetWindowFullscreenMode(SDL_Window *window)
+{
+    CHECK_WINDOW_MAGIC(window, NULL);
+
+    return SDL_GetFullscreenModeMatch(&window->fullscreen_mode);
+}
+
+void *SDL_GetWindowICCProfile(SDL_Window *window, size_t *size)
+{
+    if (!_this->GetWindowICCProfile) {
+        SDL_Unsupported();
+        return NULL;
     }
-    display->fullscreen_window = NULL;
+    return _this->GetWindowICCProfile(_this, window, size);
+}
 
-    /* Generate a mode change event here */
-    SDL_OnWindowResized(window);
+Uint32 SDL_GetWindowPixelFormat(SDL_Window *window)
+{
+    SDL_DisplayID displayID;
+    const SDL_DisplayMode *mode;
 
-    /* Restore the cursor position */
-    SDL_RestoreMousePosition(window);
+    CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
 
-    window->last_fullscreen_flags = window->flags;
-    return retval;
+    displayID = SDL_GetDisplayForWindow(window);
+    mode = SDL_GetCurrentDisplayMode(displayID);
+    if (mode) {
+        return mode->format;
+    } else {
+        return SDL_PIXELFORMAT_UNKNOWN;
+    }
 }
 
 #define CREATE_FLAGS \
@@ -1759,10 +1725,10 @@ SDL_Window *SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint
     }
     window->magic = &_this->window_magic;
     window->id = _this->next_object_id++;
-    window->x = x;
-    window->y = y;
-    window->w = w;
-    window->h = h;
+    window->windowed.x = window->x = x;
+    window->windowed.y = window->y = y;
+    window->windowed.w = window->w = w;
+    window->windowed.h = window->h = h;
     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
         SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
@@ -1770,38 +1736,22 @@ SDL_Window *SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint
 
         SDL_GetDisplayBounds(display->id, &bounds);
         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
-            window->x = bounds.x + (bounds.w - w) / 2;
+            window->windowed.x = window->x = bounds.x + (bounds.w - w) / 2;
         }
         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
-            window->y = bounds.y + (bounds.h - h) / 2;
+            window->windowed.y = window->y = bounds.y + (bounds.h - h) / 2;
         }
     }
-    window->windowed.x = window->x;
-    window->windowed.y = window->y;
-    window->windowed.w = window->w;
-    window->windowed.h = window->h;
 
     if (flags & SDL_WINDOW_FULLSCREEN_MASK) {
         SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
         SDL_Rect bounds;
 
-        SDL_GetDisplayBounds(display->id, &bounds);
+        /* Fullscreen at window creation time is always fullscreen desktop */
+        flags &= ~SDL_WINDOW_FULLSCREEN_MASK;
+        flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
 
-        /* for real fullscreen we might switch the resolution, so get width and height
-         * from closest supported mode and use that instead of current resolution
-         */
-        if ((flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0 && (bounds.w != w || bounds.h != h)) {
-            SDL_DisplayMode fullscreen_mode, closest_mode;
-            SDL_zero(fullscreen_mode);
-            fullscreen_mode.screen_w = w;
-            fullscreen_mode.screen_h = h;
-            if (SDL_GetClosestDisplayModeForDisplay(display, &fullscreen_mode, &closest_mode) != NULL) {
-                bounds.w = closest_mode.screen_w;
-                bounds.h = closest_mode.screen_h;
-            }
-        }
-        window->fullscreen_mode.screen_w = bounds.w;
-        window->fullscreen_mode.screen_h = bounds.h;
+        SDL_GetDisplayBounds(display->id, &bounds);
         window->x = bounds.x;
         window->y = bounds.y;
         window->w = bounds.w;
@@ -1813,7 +1763,7 @@ SDL_Window *SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint
     window->opacity = 1.0f;
     window->next = _this->windows;
     window->is_destroying = SDL_FALSE;
-    window->displayID = SDL_GetDisplayForWindow(window);
+    window->last_displayID = SDL_GetDisplayForWindow(window);
 
     if (_this->windows) {
         _this->windows->prev = window;
@@ -1919,7 +1869,7 @@ SDL_Window *SDL_CreateWindowFrom(const void *data)
         return NULL;
     }
 
-    window->displayID = SDL_GetDisplayForWindow(window);
+    window->last_displayID = SDL_GetDisplayForWindow(window);
     PrepareDragAndDropSupport(window);
 
     return window;
@@ -2376,13 +2326,7 @@ void SDL_SetWindowSize(SDL_Window *window, int w, int h)
     window->windowed.w = w;
     window->windowed.h = h;
 
-    if ((window->flags & SDL_WINDOW_FULLSCREEN_MASK) != 0) {
-        if (SDL_WINDOW_FULLSCREEN_VISIBLE(window) &&
-            (window->flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
-            window->last_fullscreen_flags = 0;
-            SDL_UpdateFullscreenMode(window, SDL_TRUE);
-        }
-    } else {
+    if (!SDL_WINDOW_FULLSCREEN_VISIBLE(window)) {
         if (_this->SetWindowSize) {
             _this->SetWindowSize(_this, window);
         }
@@ -2446,21 +2390,26 @@ void SDL_GetWindowSizeInPixels(SDL_Window *window, int *w, int *h)
     if (_this->GetWindowSizeInPixels) {
         _this->GetWindowSizeInPixels(_this, window, w, h);
     } else {
-        SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
+        SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
+        const SDL_DisplayMode *mode;
 
         SDL_GetWindowSize(window, w, h);
 
-        if (display)
-        {
-            if (*w == display->current_mode.screen_w) {
-                *w = display->current_mode.pixel_w;
+        if ((window->flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
+            mode = SDL_GetCurrentDisplayMode(displayID);
+        } else {
+            mode = SDL_GetDesktopDisplayMode(displayID);
+        }
+        if (mode) {
+            if (*w == mode->screen_w) {
+                *w = mode->pixel_w;
             } else {
-                *w = (int)SDL_ceilf(*w * display->current_mode.display_scale);
+                *w = (int)SDL_ceilf(*w * mode->display_scale);
             }
-            if (*h == display->current_mode.screen_h) {
-                *h = display->current_mode.pixel_h;
+            if (*h == mode->screen_h) {
+                *h = mode->pixel_h;
             } else {
-                *h = (int)SDL_ceilf(*h * display->current_mode.display_scale);
+                *h = (int)SDL_ceilf(*h * mode->display_scale);
             }
         }
     }
@@ -2648,34 +2597,30 @@ void SDL_RestoreWindow(SDL_Window *window)
     }
 }
 
-int SDL_SetWindowFullscreen(SDL_Window *window, Uint32 flags)
+int SDL_SetWindowFullscreen(SDL_Window *window, SDL_bool fullscreen)
 {
-    Uint32 oldflags;
-    CHECK_WINDOW_MAGIC(window, -1);
+    Uint32 flags;
 
-    flags &= SDL_WINDOW_FULLSCREEN_MASK;
+    CHECK_WINDOW_MAGIC(window, -1);
 
-    /* If both fullscreen exclusive and desktop flags are set, default to desktop */
-    if ((flags & SDL_WINDOW_FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_MASK) {
-        flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
+    if (fullscreen) {
+        if (SDL_GetWindowFullscreenMode(window)) {
+            flags = SDL_WINDOW_FULLSCREEN_EXCLUSIVE;
+        } else {
+            flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
+        }
+    } else {
+        flags = 0;
     }
 
     if (flags == (window->flags & SDL_WINDOW_FULLSCREEN_MASK)) {
         return 0;
     }
 
-    /* clear the previous flags and OR in the new ones */
-    oldflags = window->flags & SDL_WINDOW_FULLSCREEN_MASK;
-    window->flags &= ~SDL_WINDOW_FULLSCREEN_MASK;
-    window->flags |= flags;
+    /* Clear the previous flags and OR in the new ones */
+    window->flags = (window->flags & ~SDL_WINDOW_FULLSCREEN_MASK) | flags;
 
-    if (SDL_UpdateFullscreenMode(window, SDL_WINDOW_FULLSCREEN_VISIBLE(window)) == 0) {
-        return 0;
-    }
-
-    window->flags &= ~SDL_WINDOW_FULLSCREEN_MASK;
-    window->flags |= oldflags;
-    return -1;
+    return SDL_UpdateFullscreenMode(window, SDL_WINDOW_FULLSCREEN_VISIBLE(window));
 }
 
 static SDL_Surface *SDL_CreateWindowFramebuffer(SDL_Window *window)
@@ -3028,14 +2973,6 @@ void SDL_OnWindowHidden(SDL_Window *window)
     SDL_UpdateFullscreenMode(window, SDL_FALSE);
 }
 
-void SDL_CheckWindowDisplayChanged(SDL_Window *window)
-{
-    SDL_DisplayID displayID;
-
-    displayID = SDL_GetDisplayForWindow(window);
-    SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DISPLAY_CHANGED, (int)displayID, 0);
-}
-
 void SDL_OnWindowDisplayChanged(SDL_Window *window)
 {
     if ((window->flags & SDL_WINDOW_FULLSCREEN_MASK) != 0) {
@@ -3057,19 +2994,16 @@ void SDL_OnWindowDisplayChanged(SDL_Window *window)
          * emulated mode dimensions since the window is just being scaled.
          */
         if (!ModeSwitchingEmulated(_this) &&
-            SDL_GetDisplayBounds(window->displayID, &rect) == 0) {
+            SDL_GetDisplayBounds(SDL_GetDisplayForWindow(window), &rect) == 0) {
             int old_w = window->w;
             int old_h = window->h;
             window->x = rect.x;
             window->y = rect.y;
             window->w = rect.w;
             window->h = rect.h;
-            window->fullscreen_mode.screen_w = rect.w;
-            window->fullscreen_mode.screen_h = rect.h;
             if (_this->SetWindowSize) {
                 _this->SetWindowSize(_this, window);
             }
-
             if (window->w != old_w || window->h != old_h) {
                 SDL_OnWindowResized(window);
             }
@@ -3359,18 +3293,12 @@ void SDL_VideoQuit(void)
     }
     _this->VideoQuit(_this);
 
-    for (i = 0; i < _this->num_displays; ++i) {
+    for (i = _this->num_displays; i--; ) {
         SDL_VideoDisplay *display = &_this->displays[i];
-        SDL_ResetDisplayModes(display);
-        SDL_free(display->desktop_mode.driverdata);
-        display->desktop_mode.driverdata = NULL;
-        SDL_free(display->driverdata);
-        display->driverdata = NULL;
+        SDL_DelVideoDisplay(display->id, SDL_FALSE);
     }
     if (_this->displays) {
-        for (i = 0; i < _this->num_displays; ++i) {
-            SDL_free(_this->displays[i].name);
-        }
+        SDL_assert(_this->num_displays == 0);
         SDL_free(_this->displays);
         _this->displays = NULL;
         _this->num_displays = 0;

+ 2 - 18
src/video/android/SDL_androidvideo.c

@@ -193,8 +193,6 @@ int Android_VideoInit(_THIS)
     display = SDL_GetVideoDisplay(displayID);
     display->orientation = Android_JNI_GetDisplayOrientation();
 
-    SDL_AddDisplayMode(&_this->displays[0], &mode);
-
     Android_InitTouch();
 
     Android_InitMouse();
@@ -288,22 +286,8 @@ void Android_SendResize(SDL_Window *window)
     }
 
     if (window) {
-        /* Force the current mode to match the resize otherwise the SDL_EVENT_WINDOW_RESTORED event
-         * will fall back to the old mode */
-        int w, h;
-        SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
-        SDL_DisplayMode current_mode;
-        SDL_zero(current_mode);
-
-        current_mode.format = Android_ScreenFormat;
-        current_mode.pixel_w = Android_DeviceWidth;
-        current_mode.pixel_h = Android_DeviceHeight;
-        current_mode.display_scale = Android_ScreenDensity;
-        current_mode.refresh_rate = Android_ScreenRate;
-        SDL_SetCurrentDisplayMode(display, &current_mode);
-
-        w = (int)SDL_floorf(Android_SurfaceWidth / Android_ScreenDensity);
-        h = (int)SDL_floorf(Android_SurfaceHeight / Android_ScreenDensity);
+        int w = (int)SDL_floorf(Android_SurfaceWidth / Android_ScreenDensity);
+        int h = (int)SDL_floorf(Android_SurfaceHeight / Android_ScreenDensity);
         SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, w, h);
     }
 }

+ 6 - 26
src/video/cocoa/SDL_cocoamodes.m

@@ -236,8 +236,8 @@ static SDL_bool GetDisplayMode(_THIS, CGDisplayModeRef vidmode, SDL_bool vidmode
              * in case there are duplicate modes with different IO flags or IO
              * display mode IDs in the future. In that case I think it's better
              * to try them all in SetDisplayMode than to risk one of them being
-             * correct but it being filtered out by SDL_AddDisplayMode as being
-             * a duplicate.
+             * correct but it being filtered out by SDL_AddFullscreenDisplayMode
+             * as being a duplicate.
              */
             if (width == otherW && height == otherH && pixelW == otherpixelW && pixelH == otherpixelH && usableForGUI == otherGUI && refreshrate == otherrefresh && format == otherformat) {
                 CFArrayAppendValue(modes, othermode);
@@ -352,7 +352,6 @@ void Cocoa_InitModes(_THIS)
                 CGDisplayModeRelease(moderef);
 
                 display.desktop_mode = mode;
-                display.current_mode = mode;
                 display.driverdata = displaydata;
                 SDL_AddVideoDisplay(&display, SDL_FALSE);
                 SDL_free(display.name);
@@ -478,8 +477,6 @@ void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
 {
     SDL_DisplayData *data = display->driverdata;
     CVDisplayLinkRef link = NULL;
-    CGDisplayModeRef desktopmoderef;
-    SDL_DisplayMode desktopmode;
     CFArrayRef modes;
     CFDictionaryRef dict = NULL;
     const CFStringRef dictkeys[] = { kCGDisplayShowDuplicateLowResolutionModes };
@@ -487,23 +484,6 @@ void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
 
     CVDisplayLinkCreateWithCGDisplay(data->display, &link);
 
-    desktopmoderef = CGDisplayCopyDisplayMode(data->display);
-
-    /* CopyAllDisplayModes won't always contain the desktop display mode (if
-     * NULL is passed in) - for example on a retina 15" MBP, System Preferences
-     * allows choosing 1920x1200 but it's not in the list. AddDisplayMode makes
-     * sure there are no duplicates so it's safe to always add the desktop mode
-     * even in cases where it is in the CopyAllDisplayModes list.
-     */
-    if (desktopmoderef && GetDisplayMode(_this, desktopmoderef, SDL_TRUE, NULL, link, &desktopmode)) {
-        if (!SDL_AddDisplayMode(display, &desktopmode)) {
-            CFRelease(((SDL_DisplayModeData *)desktopmode.driverdata)->modes);
-            SDL_free(desktopmode.driverdata);
-        }
-    }
-
-    CGDisplayModeRelease(desktopmoderef);
-
     /* By default, CGDisplayCopyAllDisplayModes will only get a subset of the
      * system's available modes. For example on a 15" 2016 MBP, users can
      * choose 1920x1080@2x in System Preferences but it won't show up here,
@@ -538,7 +518,7 @@ void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
             SDL_DisplayMode mode;
 
             if (GetDisplayMode(_this, moderef, SDL_FALSE, modes, link, &mode)) {
-                if (!SDL_AddDisplayMode(display, &mode)) {
+                if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
                     CFRelease(((SDL_DisplayModeData *)mode.driverdata)->modes);
                     SDL_free(mode.driverdata);
                 }
@@ -642,15 +622,15 @@ void Cocoa_QuitModes(_THIS)
         SDL_VideoDisplay *display = &_this->displays[i];
         SDL_DisplayModeData *mode;
 
-        if (display->current_mode.driverdata != display->desktop_mode.driverdata) {
+        if (SDL_GetCurrentDisplayMode(display->id) != SDL_GetDesktopDisplayMode(display->id)) {
             Cocoa_SetDisplayMode(_this, display, &display->desktop_mode);
         }
 
         mode = (SDL_DisplayModeData *)display->desktop_mode.driverdata;
         CFRelease(mode->modes);
 
-        for (j = 0; j < display->num_display_modes; j++) {
-            mode = (SDL_DisplayModeData *)display->display_modes[j].driverdata;
+        for (j = 0; j < display->num_fullscreen_modes; j++) {
+            mode = (SDL_DisplayModeData *)display->fullscreen_modes[j].driverdata;
             CFRelease(mode->modes);
         }
     }

+ 1 - 1
src/video/cocoa/SDL_cocoaopengl.m

@@ -301,7 +301,7 @@ SDL_GLContext Cocoa_GL_CreateContext(_THIS, SDL_Window *window)
         attr[i++] = profile;
 
         attr[i++] = NSOpenGLPFAColorSize;
-        attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format) * 8;
+        attr[i++] = 32;
 
         attr[i++] = NSOpenGLPFADepthSize;
         attr[i++] = _this->gl_config.depth_size;

+ 0 - 2
src/video/dummy/SDL_nullvideo.c

@@ -150,8 +150,6 @@ int DUMMY_VideoInit(_THIS)
         return -1;
     }
 
-    SDL_AddDisplayMode(&_this->displays[0], &mode);
-
 #if SDL_INPUT_LINUXEV
     SDL_EVDEV_Init();
 #endif

+ 0 - 2
src/video/emscripten/SDL_emscriptenvideo.c

@@ -136,8 +136,6 @@ int Emscripten_VideoInit(_THIS)
         return -1;
     }
 
-    SDL_AddDisplayMode(&_this->displays[0], &mode);
-
     Emscripten_InitMouse();
 
     /* We're done! */

+ 1 - 1
src/video/haiku/SDL_bmodes.cc

@@ -244,7 +244,7 @@ void HAIKU_GetDisplayModes(_THIS, SDL_VideoDisplay *display) {
         // FIXME: Apparently there are errors with colorspace changes
         if (bmodes[i].space == this_bmode.space) {
             _BDisplayModeToSdlDisplayMode(&bmodes[i], &mode);
-            SDL_AddDisplayMode(display, &mode);
+            SDL_AddFullscreenDisplayMode(display, &mode);
         }
     }
     free(bmodes); /* This should not be SDL_free() */

+ 16 - 23
src/video/kmsdrm/SDL_kmsdrmvideo.c

@@ -490,27 +490,22 @@ KMSDRM_WaitPageflip(_THIS, SDL_WindowData *windata)
    available on the DRM connector of the display.
    We use the SDL mode list (which we filled in KMSDRM_GetDisplayModes)
    because it's ordered, while the list on the connector is mostly random.*/
-static drmModeModeInfo *KMSDRM_GetClosestDisplayMode(SDL_VideoDisplay *display,
-                                                     uint32_t width, uint32_t height, uint32_t refresh_rate)
+static drmModeModeInfo *KMSDRM_GetClosestDisplayMode(SDL_VideoDisplay *display, int width, int height)
 {
 
     SDL_DisplayData *dispdata = display->driverdata;
     drmModeConnector *connector = dispdata->connector;
 
-    SDL_DisplayMode target, closest;
+    const SDL_DisplayMode *closest;
     drmModeModeInfo *drm_mode;
 
-    SDL_zero(target);
-    target.screen_w = (int)width;
-    target.screen_h = (int)height;
-    target.refresh_rate = (int)refresh_rate;
-
-    if (!SDL_GetClosestDisplayMode(SDL_atoi(display->name), &target, &closest)) {
-        return NULL;
-    } else {
-        SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)closest.driverdata;
+    closest = SDL_GetClosestFullscreenDisplayMode(display->id, width, height, 0.0f);
+    if (closest) {
+        const SDL_DisplayModeData *modedata = (const SDL_DisplayModeData *)closest->driverdata;
         drm_mode = &connector->modes[modedata->mode_index];
         return drm_mode;
+    } else {
+        return NULL;
     }
 }
 
@@ -876,7 +871,6 @@ static void KMSDRM_AddDisplay(_THIS, drmModeConnector *connector, drmModeRes *re
     display.desktop_mode.refresh_rate = CalculateRefreshRate(&dispdata->mode);
     display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888;
     display.desktop_mode.driverdata = modedata;
-    display.current_mode = display.desktop_mode;
 
     /* Add the display to the list of SDL displays. */
     if (SDL_AddVideoDisplay(&display, SDL_FALSE) == 0) {
@@ -1124,11 +1118,7 @@ static void KMSDRM_GetModeToSet(SDL_Window *window, drmModeModeInfo *out_mode)
     if ((window->flags & SDL_WINDOW_FULLSCREEN_EXCLUSIVE) != 0) {
         *out_mode = dispdata->fullscreen_mode;
     } else {
-        drmModeModeInfo *mode;
-
-        mode = KMSDRM_GetClosestDisplayMode(display,
-                                            window->windowed.w, window->windowed.h, 0);
-
+        drmModeModeInfo *mode = KMSDRM_GetClosestDisplayMode(display, window->windowed.w, window->windowed.h);
         if (mode) {
             *out_mode = *mode;
         } else {
@@ -1161,7 +1151,6 @@ int KMSDRM_CreateSurfaces(_THIS, SDL_Window *window)
     SDL_WindowData *windata = window->driverdata;
     SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
     SDL_DisplayData *dispdata = display->driverdata;
-    SDL_DisplayMode current_mode;
 
     uint32_t surface_fmt = GBM_FORMAT_ARGB8888;
     uint32_t surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
@@ -1183,15 +1172,20 @@ int KMSDRM_CreateSurfaces(_THIS, SDL_Window *window)
 
     /* The KMSDRM backend doesn't always set the mode the higher-level code in
        SDL_video.c expects. Hulk-smash the display's current_mode to keep the
-       mode that's set in sync with what SDL_video.c thinks is set */
+       mode that's set in sync with what SDL_video.c thinks is set
+
+       FIXME: How do we do that now? Can we get a better idea at the higher level?
+     */
     KMSDRM_GetModeToSet(window, &dispdata->mode);
 
+    /*
     SDL_zero(current_mode);
     current_mode.pixel_w = dispdata->mode.hdisplay;
     current_mode.pixel_h = dispdata->mode.vdisplay;
     current_mode.refresh_rate = CalculateRefreshRate(&dispdata->mode);
     current_mode.format = SDL_PIXELFORMAT_ARGB8888;
     SDL_SetCurrentDisplayMode(display, &current_mode);
+    */
 
     windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev,
                                             dispdata->mode.hdisplay, dispdata->mode.vdisplay,
@@ -1308,7 +1302,7 @@ void KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
         mode.format = SDL_PIXELFORMAT_ARGB8888;
         mode.driverdata = modedata;
 
-        if (!SDL_AddDisplayMode(display, &mode)) {
+        if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
             SDL_free(modedata);
         }
     }
@@ -1508,8 +1502,7 @@ int KMSDRM_CreateWindow(_THIS, SDL_Window *window)
            are considered "windowed" at this point of their life.
            If a window is fullscreen, SDL internals will call
            KMSDRM_SetWindowFullscreen() to reconfigure it if necessary. */
-        mode = KMSDRM_GetClosestDisplayMode(display,
-                                            window->windowed.w, window->windowed.h, 0);
+        mode = KMSDRM_GetClosestDisplayMode(display, window->windowed.w, window->windowed.h);
 
         if (mode) {
             dispdata->fullscreen_mode = *mode;

+ 5 - 12
src/video/n3ds/SDL_n3dsvideo.c

@@ -35,7 +35,6 @@ SDL_FORCE_INLINE void AddN3DSDisplay(gfxScreen_t screen);
 
 static int N3DS_VideoInit(_THIS);
 static void N3DS_VideoQuit(_THIS);
-static void N3DS_GetDisplayModes(_THIS, SDL_VideoDisplay *display);
 static int N3DS_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect);
 static int N3DS_CreateWindow(_THIS, SDL_Window *window);
 static void N3DS_DestroyWindow(_THIS, SDL_Window *window);
@@ -65,7 +64,6 @@ static SDL_VideoDevice *N3DS_CreateDevice(void)
     device->VideoInit = N3DS_VideoInit;
     device->VideoQuit = N3DS_VideoQuit;
 
-    device->GetDisplayModes = N3DS_GetDisplayModes;
     device->GetDisplayBounds = N3DS_GetDisplayBounds;
 
     device->CreateSDLWindow = N3DS_CreateWindow;
@@ -124,7 +122,6 @@ static void AddN3DSDisplay(gfxScreen_t screen)
 
     display.name = (screen == GFX_TOP) ? "N3DS top screen" : "N3DS bottom screen";
     display.desktop_mode = mode;
-    display.current_mode = mode;
     display.driverdata = display_driver_data;
 
     SDL_AddVideoDisplay(&display, SDL_FALSE);
@@ -139,23 +136,19 @@ static void N3DS_VideoQuit(_THIS)
     gfxExit();
 }
 
-static void N3DS_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
-{
-    /* Each display only has a single mode */
-    SDL_AddDisplayMode(display, &display->current_mode);
-}
-
 static int N3DS_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
 {
     SDL_DisplayData *driver_data = display->driverdata;
+    const SDL_DisplayMode *mode = SDL_GetCurrentDisplayMode(display->id);
+
     if (driver_data == NULL) {
         return -1;
     }
+
     rect->x = 0;
     rect->y = (driver_data->screen == GFX_TOP) ? 0 : GSP_SCREEN_WIDTH;
-    rect->w = display->current_mode.screen_w;
-    rect->h = display->current_mode.screen_h;
-
+    rect->w = mode->screen_w;
+    rect->h = mode->screen_h;
     return 0;
 }
 

+ 0 - 10
src/video/ngage/SDL_ngagevideo.cpp

@@ -48,7 +48,6 @@ extern "C" {
 
 /* Initialization/Query functions */
 static int NGAGE_VideoInit(_THIS);
-static int NGAGE_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
 static void NGAGE_VideoQuit(_THIS);
 
 /* NGAGE driver bootstrap functions */
@@ -121,7 +120,6 @@ static SDL_VideoDevice *NGAGE_CreateDevice(void)
     /* General video */
     device->VideoInit = NGAGE_VideoInit;
     device->VideoQuit = NGAGE_VideoQuit;
-    device->SetDisplayMode = NGAGE_SetDisplayMode;
     device->PumpEvents = NGAGE_PumpEvents;
     device->CreateWindowFramebuffer = SDL_NGAGE_CreateWindowFramebuffer;
     device->UpdateWindowFramebuffer = SDL_NGAGE_UpdateWindowFramebuffer;
@@ -156,18 +154,10 @@ int NGAGE_VideoInit(_THIS)
         return -1;
     }
 
-    SDL_zero(mode);
-    SDL_AddDisplayMode(&_this->displays[0], &mode);
-
     /* We're done! */
     return 0;
 }
 
-static int NGAGE_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
-{
-    return 0;
-}
-
 void NGAGE_VideoQuit(_THIS)
 {
 }

+ 0 - 2
src/video/offscreen/SDL_offscreenvideo.c

@@ -109,8 +109,6 @@ int OFFSCREEN_VideoInit(_THIS)
         return -1;
     }
 
-    SDL_AddDisplayMode(&_this->displays[0], &mode);
-
     /* We're done! */
     return 0;
 }

+ 16 - 12
src/video/psp/SDL_pspvideo.c

@@ -133,7 +133,6 @@ VideoBootStrap PSP_bootstrap = {
 /*****************************************************************************/
 int PSP_VideoInit(_THIS)
 {
-    SDL_VideoDisplay display;
     SDL_DisplayMode mode;
 
     SDL_zero(mode);
@@ -144,17 +143,7 @@ int PSP_VideoInit(_THIS)
     /* 32 bpp for default */
     mode.format = SDL_PIXELFORMAT_ABGR8888;
 
-    SDL_zero(display);
-    display.desktop_mode = mode;
-    display.current_mode = mode;
-
-    SDL_AddDisplayMode(&display, &mode);
-
-    /* 16 bpp secondary mode */
-    mode.format = SDL_PIXELFORMAT_BGR565;
-    SDL_AddDisplayMode(&display, &mode);
-
-    if (SDL_AddVideoDisplay(&display, SDL_FALSE) == 0) {
+    if (SDL_AddBasicVideoDisplay(&mode) == 0) {
         return -1;
     }
     return 0;
@@ -166,12 +155,27 @@ void PSP_VideoQuit(_THIS)
 
 void PSP_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
 {
+    SDL_DisplayMode mode;
+
+    SDL_zero(mode);
+    mode.pixel_w = 480;
+    mode.pixel_h = 272;
+    mode.refresh_rate = 60.0f;
+
+    /* 32 bpp for default */
+    mode.format = SDL_PIXELFORMAT_ABGR8888;
+    SDL_AddFullscreenDisplayMode(display, &mode);
+
+    /* 16 bpp secondary mode */
+    mode.format = SDL_PIXELFORMAT_BGR565;
+    SDL_AddFullscreenDisplayMode(display, &mode);
 }
 
 int PSP_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
 {
     return 0;
 }
+
 #define EGLCHK(stmt)                           \
     do {                                       \
         EGLint err;                            \

+ 0 - 14
src/video/raspberry/SDL_rpivideo.c

@@ -102,8 +102,6 @@ static SDL_VideoDevice *RPI_Create()
     /* Setup all functions which we can handle */
     device->VideoInit = RPI_VideoInit;
     device->VideoQuit = RPI_VideoQuit;
-    device->GetDisplayModes = RPI_GetDisplayModes;
-    device->SetDisplayMode = RPI_SetDisplayMode;
     device->CreateSDLWindow = RPI_CreateWindow;
     device->CreateSDLWindowFrom = RPI_CreateWindowFrom;
     device->SetWindowTitle = RPI_SetWindowTitle;
@@ -172,7 +170,6 @@ static void AddDispManXDisplay(const int display_id)
 
     SDL_zero(display);
     display.desktop_mode = mode;
-    display.current_mode = mode;
 
     /* Allocate display internal data */
     data = (SDL_DisplayData *)SDL_calloc(1, sizeof(SDL_DisplayData));
@@ -214,17 +211,6 @@ void RPI_VideoQuit(_THIS)
 #endif
 }
 
-void RPI_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
-{
-    /* Only one display mode available, the current one */
-    SDL_AddDisplayMode(display, &display->current_mode);
-}
-
-int RPI_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
-{
-    return 0;
-}
-
 static void RPI_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
 {
     SDL_WindowData *wdata = (SDL_WindowData *)data;

+ 5 - 5
src/video/riscos/SDL_riscosframebuffer.c

@@ -37,7 +37,7 @@ int RISCOS_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, vo
     unsigned int sprite_mode;
     _kernel_oserror *error;
     _kernel_swi_regs regs;
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode *mode;
     int size;
     int w, h;
 
@@ -47,10 +47,10 @@ int RISCOS_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, vo
     RISCOS_DestroyWindowFramebuffer(_this, window);
 
     /* Create a new one */
-    SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(window), &mode);
-    if ((SDL_ISPIXELFORMAT_PACKED(mode.format) || SDL_ISPIXELFORMAT_ARRAY(mode.format))) {
-        *format = mode.format;
-        sprite_mode = (unsigned int)mode.driverdata;
+    mode = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(window));
+    if ((SDL_ISPIXELFORMAT_PACKED(mode->format) || SDL_ISPIXELFORMAT_ARRAY(mode->format))) {
+        *format = mode->format;
+        sprite_mode = (unsigned int)mode->driverdata;
     } else {
         *format = SDL_PIXELFORMAT_BGR888;
         sprite_mode = (1 | (90 << 1) | (90 << 14) | (6 << 27));

+ 1 - 1
src/video/riscos/SDL_riscosmodes.c

@@ -277,7 +277,7 @@ void RISCOS_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
             break;
         }
 
-        if (!SDL_AddDisplayMode(display, &mode)) {
+        if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
             SDL_free(mode.driverdata);
         }
     }

+ 25 - 23
src/video/uikit/SDL_uikitmodes.m

@@ -275,7 +275,7 @@ static int UIKit_AddSingleDisplayMode(SDL_VideoDisplay *display, int w, int h,
     mode.refresh_rate = UIKit_GetDisplayModeRefreshRate(uiscreen);
     mode.format = SDL_PIXELFORMAT_ABGR8888;
 
-    if (SDL_AddDisplayMode(display, &mode)) {
+    if (SDL_AddFullscreenDisplayMode(display, &mode)) {
         return 0;
     } else {
         UIKit_FreeDisplayModeData(&mode);
@@ -349,7 +349,6 @@ int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event)
 
     SDL_zero(display);
     display.desktop_mode = mode;
-    display.current_mode = mode;
 
     /* Allocate the display data */
     SDL_DisplayData *data = [[SDL_DisplayData alloc] initWithScreen:uiscreen];
@@ -378,8 +377,8 @@ void UIKit_DelDisplay(UIScreen *uiscreen)
 
             if (data && data.uiscreen == uiscreen) {
                 display->driverdata = nil;
-                SDL_DelVideoDisplay(displays[i]);
-                return;
+                SDL_DelVideoDisplay(displays[i], SDL_FALSE);
+                break;
             }
         }
         SDL_free(displays);
@@ -532,8 +531,8 @@ void UIKit_QuitModes(_THIS)
             SDL_VideoDisplay *display = &_this->displays[i];
 
             UIKit_FreeDisplayModeData(&display->desktop_mode);
-            for (j = 0; j < display->num_display_modes; j++) {
-                SDL_DisplayMode *mode = &display->display_modes[j];
+            for (j = 0; j < display->num_fullscreen_modes; j++) {
+                SDL_DisplayMode *mode = &display->fullscreen_modes[j];
                 UIKit_FreeDisplayModeData(mode);
             }
 
@@ -551,31 +550,34 @@ void SDL_OnApplicationDidChangeStatusBarOrientation()
     SDL_VideoDisplay *display = SDL_GetVideoDisplay(SDL_GetPrimaryDisplay());
 
     if (display) {
-        SDL_DisplayMode *desktopmode = &display->desktop_mode;
-        SDL_DisplayMode *currentmode = &display->current_mode;
+        SDL_DisplayMode *mode = &display->desktop_mode;
         SDL_DisplayOrientation orientation = SDL_ORIENTATION_UNKNOWN;
+        int i;
 
         /* The desktop display mode should be kept in sync with the screen
          * orientation so that updating a window's fullscreen state to
          * SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the
          * correct orientation. */
-        if (isLandscape != (desktopmode->pixel_w > desktopmode->pixel_h)) {
-            int height = desktopmode->pixel_w;
-            desktopmode->pixel_w = desktopmode->pixel_h;
-            desktopmode->pixel_h = height;
-            height = desktopmode->screen_w;
-            desktopmode->screen_w = desktopmode->screen_h;
-            desktopmode->screen_h = height;
+        if (isLandscape != (mode->pixel_w > mode->pixel_h)) {
+            int height = mode->pixel_w;
+            mode->pixel_w = mode->pixel_h;
+            mode->pixel_h = height;
+            height = mode->screen_w;
+            mode->screen_w = mode->screen_h;
+            mode->screen_h = height;
         }
 
-        /* Same deal with the current mode + SDL_GetCurrentDisplayMode. */
-        if (isLandscape != (currentmode->pixel_w > currentmode->pixel_h)) {
-            int height = currentmode->pixel_w;
-            currentmode->pixel_w = currentmode->pixel_h;
-            currentmode->pixel_h = height;
-            height = currentmode->screen_w;
-            currentmode->screen_w = currentmode->screen_h;
-            currentmode->screen_h = height;
+        /* Same deal with the fullscreen modes */
+        for (i = 0; i < display->num_fullscreen_modes; ++i) {
+            mode = &display->fullscreen_modes[i];
+            if (isLandscape != (mode->pixel_w > mode->pixel_h)) {
+                int height = mode->pixel_w;
+                mode->pixel_w = mode->pixel_h;
+                mode->pixel_h = height;
+                height = mode->screen_w;
+                mode->screen_w = mode->screen_h;
+                mode->screen_h = height;
+            }
         }
 
         switch ([UIApplication sharedApplication].statusBarOrientation) {

+ 2 - 14
src/video/uikit/SDL_uikitwindow.m

@@ -169,19 +169,7 @@ int UIKit_CreateWindow(_THIS, SDL_Window *window)
 #if !TARGET_OS_TV
         const CGSize origsize = data.uiscreen.currentMode.size;
         if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
-            if (display->num_display_modes == 0) {
-                _this->GetDisplayModes(_this, display);
-            }
-
-            int i;
-            const SDL_DisplayMode *bestmode = NULL;
-            for (i = display->num_display_modes; i >= 0; i--) {
-                const SDL_DisplayMode *mode = &display->display_modes[i];
-                if ((mode->screen_w >= window->w) && (mode->screen_h >= window->h)) {
-                    bestmode = mode;
-                }
-            }
-
+            const SDL_DisplayMode *bestmode = SDL_GetClosestFullscreenDisplayMode(display->id, window->w, window->h, 0.0f);
             if (bestmode) {
                 SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)bestmode->driverdata;
                 [data.uiscreen setCurrentMode:modedata.uiscreenmode];
@@ -189,7 +177,7 @@ int UIKit_CreateWindow(_THIS, SDL_Window *window)
                 /* desktop_mode doesn't change here (the higher level will
                  * use it to set all the screens back to their defaults
                  * upon window destruction, SDL_Quit(), etc. */
-                display->current_mode = *bestmode;
+                SDL_SetCurrentDisplayMode(display, bestmode);
             }
         }
 

+ 3 - 13
src/video/vita/SDL_vitavideo.c

@@ -106,8 +106,6 @@ static SDL_VideoDevice *VITA_Create()
     /* Setup all functions which we can handle */
     device->VideoInit = VITA_VideoInit;
     device->VideoQuit = VITA_VideoQuit;
-    device->GetDisplayModes = VITA_GetDisplayModes;
-    device->SetDisplayMode = VITA_SetDisplayMode;
     device->CreateSDLWindow = VITA_CreateWindow;
     device->CreateSDLWindowFrom = VITA_CreateWindowFrom;
     device->SetWindowTitle = VITA_SetWindowTitle;
@@ -208,7 +206,9 @@ int VITA_VideoInit(_THIS)
     /* 32 bpp for default */
     mode.format = SDL_PIXELFORMAT_ABGR8888;
 
-    SDL_AddBasicVideoDisplay(&mode);
+    if (SDL_AddBasicVideoDisplay(&mode) == 0) {
+        return -1;
+    }
 
     VITA_InitTouch();
     VITA_InitKeyboard();
@@ -222,16 +222,6 @@ void VITA_VideoQuit(_THIS)
     VITA_QuitTouch();
 }
 
-void VITA_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
-{
-    SDL_AddDisplayMode(display, &display->current_mode);
-}
-
-int VITA_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
-{
-    return 0;
-}
-
 int VITA_CreateWindow(_THIS, SDL_Window *window)
 {
     SDL_WindowData *wdata;

+ 0 - 14
src/video/vivante/SDL_vivantevideo.c

@@ -74,8 +74,6 @@ static SDL_VideoDevice *VIVANTE_Create()
     /* Setup all functions which we can handle */
     device->VideoInit = VIVANTE_VideoInit;
     device->VideoQuit = VIVANTE_VideoQuit;
-    device->GetDisplayModes = VIVANTE_GetDisplayModes;
-    device->SetDisplayMode = VIVANTE_SetDisplayMode;
     device->CreateSDLWindow = VIVANTE_CreateWindow;
     device->SetWindowTitle = VIVANTE_SetWindowTitle;
     device->SetWindowPosition = VIVANTE_SetWindowPosition;
@@ -159,7 +157,6 @@ static int VIVANTE_AddVideoDisplays(_THIS)
     SDL_zero(display);
     display.name = VIVANTE_GetDisplayName(_this);
     display.desktop_mode = mode;
-    display.current_mode = mode;
     display.driverdata = data;
     if (SDL_AddVideoDisplay(&display, SDL_FALSE) == 0) {
         return -1;
@@ -242,17 +239,6 @@ void VIVANTE_VideoQuit(_THIS)
 #endif
 }
 
-void VIVANTE_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
-{
-    /* Only one display mode available, the current one */
-    SDL_AddDisplayMode(display, &display->current_mode);
-}
-
-int VIVANTE_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
-{
-    return 0;
-}
-
 int VIVANTE_CreateWindow(_THIS, SDL_Window *window)
 {
     SDL_VideoData *videodata = _this->driverdata;

+ 2 - 3
src/video/wayland/SDL_waylandopengles.c

@@ -123,9 +123,8 @@ int Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
     if (swap_interval != 0) {
         SDL_VideoData *videodata = _this->driverdata;
         struct wl_display *display = videodata->display;
-        SDL_VideoDisplay *sdldisplay = SDL_GetVideoDisplayForWindow(window);
-        /* ~10 frames (or 1 sec), so we'll progress even if throttled to zero. */
-        const Uint64 max_wait = SDL_GetTicksNS() + (sdldisplay->current_mode.refresh_rate ? ((SDL_NS_PER_SECOND * 10 * 100) / (int)(sdldisplay->current_mode.refresh_rate * 100)) : SDL_NS_PER_SECOND);
+        /* 1 sec, so we'll progress even if throttled to zero. */
+        const Uint64 max_wait = SDL_NS_PER_SECOND;
         while (SDL_AtomicGet(&data->swap_interval_ready) == 0) {
             Uint64 now;
 

+ 19 - 20
src/video/wayland/SDL_waylandvideo.c

@@ -413,15 +413,15 @@ static void AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90)
 
     int i;
     SDL_DisplayMode mode;
-    const int native_width = dpy->display_modes->pixel_w;
-    const int native_height = dpy->display_modes->pixel_h;
+    const int native_width = dpy->desktop_mode.pixel_w;
+    const int native_height = dpy->desktop_mode.pixel_h;
 
     for (i = 0; i < SDL_arraysize(mode_list); ++i) {
         SDL_zero(mode);
-        mode.format = dpy->display_modes->format;
+        mode.format = dpy->desktop_mode.format;
         mode.display_scale = 1.0f;
-        mode.refresh_rate = dpy->display_modes->refresh_rate;
-        mode.driverdata = dpy->display_modes->driverdata;
+        mode.refresh_rate = dpy->desktop_mode.refresh_rate;
+        mode.driverdata = dpy->desktop_mode.driverdata;
 
         if (rot_90) {
             mode.pixel_w = mode_list[i].h;
@@ -435,7 +435,7 @@ static void AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90)
         if ((mode.pixel_w < native_width && mode.pixel_h < native_height) ||
             (mode.pixel_w < native_width && mode.pixel_h == native_height) ||
             (mode.pixel_w == native_width && mode.pixel_h < native_height)) {
-            SDL_AddDisplayMode(dpy, &mode);
+            SDL_AddFullscreenDisplayMode(dpy, &mode);
         }
     }
 }
@@ -458,12 +458,12 @@ static void display_handle_geometry(void *data,
     if (driverdata->wl_output_done_count) {
         /* Clear the wl_output ref so Reset doesn't free it */
         display = SDL_GetVideoDisplay(driverdata->display);
-        for (i = 0; i < display->num_display_modes; ++i) {
-            display->display_modes[i].driverdata = NULL;
+        for (i = 0; i < display->num_fullscreen_modes; ++i) {
+            display->fullscreen_modes[i].driverdata = NULL;
         }
 
         /* Okay, now it's safe to reset */
-        SDL_ResetDisplayModes(display);
+        SDL_ResetFullscreenDisplayModes(display);
 
         /* The display has officially started over. */
         driverdata->wl_output_done_count = 0;
@@ -609,15 +609,13 @@ static void display_handle_done(void *data,
     }
 
     /* Set the desktop display mode. */
-    SDL_AddDisplayMode(dpy, &desktop_mode);
-    SDL_SetCurrentDisplayMode(dpy, &desktop_mode);
-    SDL_SetDesktopDisplayMode(dpy, &desktop_mode);
+    SDL_memcpy(&dpy->desktop_mode, &desktop_mode, sizeof(&dpy->desktop_mode));
 
     /* If the desktop is scaled... */
     if (driverdata->scale_factor > 1.0f) {
         /* ...expose the native resolution if viewports are available... */
         if (video->viewporter != NULL) {
-            SDL_AddDisplayMode(dpy, &native_mode);
+            SDL_AddFullscreenDisplayMode(dpy, &native_mode);
         } else {
             /* ...if not, expose some smaller, integer scaled resolutions. */
             int i;
@@ -628,7 +626,7 @@ static void display_handle_done(void *data,
                 desktop_mode.pixel_h = base_pixel_h * i;
                 desktop_mode.display_scale = (float)i;
 
-                SDL_AddDisplayMode(dpy, &desktop_mode);
+                SDL_AddFullscreenDisplayMode(dpy, &desktop_mode);
             }
         }
     }
@@ -749,7 +747,7 @@ static void Wayland_free_display(SDL_VideoData *d, uint32_t id)
                         }
                     }
                 }
-                SDL_DelVideoDisplay(displays[i]);
+                SDL_DelVideoDisplay(displays[i], SDL_FALSE);
                 if (data->xdg_output) {
                     zxdg_output_v1_destroy(data->xdg_output);
                 }
@@ -974,10 +972,11 @@ int Wayland_VideoInit(_THIS)
 static int Wayland_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
 {
     SDL_DisplayData *driverdata = display->driverdata;
+    const SDL_DisplayMode *mode = SDL_GetCurrentDisplayMode(display->id);
     rect->x = driverdata->x;
     rect->y = driverdata->y;
-    rect->w = display->current_mode.screen_w;
-    rect->h = display->current_mode.screen_h;
+    rect->w = mode->screen_w;
+    rect->h = mode->screen_h;
     return 0;
 }
 
@@ -1017,11 +1016,11 @@ static void Wayland_VideoCleanup(_THIS)
         SDL_free(display->driverdata);
         display->driverdata = NULL;
 
-        for (j = display->num_display_modes; j--;) {
-            display->display_modes[j].driverdata = NULL;
+        for (j = display->num_fullscreen_modes; j--;) {
+            display->fullscreen_modes[j].driverdata = NULL;
         }
         display->desktop_mode.driverdata = NULL;
-        SDL_DelVideoDisplay(display->id);
+        SDL_DelVideoDisplay(display->id, SDL_FALSE);
     }
     data->output_list = NULL;
 

+ 8 - 11
src/video/wayland/SDL_waylandwindow.c

@@ -83,17 +83,14 @@ static void GetFullScreenDimensions(SDL_Window *window, int *width, int *height,
         }
     } else {
         /* If a mode was set, use it, otherwise use the native resolution. */
-        if (window->fullscreen_mode.pixel_w != 0 && window->fullscreen_mode.pixel_h != 0) {
-            fs_width = window->fullscreen_mode.screen_w;
-            fs_height = window->fullscreen_mode.screen_h;
-            buf_width = window->fullscreen_mode.pixel_w;
-            buf_height = window->fullscreen_mode.pixel_h;
-        } else {
-            fs_width = disp->display_modes[0].screen_w;
-            fs_height = disp->display_modes[0].screen_h;
-            buf_width = disp->display_modes[0].pixel_w;
-            buf_height = disp->display_modes[0].pixel_h;
-        }
+        const SDL_DisplayMode *mode = SDL_GetWindowFullscreenMode(window);
+        if (!mode) {
+            mode = &disp->desktop_mode;
+        }
+        fs_width = mode->screen_w;
+        fs_height = mode->screen_h;
+        buf_width = mode->pixel_w;
+        buf_height = mode->pixel_h;
     }
 
     if (width) {

+ 2 - 2
src/video/windows/SDL_windowsevents.c

@@ -1241,7 +1241,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         RECT rect;
         int x, y;
         int w, h;
-        SDL_DisplayID displayID = data->window->displayID;
+        SDL_DisplayID displayID = SDL_GetDisplayForWindow(data->window);
 
         if (data->initializing || data->in_border_change) {
             break;
@@ -1294,7 +1294,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         /* Forces a WM_PAINT event */
         InvalidateRect(hwnd, NULL, FALSE);
 
-        if (data->window->displayID != displayID) {
+        if (data->window->last_displayID != displayID) {
             /* Display changed, check ICC profile */
             WIN_UpdateWindowICCProfile(data->window, SDL_TRUE);
         }

+ 3 - 6
src/video/windows/SDL_windowsmodes.c

@@ -342,9 +342,7 @@ static void WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info,
                 SDL_VideoDisplay *existing_display = &_this->displays[i];
                 SDL_Rect bounds;
 
-                SDL_ResetDisplayModes(existing_display);
-                SDL_SetCurrentDisplayMode(existing_display, &mode);
-                SDL_SetDesktopDisplayMode(existing_display, &mode);
+                SDL_ResetFullscreenDisplayModes(existing_display);
                 if (WIN_GetDisplayBounds(_this, existing_display, &bounds) == 0) {
                     if (SDL_memcmp(&driverdata->bounds, &bounds, sizeof(bounds)) != 0 || moved) {
                         SDL_SendDisplayEvent(existing_display, SDL_EVENT_DISPLAY_MOVED, 0);
@@ -376,7 +374,6 @@ static void WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info,
     }
 
     display.desktop_mode = mode;
-    display.current_mode = mode;
     display.orientation = orientation;
     display.device = _this;
     display.driverdata = displaydata;
@@ -737,7 +734,7 @@ void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
             continue;
         }
         if (mode.format != SDL_PIXELFORMAT_UNKNOWN) {
-            if (!SDL_AddDisplayMode(display, &mode)) {
+            if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
                 SDL_free(mode.driverdata);
             }
         } else {
@@ -858,7 +855,7 @@ void WIN_RefreshDisplays(_THIS)
         SDL_VideoDisplay *display = &_this->displays[i];
         SDL_DisplayData *driverdata = display->driverdata;
         if (driverdata->IsValid == SDL_FALSE) {
-            SDL_DelVideoDisplay(display->id);
+            SDL_DelVideoDisplay(display->id, SDL_TRUE);
         }
     }
 }

+ 2 - 9
src/video/winrt/SDL_winrtvideo.cpp

@@ -307,17 +307,12 @@ static int WINRT_AddDisplaysForOutput(_THIS, IDXGIAdapter1 *dxgiAdapter1, int ou
         mode.pixel_h = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
         mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
         display.desktop_mode = mode;
-        display.current_mode = mode;
-        if (!SDL_AddDisplayMode(&display, &mode)) {
-            goto done;
-        }
     } else if (FAILED(hr)) {
         WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::FindClosestMatchingMode failed", hr);
         goto done;
     } else {
         display.name = WIN_StringToUTF8(dxgiOutputDesc.DeviceName);
         WINRT_DXGIModeToSDLDisplayMode(&closestMatch, &display.desktop_mode);
-        display.current_mode = display.desktop_mode;
 
         hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, NULL);
         if (FAILED(hr)) {
@@ -343,7 +338,7 @@ static int WINRT_AddDisplaysForOutput(_THIS, IDXGIAdapter1 *dxgiAdapter1, int ou
         for (UINT i = 0; i < numModes; ++i) {
             SDL_DisplayMode sdlMode;
             WINRT_DXGIModeToSDLDisplayMode(&dxgiModes[i], &sdlMode);
-            SDL_AddDisplayMode(&display, &sdlMode);
+            SDL_AddFullscreenDisplayMode(&display, &sdlMode);
         }
     }
 
@@ -432,9 +427,7 @@ static int WINRT_AddDisplaysForAdapter(_THIS, IDXGIFactory2 *dxgiFactory2, int a
 
                 mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
                 display.desktop_mode = mode;
-                display.current_mode = mode;
-                bool error = SDL_AddDisplayMode(&display, &mode) < 0 ||
-                             SDL_AddVideoDisplay(&display, SDL_FALSE) == 0;
+                bool error = (SDL_AddVideoDisplay(&display, SDL_FALSE) == 0);
                 if (display.name) {
                     SDL_free(display.name);
                 }

+ 3 - 2
src/video/x11/SDL_x11messagebox.c

@@ -470,8 +470,9 @@ static int X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data)
         if ((dev) && (dev->displays) && (dev->num_displays > 0)) {
             const SDL_VideoDisplay *dpy = &dev->displays[0];
             const SDL_DisplayData *dpydata = dpy->driverdata;
-            x = dpydata->x + ((dpy->current_mode.pixel_w - data->dialog_width) / 2);
-            y = dpydata->y + ((dpy->current_mode.pixel_h - data->dialog_height) / 3);
+            const SDL_DisplayMode *mode = SDL_GetCurrentDisplayMode(dpy->id);
+            x = dpydata->x + ((mode->pixel_w - data->dialog_width) / 2);
+            y = dpydata->y + ((mode->pixel_h - data->dialog_height) / 3);
         } else { /* oh well. This will misposition on a multi-head setup. Init first next time. */
             x = (DisplayWidth(display, data->screen) - data->dialog_width) / 2;
             y = (DisplayHeight(display, data->screen) - data->dialog_height) / 3;

+ 6 - 22
src/video/x11/SDL_x11modes.c

@@ -386,7 +386,6 @@ static int X11_AddXRandRDisplay(_THIS, Display *dpy, int screen, RROutput output
         display.name = display_name;
     }
     display.desktop_mode = mode;
-    display.current_mode = mode;
     display.driverdata = displaydata;
     if (SDL_AddVideoDisplay(&display, send_event) == 0) {
         return -1;
@@ -419,7 +418,7 @@ static void X11_HandleXRandROutputChange(_THIS, const XRROutputChangeNotifyEvent
 
     if (ev->connection == RR_Disconnected) { /* output is going away */
         if (display != NULL) {
-            SDL_DelVideoDisplay(display->id);
+            SDL_DelVideoDisplay(display->id, SDL_TRUE);
         }
     } else if (ev->connection == RR_Connected) { /* output is coming online */
         if (display != NULL) {
@@ -629,7 +628,6 @@ static int X11_InitModes_StdXlib(_THIS)
     SDL_zero(display);
     display.name = (char *)"Generic X11 Display"; /* this is just copied and thrown away, it's safe to cast to char* here. */
     display.desktop_mode = mode;
-    display.current_mode = mode;
     display.driverdata = displaydata;
     if (SDL_AddVideoDisplay(&display, SDL_TRUE) == 0) {
         return -1;
@@ -670,7 +668,7 @@ void X11_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
      * (or support recreating the window with a new visual behind the scenes)
      */
     SDL_zero(mode);
-    mode.format = sdl_display->current_mode.format;
+    mode.format = sdl_display->desktop_mode.format;
 
 #if SDL_VIDEO_DRIVER_X11_XRANDR
     if (data->use_xrandr) {
@@ -693,7 +691,7 @@ void X11_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
                     mode.driverdata = modedata;
 
                     if (!SetXRandRModeInfo(display, res, output_info->crtc, output_info->modes[i], &mode) ||
-                        !SDL_AddDisplayMode(sdl_display, &mode)) {
+                        !SDL_AddFullscreenDisplayMode(sdl_display, &mode)) {
                         SDL_free(modedata);
                     }
                 }
@@ -704,20 +702,6 @@ void X11_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
         return;
     }
 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
-
-    if (!data->use_xrandr) {
-        SDL_DisplayModeData *modedata;
-        /* Add the desktop mode */
-        mode = sdl_display->desktop_mode;
-        modedata = (SDL_DisplayModeData *)SDL_calloc(1, sizeof(SDL_DisplayModeData));
-        if (modedata) {
-            *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
-        }
-        mode.driverdata = modedata;
-        if (!SDL_AddDisplayMode(sdl_display, &mode)) {
-            SDL_free(modedata);
-        }
-    }
 }
 
 #if SDL_VIDEO_DRIVER_X11_XRANDR
@@ -832,12 +816,12 @@ void X11_QuitModes(_THIS)
 int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay *sdl_display, SDL_Rect *rect)
 {
     SDL_DisplayData *data = sdl_display->driverdata;
+    const SDL_DisplayMode *mode = SDL_GetCurrentDisplayMode(sdl_display->id);
 
     rect->x = data->x;
     rect->y = data->y;
-    rect->w = sdl_display->current_mode.screen_w;
-    rect->h = sdl_display->current_mode.screen_h;
-
+    rect->w = mode->screen_w;
+    rect->h = mode->screen_h;
     return 0;
 }
 

+ 1 - 2
src/video/x11/SDL_x11video.c

@@ -125,8 +125,7 @@ static int X11_SafetyNetErrHandler(Display *d, XErrorEvent *e)
             int i;
             for (i = 0; i < device->num_displays; i++) {
                 SDL_VideoDisplay *display = &device->displays[i];
-                if (SDL_memcmp(&display->current_mode, &display->desktop_mode,
-                               sizeof(SDL_DisplayMode)) != 0) {
+                if (SDL_GetCurrentDisplayMode(display->id) != SDL_GetDesktopDisplayMode(display->id)) {
                     X11_SetDisplayMode(device, display, &display->desktop_mode);
                 }
             }

+ 43 - 92
test/testautomation_video.c

@@ -339,12 +339,13 @@ int video_getWindowFlags(void *arg)
 }
 
 /**
- * @brief Tests the functionality of the SDL_GetNumDisplayModes function
+ * @brief Tests the functionality of the SDL_GetFullscreenDisplayModes function
  */
-int video_getNumDisplayModes(void *arg)
+int video_getFullscreenDisplayModes(void *arg)
 {
     SDL_DisplayID *displays;
-    int result;
+    const SDL_DisplayMode **modes;
+    int count;
     int i;
 
     /* Get number of displays */
@@ -354,9 +355,11 @@ int video_getNumDisplayModes(void *arg)
 
         /* Make call for each display */
         for (i = 0; displays[i]; ++i) {
-            result = SDL_GetNumDisplayModes(displays[i]);
-            SDLTest_AssertPass("Call to SDL_GetNumDisplayModes(%d)", i);
-            SDLTest_AssertCheck(result >= 1, "Validate returned value from function; expected: >=1; got: %d", result);
+            modes = SDL_GetFullscreenDisplayModes(displays[i], &count);
+            SDLTest_AssertPass("Call to SDL_GetFullscreenDisplayModes(%" SDL_PRIu32 ")", displays[i]);
+            SDLTest_AssertCheck(modes != NULL, "Validate returned value from function; expected != NULL; got: %p", modes);
+            SDLTest_AssertCheck(count >= 0, "Validate number of modes; expected: >= 0; got: %d", count);
+            SDL_free(modes);
         }
         SDL_free(displays);
     }
@@ -365,18 +368,15 @@ int video_getNumDisplayModes(void *arg)
 }
 
 /**
- * @brief Tests the functionality of the SDL_GetClosestDisplayMode function against current resolution
+ * @brief Tests the functionality of the SDL_GetClosestFullscreenDisplayMode function against current resolution
  */
 int video_getClosestDisplayModeCurrentResolution(void *arg)
 {
-    int result;
     SDL_DisplayID *displays;
+    const SDL_DisplayMode **modes;
     SDL_DisplayMode current;
-    SDL_DisplayMode target;
-    SDL_DisplayMode closest;
-    SDL_DisplayMode *dResult;
-    int i;
-    int variation;
+    const SDL_DisplayMode *closest;
+    int i, num_modes;
 
     /* Get number of displays */
     displays = SDL_GetDisplays(NULL);
@@ -388,35 +388,22 @@ int video_getClosestDisplayModeCurrentResolution(void *arg)
             SDLTest_Log("Testing against display: %" SDL_PRIu32 "", displays[i]);
 
             /* Get first display mode to get a sane resolution; this should always work */
-            result = SDL_GetDisplayMode(displays[i], 0, &current);
-            SDLTest_AssertPass("Call to SDL_GetDisplayMode()");
-            SDLTest_AssertCheck(result == 0, "Verify return value, expected: 0, got: %d", result);
-            if (result != 0) {
-                return TEST_ABORTED;
-            }
-
-            /* Set the desired resolution equals to current resolution */
-            SDL_zero(target);
-            target.pixel_w = current.pixel_w;
-            target.pixel_h = current.pixel_h;
-            for (variation = 0; variation < 8; variation++) {
-                /* Vary constraints on other query parameters */
-                target.format = (variation & 1) ? current.format : 0;
-                target.refresh_rate = (variation & 2) ? current.refresh_rate : 0.0f;
-                target.driverdata = (variation & 4) ? current.driverdata : 0;
+            modes = SDL_GetFullscreenDisplayModes(displays[i], &num_modes);
+            SDLTest_AssertPass("Call to SDL_GetDisplayModes()");
+            SDLTest_Assert(modes != NULL, "Verify returned value is not NULL");
+            if (num_modes > 0) {
+                SDL_memcpy(&current, modes[0], sizeof(current));
 
                 /* Make call */
-                dResult = SDL_GetClosestDisplayMode(displays[i], &target, &closest);
-                SDLTest_AssertPass("Call to SDL_GetClosestDisplayMode(target=current/variation%d)", variation);
-                SDLTest_Assert(dResult != NULL, "Verify returned value is not NULL");
+                closest = SDL_GetClosestFullscreenDisplayMode(displays[i], current.pixel_w, current.pixel_h, current.refresh_rate);
+                SDLTest_AssertPass("Call to SDL_GetClosestFullscreenDisplayMode(target=current)");
+                SDLTest_Assert(closest != NULL, "Verify returned value is not NULL");
 
                 /* Check that one gets the current resolution back again */
-                SDLTest_AssertCheck(closest.pixel_w == current.pixel_w, "Verify returned width matches current width; expected: %d, got: %d", current.pixel_w, closest.pixel_w);
-                SDLTest_AssertCheck(closest.pixel_h == current.pixel_h, "Verify returned height matches current height; expected: %d, got: %d", current.pixel_h, closest.pixel_h);
-                /* NOLINTBEGIN(clang-analyzer-core.NullDereference): Checked earlier for NULL */
-                SDLTest_AssertCheck(closest.pixel_w == dResult->pixel_w, "Verify return value matches assigned value; expected: %d, got: %d", closest.pixel_w, dResult->pixel_w);
-                SDLTest_AssertCheck(closest.pixel_h == dResult->pixel_h, "Verify return value matches assigned value; expected: %d, got: %d", closest.pixel_h, dResult->pixel_h);
-                /* NOLINTEND(clang-analyzer-core.NullDereference) */
+                if (closest) {
+                    SDLTest_AssertCheck(closest->pixel_w == current.pixel_w, "Verify returned width matches current width; expected: %d, got: %d", current.pixel_w, closest->pixel_w);
+                    SDLTest_AssertCheck(closest->pixel_h == current.pixel_h, "Verify returned height matches current height; expected: %d, got: %d", current.pixel_h, closest->pixel_h);
+                }
             }
         }
         SDL_free(displays);
@@ -426,13 +413,12 @@ int video_getClosestDisplayModeCurrentResolution(void *arg)
 }
 
 /**
- * @brief Tests the functionality of the SDL_GetClosestDisplayMode function against random resolution
+ * @brief Tests the functionality of the SDL_GetClosestFullscreenDisplayMode function against random resolution
  */
 int video_getClosestDisplayModeRandomResolution(void *arg)
 {
     SDL_DisplayID *displays;
     SDL_DisplayMode target;
-    SDL_DisplayMode closest;
     int i;
     int variation;
 
@@ -451,12 +437,11 @@ int video_getClosestDisplayModeRandomResolution(void *arg)
                 SDL_zero(target);
                 target.pixel_w = (variation & 1) ? SDLTest_RandomIntegerInRange(1, 4096) : 0;
                 target.pixel_h = (variation & 2) ? SDLTest_RandomIntegerInRange(1, 4096) : 0;
-                target.format = (variation & 4) ? SDLTest_RandomIntegerInRange(1, 10) : 0;
                 target.refresh_rate = (variation & 8) ? (float)SDLTest_RandomIntegerInRange(25, 120) : 0.0f;
 
                 /* Make call; may or may not find anything, so don't validate any further */
-                SDL_GetClosestDisplayMode(displays[i], &target, &closest);
-                SDLTest_AssertPass("Call to SDL_GetClosestDisplayMode(target=random/variation%d)", variation);
+                SDL_GetClosestFullscreenDisplayMode(displays[i], target.pixel_w, target.pixel_h, target.refresh_rate);
+                SDLTest_AssertPass("Call to SDL_GetClosestFullscreenDisplayMode(target=random/variation%d)", variation);
             }
         }
         SDL_free(displays);
@@ -466,31 +451,22 @@ int video_getClosestDisplayModeRandomResolution(void *arg)
 }
 
 /**
- * @brief Tests call to SDL_GetWindowDisplayMode
+ * @brief Tests call to SDL_GetWindowFullscreenMode
  *
- * @sa http://wiki.libsdl.org/SDL_GetWindowDisplayMode
+ * @sa http://wiki.libsdl.org/SDL_GetWindowFullscreenMode
  */
 int video_getWindowDisplayMode(void *arg)
 {
     SDL_Window *window;
     const char *title = "video_getWindowDisplayMode Test Window";
-    SDL_DisplayMode mode;
-    int result;
-
-    /* Invalidate part of the mode content so we can check values later */
-    mode.pixel_w = -1;
-    mode.pixel_h = -1;
-    mode.refresh_rate = -1.0f;
+    const SDL_DisplayMode *mode;
 
     /* Call against new test window */
     window = createVideoSuiteTestWindow(title);
     if (window != NULL) {
-        result = SDL_GetWindowDisplayMode(window, &mode);
-        SDLTest_AssertPass("Call to SDL_GetWindowDisplayMode()");
-        SDLTest_AssertCheck(result == 0, "Validate result value; expected: 0, got: %d", result);
-        SDLTest_AssertCheck(mode.pixel_w > 0, "Validate mode.w content; expected: >0, got: %d", mode.pixel_w);
-        SDLTest_AssertCheck(mode.pixel_h > 0, "Validate mode.h content; expected: >0, got: %d", mode.pixel_h);
-        SDLTest_AssertCheck(mode.refresh_rate > 0.0f, "Validate mode.refresh_rate content; expected: >0, got: %g", mode.refresh_rate);
+        mode = SDL_GetWindowFullscreenMode(window);
+        SDLTest_AssertPass("Call to SDL_GetWindowFullscreenMode()");
+        SDLTest_AssertCheck(mode == NULL, "Validate result value; expected: NULL, got: %p", mode);
     }
 
     /* Clean up */
@@ -519,43 +495,18 @@ static void checkInvalidWindowError()
 }
 
 /**
- * @brief Tests call to SDL_GetWindowDisplayMode with invalid input
+ * @brief Tests call to SDL_GetWindowFullscreenMode with invalid input
  *
- * @sa http://wiki.libsdl.org/SDL_GetWindowDisplayMode
+ * @sa http://wiki.libsdl.org/SDL_GetWindowFullscreenMode
  */
 int video_getWindowDisplayModeNegative(void *arg)
 {
-    const char *expectedError = "Parameter 'mode' is invalid";
-    char *lastError;
-    SDL_Window *window;
-    const char *title = "video_getWindowDisplayModeNegative Test Window";
-    SDL_DisplayMode mode;
-    int result;
-
-    /* Call against new test window */
-    window = createVideoSuiteTestWindow(title);
-    if (window != NULL) {
-        result = SDL_GetWindowDisplayMode(window, NULL);
-        SDLTest_AssertPass("Call to SDL_GetWindowDisplayMode(...,mode=NULL)");
-        SDLTest_AssertCheck(result == -1, "Validate result value; expected: -1, got: %d", result);
-        lastError = (char *)SDL_GetError();
-        SDLTest_AssertPass("SDL_GetError()");
-        SDLTest_AssertCheck(lastError != NULL, "Verify error message is not NULL");
-        if (lastError != NULL) {
-            SDLTest_AssertCheck(SDL_strcmp(lastError, expectedError) == 0,
-                                "SDL_GetError(): expected message '%s', was message: '%s'",
-                                expectedError,
-                                lastError);
-        }
-    }
-
-    /* Clean up */
-    destroyVideoSuiteTestWindow(window);
+    const SDL_DisplayMode *mode;
 
     /* Call against invalid window */
-    result = SDL_GetWindowDisplayMode(NULL, &mode);
-    SDLTest_AssertPass("Call to SDL_GetWindowDisplayMode(window=NULL,...)");
-    SDLTest_AssertCheck(result == -1, "Validate result value; expected: -1, got: %d", result);
+    mode = SDL_GetWindowFullscreenMode(NULL);
+    SDLTest_AssertPass("Call to SDL_GetWindowFullscreenMode(window=NULL)");
+    SDLTest_AssertCheck(mode == NULL, "Validate result value; expected: NULL, got: %p", mode);
     checkInvalidWindowError();
 
     return TEST_COMPLETED;
@@ -1748,7 +1699,7 @@ int video_setWindowCenteredOnDisplay(void *arg)
                 SDLTest_AssertCheck(currentY == expectedY, "Validate y (current: %d, expected: %d)", currentY, expectedY);
 
                 /* Enter fullscreen desktop */
-                result = SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
+                result = SDL_SetWindowFullscreen(window, SDL_TRUE);
                 SDLTest_AssertCheck(result == 0, "Verify return value; expected: 0, got: %d", result);
 
                 /* Check we are filling the full display */
@@ -1763,7 +1714,7 @@ int video_setWindowCenteredOnDisplay(void *arg)
                 SDLTest_AssertCheck(currentY == expectedDisplayRect.y, "Validate y (current: %d, expected: %d)", currentY, expectedDisplayRect.y);
 
                 /* Leave fullscreen desktop */
-                result = SDL_SetWindowFullscreen(window, 0);
+                result = SDL_SetWindowFullscreen(window, SDL_FALSE);
                 SDLTest_AssertCheck(result == 0, "Verify return value; expected: 0, got: %d", result);
 
                 /* Check window was restored correctly */
@@ -1832,7 +1783,7 @@ static const SDLTest_TestCaseReference videoTest5 = {
 };
 
 static const SDLTest_TestCaseReference videoTest6 = {
-    (SDLTest_TestCaseFp)video_getNumDisplayModes, "video_getNumDisplayModes", "Use SDL_GetNumDisplayModes function to get number of display modes", TEST_ENABLED
+    (SDLTest_TestCaseFp)video_getFullscreenDisplayModes, "video_getFullscreenDisplayModes", "Use SDL_GetFullscreenDisplayModes function to get number of display modes", TEST_ENABLED
 };
 
 static const SDLTest_TestCaseReference videoTest7 = {

+ 17 - 17
test/testdisplayinfo.c

@@ -32,7 +32,8 @@ print_mode(const char *prefix, const SDL_DisplayMode *mode)
 int main(int argc, char *argv[])
 {
     SDL_DisplayID *displays;
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode **modes;
+    const SDL_DisplayMode *mode;
     int num_displays, i;
 
     /* Enable standard application logging */
@@ -51,13 +52,13 @@ int main(int argc, char *argv[])
 
     for (i = 0; i < num_displays; i++) {
         SDL_DisplayID dpy = displays[i];
-        const int num_modes = SDL_GetNumDisplayModes(dpy);
         SDL_Rect rect = { 0, 0, 0, 0 };
         float ddpi, hdpi, vdpi;
-        int m;
+        int m, num_modes = 0;
 
         SDL_GetDisplayBounds(dpy, &rect);
-        SDL_Log("%" SDL_PRIu32 ": \"%s\" (%dx%d, (%d, %d)), %d modes.\n", dpy, SDL_GetDisplayName(dpy), rect.w, rect.h, rect.x, rect.y, num_modes);
+        modes = SDL_GetFullscreenDisplayModes(dpy, &num_modes);
+        SDL_Log("%" SDL_PRIu32 ": \"%s\" (%dx%d, (%d, %d)), %d fullscreen modes.\n", dpy, SDL_GetDisplayName(dpy), rect.w, rect.h, rect.x, rect.y, num_modes);
 
         if (SDL_GetDisplayPhysicalDPI(dpy, &ddpi, &hdpi, &vdpi) == -1) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "    DPI: failed to query (%s)\n", SDL_GetError());
@@ -65,27 +66,26 @@ int main(int argc, char *argv[])
             SDL_Log("    DPI: ddpi=%f; hdpi=%f; vdpi=%f\n", ddpi, hdpi, vdpi);
         }
 
-        if (SDL_GetCurrentDisplayMode(dpy, &mode) == -1) {
-            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "    CURRENT: failed to query (%s)\n", SDL_GetError());
+        mode = SDL_GetCurrentDisplayMode(dpy);
+        if (mode) {
+            print_mode("CURRENT", mode);
         } else {
-            print_mode("CURRENT", &mode);
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "    CURRENT: failed to query (%s)\n", SDL_GetError());
         }
 
-        if (SDL_GetDesktopDisplayMode(dpy, &mode) == -1) {
-            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "    DESKTOP: failed to query (%s)\n", SDL_GetError());
+        mode = SDL_GetDesktopDisplayMode(dpy);
+        if (mode) {
+            print_mode("DESKTOP", mode);
         } else {
-            print_mode("DESKTOP", &mode);
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "    DESKTOP: failed to query (%s)\n", SDL_GetError());
         }
 
         for (m = 0; m < num_modes; m++) {
-            if (SDL_GetDisplayMode(dpy, m, &mode) == -1) {
-                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "    MODE %d: failed to query (%s)\n", m, SDL_GetError());
-            } else {
-                char prefix[64];
-                (void)SDL_snprintf(prefix, sizeof prefix, "    MODE %d", m);
-                print_mode(prefix, &mode);
-            }
+            char prefix[64];
+            (void)SDL_snprintf(prefix, sizeof prefix, "    MODE %d", m);
+            print_mode(prefix, modes[i]);
         }
+        SDL_free(modes);
 
         SDL_Log("\n");
     }

+ 5 - 3
test/testgl.c

@@ -202,7 +202,7 @@ int main(int argc, char *argv[])
     int fsaa, accel;
     int value;
     int i, done;
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode *mode;
     SDL_Event event;
     Uint64 then, now;
     Uint32 frames;
@@ -293,8 +293,10 @@ int main(int argc, char *argv[])
         swap_interval = 0;
     }
 
-    SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay(), &mode);
-    SDL_Log("Screen BPP    : %" SDL_PRIu32 "\n", SDL_BITSPERPIXEL(mode.format));
+    mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
+    if (mode) {
+        SDL_Log("Screen BPP    : %" SDL_PRIu32 "\n", SDL_BITSPERPIXEL(mode->format));
+    }
 
     ret_interval = SDL_GL_GetSwapInterval(&interval);
     if (ret_interval < 0) {

+ 6 - 4
test/testgles.c

@@ -98,7 +98,7 @@ int main(int argc, char *argv[])
     int fsaa, accel;
     int value;
     int i, done;
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode *mode;
     SDL_Event event;
     Uint32 then, now, frames;
     int status;
@@ -187,9 +187,11 @@ int main(int argc, char *argv[])
         SDL_GL_SetSwapInterval(0);
     }
 
-    SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay(), &mode);
-    SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode.format));
-    SDL_Log("\n");
+    mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
+    if (mode) {
+        SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode->format));
+        SDL_Log("\n");
+    }
     SDL_Log("Vendor     : %s\n", glGetString(GL_VENDOR));
     SDL_Log("Renderer   : %s\n", glGetString(GL_RENDERER));
     SDL_Log("Version    : %s\n", glGetString(GL_VERSION));

+ 6 - 4
test/testgles2.c

@@ -615,7 +615,7 @@ int main(int argc, char *argv[])
     int fsaa, accel, threaded;
     int value;
     int i;
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode *mode;
     Uint64 then, now;
     int status;
     shader_data *data;
@@ -714,10 +714,12 @@ int main(int argc, char *argv[])
         SDL_GL_SetSwapInterval(0);
     }
 
-    SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay(), &mode);
+    mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
     SDL_Log("Threaded  : %s\n", threaded ? "yes" : "no");
-    SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode.format));
-    SDL_Log("\n");
+    if (mode) {
+        SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode->format));
+        SDL_Log("\n");
+    }
     SDL_Log("Vendor     : %s\n", ctx.glGetString(GL_VENDOR));
     SDL_Log("Renderer   : %s\n", ctx.glGetString(GL_RENDERER));
     SDL_Log("Version    : %s\n", ctx.glGetString(GL_VERSION));

+ 6 - 4
test/testgles2_sdf.c

@@ -434,7 +434,7 @@ int main(int argc, char *argv[])
     int fsaa, accel;
     int value;
     int i;
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode *mode;
     Uint64 then, now;
     int status;
     shader_data *data;
@@ -602,9 +602,11 @@ int main(int argc, char *argv[])
         SDL_GL_SetSwapInterval(0);
     }
 
-    SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay(), &mode);
-    SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode.format));
-    SDL_Log("\n");
+    mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
+    if (mode) {
+        SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode->format));
+        SDL_Log("\n");
+    }
     SDL_Log("Vendor     : %s\n", ctx.glGetString(GL_VENDOR));
     SDL_Log("Renderer   : %s\n", ctx.glGetString(GL_RENDERER));
     SDL_Log("Version    : %s\n", ctx.glGetString(GL_VERSION));

+ 5 - 3
test/testvulkan.c

@@ -1080,7 +1080,7 @@ static SDL_bool render(void)
 int main(int argc, char **argv)
 {
     int done;
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode *mode;
     SDL_Event event;
     Uint64 then, now;
     Uint32 frames;
@@ -1104,8 +1104,10 @@ int main(int argc, char **argv)
         return 1;
     }
 
-    SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay(), &mode);
-    SDL_Log("Screen BPP    : %" SDL_PRIu32 "\n", SDL_BITSPERPIXEL(mode.format));
+    mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
+    if (mode) {
+        SDL_Log("Screen BPP    : %" SDL_PRIu32 "\n", SDL_BITSPERPIXEL(mode->format));
+    }
     SDL_GetWindowSize(state->windows[0], &dw, &dh);
     SDL_Log("Window Size   : %d,%d\n", dw, dh);
     SDL_GetWindowSizeInPixels(state->windows[0], &dw, &dh);

+ 13 - 14
test/testwm.c

@@ -54,11 +54,10 @@ quit(int rc)
 static void
 draw_modes_menu(SDL_Window *window, SDL_Renderer *renderer, SDL_FRect viewport)
 {
-    SDL_DisplayMode mode;
+    const SDL_DisplayMode **modes;
     char text[1024];
     const int lineHeight = 10;
     const SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
-    const int num_modes = SDL_GetNumDisplayModes(displayID);
     int i;
     int column_chars = 0;
     int text_length;
@@ -83,7 +82,7 @@ draw_modes_menu(SDL_Window *window, SDL_Renderer *renderer, SDL_FRect viewport)
 
     y += lineHeight;
 
-    SDL_strlcpy(text, "Click on a mode to set it with SDL_SetWindowDisplayMode", sizeof text);
+    SDL_strlcpy(text, "Click on a mode to set it with SDL_SetWindowFullscreenMode", sizeof text);
     SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
     SDLTest_DrawString(renderer, x, y, text);
     y += lineHeight;
@@ -100,15 +99,13 @@ draw_modes_menu(SDL_Window *window, SDL_Renderer *renderer, SDL_FRect viewport)
         highlighted_mode = -1;
     }
 
-    for (i = 0; i < num_modes; ++i) {
+    modes = SDL_GetFullscreenDisplayModes(displayID, NULL);
+    for (i = 0; modes[i]; ++i) {
         SDL_FRect cell_rect;
-
-        if (0 != SDL_GetDisplayMode(displayID, i, &mode)) {
-            return;
-        }
+        const SDL_DisplayMode *mode = modes[i];
 
         (void)SDL_snprintf(text, sizeof text, "%d: %dx%d@%gHz",
-                           i, mode.pixel_w, mode.pixel_h, mode.refresh_rate);
+                           i, mode->pixel_w, mode->pixel_h, mode->refresh_rate);
 
         /* Update column width */
         text_length = (int)SDL_strlen(text);
@@ -141,6 +138,7 @@ draw_modes_menu(SDL_Window *window, SDL_Renderer *renderer, SDL_FRect viewport)
             column_chars = 0;
         }
     }
+    SDL_free(modes);
 }
 
 void loop()
@@ -208,12 +206,13 @@ void loop()
             SDL_Window *window = SDL_GetMouseFocus();
             if (highlighted_mode != -1 && window != NULL) {
                 SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
-                SDL_DisplayMode mode;
-                if (0 != SDL_GetDisplayMode(displayID, highlighted_mode, &mode)) {
-                    SDL_Log("Couldn't get display mode");
-                } else {
-                    SDL_SetWindowDisplayMode(window, &mode);
+                int num_modes;
+                const SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(displayID, &num_modes);
+                if (highlighted_mode < num_modes) {
+                    SDL_memcpy(&state->fullscreen_mode, modes[highlighted_mode], sizeof(state->fullscreen_mode));
+                    SDL_SetWindowFullscreenMode(window, modes[highlighted_mode]);
                 }
+                SDL_free(modes);
             }
         }
     }