Index: chrome/browser/ui/cocoa/fullscreen/fullscreen_menubar_tracker.mm |
diff --git a/chrome/browser/ui/cocoa/fullscreen/fullscreen_menubar_tracker.mm b/chrome/browser/ui/cocoa/fullscreen/fullscreen_menubar_tracker.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a1c7e5d80defada88b3600f4be40cdc865715657 |
--- /dev/null |
+++ b/chrome/browser/ui/cocoa/fullscreen/fullscreen_menubar_tracker.mm |
@@ -0,0 +1,155 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "chrome/browser/ui/cocoa/fullscreen/fullscreen_menubar_tracker.h" |
+ |
+#import "chrome/browser/ui/cocoa/browser_window_controller.h" |
+#import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_layout_manager.h" |
+ |
+namespace { |
+ |
+// The event kind value for a undocumented menubar show/hide Carbon event. |
+const CGFloat kMenuBarRevealEventKind = 2004; |
+ |
+// Visibility fractions for the menubar and toolbar. |
+const CGFloat kHideFraction = 0.0; |
+const CGFloat kShowFraction = 1.0; |
+ |
+OSStatus MenuBarRevealHandler(EventHandlerCallRef handler, |
+ EventRef event, |
+ void* context) { |
+ FullscreenMenubarTracker* self = |
+ static_cast<FullscreenMenubarTracker*>(context); |
+ |
+ // If Chrome has multiple fullscreen windows in their own space, the Handler |
+ // becomes flaky and might start receiving kMenuBarRevealEventKind events |
+ // from another space. Since the menubar in the another space is in either a |
+ // shown or hidden state, it will give us a reveal fraction of 0.0 or 1.0. |
+ // As such, we should ignore the kMenuBarRevealEventKind event if it gives |
+ // us a fraction of 0.0 or 1.0, and rely on kEventMenuBarShown and |
+ // kEventMenuBarHidden to set these values. |
+ if (GetEventKind(event) == kMenuBarRevealEventKind) { |
+ CGFloat revealFraction = 0; |
+ GetEventParameter(event, FOUR_CHAR_CODE('rvlf'), typeCGFloat, NULL, |
+ sizeof(CGFloat), NULL, &revealFraction); |
+ if (revealFraction > kHideFraction && revealFraction < kShowFraction) |
+ [self setMenubarProgress:revealFraction]; |
+ } else if (GetEventKind(event) == kEventMenuBarShown) { |
+ [self setMenubarProgress:kShowFraction]; |
+ } else { |
+ [self setMenubarProgress:kHideFraction]; |
+ } |
+ |
+ return CallNextEventHandler(handler, event); |
+} |
+ |
+} // end namespace |
+ |
+@interface FullscreenMenubarTracker () { |
+ // Our owner. |
+ FullscreenToolbarLayoutManager* owner_; // weak |
+ |
+ // The window's controller. |
+ BrowserWindowController* browserController_; // weak |
+ |
+ // A Carbon event handler that tracks the revealed fraction of the menu bar. |
+ EventHandlerRef menuBarTrackingHandler_; |
+} |
+ |
+// Returns YES if the mouse is on the same screen as the window. |
+- (BOOL)isMouseOnScreen; |
+ |
+@end |
+ |
+@implementation FullscreenMenubarTracker |
+ |
+@synthesize state = state_; |
+@synthesize menubarFraction = menubarFraction_; |
+ |
+- (id)initWithFullscreenToolbarLayoutManager: |
+ (FullscreenToolbarLayoutManager*)owner { |
+ if ((self = [super init])) { |
+ owner_ = owner; |
+ browserController_ = owner_->browser_window_controller(); |
+ state_ = FullscreenMenubarState::HIDDEN; |
+ } |
+ |
+ // Install the Carbon event handler for the menubar show, hide and |
+ // undocumented reveal event. |
+ EventTypeSpec eventSpecs[3]; |
+ |
+ eventSpecs[0].eventClass = kEventClassMenu; |
+ eventSpecs[0].eventKind = kMenuBarRevealEventKind; |
+ |
+ eventSpecs[1].eventClass = kEventClassMenu; |
+ eventSpecs[1].eventKind = kEventMenuBarShown; |
+ |
+ eventSpecs[2].eventClass = kEventClassMenu; |
+ eventSpecs[2].eventKind = kEventMenuBarHidden; |
+ |
+ InstallApplicationEventHandler(NewEventHandlerUPP(&MenuBarRevealHandler), 3, |
+ eventSpecs, self, &menuBarTrackingHandler_); |
+ |
+ // Register for Active Space change notifications. |
+ [[[NSWorkspace sharedWorkspace] notificationCenter] |
+ addObserver:self |
+ selector:@selector(activeSpaceDidChange:) |
+ name:NSWorkspaceActiveSpaceDidChangeNotification |
+ object:nil]; |
+ |
+ return self; |
+} |
+ |
+- (void)dealloc { |
+ RemoveEventHandler(menuBarTrackingHandler_); |
+ [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self]; |
+ |
+ [super dealloc]; |
+} |
+ |
+- (CGFloat)menubarFraction { |
+ return menubarFraction_; |
+} |
+ |
+- (void)setMenubarProgress:(CGFloat)progress { |
+ if (![browserController_ isInAnyFullscreenMode] || |
+ [browserController_ isFullscreenTransitionInProgress]) { |
+ return; |
+ } |
+ |
+ // If the menubarFraction increases, check if we are in the right screen |
+ // so that the toolbar is not revealed on the wrong screen. |
+ if (![self isMouseOnScreen] && progress > menubarFraction_) |
+ return; |
+ |
+ // Ignore the menubarFraction changes if the Space is inactive. |
+ if (![[browserController_ window] isOnActiveSpace]) |
+ return; |
+ |
+ if (base::mac::IsCGFloatEqual(progress, kShowFraction)) |
+ state_ = FullscreenMenubarState::SHOWN; |
+ else if (base::mac::IsCGFloatEqual(progress, kHideFraction)) |
+ state_ = FullscreenMenubarState::HIDDEN; |
+ else if (progress < menubarFraction_) |
+ state_ = FullscreenMenubarState::HIDING; |
+ else if (progress > menubarFraction_) |
+ state_ = FullscreenMenubarState::SHOWING; |
+ |
+ menubarFraction_ = progress; |
+ |
+ owner_->Layout(); |
+} |
+ |
+- (BOOL)isMouseOnScreen { |
+ return NSMouseInRect([NSEvent mouseLocation], |
+ [[browserController_ window] screen].frame, false); |
+} |
+ |
+- (void)activeSpaceDidChange:(NSNotification*)notification { |
+ menubarFraction_ = kHideFraction; |
+ state_ = FullscreenMenubarState::HIDDEN; |
+ owner_->Layout(); |
+} |
+ |
+@end |