SDL: Added SDL_EVENT_DISPLAY_SCALE_CHANGED

From 6b87d1938fe57a889157beaf48d1626df295bc53 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 3 Mar 2023 11:03:50 -0800
Subject: [PATCH] Added SDL_EVENT_DISPLAY_SCALE_CHANGED

---
 include/SDL3/SDL_events.h            |  3 ++-
 src/events/SDL_displayevents.c       |  2 +-
 src/events/SDL_events.c              |  1 +
 src/test/SDL_test_common.c           | 11 +++++++++++
 src/video/SDL_video.c                |  6 ++++++
 src/video/windows/SDL_windowsmodes.c | 13 +++++++++----
 6 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index 4ecd83403754..8e35e283efc0 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -93,8 +93,9 @@ typedef enum
     SDL_EVENT_DISPLAY_CONNECTED,           /**< Display has been added to the system */
     SDL_EVENT_DISPLAY_DISCONNECTED,        /**< Display has been removed from the system */
     SDL_EVENT_DISPLAY_MOVED,               /**< Display has changed position */
+    SDL_EVENT_DISPLAY_SCALE_CHANGED,       /**< Display has changed desktop display scale */
     SDL_EVENT_DISPLAY_FIRST = SDL_EVENT_DISPLAY_ORIENTATION,
-    SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_DISCONNECTED,
+    SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_SCALE_CHANGED,
 
     /* Window events */
     /* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */
diff --git a/src/events/SDL_displayevents.c b/src/events/SDL_displayevents.c
index 10d7bdcce6af..cf3694466ea0 100644
--- a/src/events/SDL_displayevents.c
+++ b/src/events/SDL_displayevents.c
@@ -28,7 +28,7 @@ int SDL_SendDisplayEvent(SDL_VideoDisplay *display, SDL_EventType displayevent,
 {
     int posted;
 
-    if (display == NULL) {
+    if (display == NULL || display->id == 0) {
         return 0;
     }
     switch (displayevent) {
diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index ef5b43f4d889..87152d0e6485 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -223,6 +223,7 @@ static void SDL_LogEvent(const SDL_Event *event)
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONNECTED);
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_DISCONNECTED);
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_MOVED);
+        SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_SCALE_CHANGED);
 #undef SDL_DISPLAYEVENT_CASE
 
 #define SDL_WINDOWEVENT_CASE(x)                \
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index b85d5ede53ad..47cc0bbb731e 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -1511,6 +1511,17 @@ static void SDLTest_PrintEvent(SDL_Event *event)
         SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " connected",
                 event->display.displayID);
         break;
+    case SDL_EVENT_DISPLAY_SCALE_CHANGED:
+        {
+            float display_scale = 1.0f;
+            const SDL_DisplayMode *mode = SDL_GetDesktopDisplayMode(event->display.displayID);
+            if (mode) {
+                display_scale = mode->display_scale;
+            }
+            SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " changed scale to %d%%",
+                    event->display.displayID, (int)(display_scale * 100.0f));
+        }
+        break;
     case SDL_EVENT_DISPLAY_MOVED:
         SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " changed position",
                 event->display.displayID);
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 0d9aaa322279..742b4fc2c759 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -1077,9 +1077,15 @@ const SDL_DisplayMode *SDL_GetClosestFullscreenDisplayMode(SDL_DisplayID display
 
 void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
 {
+    float display_scale = display->desktop_mode.display_scale;
+
     SDL_memcpy(&display->desktop_mode, mode, sizeof(*mode));
     display->desktop_mode.displayID = display->id;
     SDL_FinalizeDisplayMode(&display->desktop_mode);
+
+    if (display_scale != display->desktop_mode.display_scale) {
+        SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_SCALE_CHANGED, 0);
+    }
 }
 
 const SDL_DisplayMode *SDL_GetDesktopDisplayMode(SDL_DisplayID displayID)
diff --git a/src/video/windows/SDL_windowsmodes.c b/src/video/windows/SDL_windowsmodes.c
index af0962c3a60b..0da179e82ad8 100644
--- a/src/video/windows/SDL_windowsmodes.c
+++ b/src/video/windows/SDL_windowsmodes.c
@@ -324,6 +324,7 @@ static void WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info,
         SDL_DisplayData *driverdata = _this->displays[i].driverdata;
         if (SDL_wcscmp(driverdata->DeviceName, info->szDevice) == 0) {
             SDL_bool moved = (index != i);
+            SDL_bool changed_bounds = SDL_FALSE;
 
             if (moved) {
                 SDL_VideoDisplay tmp;
@@ -343,10 +344,14 @@ static void WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info,
                 SDL_Rect bounds;
 
                 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);
-                    }
+                SDL_SetDesktopDisplayMode(existing_display, &mode);
+                if (WIN_GetDisplayBounds(_this, existing_display, &bounds) == 0 &&
+                    SDL_memcmp(&driverdata->bounds, &bounds, sizeof(bounds)) != 0) {
+                    changed_bounds = SDL_TRUE;
+                    SDL_copyp(&driverdata->bounds, &bounds);
+                }
+                if (moved || changed_bounds) {
+                    SDL_SendDisplayEvent(existing_display, SDL_EVENT_DISPLAY_MOVED, 0);
                 }
                 SDL_SendDisplayEvent(existing_display, SDL_EVENT_DISPLAY_ORIENTATION, orientation);
             }