Commit 9ef0b97c6d58fe09623027d651f331eb8148bf91

Sam Lantinga 2021-04-12T11:25:44

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

diff --git a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m
index 9d9f6d1..f496cb2 100644
--- a/src/video/cocoa/SDL_cocoaevents.m
+++ b/src/video/cocoa/SDL_cocoaevents.m
@@ -36,6 +36,21 @@
 #define NSAppKitVersionNumber10_8 1187
 #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
 
 - (void)terminate:(id)sender;
@@ -145,12 +160,6 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
                    selector:@selector(localeDidChange:)
                        name:NSCurrentLocaleDidChangeNotification
                      object:nil];
-
-        [[NSAppleEventManager sharedAppleEventManager]
-            setEventHandler:self
-                andSelector:@selector(handleURLEvent:withReplyEvent:)
-            forEventClass:kInternetEventClass
-                andEventID:kAEGetURL];
     }
 
     return self;
@@ -164,6 +173,13 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
     [center removeObserver:self name:NSApplicationDidBecomeActiveNotification 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];
 }
 
@@ -175,6 +191,10 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
         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
      * 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
@@ -219,6 +239,13 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
         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();
     if (device && 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:
          */
         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];
         } else {
             appDelegate->seenFirstActivate = YES;