Browse Source

Added SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED

Fixes https://github.com/libsdl-org/SDL/issues/12785
Sam Lantinga 2 days ago
parent
commit
6677fad1c8

+ 2 - 1
include/SDL3/SDL_events.h

@@ -127,8 +127,9 @@ typedef enum SDL_EventType
     SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED,  /**< Display has changed desktop mode */
     SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED,  /**< Display has changed desktop mode */
     SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED,  /**< Display has changed current mode */
     SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED,  /**< Display has changed current mode */
     SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, /**< Display has changed content scale */
     SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, /**< Display has changed content scale */
+    SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, /**< Display has changed usable bounds */
     SDL_EVENT_DISPLAY_FIRST = SDL_EVENT_DISPLAY_ORIENTATION,
     SDL_EVENT_DISPLAY_FIRST = SDL_EVENT_DISPLAY_ORIENTATION,
-    SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED,
+    SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED,
 
 
     /* Window events */
     /* Window events */
     /* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */
     /* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */

+ 1 - 0
src/events/SDL_events.c

@@ -525,6 +525,7 @@ int SDL_GetEventDescription(const SDL_Event *event, char *buf, int buflen)
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED);
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED);
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED);
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED);
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED);
         SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED);
+        SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED);
 #undef SDL_DISPLAYEVENT_CASE
 #undef SDL_DISPLAYEVENT_CASE
 
 
 #define SDL_WINDOWEVENT_CASE(x)                \
 #define SDL_WINDOWEVENT_CASE(x)                \

+ 8 - 0
src/test/SDL_test_common.c

@@ -1626,6 +1626,14 @@ void SDLTest_PrintEvent(const SDL_Event *event)
                     event->display.displayID, (int)(scale * 100.0f));
                     event->display.displayID, (int)(scale * 100.0f));
         }
         }
         break;
         break;
+    case SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED:
+        {
+            SDL_Rect bounds;
+            SDL_GetDisplayUsableBounds(event->display.displayID, &bounds);
+            SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " changed usable bounds to %dx%d at %d,%d",
+                    event->display.displayID, bounds.w, bounds.h, bounds.x, bounds.y);
+        }
+        break;
     case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED:
     case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED:
         SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " desktop mode changed to %" SDL_PRIs32 "x%" SDL_PRIs32,
         SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " desktop mode changed to %" SDL_PRIs32 "x%" SDL_PRIs32,
                 event->display.displayID, event->display.data1, event->display.data2);
                 event->display.displayID, event->display.data1, event->display.data2);

+ 2 - 0
src/video/SDL_video.c

@@ -1064,6 +1064,7 @@ bool SDL_GetDisplayBounds(SDL_DisplayID displayID, SDL_Rect *rect)
     }
     }
 
 
     if (_this->GetDisplayBounds) {
     if (_this->GetDisplayBounds) {
+        SDL_zerop(rect);
         if (_this->GetDisplayBounds(_this, display, rect)) {
         if (_this->GetDisplayBounds(_this, display, rect)) {
             return true;
             return true;
         }
         }
@@ -1103,6 +1104,7 @@ bool SDL_GetDisplayUsableBounds(SDL_DisplayID displayID, SDL_Rect *rect)
     }
     }
 
 
     if (_this->GetDisplayUsableBounds) {
     if (_this->GetDisplayUsableBounds) {
+        SDL_zerop(rect);
         if (_this->GetDisplayUsableBounds(_this, display, rect)) {
         if (_this->GetDisplayUsableBounds(_this, display, rect)) {
             return true;
             return true;
         }
         }

+ 1 - 0
src/video/cocoa/SDL_cocoamodes.h

@@ -26,6 +26,7 @@
 struct SDL_DisplayData
 struct SDL_DisplayData
 {
 {
     CGDirectDisplayID display;
     CGDirectDisplayID display;
+    SDL_Rect usable_bounds;
 };
 };
 
 
 struct SDL_DisplayModeData
 struct SDL_DisplayModeData

+ 28 - 18
src/video/cocoa/SDL_cocoamodes.m

@@ -323,6 +323,21 @@ static void Cocoa_GetHDRProperties(CGDirectDisplayID displayID, SDL_HDROutputPro
     }
     }
 }
 }
 
 
