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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/base_bubble_controller.mm
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller.mm b/chrome/browser/ui/cocoa/base_bubble_controller.mm
index cad9e256afe77ca7ae6de721730fea5500aeb97e..60f0f9a7fd66dd9aa49e5af53863f9aeb978adf6 100644
--- a/chrome/browser/ui/cocoa/base_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/base_bubble_controller.mm
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
+#include "base/mac/closure_blocks_leopard_compat.h"
#include "base/mac/mac_util.h"
#include "base/memory/scoped_nsobject.h"
#include "base/string_util.h"
@@ -21,6 +22,26 @@
- (void)updateOriginFromAnchor;
@end
+#if !defined(MAC_OS_X_VERSION_10_6) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+@interface NSEvent (SnowLeopardDeclarations)
++ (id)addLocalMonitorForEventsMatchingMask:(NSUInteger)mask
+ handler:(NSEvent* (^)(NSEvent*))block;
++ (void)removeMonitor:(id)eventMonitor;
+@end
+
+@interface NSOperationQueue (SnowLeopardDeclarations)
++ (id)mainQueue;
+@end
+
+@interface NSNotificationCenter (SnowLeopardDeclarations)
+- (id)addObserverForName:(NSString*)name
+ object:(id)obj
+ queue:(NSOperationQueue*)queue
+ usingBlock:(void (^)(NSNotification*))block;
+@end
+#endif // MAC_OS_X_VERSION_10_6
+
namespace BaseBubbleControllerInternal {
// This bridge listens for notifications so that the bubble closes when a user
@@ -161,13 +182,27 @@ class Bridge : public content::NotificationObserver {
// position). We cannot have an addChildWindow: and a subsequent
// showWindow:. Thus, we have our own version.
- (void)showWindow:(id)sender {
- NSWindow* window = [self window]; // completes nib load
+ NSWindow* window = [self window]; // Completes nib load.
[self updateOriginFromAnchor];
[parentWindow_ addChildWindow:window ordered:NSWindowAbove];
[window makeKeyAndOrderFront:self];
+ [self registerKeyStateEventTap];
}
- (void)close {
+ // The bubble will be closing, so remove the event taps.
+ if (eventTap_) {
+ [NSEvent removeMonitor:eventTap_];
+ eventTap_ = nil;
+ }
+ if (resignationObserver_) {
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:resignationObserver_
+ name:NSWindowDidResignKeyNotification
+ object:nil];
+ resignationObserver_ = nil;
+ }
+
[[[self window] parentWindow] removeChildWindow:[self window]];
[super close];
}
@@ -185,6 +220,46 @@ class Bridge : public content::NotificationObserver {
}
}
+// Since the bubble shares first responder with its parent window, set
+// event handlers to dismiss the bubble when it would normally lose key
+// state.
+- (void)registerKeyStateEventTap {
+ // Parent key state sharing is only avaiable on 10.7+.
+ if (!base::mac::IsOSLionOrLater())
+ return;
+
+ NSWindow* window = self.window;
+ NSNotification* note =
+ [NSNotification notificationWithName:NSWindowDidResignKeyNotification
+ object:window];
+
+ // The eventTap_ catches clicks within the application that are outside the
+ // window.
+ eventTap_ = [NSEvent
+ addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask
+ handler:^NSEvent* (NSEvent* event) {
+ if (event.window != window){
+ // Call via the runloop because this block is called in the
+ // middle of event dispatch.
+ [self performSelector:@selector(windowDidResignKey:)
+ withObject:note
+ afterDelay:0];
+ }
+ return event;
+ }];
+
+ // The resignationObserver_ watches for when a window resigns key state,
+ // meaning the key window has changed and the bubble should be dismissed.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ resignationObserver_ =
+ [center addObserverForName:NSWindowDidResignKeyNotification
+ object:nil
+ queue:[NSOperationQueue mainQueue]
+ usingBlock:^(NSNotification* notif) {
+ [self windowDidResignKey:note];
+ }];
+}
+
// By implementing this, ESC causes the window to go away.
- (IBAction)cancel:(id)sender {
// This is not a "real" cancel as potential changes to the radio group are not
« 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