Cocoa: Handle more cases of lost focus when Key window closes (thanks, Alex!).
authorRyan C. Gordon <icculus@icculus.org>
Sun, 22 Mar 2015 01:25:12 -0400
changeset 94199763f689bced
parent 9418 eaafb42daa70
child 9420 5ffb5a958c43
Cocoa: Handle more cases of lost focus when Key window closes (thanks, Alex!).

Sort of fixes Bugzilla #1825 a little more. It's an ongoing effort. :)
src/video/cocoa/SDL_cocoaevents.m
src/video/cocoa/SDL_cocoawindow.m
     1.1 --- a/src/video/cocoa/SDL_cocoaevents.m	Sat Mar 21 22:42:53 2015 +0100
     1.2 +++ b/src/video/cocoa/SDL_cocoaevents.m	Sun Mar 22 01:25:12 2015 -0400
     1.3 @@ -66,11 +66,19 @@
     1.4  {
     1.5      self = [super init];
     1.6      if (self) {
     1.7 +        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
     1.8 +
     1.9          seenFirstActivate = NO;
    1.10 -        [[NSNotificationCenter defaultCenter] addObserver:self
    1.11 -                                                 selector:@selector(focusSomeWindow:)
    1.12 -                                                     name:NSApplicationDidBecomeActiveNotification
    1.13 -                                                   object:nil];
    1.14 +
    1.15 +        [center addObserver:self
    1.16 +                   selector:@selector(windowWillClose:)
    1.17 +                       name:NSWindowWillCloseNotification
    1.18 +                     object:nil];
    1.19 +
    1.20 +        [center addObserver:self
    1.21 +                   selector:@selector(focusSomeWindow:)
    1.22 +                       name:NSApplicationDidBecomeActiveNotification
    1.23 +                     object:nil];
    1.24      }
    1.25  
    1.26      return self;
    1.27 @@ -78,16 +86,65 @@
    1.28  
    1.29  - (void)dealloc
    1.30  {
    1.31 -    [[NSNotificationCenter defaultCenter] removeObserver:self];
    1.32 +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    1.33 +
    1.34 +    [center removeObserver:self name:NSWindowWillCloseNotification object:nil];
    1.35 +    [center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil];
    1.36 +
    1.37      [super dealloc];
    1.38  }
    1.39  
    1.40 +- (void)windowWillClose:(NSNotification *)notification;
    1.41 +{
    1.42 +    NSWindow *win = (NSWindow*)[notification object];
    1.43 +
    1.44 +    if (![win isKeyWindow]) {
    1.45 +        return;
    1.46 +    }
    1.47 +
    1.48 +    /* HACK: Make the next window in the z-order key when the key window is
    1.49 +     * closed. The custom event loop and/or windowing code we have seems to
    1.50 +     * prevent the normal behavior: https://bugzilla.libsdl.org/show_bug.cgi?id=1825
    1.51 +     */
    1.52 +
    1.53 +    /* +[NSApp orderedWindows] never includes the 'About' window, but we still
    1.54 +     * want to try its list first since the behavior in other apps is to only
    1.55 +     * make the 'About' window key if no other windows are on-screen.
    1.56 +     */
    1.57 +    for (NSWindow *window in [NSApp orderedWindows]) {
    1.58 +        if (window != win && [window canBecomeKeyWindow]) {
    1.59 +            if ([window respondsToSelector:@selector(isOnActiveSpace)]) {
    1.60 +                if (![window isOnActiveSpace]) {
    1.61 +                    continue;
    1.62 +                }
    1.63 +            }
    1.64 +            [window makeKeyAndOrderFront:self];
    1.65 +            return;
    1.66 +        }
    1.67 +    }
    1.68 +
    1.69 +    /* If a window wasn't found above, iterate through all visible windows
    1.70 +     * (including the 'About' window, if it's shown) and make the first one key.
    1.71 +     * Note that +[NSWindow windowNumbersWithOptions:] was added in 10.6.
    1.72 +     */
    1.73 +    if ([NSWindow respondsToSelector:@selector(windowNumbersWithOptions:)]) {
    1.74 +        /* Get all visible windows in the active Space, in z-order. */
    1.75 +        for (NSNumber *num in [NSWindow windowNumbersWithOptions:0]) {
    1.76 +            NSWindow *window = [NSApp windowWithWindowNumber:[num integerValue]];
    1.77 +            if (window && window != win && [window canBecomeKeyWindow]) {
    1.78 +                [window makeKeyAndOrderFront:self];
    1.79 +                return;
    1.80 +            }
    1.81 +        }
    1.82 +    }
    1.83 +}
    1.84 +
    1.85  - (void)focusSomeWindow:(NSNotification *)aNotification
    1.86  {
    1.87      /* HACK: Ignore the first call. The application gets a
    1.88       * applicationDidBecomeActive: a little bit after the first window is
    1.89       * created, and if we don't ignore it, a window that has been created with
    1.90 -     * SDL_WINDOW_MINIZED will ~immediately be restored.
    1.91 +     * SDL_WINDOW_MINIMIZED will ~immediately be restored.
    1.92       */
    1.93      if (!seenFirstActivate) {
    1.94          seenFirstActivate = YES;
     2.1 --- a/src/video/cocoa/SDL_cocoawindow.m	Sat Mar 21 22:42:53 2015 +0100
     2.2 +++ b/src/video/cocoa/SDL_cocoawindow.m	Sun Mar 22 01:25:12 2015 -0400
     2.3 @@ -374,7 +374,6 @@
     2.4      NSNotificationCenter *center;
     2.5      NSWindow *window = _data->nswindow;
     2.6      NSView *view = [window contentView];
     2.7 -    NSArray *windows = nil;
     2.8  
     2.9      center = [NSNotificationCenter defaultCenter];
    2.10  
    2.11 @@ -402,25 +401,6 @@
    2.12      if ([view nextResponder] == self) {
    2.13          [view setNextResponder:nil];
    2.14      }
    2.15 -
    2.16 -    /* Make the next window in the z-order Key. If we weren't the foreground
    2.17 -       when closed, this is a no-op.
    2.18 -       !!! FIXME: Note that this is a hack, and there are corner cases where
    2.19 -       !!! FIXME:  this fails (such as the About box). The typical nib+RunLoop
    2.20 -       !!! FIXME:  handles this for Cocoa apps, but we bypass all that in SDL.
    2.21 -       !!! FIXME:  We should remove this code when we find a better way to
    2.22 -       !!! FIXME:  have the system do this for us. See discussion in
    2.23 -       !!! FIXME:   http://bugzilla.libsdl.org/show_bug.cgi?id=1825
    2.24 -    */
    2.25 -    windows = [NSApp orderedWindows];
    2.26 -    for (NSWindow *win in windows) {
    2.27 -        if (win == window) {
    2.28 -            continue;
    2.29 -        }
    2.30 -
    2.31 -        [win makeKeyAndOrderFront:self];
    2.32 -        break;
    2.33 -    }
    2.34  }
    2.35  
    2.36  - (BOOL)isMoving