Chromium Code Reviews| 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..3f6deefc8be0a3ef3e5b2b85ce21301fbbddf8d9 |
| --- /dev/null |
| +++ b/chrome/browser/ui/cocoa/fullscreen/fullscreen_menubar_tracker.mm |
| @@ -0,0 +1,154 @@ |
| +// 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" |
| + |
| +#include <Carbon/Carbon.h> |
| + |
|
Robert Sesek
2016/10/19 21:06:52
#include "base/macros.h"
spqchan
2016/10/19 21:44:16
Done.
|
| +#import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| +#import "chrome/browser/ui/cocoa/fullscreen_toolbar_controller.h" |
| +#include "ui/base/cocoa/appkit_utils.h" |
| + |
| +namespace { |
| + |
| +// The event kind value for a undocumented menubar show/hide Carbon event. |
| +const CGFloat kMenuBarRevealEventKind = 2004; |
| + |
| +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 > 0.0 && revealFraction < 1.0) |
| + [self setMenubarProgress:revealFraction]; |
| + } else if (GetEventKind(event) == kEventMenuBarShown) { |
| + [self setMenubarProgress:1.0]; |
| + } else { |
| + [self setMenubarProgress:0.0]; |
| + } |
| + |
| + return CallNextEventHandler(handler, event); |
| +} |
| + |
| +} // end namespace |
| + |
| +@interface FullscreenMenubarTracker () { |
| + // Our owner. |
| + FullscreenToolbarController* owner_; // weak |
| + |
| + // The window's controller. |
| + BrowserWindowController* browserWindowController_; // weak |
| + |
| + // A Carbon event handler that tracks the revealed fraction of the menubar. |
| + 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_; |
| + |
| +- (instancetype)initWithFullscreenToolbarController: |
| + (FullscreenToolbarController*)owner { |
| + if ((self = [super init])) { |
| + owner_ = owner; |
| + browserWindowController_ = [owner_ browserWindowController]; |
| + 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), |
| + arraysize(eventSpecs), 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 (![browserWindowController_ isInAnyFullscreenMode] || |
| + [browserWindowController_ 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 (![[browserWindowController_ window] isOnActiveSpace]) |
| + return; |
| + |
| + if (ui::IsCGFloatEqual(progress, 1.0)) |
| + state_ = FullscreenMenubarState::SHOWN; |
| + else if (ui::IsCGFloatEqual(progress, 0.0)) |
| + state_ = FullscreenMenubarState::HIDDEN; |
| + else if (progress < menubarFraction_) |
| + state_ = FullscreenMenubarState::HIDING; |
| + else if (progress > menubarFraction_) |
| + state_ = FullscreenMenubarState::SHOWING; |
| + |
| + menubarFraction_ = progress; |
| + |
| + [owner_ updateToolbar]; |
| +} |
| + |
| +- (BOOL)isMouseOnScreen { |
| + return NSMouseInRect([NSEvent mouseLocation], |
| + [[browserWindowController_ window] screen].frame, false); |
| +} |
| + |
| +- (void)activeSpaceDidChange:(NSNotification*)notification { |
| + menubarFraction_ = 0.0; |
| + state_ = FullscreenMenubarState::HIDDEN; |
| + [owner_ updateToolbar]; |
| +} |
| + |
| +@end |