Fix Cocoa_GetWindowDisplayIndex failing and causing a catastrophic crash

With the introduction of this function, it is possible that for certain
monitor and window configurations, creating an SDL window will cause a
native crash.

```
Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000050
Exception Codes:       0x0000000000000001, 0x0000000000000050
Exception Note:        EXC_CORPSE_NOTIFY

Termination Reason:    Namespace SIGNAL, Code 11 Segmentation fault: 11
Terminating Process:   exc handler [56627]

VM Region Info: 0x50 is not in any region.  Bytes before following region: 140737486737328
      REGION TYPE                    START - END         [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->
      VM_ALLOCATE              7fffffe75000-7fffffe76000 [    4K] r-x/r-x SM=ALI

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libSDL2.dylib                            0x10247f665 SDL_UpdateFullscreenMode + 357
1   libSDL2.dylib                            0x10247ec70 SDL_CreateWindow_REAL + 1504
2   ???                                      0x111262de8 ???
3   ???                                      0x110c39fff ???
4   libcoreclr.dylib                         0x101fdf2a9 CallDescrWorkerInternal + 124
```

Tracking thread from our end: https://github.com/ppy/osu-framework/issues/5190
Regressed with: https://github.com/libsdl-org/SDL/pull/5573

In testing, the window would not find a valid screen if created
"hanging" off a primary display with a secondary display below it. In
checking why this was the case, the `display_centre` was being
calculated with a negative y origin, causing a final negative value
falling outside all display bounds:

```
SDL error log [debug]: display_centre.y = -1296 + 1296 / 2

SDL error log [debug]: Display rect 0: 0 0 2560 1440
SDL error log [debug]: Display rect 1: 2560 -625 1080 2560
SDL error log [debug]: Display rect 2: 0 1440 1728 1296
```

The method that was being used to find the current window using the frame
origin/size seems unreliable, so I have opted to replace it with with a
tried method (https://stackoverflow.com/a/40891902).

Initial testing shows that this works with non-standard DPI screens, but
further testing would be appreciated (cc @sezero / @misl6 from the
original PR thread).
This commit is contained in:
Dean Herbert 2022-07-13 15:01:55 +09:00 committed by Sam Lantinga
parent 041666e6c3
commit ce8aae1419

View file

@ -2230,9 +2230,6 @@ int
Cocoa_GetWindowDisplayIndex(_THIS, SDL_Window * window)
{ @autoreleasepool
{
NSRect displayframe;
SDL_Point display_center;
SDL_Rect sdl_display_rect;
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
/* Not recognized via CHECK_WINDOW_MAGIC */
@ -2240,23 +2237,17 @@ Cocoa_GetWindowDisplayIndex(_THIS, SDL_Window * window)
return 0;
}
/*
Considering that we already have the display coordinates in which the window is placed (described via displayframe)
instead of checking in which display the window is placed, we should check which SDL display matches the display described
via displayframe.
*/
displayframe = data.nswindow.screen.frame;
display_center.x = displayframe.origin.x + displayframe.size.width / 2;
display_center.y = displayframe.origin.y + displayframe.size.height / 2;
for (int i = 0; i < SDL_GetNumVideoDisplays(); i++){
SDL_GetDisplayBounds(i, &sdl_display_rect);
if (SDL_EnclosePoints(&display_center, 1, &sdl_display_rect, NULL)) {
return i;
}
NSArray *screens = [NSScreen screens];
int index = 0;
for (NSScreen *screen in screens) {
if (screen == data.nswindow.screen)
return index;
index++;
}
SDL_SetError("Couldn't find the display where the window is attached to.");
SDL_SetError("Couldn't find the display where the window is attached.");
return -1;
}}