Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/fullscreen_toolbar_controller.h" | 5 #import "chrome/browser/ui/cocoa/fullscreen_toolbar_controller.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #import "base/mac/mac_util.h" | 10 #import "base/mac/mac_util.h" |
| 11 #include "base/mac/sdk_forward_declarations.h" | 11 #include "base/mac/sdk_forward_declarations.h" |
| 12 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 12 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| 13 #include "chrome/common/chrome_switches.h" | 13 #include "chrome/common/chrome_switches.h" |
| 14 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h " | 14 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h " |
| 15 #import "ui/base/cocoa/nsview_additions.h" | 15 #import "ui/base/cocoa/nsview_additions.h" |
| 16 #import "ui/base/cocoa/tracking_area.h" | |
| 16 | 17 |
| 17 namespace { | 18 namespace { |
| 18 | 19 |
| 19 // The activation zone for the main menu is 4 pixels high; if we make it any | 20 // The duration of the toolbar show/hide animation. |
| 20 // smaller, then the menu can be made to appear without the bar sliding down. | 21 const NSTimeInterval kDropdownAnimationDuration = 0.20; |
| 21 const NSTimeInterval kDropdownAnimationDuration = 0.12; | |
| 22 | 22 |
| 23 // The duration the toolbar is revealed for tab strip changes. | 23 // If the fullscreen toolbar is hidden, it is difficult for the user to see |
| 24 const NSTimeInterval kDropdownForTabStripChangesDuration = 0.75; | 24 // changes in the tabstrip. As a result, if a tab is inserted or the current |
| 25 // tab switched to a new one, the toolbar must animate in and out to display | |
| 26 // the tabstrip changes to the user. The animation drops down the toolbar and | |
| 27 // then wait for 0.75 seconds before it hides the toolbar. | |
| 28 const NSTimeInterval kTabStripChangesDelay = 0.75; | |
| 29 | |
| 30 // Additional height threshold added at the toolbar's bottom. This is to mimic | |
| 31 // threshold the mouse position needs to be at before the menubar automatically | |
| 32 // hides. | |
| 33 const CGFloat kTrackingAreaAdditionalThreshold = 20; | |
| 25 | 34 |
| 26 // The event kind value for a undocumented menubar show/hide Carbon event. | 35 // The event kind value for a undocumented menubar show/hide Carbon event. |
| 27 const CGFloat kMenuBarRevealEventKind = 2004; | 36 const CGFloat kMenuBarRevealEventKind = 2004; |
| 28 | 37 |
| 29 // The amount by which the floating bar is offset downwards (to avoid the menu) | 38 // The amount by which the floating bar is offset downwards (to avoid the menu) |
| 30 // when the toolbar is hidden. (We can't use |-[NSMenu menuBarHeight]| since it | 39 // when the toolbar is hidden. (We can't use |-[NSMenu menuBarHeight]| since it |
| 31 // returns 0 when the menu bar is hidden.) | 40 // returns 0 when the menu bar is hidden.) |
| 32 const CGFloat kFloatingBarVerticalOffset = 22; | 41 const CGFloat kFloatingBarVerticalOffset = 22; |
| 33 | 42 |
| 34 OSStatus MenuBarRevealHandler(EventHandlerCallRef handler, | 43 OSStatus MenuBarRevealHandler(EventHandlerCallRef handler, |
| 35 EventRef event, | 44 EventRef event, |
| 36 void* context) { | 45 void* context) { |
| 37 FullscreenToolbarController* self = | 46 FullscreenToolbarController* self = |
| 38 static_cast<FullscreenToolbarController*>(context); | 47 static_cast<FullscreenToolbarController*>(context); |
| 39 | 48 |
| 40 // If Chrome has multiple fullscreen windows in their own space, the Handler | 49 // If Chrome has multiple fullscreen windows in their own space, the Handler |
| 41 // becomes flaky and might start receiving kMenuBarRevealEventKind events | 50 // becomes flaky and might start receiving kMenuBarRevealEventKind events |
| 42 // from another space. Since the menubar in the another space is in either a | 51 // from another space. Since the menubar in the another space is in either a |
| 43 // shown or hidden state, it will give us a reveal fraction of 0.0 or 1.0. | 52 // shown or hidden state, it will give us a reveal fraction of 0.0 or 1.0. |
| 44 // As such, we should ignore the kMenuBarRevealEventKind event if it gives | 53 // As such, we should ignore the kMenuBarRevealEventKind event if it gives |
| 45 // us a fraction of 0.0 or 1.0, and rely on kEventMenuBarShown and | 54 // us a fraction of 0.0 or 1.0, and rely on kEventMenuBarShown and |
| 46 // kEventMenuBarHidden to set these values. | 55 // kEventMenuBarHidden to set these values. |
| 47 if (![self isFullscreenTransitionInProgress]) { | 56 if (![self isFullscreenTransitionInProgress] && [self isInFullscreen]) { |
| 48 if (GetEventKind(event) == kMenuBarRevealEventKind) { | 57 if (GetEventKind(event) == kMenuBarRevealEventKind) { |
| 49 CGFloat revealFraction = 0; | 58 CGFloat revealFraction = 0; |
| 50 GetEventParameter(event, FOUR_CHAR_CODE('rvlf'), typeCGFloat, NULL, | 59 GetEventParameter(event, FOUR_CHAR_CODE('rvlf'), typeCGFloat, NULL, |
| 51 sizeof(CGFloat), NULL, &revealFraction); | 60 sizeof(CGFloat), NULL, &revealFraction); |
| 52 if (revealFraction > 0.0 && revealFraction < 1.0) | 61 if (revealFraction > 0.0 && revealFraction < 1.0) |
| 53 [self setMenuBarRevealProgress:revealFraction]; | 62 [self setMenuBarRevealProgress:revealFraction]; |
| 54 } else if (GetEventKind(event) == kEventMenuBarShown) { | 63 } else if (GetEventKind(event) == kEventMenuBarShown) { |
| 55 [self setMenuBarRevealProgress:1.0]; | 64 [self setMenuBarRevealProgress:1.0]; |
| 56 } else { | 65 } else { |
| 57 [self setMenuBarRevealProgress:0.0]; | 66 [self setMenuBarRevealProgress:0.0]; |
| 58 } | 67 } |
| 59 } | 68 } |
| 60 | 69 |
| 61 return CallNextEventHandler(handler, event); | 70 return CallNextEventHandler(handler, event); |
| 62 } | 71 } |
| 63 | 72 |
| 64 } // end namespace | 73 } // end namespace |
| 65 | 74 |
| 66 // Helper class to manage animations for the dropdown bar. Calls | 75 // Helper class to manage animations for the dropdown bar. Calls |
| 67 // [FullscreenToolbarController changeToolbarFraction] once per | 76 // [FullscreenToolbarController changeToolbarFraction] once per |
| 68 // animation step. | 77 // animation step. |
| 69 @interface DropdownAnimation : NSAnimation { | 78 @interface DropdownAnimation : NSAnimation { |
| 70 @private | 79 @private |
| 71 FullscreenToolbarController* controller_; | 80 FullscreenToolbarController* controller_; |
| 72 CGFloat startFraction_; | 81 CGFloat startFraction_; |
| 73 CGFloat endFraction_; | 82 CGFloat endFraction_; |
| 83 CGFloat toolbarFraction_; | |
| 74 } | 84 } |
| 75 | 85 |
| 76 @property(readonly, nonatomic) CGFloat startFraction; | |
| 77 @property(readonly, nonatomic) CGFloat endFraction; | 86 @property(readonly, nonatomic) CGFloat endFraction; |
| 87 @property(readonly, nonatomic) CGFloat toolbarFraction; | |
| 78 | 88 |
| 79 // Designated initializer. Asks |controller| for the current shown fraction, so | 89 // Designated initializer. Asks |controller| for the current shown fraction, so |
| 80 // if the bar is already partially shown or partially hidden, the animation | 90 // if the bar is already partially shown or partially hidden, the animation |
| 81 // duration may be less than |fullDuration|. | 91 // duration may be less than |fullDuration|. |
| 82 - (id)initWithFraction:(CGFloat)fromFraction | 92 - (id)initWithFraction:(CGFloat)fromFraction |
| 83 fullDuration:(CGFloat)fullDuration | 93 fullDuration:(CGFloat)fullDuration |
| 84 animationCurve:(NSAnimationCurve)animationCurve | 94 animationCurve:(NSAnimationCurve)animationCurve |
| 85 controller:(FullscreenToolbarController*)controller; | 95 controller:(FullscreenToolbarController*)controller; |
| 86 | 96 |
| 87 @end | 97 @end |
| 88 | 98 |
| 89 @implementation DropdownAnimation | 99 @implementation DropdownAnimation |
| 90 | 100 |
| 91 @synthesize startFraction = startFraction_; | |
| 92 @synthesize endFraction = endFraction_; | 101 @synthesize endFraction = endFraction_; |
| 102 @synthesize toolbarFraction = toolbarFraction_; | |
| 93 | 103 |
| 94 - (id)initWithFraction:(CGFloat)toFraction | 104 - (id)initWithFraction:(CGFloat)toFraction |
| 95 fullDuration:(CGFloat)fullDuration | 105 fullDuration:(CGFloat)fullDuration |
| 96 animationCurve:(NSAnimationCurve)animationCurve | 106 animationCurve:(NSAnimationCurve)animationCurve |
| 97 controller:(FullscreenToolbarController*)controller { | 107 controller:(FullscreenToolbarController*)controller { |
| 98 // Calculate the effective duration, based on the current shown fraction. | 108 // Calculate the effective duration, based on the current shown fraction. |
| 99 DCHECK(controller); | 109 DCHECK(controller); |
| 100 CGFloat fromFraction = controller.toolbarFraction; | 110 CGFloat fromFraction = [controller toolbarFraction]; |
| 101 CGFloat effectiveDuration = fabs(fullDuration * (fromFraction - toFraction)); | 111 CGFloat effectiveDuration = fabs(fullDuration * (fromFraction - toFraction)); |
| 102 | 112 |
| 103 if ((self = [super gtm_initWithDuration:effectiveDuration | 113 if ((self = [super gtm_initWithDuration:effectiveDuration |
| 104 eventMask:NSLeftMouseDownMask | 114 eventMask:NSLeftMouseDownMask |
| 105 animationCurve:animationCurve])) { | 115 animationCurve:animationCurve])) { |
| 106 startFraction_ = fromFraction; | 116 startFraction_ = fromFraction; |
| 107 endFraction_ = toFraction; | 117 endFraction_ = toFraction; |
| 108 controller_ = controller; | 118 controller_ = controller; |
| 109 } | 119 } |
| 110 return self; | 120 return self; |
| 111 } | 121 } |
| 112 | 122 |
| 113 // Called once per animation step. Overridden to change the floating bar's | 123 // Called once per animation step. Overridden to change the floating bar's |
| 114 // position based on the animation's progress. | 124 // position based on the animation's progress. |
| 115 - (void)setCurrentProgress:(NSAnimationProgress)progress { | 125 - (void)setCurrentProgress:(NSAnimationProgress)progress { |
| 116 CGFloat fraction = | 126 toolbarFraction_ = |
| 117 startFraction_ + (progress * (endFraction_ - startFraction_)); | 127 startFraction_ + (progress * (endFraction_ - startFraction_)); |
| 118 [controller_ changeToolbarFraction:fraction]; | 128 [controller_ updateToolbar]; |
| 119 } | 129 } |
| 120 | 130 |
| 121 @end | 131 @end |
| 122 | 132 |
| 123 @interface FullscreenToolbarController (PrivateMethods) | 133 @interface FullscreenToolbarController (PrivateMethods) |
| 124 | 134 |
| 125 // Updates the visibility of the menu bar and the dock. | 135 // Updates the visibility of the menu bar and the dock. |
| 126 - (void)updateMenuBarAndDockVisibility; | 136 - (void)updateMenuBarAndDockVisibility; |
| 127 | 137 |
| 138 // Methods to set up or remove the tracking area. | |
| 139 - (void)setupTrackingArea; | |
| 140 - (void)removeTrackingAreaIfNecessary; | |
| 141 | |
| 142 // Returns YES if the mouse is inside the tracking area. | |
| 143 - (BOOL)mouseInsideTrackingArea; | |
| 144 | |
| 128 // Whether the current screen is expected to have a menu bar, regardless of | 145 // Whether the current screen is expected to have a menu bar, regardless of |
| 129 // current visibility of the menu bar. | 146 // current visibility of the menu bar. |
| 130 - (BOOL)doesScreenHaveMenuBar; | 147 - (BOOL)doesScreenHaveMenuBar; |
| 131 | 148 |
| 132 // Returns YES if the window is on the primary screen. | 149 // Returns YES if the window is on the primary screen. |
| 133 - (BOOL)isWindowOnPrimaryScreen; | 150 - (BOOL)isWindowOnPrimaryScreen; |
| 134 | 151 |
| 135 // Returns |kFullScreenModeHideAll| when the overlay is hidden and | 152 // Returns |kFullScreenModeHideAll| when the overlay is hidden and |
| 136 // |kFullScreenModeHideDock| when the overlay is shown. | 153 // |kFullScreenModeHideDock| when the overlay is shown. |
| 137 - (base::mac::FullScreenMode)desiredSystemFullscreenMode; | 154 - (base::mac::FullScreenMode)desiredSystemFullscreenMode; |
| 138 | 155 |
| 139 // Change the overlay to the given fraction, with or without animation. Only | 156 // Animate the overlay to the given visibility with animation. If |visible| |
| 140 // guaranteed to work properly with |fraction == 0| or |fraction == 1|. This | 157 // is true, animate the toolbar to a fraction of 1.0. Otherwise it's 0.0. |
| 141 // performs the show/hide (animation) immediately. It does not touch the timers. | 158 - (void)animateToolbarVisibility:(BOOL)visible; |
| 142 - (void)changeOverlayToFraction:(CGFloat)fraction withAnimation:(BOOL)animate; | |
| 143 | 159 |
| 144 // Cancels the timer for hiding the floating bar. | 160 // Cancels the timer for hiding the floating bar. |
| 145 - (void)cancelHideTimer; | 161 - (void)cancelHideTimer; |
| 146 | 162 |
| 147 // Methods called when the hide timers fire. Do not call directly. | 163 // Methods called when the hide timers fire. Do not call directly. |
| 148 - (void)hideTimerFire:(NSTimer*)timer; | 164 - (void)hideTimerFire:(NSTimer*)timer; |
| 149 | 165 |
| 150 // Stops any running animations, etc. | 166 // Stops any running animations, etc. |
| 151 - (void)cleanup; | 167 - (void)cleanup; |
| 152 | 168 |
| 153 // Shows and hides the UI associated with this window being active (having main | |
| 154 // status). This includes hiding the menu bar. These functions are called when | |
| 155 // the window gains or loses main status as well as in |-cleanup|. | |
| 156 - (void)showActiveWindowUI; | |
| 157 - (void)hideActiveWindowUI; | |
| 158 | |
| 159 // Whether the menu bar should be shown in immersive fullscreen for the screen | 169 // Whether the menu bar should be shown in immersive fullscreen for the screen |
| 160 // that contains the window. | 170 // that contains the window. |
| 161 - (BOOL)shouldShowMenubarInImmersiveFullscreen; | 171 - (BOOL)shouldShowMenubarInImmersiveFullscreen; |
| 162 | 172 |
| 163 @end | 173 @end |
| 164 | 174 |
| 165 @implementation FullscreenToolbarController | 175 @implementation FullscreenToolbarController |
| 166 | 176 |
| 167 @synthesize slidingStyle = slidingStyle_; | 177 @synthesize slidingStyle = slidingStyle_; |
| 168 @synthesize toolbarFraction = toolbarFraction_; | |
| 169 | 178 |
| 170 - (id)initWithBrowserController:(BrowserWindowController*)controller | 179 - (id)initWithBrowserController:(BrowserWindowController*)controller |
| 171 style:(fullscreen_mac::SlidingStyle)style { | 180 style:(fullscreen_mac::SlidingStyle)style { |
| 172 if ((self = [super init])) { | 181 if ((self = [super init])) { |
| 173 browserController_ = controller; | 182 browserController_ = controller; |
| 174 systemFullscreenMode_ = base::mac::kFullScreenModeNormal; | 183 systemFullscreenMode_ = base::mac::kFullScreenModeNormal; |
| 175 slidingStyle_ = style; | 184 slidingStyle_ = style; |
| 176 } | 185 } |
| 177 | 186 |
| 178 // Install the Carbon event handler for the menubar show, hide and | 187 // Install the Carbon event handler for the menubar show, hide and |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 193 | 202 |
| 194 return self; | 203 return self; |
| 195 } | 204 } |
| 196 | 205 |
| 197 - (void)dealloc { | 206 - (void)dealloc { |
| 198 RemoveEventHandler(menuBarTrackingHandler_); | 207 RemoveEventHandler(menuBarTrackingHandler_); |
| 199 DCHECK(!inFullscreenMode_); | 208 DCHECK(!inFullscreenMode_); |
| 200 [super dealloc]; | 209 [super dealloc]; |
| 201 } | 210 } |
| 202 | 211 |
| 203 - (void)setupFullscreenToolbarWithDropdown:(BOOL)showDropdown { | 212 - (void)setupFullscreenToolbarForContentView:(NSView*)contentView { |
| 204 DCHECK(!inFullscreenMode_); | 213 DCHECK(!inFullscreenMode_); |
| 214 contentView_ = contentView; | |
| 205 inFullscreenMode_ = YES; | 215 inFullscreenMode_ = YES; |
| 206 [self changeToolbarFraction:(showDropdown ? 1 : 0)]; | 216 |
| 207 [self updateMenuBarAndDockVisibility]; | 217 [self updateMenuBarAndDockVisibility]; |
| 208 | 218 |
| 209 // Register for notifications. Self is removed as an observer in |-cleanup|. | 219 // Register for notifications. Self is removed as an observer in |-cleanup|. |
| 210 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; | 220 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
| 211 NSWindow* window = [browserController_ window]; | 221 NSWindow* window = [browserController_ window]; |
| 212 | 222 |
| 213 [nc addObserver:self | 223 [nc addObserver:self |
| 214 selector:@selector(windowDidBecomeMain:) | 224 selector:@selector(windowDidBecomeMain:) |
| 215 name:NSWindowDidBecomeMainNotification | 225 name:NSWindowDidBecomeMainNotification |
| 216 object:window]; | 226 object:window]; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 230 | 240 |
| 231 - (void)windowDidChangeScreen:(NSNotification*)notification { | 241 - (void)windowDidChangeScreen:(NSNotification*)notification { |
| 232 [browserController_ resizeFullscreenWindow]; | 242 [browserController_ resizeFullscreenWindow]; |
| 233 } | 243 } |
| 234 | 244 |
| 235 - (void)windowDidMove:(NSNotification*)notification { | 245 - (void)windowDidMove:(NSNotification*)notification { |
| 236 [browserController_ resizeFullscreenWindow]; | 246 [browserController_ resizeFullscreenWindow]; |
| 237 } | 247 } |
| 238 | 248 |
| 239 - (void)windowDidBecomeMain:(NSNotification*)notification { | 249 - (void)windowDidBecomeMain:(NSNotification*)notification { |
| 240 [self showActiveWindowUI]; | 250 [self updateMenuBarAndDockVisibility]; |
| 241 } | 251 } |
| 242 | 252 |
| 243 - (void)windowDidResignMain:(NSNotification*)notification { | 253 - (void)windowDidResignMain:(NSNotification*)notification { |
| 244 [self hideActiveWindowUI]; | 254 [self updateMenuBarAndDockVisibility]; |
| 245 } | 255 } |
| 246 | 256 |
| 247 - (CGFloat)floatingBarVerticalOffset { | 257 - (CGFloat)floatingBarVerticalOffset { |
| 248 return kFloatingBarVerticalOffset; | 258 return kFloatingBarVerticalOffset; |
| 249 } | 259 } |
| 250 | 260 |
| 251 - (void)ensureOverlayShownWithAnimation:(BOOL)animate { | 261 - (void)ensureOverlayShownWithAnimation:(BOOL)animate { |
| 252 if (!inFullscreenMode_) | 262 if (!inFullscreenMode_) |
| 253 return; | 263 return; |
| 254 | 264 |
| 255 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) | 265 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) |
| 256 return; | 266 return; |
| 257 | 267 |
| 258 if (self.slidingStyle == fullscreen_mac::OMNIBOX_TABS_PRESENT) | 268 if (self.slidingStyle != fullscreen_mac::OMNIBOX_TABS_HIDDEN) |
| 259 return; | 269 return; |
| 260 | 270 |
| 261 [self cancelHideTimer]; | 271 [self cancelHideTimer]; |
| 262 [self changeOverlayToFraction:1 withAnimation:animate]; | 272 [self animateToolbarVisibility:YES]; |
| 263 } | 273 } |
| 264 | 274 |
| 265 - (void)ensureOverlayHiddenWithAnimation:(BOOL)animate { | 275 - (void)ensureOverlayHiddenWithAnimation:(BOOL)animate { |
| 266 if (!inFullscreenMode_) | 276 if (!inFullscreenMode_) |
| 267 return; | 277 return; |
| 268 | 278 |
| 269 if (self.slidingStyle == fullscreen_mac::OMNIBOX_TABS_PRESENT) | 279 if (self.slidingStyle != fullscreen_mac::OMNIBOX_TABS_HIDDEN) |
| 270 return; | 280 return; |
| 271 | 281 |
| 272 [self cancelHideTimer]; | 282 [self cancelHideTimer]; |
| 273 [self changeOverlayToFraction:0 withAnimation:animate]; | 283 [self animateToolbarVisibility:NO]; |
| 274 } | 284 } |
| 275 | 285 |
| 276 - (void)cancelAnimationAndTimer { | 286 - (void)cancelAnimationAndTimer { |
| 277 [self cancelHideTimer]; | 287 [self cancelHideTimer]; |
| 278 [currentAnimation_ stopAnimation]; | 288 [currentAnimation_ stopAnimation]; |
| 279 currentAnimation_.reset(); | 289 currentAnimation_.reset(); |
| 280 } | 290 } |
| 281 | 291 |
| 282 - (void)revealToolbarForTabStripChanges { | 292 - (void)revealToolbarForTabStripChanges { |
|
erikchen
2016/08/24 23:52:58
nit: Having a method named "foo" which changes the
spqchan
2016/08/26 00:46:30
Done.
| |
| 283 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | 293 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 284 switches::kEnableFullscreenToolbarReveal)) { | 294 switches::kEnableFullscreenToolbarReveal)) { |
| 285 return; | 295 return; |
| 286 } | 296 } |
| 287 | 297 |
| 288 revealToolbarForTabStripChanges_ = YES; | 298 // Reveal the toolbar for tabstrip changes if the toolbar |
| 289 [self ensureOverlayShownWithAnimation:YES]; | 299 // isn't shown. |
| 300 if ([self toolbarFraction] == 0.0) { | |
|
erikchen
2016/08/24 23:52:58
nit: You have a lot of double comparisons in your
spqchan
2016/08/26 00:46:30
Added IsCGFloatEqual(). Is this what you mean?
erikchen
2016/08/26 00:56:58
Ideally, we would be able to avoid any type of flo
| |
| 301 revealToolbarForTabStripChanges_ = YES; | |
| 302 [self ensureOverlayShownWithAnimation:YES]; | |
| 303 } | |
| 290 } | 304 } |
| 291 | 305 |
| 292 - (void)setSystemFullscreenModeTo:(base::mac::FullScreenMode)mode { | 306 - (void)setSystemFullscreenModeTo:(base::mac::FullScreenMode)mode { |
| 293 if (mode == systemFullscreenMode_) | 307 if (mode == systemFullscreenMode_) |
| 294 return; | 308 return; |
| 295 if (systemFullscreenMode_ == base::mac::kFullScreenModeNormal) | 309 if (systemFullscreenMode_ == base::mac::kFullScreenModeNormal) |
| 296 base::mac::RequestFullScreen(mode); | 310 base::mac::RequestFullScreen(mode); |
| 297 else if (mode == base::mac::kFullScreenModeNormal) | 311 else if (mode == base::mac::kFullScreenModeNormal) |
| 298 base::mac::ReleaseFullScreen(systemFullscreenMode_); | 312 base::mac::ReleaseFullScreen(systemFullscreenMode_); |
| 299 else | 313 else |
| 300 base::mac::SwitchFullScreenModes(systemFullscreenMode_, mode); | 314 base::mac::SwitchFullScreenModes(systemFullscreenMode_, mode); |
| 301 systemFullscreenMode_ = mode; | 315 systemFullscreenMode_ = mode; |
| 302 } | 316 } |
| 303 | 317 |
| 304 - (void)changeToolbarFraction:(CGFloat)fraction { | 318 - (void)mouseEntered:(NSEvent*)event { |
| 305 toolbarFraction_ = fraction; | 319 // Empty implementation. Required for CrTrackingArea. |
| 320 } | |
| 321 | |
| 322 - (void)mouseExited:(NSEvent*)event { | |
| 323 DCHECK(inFullscreenMode_); | |
| 324 | |
| 325 // If the menubar is gone, animate the toolbar out. | |
| 326 if ([event trackingArea] == trackingArea_.get()) { | |
|
erikchen
2016/08/24 23:52:58
nit: Should this be DCHECK_EQ([event trackingArea]
spqchan
2016/08/26 00:46:30
Done.
| |
| 327 if (menubarFraction_ == 0.0) | |
| 328 [self ensureOverlayHiddenWithAnimation:YES]; | |
| 329 | |
| 330 [self removeTrackingAreaIfNecessary]; | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 - (void)updateToolbar { | |
| 306 [browserController_ layoutSubviews]; | 335 [browserController_ layoutSubviews]; |
| 307 | 336 |
| 308 // In AppKit fullscreen, moving the mouse to the top of the screen toggles | 337 // In AppKit fullscreen, moving the mouse to the top of the screen toggles |
| 309 // menu visibility. Replicate the same effect for immersive fullscreen. | 338 // menu visibility. Replicate the same effect for immersive fullscreen. |
| 310 if ([browserController_ isInImmersiveFullscreen]) | 339 if ([browserController_ isInImmersiveFullscreen]) |
| 311 [self updateMenuBarAndDockVisibility]; | 340 [self updateMenuBarAndDockVisibility]; |
| 312 } | 341 } |
| 313 | 342 |
| 314 // This method works, but is fragile. | 343 // This method works, but is fragile. |
| 315 // | 344 // |
| 316 // It gets used during view layout, which sometimes needs to be done at the | 345 // It gets used during view layout, which sometimes needs to be done at the |
| 317 // beginning of an animation. As such, this method needs to reflect the | 346 // beginning of an animation. As such, this method needs to reflect the |
| 318 // menubarOffset expected at the end of the animation. This information is not | 347 // menubarOffset expected at the end of the animation. This information is not |
| 319 // readily available. (The layout logic needs a refactor). | 348 // readily available. (The layout logic needs a refactor). |
| 320 // | 349 // |
| 321 // For AppKit Fullscreen, the menubar always starts hidden, and | 350 // For AppKit Fullscreen, the menubar always starts hidden, and |
| 322 // menubarFraction_ always starts at 0, so the logic happens to work. For | 351 // menubarFraction_ always starts at 0, so the logic happens to work. For |
| 323 // Immersive Fullscreen, this class controls the visibility of the menu bar, so | 352 // Immersive Fullscreen, this class controls the visibility of the menu bar, so |
| 324 // the logic is correct and not fragile. | 353 // the logic is correct and not fragile. |
| 325 - (CGFloat)menubarOffset { | 354 - (CGFloat)menubarOffset { |
| 326 if ([browserController_ isInAppKitFullscreen]) | 355 if ([browserController_ isInAppKitFullscreen]) |
| 327 return -std::floor(menubarFraction_ * [self floatingBarVerticalOffset]); | 356 return -std::floor(menubarFraction_ * [self floatingBarVerticalOffset]); |
| 328 | 357 |
| 329 return [self shouldShowMenubarInImmersiveFullscreen] | 358 return [self shouldShowMenubarInImmersiveFullscreen] |
| 330 ? -[self floatingBarVerticalOffset] | 359 ? -[self floatingBarVerticalOffset] |
| 331 : 0; | 360 : 0; |
| 332 } | 361 } |
| 333 | 362 |
| 363 - (CGFloat)toolbarFraction { | |
|
erikchen
2016/08/24 23:52:58
Wow. This is amazing. Thank you.
spqchan
2016/08/26 00:46:30
Ack
| |
| 364 if ([browserController_ isBarVisibilityLockedForOwner:nil]) | |
| 365 return 1.0; | |
| 366 | |
| 367 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) | |
| 368 return 0.0; | |
| 369 | |
| 370 switch (slidingStyle_) { | |
| 371 case fullscreen_mac::OMNIBOX_TABS_PRESENT: | |
| 372 return 1.0; | |
| 373 case fullscreen_mac::OMNIBOX_TABS_NONE: | |
| 374 return 0.0; | |
| 375 case fullscreen_mac::OMNIBOX_TABS_HIDDEN: | |
| 376 if (currentAnimation_.get()) | |
| 377 return [currentAnimation_ toolbarFraction]; | |
| 378 return toolbarFractionFromMenuProgress_; | |
| 379 } | |
| 380 } | |
| 381 | |
| 334 - (BOOL)isFullscreenTransitionInProgress { | 382 - (BOOL)isFullscreenTransitionInProgress { |
| 335 return [browserController_ isFullscreenTransitionInProgress]; | 383 return [browserController_ isFullscreenTransitionInProgress]; |
| 336 } | 384 } |
| 337 | 385 |
| 386 - (BOOL)isInFullscreen { | |
| 387 return inFullscreenMode_; | |
| 388 } | |
| 389 | |
| 338 - (BOOL)isMouseOnScreen { | 390 - (BOOL)isMouseOnScreen { |
| 339 return NSMouseInRect([NSEvent mouseLocation], | 391 return NSMouseInRect([NSEvent mouseLocation], |
| 340 [[browserController_ window] screen].frame, false); | 392 [[browserController_ window] screen].frame, false); |
| 341 } | 393 } |
| 342 | 394 |
| 395 - (void)setTrackingAreaFromOverlayFrame:(NSRect)frame { | |
| 396 NSRect contentBounds = [contentView_ bounds]; | |
| 397 trackingAreaFrame_ = frame; | |
| 398 trackingAreaFrame_.origin.y -= kTrackingAreaAdditionalThreshold; | |
| 399 trackingAreaFrame_.size.height = | |
| 400 NSMaxY(contentBounds) - trackingAreaFrame_.origin.y; | |
| 401 } | |
| 402 | |
| 343 - (void)animationDidStop:(NSAnimation*)animation { | 403 - (void)animationDidStop:(NSAnimation*)animation { |
| 344 // Reset the |currentAnimation_| pointer now that the animation is over. | 404 // Reset the |currentAnimation_| pointer now that the animation is over. |
| 345 currentAnimation_.reset(); | 405 currentAnimation_.reset(); |
|
erikchen
2016/08/24 23:52:58
If -toolbarFraction is called after the animation
spqchan
2016/08/26 00:46:30
Good point.
| |
| 346 | 406 |
| 347 if (revealToolbarForTabStripChanges_) { | 407 if (revealToolbarForTabStripChanges_) { |
| 348 if (toolbarFraction_ > 0.0) { | 408 if ([self toolbarFraction] > 0.0) { |
| 349 // Set the timer to hide the toolbar. | 409 // Set the timer to hide the toolbar. |
| 350 [hideTimer_ invalidate]; | 410 [hideTimer_ invalidate]; |
| 351 hideTimer_.reset([[NSTimer | 411 hideTimer_.reset( |
| 352 scheduledTimerWithTimeInterval:kDropdownForTabStripChangesDuration | 412 [[NSTimer scheduledTimerWithTimeInterval:kTabStripChangesDelay |
| 353 target:self | 413 target:self |
| 354 selector:@selector(hideTimerFire:) | 414 selector:@selector(hideTimerFire:) |
| 355 userInfo:nil | 415 userInfo:nil |
| 356 repeats:NO] retain]); | 416 repeats:NO] retain]); |
| 357 } else { | 417 } else { |
| 358 revealToolbarForTabStripChanges_ = NO; | 418 revealToolbarForTabStripChanges_ = NO; |
| 359 } | 419 } |
| 360 } | 420 } |
| 361 } | 421 } |
| 362 | 422 |
| 363 - (void)animationDidEnd:(NSAnimation*)animation { | 423 - (void)animationDidEnd:(NSAnimation*)animation { |
| 364 [self animationDidStop:animation]; | 424 [self animationDidStop:animation]; |
| 425 [self setupTrackingArea]; | |
| 365 } | 426 } |
| 366 | 427 |
| 367 - (void)setMenuBarRevealProgress:(CGFloat)progress { | 428 - (void)setMenuBarRevealProgress:(CGFloat)progress { |
| 368 // If the menubarFraction increases, check if we are in the right screen | 429 // If the menubarFraction increases, check if we are in the right screen |
| 369 // so that the toolbar is not revealed on the wrong screen. | 430 // so that the toolbar is not revealed on the wrong screen. |
| 370 if (![self isMouseOnScreen] && progress > menubarFraction_) | 431 if (![self isMouseOnScreen] && progress > menubarFraction_) |
| 371 return; | 432 return; |
| 372 | 433 |
| 373 menubarFraction_ = progress; | 434 menubarFraction_ = progress; |
| 374 | 435 |
| 436 if (self.slidingStyle == fullscreen_mac::OMNIBOX_TABS_HIDDEN) { | |
| 437 if (menubarFraction_ == 1.0) | |
|
erikchen
2016/08/24 23:52:58
This double comparison relies on the assumption th
spqchan
2016/08/26 00:46:30
Ditto from above
| |
| 438 [self setupTrackingArea]; | |
| 439 | |
| 440 // If the menubar is disappearing from the screen, check if the mouse | |
| 441 // is still interacting with the. If it is, then don't set | |
|
erikchen
2016/08/24 23:52:58
incomplete sentence?
spqchan
2016/08/26 00:46:30
Done.
| |
| 442 // |toolbarFractionFromMenuProgress_| so that the the toolbar will remain | |
| 443 // on the screen. | |
| 444 BOOL isMenuBarDisappearing = | |
| 445 menubarFraction_ < toolbarFractionFromMenuProgress_; | |
| 446 if (!(isMenuBarDisappearing && [self mouseInsideTrackingArea])) | |
| 447 toolbarFractionFromMenuProgress_ = progress; | |
|
erikchen
2016/08/24 23:52:58
Can we separate the logic for toolbarFractionFromM
spqchan
2016/08/26 00:46:30
I already tried that. I find that having |toolbarF
erikchen
2016/08/26 00:56:58
Acknowledged.
| |
| 448 } | |
| 449 | |
| 375 // If an animation is not running, then -layoutSubviews will not be called | 450 // If an animation is not running, then -layoutSubviews will not be called |
| 376 // for each tick of the menu bar reveal. Do that manually. | 451 // for each tick of the menu bar reveal. Do that manually. |
| 377 // TODO(erikchen): The animation is janky. layoutSubviews need a refactor so | 452 // TODO(erikchen): The animation is janky. layoutSubviews need a refactor so |
| 378 // that it calls setFrameOffset: instead of setFrame: if the frame's size has | 453 // that it calls setFrameOffset: instead of setFrame: if the frame's size has |
| 379 // not changed. | 454 // not changed. |
| 380 if (!currentAnimation_.get()) { | 455 if (!currentAnimation_.get()) |
| 381 if (self.slidingStyle != fullscreen_mac::OMNIBOX_TABS_NONE) | |
| 382 toolbarFraction_ = progress; | |
| 383 [browserController_ layoutSubviews]; | 456 [browserController_ layoutSubviews]; |
| 384 } | |
| 385 } | 457 } |
| 386 | 458 |
| 387 @end | 459 @end |
| 388 | 460 |
| 389 @implementation FullscreenToolbarController (PrivateMethods) | 461 @implementation FullscreenToolbarController (PrivateMethods) |
| 390 | 462 |
| 391 - (void)updateMenuBarAndDockVisibility { | 463 - (void)updateMenuBarAndDockVisibility { |
| 392 if (![self isMouseOnScreen] || | 464 if (![self isMouseOnScreen] || |
| 393 ![browserController_ isInImmersiveFullscreen]) { | 465 ![browserController_ isInImmersiveFullscreen]) { |
| 394 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; | 466 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; |
| 395 return; | 467 return; |
| 396 } | 468 } |
| 397 | 469 |
| 398 // The screen does not have a menu bar, so there's no need to hide it. | 470 // The screen does not have a menu bar, so there's no need to hide it. |
| 399 if (![self doesScreenHaveMenuBar]) { | 471 if (![self doesScreenHaveMenuBar]) { |
| 400 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeHideDock]; | 472 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeHideDock]; |
| 401 return; | 473 return; |
| 402 } | 474 } |
| 403 | 475 |
| 404 [self setSystemFullscreenModeTo:[self desiredSystemFullscreenMode]]; | 476 [self setSystemFullscreenModeTo:[self desiredSystemFullscreenMode]]; |
| 405 } | 477 } |
| 406 | 478 |
| 479 - (void)setupTrackingArea { | |
| 480 if (trackingArea_) { | |
| 481 // If the tracking rectangle is already |trackingAreaBounds_|, quit early. | |
| 482 NSRect oldRect = [trackingArea_ rect]; | |
| 483 if (NSEqualRects(trackingAreaFrame_, oldRect)) | |
| 484 return; | |
| 485 | |
| 486 // Otherwise, remove it. | |
| 487 [self removeTrackingAreaIfNecessary]; | |
| 488 } | |
| 489 | |
| 490 // Create and add a new tracking area for |frame|. | |
| 491 trackingArea_.reset([[CrTrackingArea alloc] | |
| 492 initWithRect:trackingAreaFrame_ | |
| 493 options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | |
| 494 owner:self | |
| 495 userInfo:nil]); | |
| 496 DCHECK(contentView_); | |
| 497 [contentView_ addTrackingArea:trackingArea_]; | |
| 498 } | |
| 499 | |
| 500 - (void)removeTrackingAreaIfNecessary { | |
| 501 if (trackingArea_) { | |
| 502 DCHECK(contentView_); // |contentView_| better be valid. | |
| 503 [contentView_ removeTrackingArea:trackingArea_]; | |
| 504 trackingArea_.reset(); | |
| 505 } | |
| 506 } | |
| 507 | |
| 508 - (BOOL)mouseInsideTrackingArea { | |
| 509 NSWindow* window = [browserController_ window]; | |
| 510 NSPoint mouseLoc = [window mouseLocationOutsideOfEventStream]; | |
| 511 NSPoint mousePos = [contentView_ convertPoint:mouseLoc fromView:nil]; | |
| 512 return NSMouseInRect(mousePos, trackingAreaFrame_, [contentView_ isFlipped]); | |
| 513 } | |
| 514 | |
| 407 - (BOOL)doesScreenHaveMenuBar { | 515 - (BOOL)doesScreenHaveMenuBar { |
| 408 if (![[NSScreen class] | 516 if (![[NSScreen class] |
| 409 respondsToSelector:@selector(screensHaveSeparateSpaces)]) | 517 respondsToSelector:@selector(screensHaveSeparateSpaces)]) |
| 410 return [self isWindowOnPrimaryScreen]; | 518 return [self isWindowOnPrimaryScreen]; |
| 411 | 519 |
| 412 BOOL eachScreenShouldHaveMenuBar = [NSScreen screensHaveSeparateSpaces]; | 520 BOOL eachScreenShouldHaveMenuBar = [NSScreen screensHaveSeparateSpaces]; |
| 413 return eachScreenShouldHaveMenuBar ?: [self isWindowOnPrimaryScreen]; | 521 return eachScreenShouldHaveMenuBar ?: [self isWindowOnPrimaryScreen]; |
| 414 } | 522 } |
| 415 | 523 |
| 416 - (BOOL)isWindowOnPrimaryScreen { | 524 - (BOOL)isWindowOnPrimaryScreen { |
| 417 NSScreen* screen = [[browserController_ window] screen]; | 525 NSScreen* screen = [[browserController_ window] screen]; |
| 418 NSScreen* primaryScreen = [[NSScreen screens] firstObject]; | 526 NSScreen* primaryScreen = [[NSScreen screens] firstObject]; |
| 419 return (screen == primaryScreen); | 527 return (screen == primaryScreen); |
| 420 } | 528 } |
| 421 | 529 |
| 422 - (base::mac::FullScreenMode)desiredSystemFullscreenMode { | 530 - (base::mac::FullScreenMode)desiredSystemFullscreenMode { |
| 423 if ([self shouldShowMenubarInImmersiveFullscreen]) | 531 if ([self shouldShowMenubarInImmersiveFullscreen]) |
| 424 return base::mac::kFullScreenModeHideDock; | 532 return base::mac::kFullScreenModeHideDock; |
| 425 return base::mac::kFullScreenModeHideAll; | 533 return base::mac::kFullScreenModeHideAll; |
| 426 } | 534 } |
| 427 | 535 |
| 428 - (void)changeOverlayToFraction:(CGFloat)fraction withAnimation:(BOOL)animate { | 536 - (void)animateToolbarVisibility:(BOOL)visible { |
| 429 // The non-animated case is really simple, so do it and return. | 537 CGFloat fraction = visible ? 1.0 : 0.0; |
| 430 if (!animate) { | |
| 431 [currentAnimation_ stopAnimation]; | |
| 432 [self changeToolbarFraction:fraction]; | |
| 433 return; | |
| 434 } | |
| 435 | 538 |
| 436 // If we're already animating to the given fraction, then there's nothing more | 539 // If we're already animating to the given fraction, then there's nothing |
| 437 // to do. | 540 // more to do. |
| 438 if (currentAnimation_ && [currentAnimation_ endFraction] == fraction) | 541 if (currentAnimation_ && [currentAnimation_ endFraction] == fraction) |
| 439 return; | 542 return; |
| 440 | 543 |
| 441 // In all other cases, we want to cancel any running animation (which may be | 544 // In all other cases, we want to cancel any running animation (which may be |
| 442 // to show or to hide). | 545 // to show or to hide). |
| 443 [currentAnimation_ stopAnimation]; | 546 [currentAnimation_ stopAnimation]; |
| 444 | 547 |
| 445 // Create the animation and set it up. | 548 // Create the animation and set it up. |
| 446 currentAnimation_.reset([[DropdownAnimation alloc] | 549 currentAnimation_.reset([[DropdownAnimation alloc] |
| 447 initWithFraction:fraction | 550 initWithFraction:fraction |
| 448 fullDuration:kDropdownAnimationDuration | 551 fullDuration:kDropdownAnimationDuration |
| 449 animationCurve:NSAnimationEaseOut | 552 animationCurve:NSAnimationEaseOut |
| 450 controller:self]); | 553 controller:self]); |
| 451 DCHECK(currentAnimation_); | 554 DCHECK(currentAnimation_); |
| 452 [currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; | 555 [currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; |
| 453 [currentAnimation_ setDelegate:self]; | 556 [currentAnimation_ setDelegate:self]; |
| 454 | 557 |
| 558 // If there is an existing tracking area, remove it. We do not track mouse | |
| 559 // movements during animations (see class comment in the header file). | |
| 560 [self removeTrackingAreaIfNecessary]; | |
| 561 | |
| 455 [currentAnimation_ startAnimation]; | 562 [currentAnimation_ startAnimation]; |
| 456 } | 563 } |
| 457 | 564 |
| 458 - (void)cancelHideTimer { | 565 - (void)cancelHideTimer { |
| 459 [hideTimer_ invalidate]; | 566 [hideTimer_ invalidate]; |
| 460 hideTimer_.reset(); | 567 hideTimer_.reset(); |
| 461 } | 568 } |
| 462 | 569 |
| 463 - (void)hideTimerFire:(NSTimer*)timer { | 570 - (void)hideTimerFire:(NSTimer*)timer { |
| 464 DCHECK_EQ(hideTimer_, timer); // This better be our hide timer. | 571 DCHECK_EQ(hideTimer_, timer); // This better be our hide timer. |
| 465 [hideTimer_ invalidate]; // Make sure it doesn't repeat. | 572 [hideTimer_ invalidate]; // Make sure it doesn't repeat. |
| 466 hideTimer_.reset(); // And get rid of it. | 573 hideTimer_.reset(); // And get rid of it. |
| 467 [self changeOverlayToFraction:0 withAnimation:YES]; | 574 [self animateToolbarVisibility:NO]; |
| 468 } | 575 } |
| 469 | 576 |
| 470 - (void)cleanup { | 577 - (void)cleanup { |
| 471 [self cancelAnimationAndTimer]; | 578 [self cancelAnimationAndTimer]; |
| 472 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 579 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 473 | 580 |
| 474 // This isn't tracked when not in fullscreen mode. | 581 [self removeTrackingAreaIfNecessary]; |
| 475 [browserController_ releaseBarVisibilityForOwner:self withAnimation:NO]; | |
| 476 | 582 |
| 477 // Call the main status resignation code to perform the associated cleanup, | 583 // Call the main status resignation code to perform the associated cleanup, |
| 478 // since we will no longer be receiving actual status resignation | 584 // since we will no longer be receiving actual status resignation |
| 479 // notifications. | 585 // notifications. |
| 480 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; | 586 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; |
| 481 | 587 |
| 482 // No more calls back up to the BWC. | 588 // No more calls back up to the BWC. |
| 483 browserController_ = nil; | 589 browserController_ = nil; |
| 484 } | 590 } |
| 485 | 591 |
| 486 - (void)showActiveWindowUI { | |
| 487 [self updateMenuBarAndDockVisibility]; | |
| 488 } | |
| 489 | |
| 490 - (void)hideActiveWindowUI { | |
| 491 [self updateMenuBarAndDockVisibility]; | |
| 492 } | |
| 493 | |
| 494 - (BOOL)shouldShowMenubarInImmersiveFullscreen { | 592 - (BOOL)shouldShowMenubarInImmersiveFullscreen { |
| 495 return [self doesScreenHaveMenuBar] && toolbarFraction_ > 0.99; | 593 return [self doesScreenHaveMenuBar] && [self toolbarFraction] > 0.99; |
| 496 } | 594 } |
| 497 | 595 |
| 498 @end | 596 @end |
| OLD | NEW |