Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(376)

Side by Side Diff: chrome/browser/ui/cocoa/base_bubble_controller.mm

Issue 9732012: [Mac] Have BaseBubbleController dismiss bubbles when they would lose key state on 10.8. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/base_bubble_controller.h ('k') | chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698