From eef9e991e97445343420fa02d22eb99d0de75578 Mon Sep 17 00:00:00 2001 From: fredkiefer Date: Tue, 28 Aug 2007 22:01:29 +0000 Subject: [PATCH] Leave the focus transfer when a window closes to the window not the application and improve the code there. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@25420 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 7 + Source/NSApplication.m | 428 ++++++++++++++++------------------------- Source/NSWindow.m | 263 +++++++++++++------------ 3 files changed, 311 insertions(+), 387 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3907f7608..95a51219b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2007-08-28 Fred Kiefer + + * Source/NSApplication.m (-_windowWillClose:): Don't call + resignKey on the window. Reorganise the code some more and add comments. + * Source/NSWindow.m (-_lossOfKeyOrMainWindow): Check all windows + whether they could take key or main status. + 2007-08-28 Fred Kiefer * Source/NSCell.m (#initialize): Increase version number. diff --git a/Source/NSApplication.m b/Source/NSApplication.m index eb5d77000..5ee7d563e 100644 --- a/Source/NSApplication.m +++ b/Source/NSApplication.m @@ -512,46 +512,45 @@ static NSSize scaledIconSizeForSize(NSSize imageSize) { /* if not hidden raise windows which are possibly obscured. */ if ([NSApp isHidden] == NO) - { - NSArray *windows = RETAIN(GSOrderedWindows()); - NSWindow *aWin; - NSEnumerator *iter = [windows reverseObjectEnumerator]; - - while ((aWin = [iter nextObject])) - { - - if ([aWin isVisible] == YES && [aWin isMiniaturized] == NO - && aWin != [NSApp keyWindow] && aWin != [NSApp mainWindow] - && aWin != [self window] - && ([aWin styleMask] & NSMiniWindowMask) == 0) - { - [aWin orderFrontRegardless]; - } - } + { + NSArray *windows = RETAIN(GSOrderedWindows()); + NSWindow *aWin; + NSEnumerator *iter = [windows reverseObjectEnumerator]; + + while ((aWin = [iter nextObject])) + { + if ([aWin isVisible] == YES && [aWin isMiniaturized] == NO + && aWin != [NSApp keyWindow] && aWin != [NSApp mainWindow] + && aWin != [self window] + && ([aWin styleMask] & NSMiniWindowMask) == 0) + { + [aWin orderFrontRegardless]; + } + } - if ([NSApp isActive] == YES) - { - if ([NSApp keyWindow] != nil) - { - [[NSApp keyWindow] orderFront: self]; - } - else if ([NSApp mainWindow] != nil) - { - [[NSApp mainWindow] makeKeyAndOrderFront: self]; - } - else - { - /* We need give input focus to some window otherwise we'll - never get keyboard events. FIXME: doesn't work. */ - NSWindow *menu_window= [[NSApp mainMenu] window]; - NSDebugLLog(@"Focus", @"No key on activation - make menu key"); - [GSServerForWindow(menu_window) setinputfocus: - [menu_window windowNumber]]; - } - } + if ([NSApp isActive] == YES) + { + if ([NSApp keyWindow] != nil) + { + [[NSApp keyWindow] orderFront: self]; + } + else if ([NSApp mainWindow] != nil) + { + [[NSApp mainWindow] makeKeyAndOrderFront: self]; + } + else + { + /* We need give input focus to some window otherwise we'll + never get keyboard events. FIXME: doesn't work. */ + NSWindow *menu_window= [[NSApp mainMenu] window]; + NSDebugLLog(@"Focus", @"No key on activation - make menu key"); + [GSServerForWindow(menu_window) setinputfocus: + [menu_window windowNumber]]; + } + } RELEASE(windows); - } + } [NSApp unhide: self]; // or activate or do nothing. } @@ -1151,57 +1150,57 @@ static NSSize scaledIconSizeForSize(NSSize imageSize) * visible when the application is active. */ [nc postNotificationName: NSApplicationWillBecomeActiveNotification - object: self]; + object: self]; _app_is_active = YES; /* Make sure to calculate count after the notification, since - inactive status might be changed by a notifiee. */ + inactive status might be changed by a notifiee. */ count = [_inactive count]; for (i = 0; i < count; i++) - { - [[_inactive objectAtIndex: i] orderFrontRegardless]; - } + { + [[_inactive objectAtIndex: i] orderFrontRegardless]; + } [_inactive removeAllObjects]; if (_unhide_on_activation) - { - [self unhide: nil]; - } + { + [self unhide: nil]; + } if ([self keyWindow] == nil && _hidden_key != nil - && [[self windows] indexOfObjectIdenticalTo: _hidden_key] != NSNotFound) - { - [_hidden_key makeKeyWindow]; - _hidden_key = nil; - } - + && [[self windows] indexOfObjectIdenticalTo: _hidden_key] != NSNotFound) + { + [_hidden_key makeKeyWindow]; + _hidden_key = nil; + } + if ([self keyWindow] != nil) - { - [[self keyWindow] orderFront: self]; - } + { + [[self keyWindow] orderFront: self]; + } else if ([self mainWindow] != nil) - { - [[self mainWindow] makeKeyAndOrderFront: self]; - } + { + [[self mainWindow] makeKeyAndOrderFront: self]; + } else { - /* We need give input focus to some window otherwise we'll never get - keyboard events. FIXME: doesn't work. */ - NSWindow *menu_window= [[self mainMenu] window]; - NSDebugLLog(@"Focus", @"No key on activation - make menu key"); - [GSServerForWindow(menu_window) setinputfocus: - [menu_window windowNumber]]; + /* We need give input focus to some window otherwise we'll never get + keyboard events. FIXME: doesn't work. */ + NSWindow *menu_window= [[self mainMenu] window]; + NSDebugLLog(@"Focus", @"No key on activation - make menu key"); + [GSServerForWindow(menu_window) setinputfocus: + [menu_window windowNumber]]; } info = [self _notificationUserInfo]; [nc postNotificationName: NSApplicationDidBecomeActiveNotification - object: self + object: self userInfo: info]; [[[NSWorkspace sharedWorkspace] notificationCenter] - postNotificationName: NSApplicationDidBecomeActiveNotification + postNotificationName: NSApplicationDidBecomeActiveNotification object: [NSWorkspace sharedWorkspace] - userInfo: info]; + userInfo: info]; } } @@ -1219,16 +1218,15 @@ static NSSize scaledIconSizeForSize(NSSize imageSize) NSEnumerator *iter; [nc postNotificationName: NSApplicationWillResignActiveNotification - object: self]; + object: self]; - _app_is_active = NO; if ([self keyWindow] != nil) - { - _hidden_key = [self keyWindow]; - [_hidden_key resignKeyWindow]; - } + { + _hidden_key = [self keyWindow]; + [_hidden_key resignKeyWindow]; + } // FIXME: main window is not saved for when the app is activated again. // This is not a problem if it is also key, and I'm not sure if it // is a problem at all. May be annoying in the case of workspace switch. @@ -1238,47 +1236,47 @@ static NSSize scaledIconSizeForSize(NSSize imageSize) iter = [windows_list reverseObjectEnumerator]; while ((win = [iter nextObject])) - { - NSModalSession theSession; + { + NSModalSession theSession; - if ([win isVisible] == NO) - { - continue; /* Already invisible */ - } - if ([win canHide] == NO) - { - continue; /* Can't be hidden */ - } - if (win == _app_icon_window) - { - continue; /* can't hide the app icon. */ - } - /* Don't order out modal windows */ - theSession = _session; - while (theSession != 0) - { - if (win == theSession->window) - break; - theSession = theSession->previous; - } - if (theSession) - continue; - - if ([win hidesOnDeactivate] == YES) - { - [_inactive addObject: win]; - [win orderOut: self]; - } - } - + if ([win isVisible] == NO) + { + continue; /* Already invisible */ + } + if ([win canHide] == NO) + { + continue; /* Can't be hidden */ + } + if (win == _app_icon_window) + { + continue; /* can't hide the app icon. */ + } + /* Don't order out modal windows */ + theSession = _session; + while (theSession != 0) + { + if (win == theSession->window) + break; + theSession = theSession->previous; + } + if (theSession) + continue; + + if ([win hidesOnDeactivate] == YES) + { + [_inactive addObject: win]; + [win orderOut: self]; + } + } + info = [self _notificationUserInfo]; [nc postNotificationName: NSApplicationDidResignActiveNotification - object: self + object: self userInfo: info]; [[[NSWorkspace sharedWorkspace] notificationCenter] - postNotificationName: NSApplicationDidResignActiveNotification + postNotificationName: NSApplicationDidResignActiveNotification object: [NSWorkspace sharedWorkspace] - userInfo: info]; + userInfo: info]; } } @@ -2223,35 +2221,35 @@ image.

