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

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: local changes 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:(NSEventMask)mask
29 handler:(NSEvent* (^)(NSEvent*))block;
30 + (void)removeMonitor:(id)eventMonitor;
31 @end
32
33 @interface NSOperationQueue (SnowLeopardDeclarations)
34 + (id)mainQueue;
35 @end
36 #endif // MAC_OS_X_VERSION_10_6
37
24 namespace BaseBubbleControllerInternal { 38 namespace BaseBubbleControllerInternal {
25 39
26 // This bridge listens for notifications so that the bubble closes when a user 40 // This bridge listens for notifications so that the bubble closes when a user
27 // switches tabs (including by opening a new one). 41 // switches tabs (including by opening a new one).
28 class Bridge : public content::NotificationObserver { 42 class Bridge : public content::NotificationObserver {
29 public: 43 public:
30 explicit Bridge(BaseBubbleController* controller) : controller_(controller) { 44 explicit Bridge(BaseBubbleController* controller) : controller_(controller) {
31 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_HIDDEN, 45 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_HIDDEN,
32 content::NotificationService::AllSources()); 46 content::NotificationService::AllSources());
33 } 47 }
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 [self autorelease]; 168 [self autorelease];
155 } 169 }
156 170
157 // We want this to be a child of a browser window. addChildWindow: 171 // We want this to be a child of a browser window. addChildWindow:
158 // (called from this function) will bring the window on-screen; 172 // (called from this function) will bring the window on-screen;
159 // unfortunately, [NSWindowController showWindow:] will also bring it 173 // unfortunately, [NSWindowController showWindow:] will also bring it
160 // on-screen (but will cause unexpected changes to the window's 174 // on-screen (but will cause unexpected changes to the window's
161 // position). We cannot have an addChildWindow: and a subsequent 175 // position). We cannot have an addChildWindow: and a subsequent
162 // showWindow:. Thus, we have our own version. 176 // showWindow:. Thus, we have our own version.
163 - (void)showWindow:(id)sender { 177 - (void)showWindow:(id)sender {
164 NSWindow* window = [self window]; // completes nib load 178 NSWindow* window = [self window]; // Completes nib load.
165 [self updateOriginFromAnchor]; 179 [self updateOriginFromAnchor];
166 [parentWindow_ addChildWindow:window ordered:NSWindowAbove]; 180 [parentWindow_ addChildWindow:window ordered:NSWindowAbove];
167 [window makeKeyAndOrderFront:self]; 181 [window makeKeyAndOrderFront:self];
182 [self registerKeyStateEventTap];
168 } 183 }
169 184
170 - (void)close { 185 - (void)close {
186 // The bubble will be closing, so remove the event taps.
187 if (eventTap_) {
188 [NSEvent removeMonitor:eventTap_];
189 eventTap_ = nil;
190 }
191 if (resignationObserver_) {
192 [[NSNotificationCenter defaultCenter]
193 removeObserver:resignationObserver_
194 name:NSWindowDidResignKeyNotification
195 object:nil];
196 resignationObserver_ = nil;
197 }
198
171 [[[self window] parentWindow] removeChildWindow:[self window]]; 199 [[[self window] parentWindow] removeChildWindow:[self window]];
172 [super close]; 200 [super close];
173 } 201 }
174 202
175 // The controller is the delegate of the window so it receives did resign key 203 // 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 204 // notifications. When key is resigned mirror Windows behavior and close the
177 // window. 205 // window.
178 - (void)windowDidResignKey:(NSNotification*)notification { 206 - (void)windowDidResignKey:(NSNotification*)notification {
179 NSWindow* window = [self window]; 207 NSWindow* window = [self window];
180 DCHECK_EQ([notification object], window); 208 DCHECK_EQ([notification object], window);
181 if ([window isVisible]) { 209 if ([window isVisible]) {
182 // If the window isn't visible, it is already closed, and this notification 210 // 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. 211 // has been sent as part of the closing operation, so no need to close.
184 [self close]; 212 [self close];
185 } 213 }
186 } 214 }
187 215
216 // Since the bubble shares first responder with its parent window, set
217 // event handlers to dismiss the bubble when it would normally lose key
218 // state.
219 - (void)registerKeyStateEventTap {
220 // Parent key state sharing is only avaiable on 10.7+.
221 if (!base::mac::IsOSLionOrLater())
222 return;
223
224 NSWindow* window = self.window;
225 NSNotification* note =
226 [NSNotification notificationWithName:NSWindowDidResignKeyNotification
227 object:window];
228
229 // The eventTap_ catches clicks within the application that are outside the
230 // window.
231 eventTap_ = [NSEvent
232 addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask
233 handler:^NSEvent* (NSEvent* event) {
234 if (event.window != window){
235 // Call via the runloop because this block is called in the
236 // middle of event dispatch.
237 [self performSelector:@selector(windowDidResignKey:)
238 withObject:note
239 afterDelay:0];
240 }
241 return event;
242 }];
243
244 // The resignationObserver_ watches for when a window resigns key state,
245 // meaning the key window has changed and the bubble should be dismissed.
246 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
247 resignationObserver_ =
248 [center addObserverForName:NSWindowDidResignKeyNotification
249 object:nil
250 queue:[NSOperationQueue mainQueue]
251 usingBlock:^(NSNotification* notif) {
252 [self windowDidResignKey:note];
253 }];
254 }
255
188 // By implementing this, ESC causes the window to go away. 256 // By implementing this, ESC causes the window to go away.
189 - (IBAction)cancel:(id)sender { 257 - (IBAction)cancel:(id)sender {
190 // This is not a "real" cancel as potential changes to the radio group are not 258 // This is not a "real" cancel as potential changes to the radio group are not
191 // undone. That's ok. 259 // undone. That's ok.
192 [self close]; 260 [self close];
193 } 261 }
194 262
195 // Takes the |anchor_| point and adjusts the window's origin accordingly. 263 // Takes the |anchor_| point and adjusts the window's origin accordingly.
196 - (void)updateOriginFromAnchor { 264 - (void)updateOriginFromAnchor {
197 NSWindow* window = [self window]; 265 NSWindow* window = [self window];
(...skipping 24 matching lines...) Expand all
222 290
223 default: 291 default:
224 NOTREACHED(); 292 NOTREACHED();
225 } 293 }
226 294
227 origin.y -= NSHeight([window frame]); 295 origin.y -= NSHeight([window frame]);
228 [window setFrameOrigin:origin]; 296 [window setFrameOrigin:origin];
229 } 297 }
230 298
231 @end // BaseBubbleController 299 @end // BaseBubbleController
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698