SDL: Update the orientation and display modes when the display settings change on Windows

From fed857787af1120765a95a352c89f1c9b4206011 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 10 Nov 2021 08:47:39 -0800
Subject: [PATCH] Update the orientation and display modes when the display
 settings change on Windows

Fixes https://github.com/libsdl-org/SDL/issues/1061
---
 src/video/SDL_sysvideo.h             |  4 +++
 src/video/SDL_video.c                | 50 ++++++++++++++++++++++------
 src/video/windows/SDL_windowsmodes.c | 10 +++++-
 3 files changed, 53 insertions(+), 11 deletions(-)

diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index d57731eda4..bbe4eab170 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -341,6 +341,7 @@ struct SDL_VideoDevice
     Uint8 window_magic;
     Uint32 next_object_id;
     char *clipboard_text;
+    SDL_bool setting_display_mode;
 
     /* * * */
     /* Data used by the GL drivers */
@@ -459,6 +460,9 @@ extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode);
 extern int SDL_AddVideoDisplay(const SDL_VideoDisplay * display, SDL_bool send_event);
 extern void SDL_DelVideoDisplay(int index);
 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_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode * mode);
+extern void SDL_ResetDisplayModes(int displayIndex);
 extern int SDL_GetIndexOfDisplay(SDL_VideoDisplay *display);
 extern SDL_VideoDisplay *SDL_GetDisplay(int displayIndex);
 extern SDL_VideoDisplay *SDL_GetDisplayForWindow(SDL_Window *window);
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 573b6afbf0..276c0674bb 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -796,7 +796,7 @@ SDL_GetDisplayOrientation(int displayIndex)
 }
 
 SDL_bool
-SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
+SDL_AddDisplayMode(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
 {
     SDL_DisplayMode *modes;
     int i, nmodes;
@@ -831,6 +831,18 @@ SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
     return SDL_TRUE;
 }
 
+void
+SDL_SetCurrentDisplayMode(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
+{
+    SDL_memcpy(&display->current_mode, mode, sizeof(*mode));
+}
+
+void
+SDL_SetDesktopDisplayMode(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
+{
+    SDL_memcpy(&display->desktop_mode, mode, sizeof(*mode));
+}
+
 static int
 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
 {
@@ -850,6 +862,25 @@ SDL_GetNumDisplayModes(int displayIndex)
     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
 }
 
+void
+SDL_ResetDisplayModes(int displayIndex)
+{
+    SDL_VideoDisplay *display;
+    int i;
+
+    CHECK_DISPLAY_INDEX(displayIndex,);
+
+    display = &_this->displays[displayIndex];
+    for (i = display->num_display_modes; i--;) {
+        SDL_free(display->display_modes[i].driverdata);
+        display->display_modes[i].driverdata = NULL;
+    }
+    SDL_free(display->display_modes);
+    display->display_modes = NULL;
+    display->num_display_modes = 0;
+    display->max_display_modes = 0;
+}
+
 int
 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
 {
@@ -1021,6 +1052,7 @@ SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode *
 {
     SDL_DisplayMode display_mode;
     SDL_DisplayMode current_mode;
+    int result;
 
     if (mode) {
         display_mode = *mode;
@@ -1058,10 +1090,13 @@ SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode *
     if (!_this->SetDisplayMode) {
         return SDL_SetError("SDL video driver doesn't support changing display mode");
     }
-    if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
+    _this->setting_display_mode = SDL_TRUE;
+    result = _this->SetDisplayMode(_this, display, &display_mode);
+    _this->setting_display_mode = SDL_FALSE;
+    if (result < 0) {
         return -1;
     }
-    display->current_mode = display_mode;
+    SDL_SetCurrentDisplayMode(display, &display_mode);
     return 0;
 }
 
@@ -3157,7 +3192,7 @@ SDL_DisableScreenSaver()
 void
 SDL_VideoQuit(void)
 {
-    int i, j;
+    int i;
 
     if (!_this) {
         return;
@@ -3179,12 +3214,7 @@ SDL_VideoQuit(void)
 
     for (i = 0; i < _this->num_displays; ++i) {
         SDL_VideoDisplay *display = &_this->displays[i];
-        for (j = display->num_display_modes; j--;) {
-            SDL_free(display->display_modes[j].driverdata);
-            display->display_modes[j].driverdata = NULL;
-        }
-        SDL_free(display->display_modes);
-        display->display_modes = NULL;
+        SDL_ResetDisplayModes(i);
         SDL_free(display->desktop_mode.driverdata);
         display->desktop_mode.driverdata = NULL;
         SDL_free(display->driverdata);
diff --git a/src/video/windows/SDL_windowsmodes.c b/src/video/windows/SDL_windowsmodes.c
index 3abb5d42c0..b9a4ac06f1 100644
--- a/src/video/windows/SDL_windowsmodes.c
+++ b/src/video/windows/SDL_windowsmodes.c
@@ -23,6 +23,7 @@
 #if SDL_VIDEO_DRIVER_WINDOWS
 
 #include "SDL_windowsvideo.h"
+#include "../../events/SDL_displayevents_c.h"
 
 /* Windows CE compatibility */
 #ifndef CDS_FULLSCREEN
@@ -211,6 +212,13 @@ WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info, SDL_bool se
         if (SDL_wcscmp(driverdata->DeviceName, info->szDevice) == 0) {
             driverdata->MonitorHandle = hMonitor;
             driverdata->IsValid = SDL_TRUE;
+
+            if (!_this->setting_display_mode) {
+                SDL_ResetDisplayModes(i);
+                SDL_SetCurrentDisplayMode(&_this->displays[i], &mode);
+                SDL_SetDesktopDisplayMode(&_this->displays[i], &mode);
+                SDL_SendDisplayEvent(&_this->displays[i], SDL_DISPLAYEVENT_ORIENTATION, orientation);
+            }
             return SDL_FALSE;
         }
     }
@@ -405,7 +413,7 @@ WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
     DWORD i;
     SDL_DisplayMode mode;
 
-    for (i = 0;; ++i) {
+    for (i = 0; ; ++i) {
         if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode, NULL)) {
             break;
         }