Make sure toolbar items are validated w.r.t. the responder chain of

their respective window.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@27627 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Wolfgang Lux 2009-01-18 15:33:01 +00:00
parent cdc21a5395
commit f7e864e8ab
2 changed files with 124 additions and 86 deletions

View file

@ -1,6 +1,3 @@
2009-01-18 Wolfgang Lux <wlux@uni-muenster.de>
2009-01-18 Wolfgang Lux <wolfgang.lux@gmail.com>
* Source/NSMenu.m (-update, -setAutoenablesItems:, initWithCoder):
@ -18,6 +15,12 @@
item before adding a menu item to an overflow menu. Also rename
method to make its purpose clear.
* Source/NSApplication.m (-targetForAction:to:from:): Make sure
toolbar items are validated w.r.t. the responder chain of their
respective window.
* Source/NSApplication.m (-_targetForAction:keyWindow:mainWindow:):
Helper method to consolidate target look up in the responder chain.
2009-01-17 Wolfgang Lux <wolfgang.lux@gmail.com>
* Source/NSDocument.m (-windowForSheet): Return nil if the

View file

@ -74,6 +74,7 @@
#include "AppKit/NSPageLayout.h"
#include "AppKit/NSPanel.h"
#include "AppKit/NSPasteboard.h"
#include "AppKit/NSToolbarItem.h"
#include "AppKit/NSWorkspace.h"
#include "AppKit/NSScreen.h"
#include "AppKit/PSOperators.h"
@ -84,6 +85,7 @@
#include "GNUstepGUI/GSInfoPanel.h"
#include "GNUstepGUI/GSVersion.h"
#include "NSDocumentFrameworkPrivate.h"
#include "NSToolbarFrameworkPrivate.h"
/* The -gui thread. See the comment in initialize_gnustep_backend. */
NSThread *GSAppKitThread;
@ -360,6 +362,9 @@ struct _NSModalSession {
- _appIconInit;
- (NSDictionary*) _notificationUserInfo;
- (void) _openDocument: (NSString*)name;
- (id) _targetForAction: (SEL)aSelector
keyWindow: (NSWindow *)keyWindow
mainWindow: (NSWindow *)mainWindow;
- (void) _windowDidBecomeKey: (NSNotification*) notification;
- (void) _windowDidBecomeMain: (NSNotification*) notification;
- (void) _windowDidResignKey: (NSNotification*) notification;
@ -2053,51 +2058,30 @@ IF_NO_GC(NSAssert([event retainCount] > 0, NSInternalInconsistencyException));
{
return theTarget;
}
else if ([sender isKindOfClass: [NSToolbarItem class]])
{
/* Special case for toolbar items which must look up the target in the
responder chain of the window containing their toolbar not in the key
or main window.
Note: If (and only if) the toolbar's window is key window we must
pass it as such to _targetForAction:... so that toolbar items in a
modal dialog panel work.
*/
NSWindow *toolbarWindow =
[[[(NSToolbarItem *)sender toolbar] _toolbarView] window];
NSWindow *keyWindow = [self keyWindow];
if (keyWindow != toolbarWindow)
keyWindow = nil;
return [self _targetForAction: theAction
keyWindow: keyWindow
mainWindow: toolbarWindow];
}
else
{
return [self targetForAction: theAction];
}
}
/*
* Helper method to avoid duplicating code for key and main window
*/
- (id) targetForAction: (SEL)aSelector forWindow: (NSWindow *)window
{
id resp, delegate;
resp = [window firstResponder];
while (resp != nil && resp != self)
{
if ([resp respondsToSelector: aSelector])
{
return resp;
}
if (resp == window)
{
delegate = [window delegate];
if ([delegate respondsToSelector: aSelector])
{
return delegate;
}
}
resp = [resp nextResponder];
}
if ([NSDocumentController isDocumentBasedApplication])
{
resp = [[NSDocumentController sharedDocumentController]
documentForWindow: window];
if (resp != nil && [resp respondsToSelector: aSelector])
{
return resp;
}
}
return nil;
}
/**
* <p>
* Returns the target object that will respond to aSelector, if any. The
@ -2109,52 +2093,12 @@ IF_NO_GC(NSAssert([event retainCount] > 0, NSInternalInconsistencyException));
*/
- (id) targetForAction: (SEL)aSelector
{
NSWindow *keyWindow;
NSWindow *mainWindow;
id resp;
if (aSelector == NULL)
return nil;
keyWindow = [self keyWindow];
if (keyWindow != nil)
{
resp = [self targetForAction: aSelector forWindow: keyWindow];
if (resp != nil)
return resp;
}
if (_session != 0)
return nil;
mainWindow = [self mainWindow];
if (keyWindow != mainWindow && mainWindow != nil)
{
resp = [self targetForAction: aSelector forWindow: mainWindow];
if (resp != nil)
return resp;
}
if ([self respondsToSelector: aSelector])
{
return self;
}
if (_delegate != nil && [_delegate respondsToSelector: aSelector])
{
return _delegate;
}
if ([NSDocumentController isDocumentBasedApplication]
&& [[NSDocumentController sharedDocumentController]
respondsToSelector: aSelector])
{
return [NSDocumentController sharedDocumentController];
}
return nil;
return [self _targetForAction: aSelector
keyWindow: [self keyWindow]
mainWindow: [self mainWindow]];
}
/**
* Attempts to perform aSelector using [NSResponder-tryToPerform:with:]
* and if that is not possible, attempts to get the application
@ -3614,6 +3558,97 @@ struct _DelegateWrapper
[_listener application: self openFile: filePath];
}
- (id) _targetForAction: (SEL)aSelector
keyWindow: (NSWindow *)keyWindow
mainWindow: (NSWindow *)mainWindow
{
id resp, delegate;
NSWindow *window;
if (aSelector == NULL)
return nil;
/* if we have a key window, start looking in its responder chain, ... */
if (keyWindow != nil)
{
window = keyWindow;
}
/* ... otherwise in the main window's responder chain */
else
{
if (_session != 0)
return nil;
window = mainWindow;
}
if (window != nil)
{
/* traverse the responder chain including the window's delegate */
resp = [window firstResponder];
while (resp != nil && resp != self)
{
if ([resp respondsToSelector: aSelector])
{
return resp;
}
if (resp == window)
{
delegate = [window delegate];
if ([delegate respondsToSelector: aSelector])
{
return delegate;
}
}
resp = [resp nextResponder];
}
/* in a document based app try the window's document */
if ([NSDocumentController isDocumentBasedApplication])
{
resp = [[NSDocumentController sharedDocumentController]
documentForWindow: window];
if (resp != nil && [resp respondsToSelector: aSelector])
{
return resp;
}
}
}
/* if we've found no target in the key window start over without key window */
if (keyWindow != nil)
{
if (_session != 0)
return nil;
if (mainWindow != nil && mainWindow != keyWindow)
return [self _targetForAction: aSelector
keyWindow: nil
mainWindow: mainWindow];
}
/* try the shared application imstance and its delegate */
if ([self respondsToSelector: aSelector])
{
return self;
}
if (_delegate != nil && [_delegate respondsToSelector: aSelector])
{
return _delegate;
}
/* as a last resort in a document based app, try the document controller */
if ([NSDocumentController isDocumentBasedApplication]
&& [[NSDocumentController sharedDocumentController]
respondsToSelector: aSelector])
{
return [NSDocumentController sharedDocumentController];
}
/* give up */
return nil;
}
- (void) _windowDidBecomeKey: (NSNotification*) notification
{
id obj = [notification object];