Changes to macOS event handler to better interact with the running app

- Only focus a new window when one closes if the window that was closed was an SDL window

- If the application already has a key window set that is not an SDL window, don't replace it when the application is activated

- Only register the URL event handler when SDLAppDelegate is going to be set as the applications app delegate. This is to
   be consistent with previous behavior that would only register the handler in -[SDLAppDelegate applicationDidFinishLaunching:]
   and allows the running app to opt out of the behavior by setting its own app delegate.

- The URL event handler is now removed if it was set on SDLAppDelegate dealloc
This commit is contained in:
Sam Lantinga 2021-04-12 11:25:44 -07:00
parent 2a20cc0f1d
commit 9ef0b97c6d
1 changed files with 42 additions and 6 deletions

View File

@ -36,6 +36,21 @@
#define NSAppKitVersionNumber10_8 1187 #define NSAppKitVersionNumber10_8 1187
#endif #endif
static SDL_Window *FindSDLWindowForNSWindow(NSWindow *win)
{
SDL_Window *sdlwindow = NULL;
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (device && device->windows) {
for (sdlwindow = device->windows; sdlwindow; sdlwindow = sdlwindow->next) {
NSWindow *nswindow = ((SDL_WindowData *) sdlwindow->driverdata)->nswindow;
if (win == nswindow)
return sdlwindow;
}
}
return sdlwindow;
}
@interface SDLApplication : NSApplication @interface SDLApplication : NSApplication
- (void)terminate:(id)sender; - (void)terminate:(id)sender;
@ -145,12 +160,6 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
selector:@selector(localeDidChange:) selector:@selector(localeDidChange:)
name:NSCurrentLocaleDidChangeNotification name:NSCurrentLocaleDidChangeNotification
object:nil]; object:nil];
[[NSAppleEventManager sharedAppleEventManager]
setEventHandler:self
andSelector:@selector(handleURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
} }
return self; return self;
@ -164,6 +173,13 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
[center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil]; [center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil];
[center removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil]; [center removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil];
/* Remove our URL event handler only if we set it */
if ([NSApp delegate] == self) {
[[NSAppleEventManager sharedAppleEventManager]
removeEventHandlerForEventClass:kInternetEventClass
andEventID:kAEGetURL];
}
[super dealloc]; [super dealloc];
} }
@ -175,6 +191,10 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
return; return;
} }
/* Don't do anything if this was not an SDL window that was closed */
if (FindSDLWindowForNSWindow(win) == NULL)
return;
/* HACK: Make the next window in the z-order key when the key window is /* HACK: Make the next window in the z-order key when the key window is
* closed. The custom event loop and/or windowing code we have seems to * closed. The custom event loop and/or windowing code we have seems to
* prevent the normal behavior: https://bugzilla.libsdl.org/show_bug.cgi?id=1825 * prevent the normal behavior: https://bugzilla.libsdl.org/show_bug.cgi?id=1825
@ -219,6 +239,13 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
return; return;
} }
/* Don't do anything if the application already has a key window
* that is not an SDL window.
*/
if ([NSApp keyWindow] && FindSDLWindowForNSWindow([NSApp keyWindow]) == NULL) {
return;
}
SDL_VideoDevice *device = SDL_GetVideoDevice(); SDL_VideoDevice *device = SDL_GetVideoDevice();
if (device && device->windows) { if (device && device->windows) {
SDL_Window *window = device->windows; SDL_Window *window = device->windows;
@ -469,6 +496,15 @@ Cocoa_RegisterApp(void)
* termination into SDL_Quit, and we can't handle application:openFile: * termination into SDL_Quit, and we can't handle application:openFile:
*/ */
if (![NSApp delegate]) { if (![NSApp delegate]) {
/* Only register the URL event handler if we are being set as the
* app delegate to avoid replacing any existing event handler.
*/
[[NSAppleEventManager sharedAppleEventManager]
setEventHandler:appDelegate
andSelector:@selector(handleURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
[(NSApplication *)NSApp setDelegate:appDelegate]; [(NSApplication *)NSApp setDelegate:appDelegate];
} else { } else {
appDelegate->seenFirstActivate = YES; appDelegate->seenFirstActivate = YES;