+static bool Cocoa_GetUsableBounds(CGDirectDisplayID displayID, SDL_Rect *rect)
+{
+    NSScreen *screen = GetNSScreenForDisplayID(displayID);
+
+    if (screen == nil) {
+        return false;
+    }
+
+    const NSRect frame = [screen visibleFrame];
+    rect->x = (int)frame.origin.x;
+    rect->y = (int)(CGDisplayPixelsHigh(kCGDirectMainDisplay) - frame.origin.y - frame.size.height);
+    rect->w = (int)frame.size.width;
+    rect->h = (int)frame.size.height;
+    return true;
+}
 
 
 bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
 bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
 {
 {
@@ -331,7 +346,7 @@ bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
         return false;
         return false;
     }
     }
 
 
-    SDL_DisplayData *displaydata = (SDL_DisplayData *)SDL_malloc(sizeof(*displaydata));
+    SDL_DisplayData *displaydata = (SDL_DisplayData *)SDL_calloc(1, sizeof(*displaydata));
     if (!displaydata) {
     if (!displaydata) {
         CGDisplayModeRelease(moderef);
         CGDisplayModeRelease(moderef);
         return false;
         return false;
@@ -359,6 +374,8 @@ bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
 
 
     Cocoa_GetHDRProperties(displaydata->display, &viddisplay.HDR);
     Cocoa_GetHDRProperties(displaydata->display, &viddisplay.HDR);
 
 
+    Cocoa_GetUsableBounds(displaydata->display, &displaydata->usable_bounds);
+
     viddisplay.desktop_mode = mode;
     viddisplay.desktop_mode = mode;
     viddisplay.internal = displaydata;
     viddisplay.internal = displaydata;
     const bool retval = SDL_AddVideoDisplay(&viddisplay, send_event);
     const bool retval = SDL_AddVideoDisplay(&viddisplay, send_event);
@@ -538,6 +555,13 @@ void Cocoa_UpdateDisplays(SDL_VideoDevice *_this)
 
 
         Cocoa_GetHDRProperties(displaydata->display, &HDR);
         Cocoa_GetHDRProperties(displaydata->display, &HDR);
         SDL_SetDisplayHDRProperties(display, &HDR);
         SDL_SetDisplayHDRProperties(display, &HDR);
+
+        SDL_Rect rect;
+        if (Cocoa_GetUsableBounds(displaydata->display, &rect) &&
+            SDL_memcmp(&displaydata->usable_bounds, &rect, sizeof(rect)) != 0) {
+            SDL_memcpy(&displaydata->usable_bounds, &rect, sizeof(rect));
+            SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, 0, 0);
+        }
     }
     }
 }
 }
 
 
@@ -556,24 +580,10 @@ bool Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, S
 
 
 bool Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
 bool Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
 {
 {
-    @autoreleasepool {
-        SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal;
-        NSScreen *screen = GetNSScreenForDisplayID(displaydata->display);
-
-        if (screen == nil) {
-            return SDL_SetError("Couldn't get NSScreen for display");
-        }
-
-        {
-            const NSRect frame = [screen visibleFrame];
-            rect->x = (int)frame.origin.x;
-            rect->y = (int)(CGDisplayPixelsHigh(kCGDirectMainDisplay) - frame.origin.y - frame.size.height);
-            rect->w = (int)frame.size.width;
-            rect->h = (int)frame.size.height;
-        }
+    SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal;
 
 
-        return true;
-    }
+    SDL_memcpy(rect, &displaydata->usable_bounds, sizeof(*rect));
+    return true;
 }
 }
 
 
 bool Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
 bool Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)

+ 3 - 0
src/video/windows/SDL_windowsevents.c

@@ -2422,6 +2422,9 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
         if (wParam == SPI_SETMOUSE || wParam == SPI_SETMOUSESPEED) {
         if (wParam == SPI_SETMOUSE || wParam == SPI_SETMOUSESPEED) {
             WIN_UpdateMouseSystemScale();
             WIN_UpdateMouseSystemScale();
         }
         }
+        if (wParam == SPI_SETWORKAREA) {
+            WIN_UpdateDisplayUsableBounds(SDL_GetVideoDevice());
+        }
         break;
         break;
 
 
 #endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
 #endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)

+ 8 - 0
src/video/windows/SDL_windowsmodes.c

@@ -933,6 +933,14 @@ void WIN_RefreshDisplays(SDL_VideoDevice *_this)
     }
     }
 }
 }
 
 
