SDL: Fixed unclipping the mouse when a monitor is placed left of the primary one on Windows.

From e56f05bac15cbab5198a0921f084460aa21b5bae Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 24 Apr 2024 12:03:50 -0700
Subject: [PATCH] Fixed unclipping the mouse when a monitor is placed left of
 the primary one on Windows.

There is now a desktop bounds variable that could potentially be exposed in the API if we wanted.
---
 src/events/SDL_displayevents.c        |  3 +++
 src/video/SDL_sysvideo.h              |  2 ++
 src/video/SDL_video.c                 | 31 +++++++++++++++++++++++++++
 src/video/windows/SDL_windowswindow.c |  5 ++++-
 4 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/src/events/SDL_displayevents.c b/src/events/SDL_displayevents.c
index 14c29f308e398..4b6fb98f20f57 100644
--- a/src/events/SDL_displayevents.c
+++ b/src/events/SDL_displayevents.c
@@ -57,6 +57,9 @@ int SDL_SendDisplayEvent(SDL_VideoDisplay *display, SDL_EventType displayevent,
     case SDL_EVENT_DISPLAY_ADDED:
         SDL_OnDisplayAdded(display);
         break;
+    case SDL_EVENT_DISPLAY_MOVED:
+        SDL_OnDisplayMoved(display);
+        break;
     default:
         break;
     }
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 01c2eff203169..065d11b8ea6f3 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -352,6 +352,7 @@ struct SDL_VideoDevice
     SDL_Mutex *wakeup_lock; /* Initialized only if WaitEventTimeout/SendWakeupEvent are supported */
     int num_displays;
     SDL_VideoDisplay **displays;
+    SDL_Rect desktop_bounds;
     SDL_Window *windows;
     SDL_Window *grabbed_window;
     Uint8 window_magic;
@@ -515,6 +516,7 @@ extern void SDL_RelativeToGlobalForWindow(SDL_Window *window, int rel_x, int rel
 extern void SDL_GlobalToRelativeForWindow(SDL_Window *window, int abs_x, int abs_y, int *rel_x, int *rel_y);
 
 extern void SDL_OnDisplayAdded(SDL_VideoDisplay *display);
+extern void SDL_OnDisplayMoved(SDL_VideoDisplay *display);
 extern void SDL_OnWindowShown(SDL_Window *window);
 extern void SDL_OnWindowHidden(SDL_Window *window);
 extern void SDL_OnWindowMoved(SDL_Window *window);
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 4d05869bfbfab..69d4bffd97469 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -624,6 +624,28 @@ SDL_SystemTheme SDL_GetSystemTheme(void)
     }
 }
 
+static void SDL_UpdateDesktopBounds()
+{
+    SDL_Rect rect;
+    SDL_zero(rect);
+
+    SDL_DisplayID *displays = SDL_GetDisplays(NULL);
+    if (displays) {
+        for (int i = 0; displays[i]; ++i) {
+            SDL_Rect bounds;
+            if (SDL_GetDisplayBounds(displays[i], &bounds) == 0) {
+                if (i == 0) {
+                    SDL_copyp(&rect, &bounds);
+                } else {
+                    SDL_GetRectUnion(&rect, &bounds, &rect);
+                }
+            }
+        }
+        SDL_free(displays);
+    }
+    SDL_copyp(&_this->desktop_bounds, &rect);
+}
+
 static void SDL_FinalizeDisplayMode(SDL_DisplayMode *mode)
 {
     /* Make sure all the fields are set up correctly */
@@ -705,6 +727,8 @@ SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send
         SDL_SetFloatProperty(props, SDL_PROP_DISPLAY_HDR_HEADROOM_FLOAT, display->HDR.HDR_headroom);
     }
 
+    SDL_UpdateDesktopBounds();
+
     return id;
 }
 
@@ -718,6 +742,11 @@ void SDL_OnDisplayAdded(SDL_VideoDisplay *display)
     }
 }
 
+void SDL_OnDisplayMoved(SDL_VideoDisplay *display)
+{
+    SDL_UpdateDesktopBounds();
+}
+
 void SDL_DelVideoDisplay(SDL_DisplayID displayID, SDL_bool send_event)
 {
     SDL_VideoDisplay *display;
@@ -745,6 +774,8 @@ void SDL_DelVideoDisplay(SDL_DisplayID displayID, SDL_bool send_event)
         SDL_memmove(&_this->displays[display_index], &_this->displays[display_index + 1], (_this->num_displays - display_index - 1) * sizeof(_this->displays[display_index]));
     }
     --_this->num_displays;
+
+    SDL_UpdateDesktopBounds();
 }
 
 SDL_DisplayID *SDL_GetDisplays(int *count)
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index ee20396f75d25..b2dd17b187498 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -1492,6 +1492,7 @@ static BOOL GetClientScreenRect(HWND hwnd, RECT *rect)
 
 void WIN_UpdateClipCursor(SDL_Window *window)
 {
+    SDL_VideoDevice *videodevice = SDL_GetVideoDevice();
     SDL_WindowData *data = window->driverdata;
     SDL_Mouse *mouse = SDL_GetMouse();
     RECT rect, clipped_rect;
@@ -1568,7 +1569,9 @@ void WIN_UpdateClipCursor(SDL_Window *window)
         SDL_bool unclip_cursor = SDL_FALSE;
 
         /* If the cursor is clipped to the screen, clear the clip state */
-        if (clipped_rect.left == 0 && clipped_rect.top == 0) {
+        if (!videodevice ||
+            (clipped_rect.left == videodevice->desktop_bounds.x &&
+             clipped_rect.top == videodevice->desktop_bounds.y)) {
             unclip_cursor = SDL_TRUE;
         } else {
             POINT first, second;