See Also: -applicationIconImage

object: self]; if ([self keyWindow] != nil) - { - _hidden_key = [self keyWindow]; - [_hidden_key resignKeyWindow]; - } + { + _hidden_key = [self keyWindow]; + [_hidden_key resignKeyWindow]; + } windows_list = GSOrderedWindows(); iter = [windows_list reverseObjectEnumerator]; while ((win = [iter nextObject])) - { - if ([win isVisible] == NO) - { - continue; /* Already invisible */ - } - if ([win canHide] == NO) - { - continue; /* Not hideable */ - } - if (win == _app_icon_window) - { - continue; /* can't hide the app icon. */ - } - if (_app_is_active == YES && [win hidesOnDeactivate] == YES) - { - continue; /* Will be hidden by deactivation */ - } - [_hidden addObject: win]; - [win orderOut: self]; - } + { + if ([win isVisible] == NO) + { + continue; /* Already invisible */ + } + if ([win canHide] == NO) + { + continue; /* Not hideable */ + } + if (win == _app_icon_window) + { + continue; /* can't hide the app icon. */ + } + if (_app_is_active == YES && [win hidesOnDeactivate] == YES) + { + continue; /* Will be hidden by deactivation */ + } + [_hidden addObject: win]; + [win orderOut: self]; + } _app_is_hidden = YES; [[_app_icon_window contentView] setNeedsDisplay: YES]; @@ -3610,145 +3608,43 @@ struct _DelegateWrapper - (void) _windowWillClose: (NSNotification*) notification { - NSWindow *win = [notification object]; - NSArray *windows_list = GSOrderedWindows(); - unsigned count = [windows_list count]; - unsigned i; - NSMutableArray *list = [NSMutableArray arrayWithCapacity: count]; - BOOL wasKey = [win isKeyWindow]; - BOOL wasMain = [win isMainWindow]; - NSEnumerator *iter = [windows_list objectEnumerator]; - NSWindow *tmp; - - while ((tmp = [iter nextObject])) - { - if ([tmp canBecomeMainWindow] == YES && [tmp isVisible] == YES) - { - [list addObject: tmp]; - } - } - [list removeObjectIdenticalTo: win]; - count = [list count]; - - /* If there's only one window left, and that's the one being closed, - then we ask the delegate if the app is to be terminated. */ - if (wasMain && count == 0 && _app_is_running) - { - if ([_delegate respondsToSelector: - @selector(applicationShouldTerminateAfterLastWindowClosed:)]) - { - if ([_delegate applicationShouldTerminateAfterLastWindowClosed: self]) - { - [self terminate: self]; - } - } - } - - if (wasMain == YES) - { - [win resignMainWindow]; - } - if (wasKey == YES) - { - [win resignKeyWindow]; - } + NSWindow *win = [notification object]; + BOOL wasMain = [win isMainWindow]; if (_app_is_running) { - /* - * If we are not quitting, we may need to find a new key/main window. - */ - if (wasKey == YES && [self keyWindow] == nil) - { - win = [self mainWindow]; - if (win != nil && [win canBecomeKeyWindow] == YES) - { - /* - * We have a main window that can become key, so do it. - */ - [win makeKeyAndOrderFront: self]; - } - else if (win != nil) - { - /* - * We have a main window that can't become key, so we just - * find a new window to make into our key window. - */ - for (i = 0; i < count; i++) - { - win = [list objectAtIndex: i]; + NSArray *windows_list = GSOrderedWindows(); + unsigned count = [windows_list count]; + NSEnumerator *iter = [windows_list objectEnumerator]; + NSMutableArray *list = [NSMutableArray arrayWithCapacity: count]; + NSWindow *tmp; - if ([win canBecomeKeyWindow] == YES) - { - [win makeKeyAndOrderFront: self]; - } - } - } - else - { - /* - * Find a window that can be made key and main - and do it. - */ - for (i = 0; i < count; i++) - { - win = [list objectAtIndex: i]; - if ([win canBecomeKeyWindow] && [win canBecomeMainWindow]) - { - break; - } - } - if (i < count) - { - [win makeMainWindow]; - [win makeKeyAndOrderFront: self]; - } - else - { - /* - * No window we can use, so just find any candidate to - * be main window and another to be key window. - */ - for (i = 0; i < count; i++) - { - win = [list objectAtIndex: i]; - if ([win canBecomeMainWindow] == YES) - { - [win makeMainWindow]; - break; - } - } - for (i = 0; i < count; i++) - { - win = [list objectAtIndex: i]; - if ([win canBecomeKeyWindow] == YES) - { - [win makeKeyAndOrderFront: self]; - break; - } - } - } - } - } - else if ([self mainWindow] == nil) - { - win = [self keyWindow]; - if ([win canBecomeMainWindow] == YES) - { - [win makeMainWindow]; - } - else - { - for (i = 0; i < count; i++) - { - win = [list objectAtIndex: i]; - if ([win canBecomeMainWindow] == YES) - { - [win makeMainWindow]; - break; - } - } - } - } + /* FIXME: Why are non-visible windows not counted? When there are + minimized windows left over, this would still terminate the application. + */ + while ((tmp = [iter nextObject])) + { + if ([tmp canBecomeMainWindow] == YES && [tmp isVisible] == YES) + { + [list addObject: tmp]; + } + } + [list removeObjectIdenticalTo: win]; + count = [list count]; + + /* If there's only one window left, and that's the one being closed, + then we ask the delegate if the app is to be terminated. */ + if (wasMain && count == 0) + { + if ([_delegate respondsToSelector: + @selector(applicationShouldTerminateAfterLastWindowClosed:)]) + { + if ([_delegate applicationShouldTerminateAfterLastWindowClosed: self]) + { + [self terminate: self]; + } + } + } } } diff --git a/Source/NSWindow.m b/Source/NSWindow.m index d5641e9c1..049e0ba8f 100644 --- a/Source/NSWindow.m +++ b/Source/NSWindow.m @@ -235,70 +235,91 @@ has blocked and waited for events. - (void) _lossOfKeyOrMainWindow { NSArray *windowList = GSOrderedWindows(); - unsigned pos = [windowList indexOfObjectIdenticalTo: self]; - unsigned c = [windowList count]; - unsigned i,ti; - NSWindow *w; + unsigned pos = [windowList indexOfObjectIdenticalTo: self]; + unsigned c = [windowList count]; + unsigned i; + + // Don't bother when application is closing. + if ([NSApp isRunning] == NO) + return; if (!c) return; - i = pos + 1; - if (pos >= c || pos + 1 == c) + if (pos == NSNotFound) { - pos = c - 1; - i = 0; + pos = c; } - ti = i; if ([self isKeyWindow]) { - NSWindow *menu_window = [[NSApp mainMenu] window]; + NSWindow *w = [NSApp mainWindow]; [self resignKeyWindow]; + if (w != nil && w != self + && [w canBecomeKeyWindow]) + { + [w makeKeyWindow]; + } + else + { + NSWindow *menu_window = [[NSApp mainMenu] window]; - for (; i != pos && i < c; i++) - { - w = [windowList objectAtIndex: i]; - if ([w isVisible] && [w canBecomeKeyWindow] && w != menu_window) - { - [w makeKeyWindow]; - break; - } - } - /* - * if we didn't find a possible key window - use the main menu window - */ - if (i == c) - { - if (menu_window != nil) - { - [GSServerForWindow(menu_window) setinputfocus: - [menu_window windowNumber]]; - } - } + // try all windows front to back except self and menu + for (i = 0; i < c; i++) + { + if (i != pos) + { + w = [windowList objectAtIndex: i]; + if ([w isVisible] && [w canBecomeKeyWindow] + && w != menu_window) + { + [w makeKeyWindow]; + break; + } + } + } + + /* + * if we didn't find a possible key window - use the main menu window + */ + if (i == c) + { + if (menu_window != nil) + { + // FIXME: Why this call and not makeKeyWindow? + [GSServerForWindow(menu_window) setinputfocus: + [menu_window windowNumber]]; + } + } + } } + if ([self isMainWindow]) { - NSWindow *w = [NSApp keyWindow]; + NSWindow *w = [NSApp keyWindow]; [self resignMainWindow]; if (w != nil && [w canBecomeMainWindow]) - { - [w makeMainWindow]; - } + { + [w makeMainWindow]; + } else - { - for (i = ti; i != pos && i < c; i++) - { - w = [windowList objectAtIndex: i]; - if ([w isVisible] && [w canBecomeMainWindow]) - { - [w makeMainWindow]; - break; - } - } - } + { + // try all windows front to back except self + for (i = 0; i < c; i++) + { + if (i != pos) + { + w = [windowList objectAtIndex: i]; + if ([w isVisible] && [w canBecomeMainWindow]) + { + [w makeMainWindow]; + break; + } + } + } + } } } @@ -1554,8 +1575,8 @@ many times. { if (_windowNum == 0) { - return; /* This deferred window was never ordered in. */ - } + return; /* This deferred window was never ordered in. */ + } _f.visible = NO; /* * Don't keep trying to update the window while it is ordered out @@ -1566,23 +1587,23 @@ many times. else { /* Windows need to be constrained when displayed or resized - but only - titled windows are constrained. Also, and this is the tricky part, + titled windows are constrained. Also, and this is the tricky part, don't constrain if we are merely unhidding the window or if it's already visible and is just being reordered. */ if ((_styleMask & NSTitledWindowMask) - && [NSApp isHidden] == NO - && _f.visible == NO) - { - NSRect nframe = [self constrainFrameRect: _frame - toScreen: [self screen]]; - [self setFrame: nframe display: NO]; - } + && [NSApp isHidden] == NO + && _f.visible == NO) + { + NSRect nframe = [self constrainFrameRect: _frame + toScreen: [self screen]]; + [self setFrame: nframe display: NO]; + } // create deferred window if (_windowNum == 0) - { - [self _initBackendWindow]; - display = YES; - } + { + [self _initBackendWindow]; + display = YES; + } } // Draw content before backend window ordering @@ -1612,32 +1633,32 @@ many times. [isa _addAutodisplayedWindow: self]; if (_f.has_closed == YES) - { - _f.has_closed = NO; /* A closed window has re-opened */ - } + { + _f.has_closed = NO; /* A closed window has re-opened */ + } if (_f.has_opened == NO) - { - _f.has_opened = YES; - if (_f.menu_exclude == NO) - { - BOOL isFileName; - NSString *aString; - - aString = [NSString stringWithFormat: @"%@ -- %@", - [_representedFilename lastPathComponent], - [_representedFilename stringByDeletingLastPathComponent]]; - isFileName = [_windowTitle isEqual: aString]; + { + _f.has_opened = YES; + if (_f.menu_exclude == NO) + { + BOOL isFileName; + NSString *aString; + + aString = [NSString stringWithFormat: @"%@ -- %@", + [_representedFilename lastPathComponent], + [_representedFilename stringByDeletingLastPathComponent]]; + isFileName = [_windowTitle isEqual: aString]; - [NSApp addWindowsItem: self - title: _windowTitle - filename: isFileName]; - } - } + [NSApp addWindowsItem: self + title: _windowTitle + filename: isFileName]; + } + } if ([self isKeyWindow] == YES) - { - [_wv setInputState: GSTitleBarKey]; - [srv setinputfocus: _windowNum]; - } + { + [_wv setInputState: GSTitleBarKey]; + [srv setinputfocus: _windowNum]; + } _f.visible = YES; } else if ([self isOneShot]) @@ -1651,19 +1672,19 @@ many times. if (_f.is_key == YES) { if ((_firstResponder != self) - && [_firstResponder respondsToSelector: @selector(resignKeyWindow)]) - [_firstResponder resignKeyWindow]; + && [_firstResponder respondsToSelector: @selector(resignKeyWindow)]) + [_firstResponder resignKeyWindow]; _f.is_key = NO; if (_f.is_main == YES) - { - [_wv setInputState: GSTitleBarMain]; - } + { + [_wv setInputState: GSTitleBarMain]; + } else - { - [_wv setInputState: GSTitleBarNormal]; - } + { + [_wv setInputState: GSTitleBarNormal]; + } [self discardCursorRects]; [nc postNotificationName: NSWindowDidResignKeyNotification object: self]; @@ -1676,13 +1697,13 @@ many times. { _f.is_main = NO; if (_f.is_key == YES) - { - [_wv setInputState: GSTitleBarKey]; - } + { + [_wv setInputState: GSTitleBarKey]; + } else - { - [_wv setInputState: GSTitleBarNormal]; - } + { + [_wv setInputState: GSTitleBarNormal]; + } [nc postNotificationName: NSWindowDidResignMainNotification object: self]; } } @@ -2447,9 +2468,9 @@ resetCursorRectsForView(NSView *theView) we close). */ if (!_f.is_released_when_closed) - { - RETAIN(self); - } + { + RETAIN(self); + } [nc postNotificationName: NSWindowWillCloseNotification object: self]; _f.has_opened = NO; @@ -3524,31 +3545,31 @@ resetCursorRectsForView(NSView *theView) case GSAppKitWindowFocusIn: if (_f.is_miniaturized) - { - /* Window Manager just deminiaturized us */ - [self deminiaturize: self]; - } + { + /* Window Manager just deminiaturized us */ + [self deminiaturize: self]; + } if ([NSApp modalWindow] - && self != [NSApp modalWindow]) - { - /* Ignore this request. We're in a modal loop and the - user pressed on the title bar of another window. */ - break; - } + && self != [NSApp modalWindow]) + { + /* Ignore this request. We're in a modal loop and the + user pressed on the title bar of another window. */ + break; + } if ([self canBecomeKeyWindow] == YES) - { - NSDebugLLog(@"Focus", @"Making %d key", _windowNum); - [self makeKeyWindow]; - [self makeMainWindow]; - [NSApp activateIgnoringOtherApps: YES]; - } + { + NSDebugLLog(@"Focus", @"Making %d key", _windowNum); + [self makeKeyWindow]; + [self makeMainWindow]; + [NSApp activateIgnoringOtherApps: YES]; + } if (self == [[NSApp mainMenu] window]) - { - /* We should really find another window that can become - key (if possible) - */ - [self _lossOfKeyOrMainWindow]; - } + { + /* We should really find another window that can become + key (if possible) + */ + [self _lossOfKeyOrMainWindow]; + } break; case GSAppKitWindowFocusOut: