| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_menubar_tracker.h" |
| 6 |
| 7 #include <Carbon/Carbon.h> |
| 8 |
| 9 #include "base/macros.h" |
| 10 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| 11 #import "chrome/browser/ui/cocoa/fullscreen_toolbar_controller.h" |
| 12 #include "ui/base/cocoa/appkit_utils.h" |
| 13 |
| 14 namespace { |
| 15 |
| 16 // The event kind value for a undocumented menubar show/hide Carbon event. |
| 17 const CGFloat kMenuBarRevealEventKind = 2004; |
| 18 |
| 19 OSStatus MenuBarRevealHandler(EventHandlerCallRef handler, |
| 20 EventRef event, |
| 21 void* context) { |
| 22 FullscreenMenubarTracker* self = |
| 23 static_cast<FullscreenMenubarTracker*>(context); |
| 24 |
| 25 // If Chrome has multiple fullscreen windows in their own space, the Handler |
| 26 // becomes flaky and might start receiving kMenuBarRevealEventKind events |
| 27 // from another space. Since the menubar in the another space is in either a |
| 28 // shown or hidden state, it will give us a reveal fraction of 0.0 or 1.0. |
| 29 // As such, we should ignore the kMenuBarRevealEventKind event if it gives |
| 30 // us a fraction of 0.0 or 1.0, and rely on kEventMenuBarShown and |
| 31 // kEventMenuBarHidden to set these values. |
| 32 if (GetEventKind(event) == kMenuBarRevealEventKind) { |
| 33 CGFloat revealFraction = 0; |
| 34 GetEventParameter(event, FOUR_CHAR_CODE('rvlf'), typeCGFloat, NULL, |
| 35 sizeof(CGFloat), NULL, &revealFraction); |
| 36 if (revealFraction > 0.0 && revealFraction < 1.0) |
| 37 [self setMenubarProgress:revealFraction]; |
| 38 } else if (GetEventKind(event) == kEventMenuBarShown) { |
| 39 [self setMenubarProgress:1.0]; |
| 40 } else { |
| 41 [self setMenubarProgress:0.0]; |
| 42 } |
| 43 |
| 44 return CallNextEventHandler(handler, event); |
| 45 } |
| 46 |
| 47 } // end namespace |
| 48 |
| 49 @interface FullscreenMenubarTracker () { |
| 50 // Our owner. |
| 51 FullscreenToolbarController* owner_; // weak |
| 52 |
| 53 // The window's controller. |
| 54 BrowserWindowController* browserWindowController_; // weak |
| 55 |
| 56 // A Carbon event handler that tracks the revealed fraction of the menubar. |
| 57 EventHandlerRef menubarTrackingHandler_; |
| 58 } |
| 59 |
| 60 // Returns YES if the mouse is on the same screen as the window. |
| 61 - (BOOL)isMouseOnScreen; |
| 62 |
| 63 @end |
| 64 |
| 65 @implementation FullscreenMenubarTracker |
| 66 |
| 67 @synthesize state = state_; |
| 68 @synthesize menubarFraction = menubarFraction_; |
| 69 |
| 70 - (instancetype)initWithFullscreenToolbarController: |
| 71 (FullscreenToolbarController*)owner { |
| 72 if ((self = [super init])) { |
| 73 owner_ = owner; |
| 74 browserWindowController_ = [owner_ browserWindowController]; |
| 75 state_ = FullscreenMenubarState::HIDDEN; |
| 76 |
| 77 // Install the Carbon event handler for the menubar show, hide and |
| 78 // undocumented reveal event. |
| 79 EventTypeSpec eventSpecs[3]; |
| 80 |
| 81 eventSpecs[0].eventClass = kEventClassMenu; |
| 82 eventSpecs[0].eventKind = kMenuBarRevealEventKind; |
| 83 |
| 84 eventSpecs[1].eventClass = kEventClassMenu; |
| 85 eventSpecs[1].eventKind = kEventMenuBarShown; |
| 86 |
| 87 eventSpecs[2].eventClass = kEventClassMenu; |
| 88 eventSpecs[2].eventKind = kEventMenuBarHidden; |
| 89 |
| 90 InstallApplicationEventHandler(NewEventHandlerUPP(&MenuBarRevealHandler), |
| 91 arraysize(eventSpecs), eventSpecs, self, |
| 92 &menubarTrackingHandler_); |
| 93 |
| 94 // Register for Active Space change notifications. |
| 95 [[[NSWorkspace sharedWorkspace] notificationCenter] |
| 96 addObserver:self |
| 97 selector:@selector(activeSpaceDidChange:) |
| 98 name:NSWorkspaceActiveSpaceDidChangeNotification |
| 99 object:nil]; |
| 100 } |
| 101 return self; |
| 102 } |
| 103 |
| 104 - (void)dealloc { |
| 105 RemoveEventHandler(menubarTrackingHandler_); |
| 106 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self]; |
| 107 |
| 108 [super dealloc]; |
| 109 } |
| 110 |
| 111 - (CGFloat)menubarFraction { |
| 112 return menubarFraction_; |
| 113 } |
| 114 |
| 115 - (void)setMenubarProgress:(CGFloat)progress { |
| 116 if (![browserWindowController_ isInAnyFullscreenMode] || |
| 117 [browserWindowController_ isFullscreenTransitionInProgress]) { |
| 118 return; |
| 119 } |
| 120 |
| 121 // If the menubarFraction increases, check if we are in the right screen |
| 122 // so that the toolbar is not revealed on the wrong screen. |
| 123 if (![self isMouseOnScreen] && progress > menubarFraction_) |
| 124 return; |
| 125 |
| 126 // Ignore the menubarFraction changes if the Space is inactive. |
| 127 if (![[browserWindowController_ window] isOnActiveSpace]) |
| 128 return; |
| 129 |
| 130 if (ui::IsCGFloatEqual(progress, 1.0)) |
| 131 state_ = FullscreenMenubarState::SHOWN; |
| 132 else if (ui::IsCGFloatEqual(progress, 0.0)) |
| 133 state_ = FullscreenMenubarState::HIDDEN; |
| 134 else if (progress < menubarFraction_) |
| 135 state_ = FullscreenMenubarState::HIDING; |
| 136 else if (progress > menubarFraction_) |
| 137 state_ = FullscreenMenubarState::SHOWING; |
| 138 |
| 139 menubarFraction_ = progress; |
| 140 |
| 141 [owner_ updateToolbar]; |
| 142 } |
| 143 |
| 144 - (BOOL)isMouseOnScreen { |
| 145 return NSMouseInRect([NSEvent mouseLocation], |
| 146 [[browserWindowController_ window] screen].frame, false); |
| 147 } |
| 148 |
| 149 - (void)activeSpaceDidChange:(NSNotification*)notification { |
| 150 menubarFraction_ = 0.0; |
| 151 state_ = FullscreenMenubarState::HIDDEN; |
| 152 [owner_ updateToolbar]; |
| 153 } |
| 154 |
| 155 @end |
| OLD | NEW |