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