Update V8 to version 4.7.45.
[chromium-blink-merge.git] / ui / base / cocoa / command_dispatcher.mm
blob64ac8fd1bb229d5c448b7f73195ead700d89e2cd
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ui/base/cocoa/command_dispatcher.h"
7 #include "base/logging.h"
9 namespace {
11 // Duplicate the given key event, but changing the associated window.
12 NSEvent* KeyEventForWindow(NSWindow* window, NSEvent* event) {
13   NSEventType event_type = [event type];
15   // Convert the event's location from the original window's coordinates into
16   // our own.
17   NSPoint location = [event locationInWindow];
18   location = [[event window] convertBaseToScreen:location];
19   location = [window convertScreenToBase:location];
21   // Various things *only* apply to key down/up.
22   bool is_a_repeat = false;
23   NSString* characters = nil;
24   NSString* charactors_ignoring_modifiers = nil;
25   if (event_type == NSKeyDown || event_type == NSKeyUp) {
26     is_a_repeat = [event isARepeat];
27     characters = [event characters];
28     charactors_ignoring_modifiers = [event charactersIgnoringModifiers];
29   }
31   // This synthesis may be slightly imperfect: we provide nil for the context,
32   // since I (viettrungluu) am sceptical that putting in the original context
33   // (if one is given) is valid.
34   return [NSEvent keyEventWithType:event_type
35                           location:location
36                      modifierFlags:[event modifierFlags]
37                          timestamp:[event timestamp]
38                       windowNumber:[window windowNumber]
39                            context:nil
40                         characters:characters
41        charactersIgnoringModifiers:charactors_ignoring_modifiers
42                          isARepeat:is_a_repeat
43                            keyCode:[event keyCode]];
46 }  // namespace
48 @implementation CommandDispatcher {
49  @private
50   BOOL redispatchingEvent_;
51   BOOL eventHandled_;
52   NSWindow<CommandDispatchingWindow>* owner_;  // Weak, owns us.
55 @synthesize delegate = delegate_;
57 - (instancetype)initWithOwner:(NSWindow<CommandDispatchingWindow>*)owner {
58   if ((self = [super init])) {
59     owner_ = owner;
60   }
61   return self;
64 - (BOOL)performKeyEquivalent:(NSEvent*)event {
65   if ([delegate_ eventHandledByExtensionCommand:event
66                                    isRedispatch:redispatchingEvent_]) {
67     return YES;
68   }
70   if (redispatchingEvent_)
71     return NO;
73   // Give a CommandDispatcherTarget (e.g. a web site) a chance to handle the
74   // event. If it doesn't want to handle it, it will call us back with
75   // -redispatchKeyEvent:.
76   NSResponder* r = [owner_ firstResponder];
77   if ([r conformsToProtocol:@protocol(CommandDispatcherTarget)])
78     return [r performKeyEquivalent:event];
80   if ([delegate_ prePerformKeyEquivalent:event window:owner_])
81     return YES;
83   if ([owner_ defaultPerformKeyEquivalent:event])
84     return YES;
86   return [delegate_ postPerformKeyEquivalent:event window:owner_];
89 - (BOOL)redispatchKeyEvent:(NSEvent*)event {
90   DCHECK(event);
91   NSEventType eventType = [event type];
92   if (eventType != NSKeyDown && eventType != NSKeyUp &&
93       eventType != NSFlagsChanged) {
94     NOTREACHED();
95     return YES;  // Pretend it's been handled in an effort to limit damage.
96   }
98   // Ordinarily, the event's window should be |owner_|. However, when switching
99   // between normal and fullscreen mode, we switch out the window, and the
100   // event's window might be the previous window (or even an earlier one if the
101   // renderer is running slowly and several mode switches occur). In this rare
102   // case, we synthesize a new key event so that its associate window (number)
103   // is our |owner_|'s.
104   if ([event window] != owner_)
105     event = KeyEventForWindow(owner_, event);
107   // Redispatch the event.
108   eventHandled_ = YES;
109   redispatchingEvent_ = YES;
110   [NSApp sendEvent:event];
111   redispatchingEvent_ = NO;
113   // If the event was not handled by [NSApp sendEvent:], the sendEvent:
114   // method below will be called, and because |redispatchingEvent_| is YES,
115   // |eventHandled_| will be set to NO.
116   return eventHandled_;
119 - (BOOL)preSendEvent:(NSEvent*)event {
120   if (redispatchingEvent_) {
121     // If we get here, then the event was not handled by NSApplication.
122     eventHandled_ = NO;
123     // Return YES to stop native -sendEvent handling.
124     return YES;
125   }
127   return NO;
130 @end