OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/base_bubble_controller.h" | 5 #import "chrome/browser/ui/cocoa/base_bubble_controller.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/mac/bundle_locations.h" | 8 #include "base/mac/bundle_locations.h" |
| 9 #include "base/mac/closure_blocks_leopard_compat.h" |
9 #include "base/mac/mac_util.h" | 10 #include "base/mac/mac_util.h" |
10 #include "base/memory/scoped_nsobject.h" | 11 #include "base/memory/scoped_nsobject.h" |
11 #include "base/string_util.h" | 12 #include "base/string_util.h" |
12 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | 13 #import "chrome/browser/ui/cocoa/info_bubble_view.h" |
13 #include "content/public/browser/notification_observer.h" | 14 #include "content/public/browser/notification_observer.h" |
14 #include "content/public/browser/notification_registrar.h" | 15 #include "content/public/browser/notification_registrar.h" |
15 #include "content/public/browser/notification_service.h" | 16 #include "content/public/browser/notification_service.h" |
16 #include "content/public/browser/notification_types.h" | 17 #include "content/public/browser/notification_types.h" |
17 #include "grit/generated_resources.h" | 18 #include "grit/generated_resources.h" |
18 #include "ui/base/l10n/l10n_util.h" | 19 #include "ui/base/l10n/l10n_util.h" |
19 | 20 |
20 @interface BaseBubbleController (Private) | 21 @interface BaseBubbleController (Private) |
21 - (void)updateOriginFromAnchor; | 22 - (void)updateOriginFromAnchor; |
22 @end | 23 @end |
23 | 24 |
| 25 #if !defined(MAC_OS_X_VERSION_10_6) || \ |
| 26 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 |
| 27 @interface NSEvent (SnowLeopardDeclarations) |
| 28 + (id)addLocalMonitorForEventsMatchingMask:(NSUInteger)mask |
| 29 handler:(NSEvent* (^)(NSEvent*))block; |
| 30 + (void)removeMonitor:(id)eventMonitor; |
| 31 @end |
| 32 |
| 33 @interface NSOperationQueue (SnowLeopardDeclarations) |
| 34 + (id)mainQueue; |
| 35 @end |
| 36 |
| 37 @interface NSNotificationCenter (SnowLeopardDeclarations) |
| 38 - (id)addObserverForName:(NSString*)name |
| 39 object:(id)obj |
| 40 queue:(NSOperationQueue*)queue |
| 41 usingBlock:(void (^)(NSNotification*))block; |
| 42 @end |
| 43 #endif // MAC_OS_X_VERSION_10_6 |
| 44 |
24 namespace BaseBubbleControllerInternal { | 45 namespace BaseBubbleControllerInternal { |
25 | 46 |
26 // This bridge listens for notifications so that the bubble closes when a user | 47 // This bridge listens for notifications so that the bubble closes when a user |
27 // switches tabs (including by opening a new one). | 48 // switches tabs (including by opening a new one). |
28 class Bridge : public content::NotificationObserver { | 49 class Bridge : public content::NotificationObserver { |
29 public: | 50 public: |
30 explicit Bridge(BaseBubbleController* controller) : controller_(controller) { | 51 explicit Bridge(BaseBubbleController* controller) : controller_(controller) { |
31 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_HIDDEN, | 52 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_HIDDEN, |
32 content::NotificationService::AllSources()); | 53 content::NotificationService::AllSources()); |
33 } | 54 } |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 [self autorelease]; | 175 [self autorelease]; |
155 } | 176 } |
156 | 177 |
157 // We want this to be a child of a browser window. addChildWindow: | 178 // We want this to be a child of a browser window. addChildWindow: |
158 // (called from this function) will bring the window on-screen; | 179 // (called from this function) will bring the window on-screen; |
159 // unfortunately, [NSWindowController showWindow:] will also bring it | 180 // unfortunately, [NSWindowController showWindow:] will also bring it |
160 // on-screen (but will cause unexpected changes to the window's | 181 // on-screen (but will cause unexpected changes to the window's |
161 // position). We cannot have an addChildWindow: and a subsequent | 182 // position). We cannot have an addChildWindow: and a subsequent |
162 // showWindow:. Thus, we have our own version. | 183 // showWindow:. Thus, we have our own version. |
163 - (void)showWindow:(id)sender { | 184 - (void)showWindow:(id)sender { |
164 NSWindow* window = [self window]; // completes nib load | 185 NSWindow* window = [self window]; // Completes nib load. |
165 [self updateOriginFromAnchor]; | 186 [self updateOriginFromAnchor]; |
166 [parentWindow_ addChildWindow:window ordered:NSWindowAbove]; | 187 [parentWindow_ addChildWindow:window ordered:NSWindowAbove]; |
167 [window makeKeyAndOrderFront:self]; | 188 [window makeKeyAndOrderFront:self]; |
| 189 [self registerKeyStateEventTap]; |
168 } | 190 } |
169 | 191 |
170 - (void)close { | 192 - (void)close { |
| 193 // The bubble will be closing, so remove the event taps. |
| 194 if (eventTap_) { |
| 195 [NSEvent removeMonitor:eventTap_]; |
| 196 eventTap_ = nil; |
| 197 } |
| 198 if (resignationObserver_) { |
| 199 [[NSNotificationCenter defaultCenter] |
| 200 removeObserver:resignationObserver_ |
| 201 name:NSWindowDidResignKeyNotification |
| 202 object:nil]; |
| 203 resignationObserver_ = nil; |
| 204 } |
| 205 |
171 [[[self window] parentWindow] removeChildWindow:[self window]]; | 206 [[[self window] parentWindow] removeChildWindow:[self window]]; |
172 [super close]; | 207 [super close]; |
173 } | 208 } |
174 | 209 |
175 // The controller is the delegate of the window so it receives did resign key | 210 // The controller is the delegate of the window so it receives did resign key |
176 // notifications. When key is resigned mirror Windows behavior and close the | 211 // notifications. When key is resigned mirror Windows behavior and close the |
177 // window. | 212 // window. |
178 - (void)windowDidResignKey:(NSNotification*)notification { | 213 - (void)windowDidResignKey:(NSNotification*)notification { |
179 NSWindow* window = [self window]; | 214 NSWindow* window = [self window]; |
180 DCHECK_EQ([notification object], window); | 215 DCHECK_EQ([notification object], window); |
181 if ([window isVisible]) { | 216 if ([window isVisible]) { |
182 // If the window isn't visible, it is already closed, and this notification | 217 // If the window isn't visible, it is already closed, and this notification |
183 // has been sent as part of the closing operation, so no need to close. | 218 // has been sent as part of the closing operation, so no need to close. |
184 [self close]; | 219 [self close]; |
185 } | 220 } |
186 } | 221 } |
187 | 222 |
| 223 // Since the bubble shares first responder with its parent window, set |
| 224 // event handlers to dismiss the bubble when it would normally lose key |
| 225 // state. |
| 226 - (void)registerKeyStateEventTap { |
| 227 // Parent key state sharing is only avaiable on 10.7+. |
| 228 if (!base::mac::IsOSLionOrLater()) |
| 229 return; |
| 230 |
| 231 NSWindow* window = self.window; |
| 232 NSNotification* note = |
| 233 [NSNotification notificationWithName:NSWindowDidResignKeyNotification |
| 234 object:window]; |
| 235 |
| 236 // The eventTap_ catches clicks within the application that are outside the |
| 237 // window. |
| 238 eventTap_ = [NSEvent |
| 239 addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask |
| 240 handler:^NSEvent* (NSEvent* event) { |
| 241 if (event.window != window){ |
| 242 // Call via the runloop because this block is called in the |
| 243 // middle of event dispatch. |
| 244 [self performSelector:@selector(windowDidResignKey:) |
| 245 withObject:note |
| 246 afterDelay:0]; |
| 247 } |
| 248 return event; |
| 249 }]; |
| 250 |
| 251 // The resignationObserver_ watches for when a window resigns key state, |
| 252 // meaning the key window has changed and the bubble should be dismissed. |
| 253 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; |
| 254 resignationObserver_ = |
| 255 [center addObserverForName:NSWindowDidResignKeyNotification |
| 256 object:nil |
| 257 queue:[NSOperationQueue mainQueue] |
| 258 usingBlock:^(NSNotification* notif) { |
| 259 [self windowDidResignKey:note]; |
| 260 }]; |
| 261 } |
| 262 |
188 // By implementing this, ESC causes the window to go away. | 263 // By implementing this, ESC causes the window to go away. |
189 - (IBAction)cancel:(id)sender { | 264 - (IBAction)cancel:(id)sender { |
190 // This is not a "real" cancel as potential changes to the radio group are not | 265 // This is not a "real" cancel as potential changes to the radio group are not |
191 // undone. That's ok. | 266 // undone. That's ok. |
192 [self close]; | 267 [self close]; |
193 } | 268 } |
194 | 269 |
195 // Takes the |anchor_| point and adjusts the window's origin accordingly. | 270 // Takes the |anchor_| point and adjusts the window's origin accordingly. |
196 - (void)updateOriginFromAnchor { | 271 - (void)updateOriginFromAnchor { |
197 NSWindow* window = [self window]; | 272 NSWindow* window = [self window]; |
(...skipping 24 matching lines...) Expand all Loading... |
222 | 297 |
223 default: | 298 default: |
224 NOTREACHED(); | 299 NOTREACHED(); |
225 } | 300 } |
226 | 301 |
227 origin.y -= NSHeight([window frame]); | 302 origin.y -= NSHeight([window frame]); |
228 [window setFrameOrigin:origin]; | 303 [window setFrameOrigin:origin]; |
229 } | 304 } |
230 | 305 |
231 @end // BaseBubbleController | 306 @end // BaseBubbleController |
OLD | NEW |