SDL: Implemented SDL_SetWindowMouseRect() on Windows

From 7d21322df1fdf1ea9deaec4cdf3250fa3d736177 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 8 Nov 2021 16:29:19 -0800
Subject: [PATCH] Implemented SDL_SetWindowMouseRect() on Windows

---
 src/video/SDL_sysvideo.h              |  2 +-
 src/video/windows/SDL_windowsvideo.c  |  1 +
 src/video/windows/SDL_windowswindow.c | 42 ++++++++++++++++++++++++---
 src/video/windows/SDL_windowswindow.h |  2 ++
 src/video/x11/SDL_x11window.c         |  6 ----
 5 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 2098053af5..ae29dd3fc0 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -235,6 +235,7 @@ struct SDL_VideoDevice
     int (*SetWindowGammaRamp) (_THIS, SDL_Window * window, const Uint16 * ramp);
     int (*GetWindowGammaRamp) (_THIS, SDL_Window * window, Uint16 * ramp);
     void* (*GetWindowICCProfile) (_THIS, SDL_Window * window, size_t* size);
+    int (*SetWindowMouseRect)(_THIS, SDL_Window * window, const SDL_Rect * rect);
     void (*SetWindowMouseGrab) (_THIS, SDL_Window * window, SDL_bool grabbed);
     void (*SetWindowKeyboardGrab) (_THIS, SDL_Window * window, SDL_bool grabbed);
     void (*DestroyWindow) (_THIS, SDL_Window * window);
@@ -243,7 +244,6 @@ struct SDL_VideoDevice
     void (*DestroyWindowFramebuffer) (_THIS, SDL_Window * window);
     void (*OnWindowEnter) (_THIS, SDL_Window * window);
     int (*FlashWindow) (_THIS, SDL_Window * window, SDL_FlashOperation operation);
-    int (*SetWindowMouseRect)(_THIS, SDL_Window * window, const SDL_Rect * rect);
 
     /* * * */
     /*
diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c
index 2968e91e3a..27869c0301 100644
--- a/src/video/windows/SDL_windowsvideo.c
+++ b/src/video/windows/SDL_windowsvideo.c
@@ -167,6 +167,7 @@ WIN_CreateDevice(int devindex)
     device->SetWindowGammaRamp = WIN_SetWindowGammaRamp;
     device->GetWindowICCProfile = WIN_GetWindowICCProfile;
     device->GetWindowGammaRamp = WIN_GetWindowGammaRamp;
+    device->SetWindowMouseRect = WIN_SetWindowMouseRect;
     device->SetWindowMouseGrab = WIN_SetWindowMouseGrab;
     device->SetWindowKeyboardGrab = WIN_SetWindowKeyboardGrab;
     device->DestroyWindow = WIN_DestroyWindow;
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 892dde7b15..52159133c1 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -814,6 +814,19 @@ void WIN_UngrabKeyboard(SDL_Window *window)
     }
 }
 
+void
+WIN_SetWindowMouseRect(_THIS, SDL_Window * window, SDL_Rect * rect)
+{
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+
+    if (rect) {
+        SDL_memcpy(&data->mouse_rect, rect, sizeof(*rect));
+    } else {
+        SDL_zero(data->mouse_rect);
+    }
+    WIN_UpdateClipCursor(window);
+}
+
 void
 WIN_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
 {
@@ -998,7 +1011,8 @@ WIN_UpdateClipCursor(SDL_Window *window)
         return;
     }
 
-    if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) &&
+    if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED) ||
+         (data->mouse_rect.w > 0 && data->mouse_rect.h > 0)) &&
         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
         if (mouse->relative_mode && !mouse->relative_mode_warp) {
             if (GetWindowRect(data->hwnd, &rect)) {
@@ -1020,12 +1034,32 @@ WIN_UpdateClipCursor(SDL_Window *window)
                 }
             }
         } else {
-            if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
+            if (GetClientRect(data->hwnd, &rect)) {
                 ClientToScreen(data->hwnd, (LPPOINT) & rect);
                 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
+                if (data->mouse_rect.w > 0 && data->mouse_rect.h > 0) {
+                    RECT mouse_rect, intersection;
+
+                    mouse_rect.left = rect.left + data->mouse_rect.x;
+                    mouse_rect.top = rect.top + data->mouse_rect.y;
+                    mouse_rect.right = mouse_rect.left + data->mouse_rect.w - 1;
+                    mouse_rect.bottom = mouse_rect.top + data->mouse_rect.h - 1;
+                    if (IntersectRect(&intersection, &rect, &mouse_rect)) {
+                        SDL_memcpy(&rect, &intersection, sizeof(rect));
+                    } else if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) {
+                        /* Mouse rect was invalid, just do the normal grab */
+                    } else {
+                        SDL_zero(rect);
+                    }
+                }
                 if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) {
-                    if (ClipCursor(&rect)) {
-                        data->cursor_clipped_rect = rect;
+                    if (!IsRectEmpty(&rect)) {
+                        if (ClipCursor(&rect)) {
+                            data->cursor_clipped_rect = rect;
+                        }
+                    } else {
+                        ClipCursor(NULL);
+                        SDL_zero(data->cursor_clipped_rect);
                     }
                 }
             }
diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h
index 66a57546ca..c292b826b1 100644
--- a/src/video/windows/SDL_windowswindow.h
+++ b/src/video/windows/SDL_windowswindow.h
@@ -51,6 +51,7 @@ typedef struct
     Uint32 last_updated_clipcursor;
     SDL_bool windowed_mode_was_maximized;
     SDL_bool in_window_deactivation;
+    SDL_Rect mouse_rect;
     RECT cursor_clipped_rect;
     SDL_Point last_raw_mouse_position;
     SDL_bool mouse_tracked;
@@ -81,6 +82,7 @@ extern void WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay
 extern int WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
 extern void* WIN_GetWindowICCProfile(_THIS, SDL_Window * window, size_t * size);
 extern int WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
+extern void WIN_SetWindowMouseRect(_THIS, SDL_Window * window, SDL_Rect * rect);
 extern void WIN_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
 extern void WIN_SetWindowKeyboardGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
 extern void WIN_DestroyWindow(_THIS, SDL_Window * window);
diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c
index 9cf88fb593..def7ae9b11 100644
--- a/src/video/x11/SDL_x11window.c
+++ b/src/video/x11/SDL_x11window.c
@@ -331,12 +331,6 @@ SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
         }
     }
 
-#if SDL_VIDEO_DRIVER_X11_XFIXES
-    data->pointer_barrier_active = SDL_FALSE;
-    SDL_memset(&data->barrier, 0, sizeof(data->barrier));
-    SDL_memset(&data->barrier_rect, 0, sizeof(SDL_Rect));
-#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
-
     /* All done! */
     window->driverdata = data;
     return 0;