Index: ui/base/cocoa/command_dispatcher.mm |
diff --git a/ui/base/cocoa/command_dispatcher.mm b/ui/base/cocoa/command_dispatcher.mm |
index 46a351b4ce8c09b399011bf36313ac34db9fb6ec..e6660c3871ad94a7b9a0f997195fa3b4d2b4bacb 100644 |
--- a/ui/base/cocoa/command_dispatcher.mm |
+++ b/ui/base/cocoa/command_dispatcher.mm |
@@ -6,6 +6,19 @@ |
#include "base/logging.h" |
#include "ui/base/cocoa/cocoa_base_utils.h" |
+#import "ui/base/cocoa/user_interface_item_command_handler.h" |
+ |
+// Expose -[NSWindow hasKeyAppearance], which determines whether the traffic |
+// lights on the window are "lit". CommandDispatcher uses this property on a |
+// parent window to decide whether keys and commands should bubble up. |
+@interface NSWindow (PrivateAPI) |
+- (BOOL)hasKeyAppearance; |
+@end |
+ |
+@interface CommandDispatcher () |
+// The parent to bubble events to, or nil. |
+- (NSWindow<CommandDispatchingWindow>*)bubbleParent; |
+@end |
namespace { |
@@ -73,10 +86,13 @@ NSEvent* KeyEventForWindow(NSWindow* window, NSEvent* event) { |
// Give a CommandDispatcherTarget (e.g. a web site) a chance to handle the |
// event. If it doesn't want to handle it, it will call us back with |
- // -redispatchKeyEvent:. |
- NSResponder* r = [owner_ firstResponder]; |
- if ([r conformsToProtocol:@protocol(CommandDispatcherTarget)]) |
- return [r performKeyEquivalent:event]; |
+ // -redispatchKeyEvent:. Only allow this behavior when dispatching key events |
+ // on the key window. |
+ if ([owner_ isKeyWindow]) { |
+ NSResponder* r = [owner_ firstResponder]; |
+ if ([r conformsToProtocol:@protocol(CommandDispatcherTarget)]) |
+ return [r performKeyEquivalent:event]; |
+ } |
if ([delegate_ prePerformKeyEquivalent:event window:owner_]) |
return YES; |
@@ -84,7 +100,35 @@ NSEvent* KeyEventForWindow(NSWindow* window, NSEvent* event) { |
if ([owner_ defaultPerformKeyEquivalent:event]) |
return YES; |
- return [delegate_ postPerformKeyEquivalent:event window:owner_]; |
+ if ([delegate_ postPerformKeyEquivalent:event window:owner_]) |
+ return YES; |
+ |
+ // Allow commands to "bubble up" to CommandDispatchers in parent windows, if |
+ // they were not handled here. |
+ return [[self bubbleParent] performKeyEquivalent:event]; |
+} |
+ |
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item |
+ forHandler:(id<UserInterfaceItemCommandHandler>)handler { |
+ // Since this class implements these selectors, |super| will always say they |
+ // are enabled. Only use [super] to validate other selectors. If there is no |
+ // command handler, defer to AppController. |
+ if ([item action] == @selector(commandDispatch:) || |
+ [item action] == @selector(commandDispatchUsingKeyModifiers:)) { |
+ if (handler) |
Robert Sesek
2017/02/01 14:27:20
Why the discrepancy in handling the result of vali
tapted
2017/02/01 23:36:01
The problem is that (unlike performKeyEquivalent)
|
+ return [handler validateUserInterfaceItem:item window:owner_]; |
+ |
+ id appController = [NSApp delegate]; |
+ DCHECK([appController |
+ conformsToProtocol:@protocol(NSUserInterfaceValidations)]); |
+ if ([appController validateUserInterfaceItem:item]) |
+ return YES; |
+ } |
+ |
+ if ([owner_ defaultValidateUserInterfaceItem:item]) |
+ return YES; |
+ |
+ return [[self bubbleParent] validateUserInterfaceItem:item]; |
} |
- (BOOL)redispatchKeyEvent:(NSEvent*)event { |
@@ -128,4 +172,28 @@ NSEvent* KeyEventForWindow(NSWindow* window, NSEvent* event) { |
return NO; |
} |
+- (void)dispatch:(id)sender |
+ forHandler:(id<UserInterfaceItemCommandHandler>)handler { |
tapted
2017/02/01 10:35:01
I might be able to store this in the CommandDispat
|
+ if (handler) |
+ [handler commandDispatch:sender window:owner_]; |
+ else |
+ [[self bubbleParent] commandDispatch:sender]; |
+} |
+ |
+- (void)dispatchUsingKeyModifiers:(id)sender |
+ forHandler:(id<UserInterfaceItemCommandHandler>)handler { |
+ if (handler) |
+ [handler commandDispatchUsingKeyModifiers:sender window:owner_]; |
+ else |
+ [[self bubbleParent] commandDispatchUsingKeyModifiers:sender]; |
+} |
+ |
+- (NSWindow<CommandDispatchingWindow>*)bubbleParent { |
+ NSWindow* parent = [owner_ parentWindow]; |
+ if (parent && [parent hasKeyAppearance] && |
+ [parent conformsToProtocol:@protocol(CommandDispatchingWindow)]) |
+ return static_cast<NSWindow<CommandDispatchingWindow>*>(parent); |
+ return nil; |
+} |
+ |
@end |