+void WIN_UpdateDisplayUsableBounds(SDL_VideoDevice *_this)
+{
+    // This almost never happens, so just go ahead and send update events for all displays
+    for (int i = 0; i < _this->num_displays; ++i) {
+        SDL_SendDisplayEvent(_this->displays[i], SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, 0, 0);
+    }
+}
+
 void WIN_QuitModes(SDL_VideoDevice *_this)
 void WIN_QuitModes(SDL_VideoDevice *_this)
 {
 {
     // All fullscreen windows should have restored modes by now
     // All fullscreen windows should have restored modes by now

+ 1 - 0
src/video/windows/SDL_windowsmodes.h

@@ -50,6 +50,7 @@ extern bool WIN_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay
 extern bool WIN_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
 extern bool WIN_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
 extern bool WIN_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
 extern bool WIN_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
 extern void WIN_RefreshDisplays(SDL_VideoDevice *_this);
 extern void WIN_RefreshDisplays(SDL_VideoDevice *_this);
+extern void WIN_UpdateDisplayUsableBounds(SDL_VideoDevice *_this);
 extern void WIN_QuitModes(SDL_VideoDevice *_this);
 extern void WIN_QuitModes(SDL_VideoDevice *_this);
 
 
 #endif // SDL_windowsmodes_h_
 #endif // SDL_windowsmodes_h_

+ 21 - 19
src/video/x11/SDL_x11events.c

@@ -1418,31 +1418,33 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
 
 
                 X11_UpdateKeymap(_this, true);
                 X11_UpdateKeymap(_this, true);
             }
             }
-        } else if (xevent->type == PropertyNotify && videodata && videodata->windowlist) {
+        } else if (xevent->type == PropertyNotify && videodata) {
             char *name_of_atom = X11_XGetAtomName(display, xevent->xproperty.atom);
             char *name_of_atom = X11_XGetAtomName(display, xevent->xproperty.atom);
-
-            if (SDL_strncmp(name_of_atom, "_ICC_PROFILE", sizeof("_ICC_PROFILE") - 1) == 0) {
-                XWindowAttributes attrib;
-                int screennum;
-                for (i = 0; i < videodata->numwindows; ++i) {
-                    if (videodata->windowlist[i] != NULL) {
-                        data = videodata->windowlist[i];
-                        X11_XGetWindowAttributes(display, data->xwindow, &attrib);
-                        screennum = X11_XScreenNumberOfScreen(attrib.screen);
-                        if (screennum == 0 && SDL_strcmp(name_of_atom, "_ICC_PROFILE") == 0) {
-                            SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0);
-                        } else if (SDL_strncmp(name_of_atom, "_ICC_PROFILE_", sizeof("_ICC_PROFILE_") - 1) == 0 && SDL_strlen(name_of_atom) > sizeof("_ICC_PROFILE_") - 1) {
-                            int iccscreennum = SDL_atoi(&name_of_atom[sizeof("_ICC_PROFILE_") - 1]);
-
-                            if (screennum == iccscreennum) {
+            if (name_of_atom) {
+                if (SDL_startswith(name_of_atom, "_ICC_PROFILE")) {
+                    XWindowAttributes attrib;
+                    int screennum;
+                    for (i = 0; i < videodata->numwindows; ++i) {
+                        if (videodata->windowlist[i] != NULL) {
+                            data = videodata->windowlist[i];
+                            X11_XGetWindowAttributes(display, data->xwindow, &attrib);
+                            screennum = X11_XScreenNumberOfScreen(attrib.screen);
+                            if (screennum == 0 && SDL_strcmp(name_of_atom, "_ICC_PROFILE") == 0) {
                                 SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0);
                                 SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0);
+                            } else if (SDL_strncmp(name_of_atom, "_ICC_PROFILE_", sizeof("_ICC_PROFILE_") - 1) == 0 && SDL_strlen(name_of_atom) > sizeof("_ICC_PROFILE_") - 1) {
+                                int iccscreennum = SDL_atoi(&name_of_atom[sizeof("_ICC_PROFILE_") - 1]);
+
+                                if (screennum == iccscreennum) {
+                                    SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0);
+                                }
                             }
                             }
                         }
                         }
                     }
                     }
+                } else if (SDL_strcmp(name_of_atom, "_NET_WORKAREA") == 0) {
+                    for (i = 0; i < _this->num_displays; ++i) {
+                        SDL_SendDisplayEvent(_this->displays[i], SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, 0, 0);
+                    }
                 }
                 }
-            }
-
-            if (name_of_atom) {
                 X11_XFree(name_of_atom);
                 X11_XFree(name_of_atom);
             }
             }
         }
         }