cocoa: Fix SDL_CocoaWindowData keyboard_focus being left pointing to a destroyed SDL window if input focus not previously reset for that window

- If a window being destroyed is a child of an inactive window and was the last keyboard focus of the window, that window will be left with a stale pointer
  to the destroyed window that it will attempt to restore the next time that window is focused. SDL_DestroyWindow will have already taken care of moving
  focus if this window is the current SDL keyboard focus so this change intentionally does not set focus.

- Like Cocoa_HideWindow, this attempts to move the focus to the closest parent window that is not hidden or destroying.
This commit is contained in:
Sam Lantinga
2024-01-18 03:36:54 -08:00
parent 0a99ad7a68
commit fd34bc56f9

View File

@@ -546,16 +546,23 @@ static void Cocoa_UpdateClipCursor(SDL_Window *window)
}
}
static void Cocoa_SetKeyboardFocus(SDL_Window *window)
static SDL_Window *GetTopmostWindow(SDL_Window *window)
{
SDL_Window *topmost = window;
SDL_CocoaWindowData *topmost_data;
/* Find the topmost parent */
while (topmost->parent != NULL) {
topmost = topmost->parent;
}
return topmost;
}
static void Cocoa_SetKeyboardFocus(SDL_Window *window)
{
SDL_Window *topmost = GetTopmostWindow(window);
SDL_CocoaWindowData *topmost_data;
topmost_data = (__bridge SDL_CocoaWindowData *)topmost->driverdata;
topmost_data.keyboard_focus = window;
SDL_SetKeyboardFocus(window);
@@ -2732,6 +2739,22 @@ void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
NSArray *contexts;
#endif /* SDL_VIDEO_OPENGL */
SDL_Window *topmost = GetTopmostWindow(window);
SDL_CocoaWindowData *topmost_data = (__bridge SDL_CocoaWindowData *)topmost->driverdata;
/* Reset the input focus of the root window if this window is still set as keyboard focus.
* SDL_DestroyWindow will have already taken care of reassigning focus if this is the SDL
* keyboard focus, this ensures that an inactive window with this window set as input focus
* does not try to reference it the next time it gains focus.
*/
if (topmost_data.keyboard_focus == window) {
SDL_Window *new_focus = window;
while(new_focus->parent && (new_focus->is_hiding || new_focus->is_destroying)) {
new_focus = new_focus->parent;
}
topmost_data.keyboard_focus = new_focus;
}
if ([data.listener isInFullscreenSpace]) {
[NSMenu setMenuBarVisible:YES];