Added SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED

Fixes https://github.com/libsdl-org/SDL/issues/12785
This commit is contained in:
Sam Lantinga
2025-10-09 15:11:13 -07:00
parent bfc96c92fd
commit 6677fad1c8
10 changed files with 75 additions and 38 deletions

View File

@@ -127,8 +127,9 @@ typedef enum SDL_EventType
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_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_LAST = SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED,
SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED,
/* Window events */
/* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */

View File

@@ -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_CURRENT_MODE_CHANGED);
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED);
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED);
#undef SDL_DISPLAYEVENT_CASE
#define SDL_WINDOWEVENT_CASE(x) \

View File

@@ -1626,6 +1626,14 @@ void SDLTest_PrintEvent(const SDL_Event *event)
event->display.displayID, (int)(scale * 100.0f));
}
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:
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);

View File

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

View File

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

View File

@@ -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)
{
@@ -331,7 +346,7 @@ bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
return false;
}
SDL_DisplayData *displaydata = (SDL_DisplayData *)SDL_malloc(sizeof(*displaydata));
SDL_DisplayData *displaydata = (SDL_DisplayData *)SDL_calloc(1, sizeof(*displaydata));
if (!displaydata) {
CGDisplayModeRelease(moderef);
return false;
@@ -359,6 +374,8 @@ bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
Cocoa_GetHDRProperties(displaydata->display, &viddisplay.HDR);
Cocoa_GetUsableBounds(displaydata->display, &displaydata->usable_bounds);
viddisplay.desktop_mode = mode;
viddisplay.internal = displaydata;
const bool retval = SDL_AddVideoDisplay(&viddisplay, send_event);
@@ -538,6 +555,13 @@ void Cocoa_UpdateDisplays(SDL_VideoDevice *_this)
Cocoa_GetHDRProperties(displaydata->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)
{
@autoreleasepool {
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal;
NSScreen *screen = GetNSScreenForDisplayID(displaydata->display);
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal;
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;
}
return true;
}
SDL_memcpy(rect, &displaydata->usable_bounds, sizeof(*rect));
return true;
}
bool Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)

View File

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

View File

@@ -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)
{
// All fullscreen windows should have restored modes by now

View File

@@ -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_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
extern void WIN_RefreshDisplays(SDL_VideoDevice *_this);
extern void WIN_UpdateDisplayUsableBounds(SDL_VideoDevice *_this);
extern void WIN_QuitModes(SDL_VideoDevice *_this);
#endif // SDL_windowsmodes_h_

View File

@@ -1418,31 +1418,33 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
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);
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);
} 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);
}
}