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 | |
430 shouldAnimateToolbarOut_ = NO; | |
erikchen
2016/08/26 00:56:59
Does this need to get unset anytime currentAnimati
spqchan
2016/08/26 01:23:21
See below
| |
431 | |
344 // Reset the |currentAnimation_| pointer now that the animation is over. | 432 // Reset the |currentAnimation_| pointer now that the animation is over. |
345 currentAnimation_.reset(); | 433 currentAnimation_.reset(); |
346 | 434 // [self updateToolbar]; |
erikchen
2016/08/26 00:56:59
why is this commented out?
spqchan
2016/08/26 01:23:21
Done.
| |
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 } | 435 } |
362 | 436 |
363 - (void)animationDidEnd:(NSAnimation*)animation { | 437 - (void)animationDidEnd:(NSAnimation*)animation { |
364 [self animationDidStop:animation]; | 438 [self animationDidStop:animation]; |
439 [self setupTrackingArea]; | |
365 } | 440 } |
366 | 441 |
367 - (void)setMenuBarRevealProgress:(CGFloat)progress { | 442 - (void)setMenuBarRevealProgress:(CGFloat)progress { |
368 // If the menubarFraction increases, check if we are in the right screen | 443 // If the menubarFraction increases, check if we are in the right screen |
369 // so that the toolbar is not revealed on the wrong screen. | 444 // so that the toolbar is not revealed on the wrong screen. |
370 if (![self isMouseOnScreen] && progress > menubarFraction_) | 445 if (![self isMouseOnScreen] && progress > menubarFraction_) |
371 return; | 446 return; |
372 | 447 |
373 menubarFraction_ = progress; | 448 menubarFraction_ = progress; |
374 | 449 |
450 if (self.slidingStyle == fullscreen_mac::OMNIBOX_TABS_HIDDEN) { | |
451 if (IsCGFloatEqual(menubarFraction_, kShowFraction)) | |
452 [self setupTrackingArea]; | |
453 | |
454 // If the menubar is disappearing from the screen, check if the mouse | |
455 // is still interacting with the toolbar. If it is, don't set | |
456 // |toolbarFractionFromMenuProgress_| so that the the toolbar will remain | |
457 // on the screen. | |
458 BOOL isMenuBarDisappearing = | |
459 menubarFraction_ < toolbarFractionFromMenuProgress_; | |
460 if (!(isMenuBarDisappearing && [self mouseInsideTrackingArea])) | |
461 toolbarFractionFromMenuProgress_ = progress; | |
462 } | |
463 | |
375 // If an animation is not running, then -layoutSubviews will not be called | 464 // If an animation is not running, then -layoutSubviews will not be called |
376 // for each tick of the menu bar reveal. Do that manually. | 465 // for each tick of the menu bar reveal. Do that manually. |
377 // TODO(erikchen): The animation is janky. layoutSubviews need a refactor so | 466 // 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 | 467 // that it calls setFrameOffset: instead of setFrame: if the frame's size has |
379 // not changed. | 468 // not changed. |
380 if (!currentAnimation_.get()) { | 469 if (!currentAnimation_.get()) |
381 if (self.slidingStyle != fullscreen_mac::OMNIBOX_TABS_NONE) | |
382 toolbarFraction_ = progress; | |
383 [browserController_ layoutSubviews]; | 470 [browserController_ layoutSubviews]; |
384 } | |
385 } | 471 } |
386 | 472 |
387 @end | 473 @end |
388 | 474 |
389 @implementation FullscreenToolbarController (PrivateMethods) | 475 @implementation FullscreenToolbarController (PrivateMethods) |
390 | 476 |
391 - (void)updateMenuBarAndDockVisibility { | 477 - (void)updateMenuBarAndDockVisibility { |
392 if (![self isMouseOnScreen] || | 478 if (![self isMouseOnScreen] || |
393 ![browserController_ isInImmersiveFullscreen]) { | 479 ![browserController_ isInImmersiveFullscreen]) { |
394 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; | 480 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; |
395 return; | 481 return; |
396 } | 482 } |
397 | 483 |
398 // The screen does not have a menu bar, so there's no need to hide it. | 484 // The screen does not have a menu bar, so there's no need to hide it. |
399 if (![self doesScreenHaveMenuBar]) { | 485 if (![self doesScreenHaveMenuBar]) { |
400 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeHideDock]; | 486 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeHideDock]; |
401 return; | 487 return; |
402 } | 488 } |
403 | 489 |
404 [self setSystemFullscreenModeTo:[self desiredSystemFullscreenMode]]; | 490 [self setSystemFullscreenModeTo:[self desiredSystemFullscreenMode]]; |
405 } | 491 } |
406 | 492 |
493 - (void)setupTrackingArea { | |
494 if (trackingArea_) { | |
495 // If the tracking rectangle is already |trackingAreaBounds_|, quit early. | |
496 NSRect oldRect = [trackingArea_ rect]; | |
497 if (NSEqualRects(trackingAreaFrame_, oldRect)) | |
498 return; | |
499 | |
500 // Otherwise, remove it. | |
501 [self removeTrackingAreaIfNecessary]; | |
502 } | |
503 | |
504 // Create and add a new tracking area for |frame|. | |
505 trackingArea_.reset([[CrTrackingArea alloc] | |
506 initWithRect:trackingAreaFrame_ | |
507 options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | |
508 owner:self | |
509 userInfo:nil]); | |
510 DCHECK(contentView_); | |
511 [contentView_ addTrackingArea:trackingArea_]; | |
512 } | |
513 | |
514 - (void)removeTrackingAreaIfNecessary { | |
515 if (trackingArea_) { | |
516 DCHECK(contentView_); // |contentView_| better be valid. | |
517 [contentView_ removeTrackingArea:trackingArea_]; | |
518 trackingArea_.reset(); | |
519 } | |
520 } | |
521 | |
522 - (BOOL)mouseInsideTrackingArea { | |
523 NSWindow* window = [browserController_ window]; | |
524 NSPoint mouseLoc = [window mouseLocationOutsideOfEventStream]; | |
525 NSPoint mousePos = [contentView_ convertPoint:mouseLoc fromView:nil]; | |
526 return NSMouseInRect(mousePos, trackingAreaFrame_, [contentView_ isFlipped]); | |
527 } | |
528 | |
407 - (BOOL)doesScreenHaveMenuBar { | 529 - (BOOL)doesScreenHaveMenuBar { |
408 if (![[NSScreen class] | 530 if (![[NSScreen class] |
409 respondsToSelector:@selector(screensHaveSeparateSpaces)]) | 531 respondsToSelector:@selector(screensHaveSeparateSpaces)]) |
410 return [self isWindowOnPrimaryScreen]; | 532 return [self isWindowOnPrimaryScreen]; |
411 | 533 |
412 BOOL eachScreenShouldHaveMenuBar = [NSScreen screensHaveSeparateSpaces]; | 534 BOOL eachScreenShouldHaveMenuBar = [NSScreen screensHaveSeparateSpaces]; |
413 return eachScreenShouldHaveMenuBar ?: [self isWindowOnPrimaryScreen]; | 535 return eachScreenShouldHaveMenuBar ?: [self isWindowOnPrimaryScreen]; |
414 } | 536 } |
415 | 537 |
416 - (BOOL)isWindowOnPrimaryScreen { | 538 - (BOOL)isWindowOnPrimaryScreen { |
417 NSScreen* screen = [[browserController_ window] screen]; | 539 NSScreen* screen = [[browserController_ window] screen]; |
418 NSScreen* primaryScreen = [[NSScreen screens] firstObject]; | 540 NSScreen* primaryScreen = [[NSScreen screens] firstObject]; |
419 return (screen == primaryScreen); | 541 return (screen == primaryScreen); |
420 } | 542 } |
421 | 543 |
422 - (base::mac::FullScreenMode)desiredSystemFullscreenMode { | 544 - (base::mac::FullScreenMode)desiredSystemFullscreenMode { |
423 if ([self shouldShowMenubarInImmersiveFullscreen]) | 545 if ([self shouldShowMenubarInImmersiveFullscreen]) |
424 return base::mac::kFullScreenModeHideDock; | 546 return base::mac::kFullScreenModeHideDock; |
425 return base::mac::kFullScreenModeHideAll; | 547 return base::mac::kFullScreenModeHideAll; |
426 } | 548 } |
427 | 549 |
428 - (void)changeOverlayToFraction:(CGFloat)fraction withAnimation:(BOOL)animate { | 550 - (void)animateToolbarVisibility:(BOOL)visible { |
429 // The non-animated case is really simple, so do it and return. | 551 CGFloat fraction = visible ? kShowFraction : kHideFraction; |
430 if (!animate) { | |
431 [currentAnimation_ stopAnimation]; | |
432 [self changeToolbarFraction:fraction]; | |
433 return; | |
434 } | |
435 | 552 |
436 // If we're already animating to the given fraction, then there's nothing more | 553 // If we're already animating to the given fraction, then there's nothing |
437 // to do. | 554 // more to do. |
438 if (currentAnimation_ && [currentAnimation_ endFraction] == fraction) | 555 if (currentAnimation_ && [currentAnimation_ endFraction] == fraction) |
439 return; | 556 return; |
440 | 557 |
441 // In all other cases, we want to cancel any running animation (which may be | 558 // In all other cases, we want to cancel any running animation (which may be |
442 // to show or to hide). | 559 // to show or to hide). |
443 [currentAnimation_ stopAnimation]; | 560 [currentAnimation_ stopAnimation]; |
444 | 561 |
445 // Create the animation and set it up. | 562 // Create the animation and set it up. |
446 currentAnimation_.reset([[DropdownAnimation alloc] | 563 currentAnimation_.reset([[DropdownAnimation alloc] |
447 initWithFraction:fraction | 564 initWithFraction:fraction |
448 fullDuration:kDropdownAnimationDuration | 565 fullDuration:kDropdownAnimationDuration |
449 animationCurve:NSAnimationEaseOut | 566 animationCurve:NSAnimationEaseOut |
450 controller:self]); | 567 controller:self]); |
451 DCHECK(currentAnimation_); | 568 DCHECK(currentAnimation_); |
452 [currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; | 569 [currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; |
453 [currentAnimation_ setDelegate:self]; | 570 [currentAnimation_ setDelegate:self]; |
454 | 571 |
572 // If there is an existing tracking area, remove it. We do not track mouse | |
573 // movements during animations (see class comment in the header file). | |
574 [self removeTrackingAreaIfNecessary]; | |
575 | |
455 [currentAnimation_ startAnimation]; | 576 [currentAnimation_ startAnimation]; |
456 } | 577 } |
457 | 578 |
458 - (void)cancelHideTimer { | 579 - (void)cancelHideTimer { |
459 [hideTimer_ invalidate]; | 580 [hideTimer_ invalidate]; |
460 hideTimer_.reset(); | 581 hideTimer_.reset(); |
461 } | 582 } |
462 | 583 |
463 - (void)hideTimerFire:(NSTimer*)timer { | 584 - (void)hideTimerFire:(NSTimer*)timer { |
464 DCHECK_EQ(hideTimer_, timer); // This better be our hide timer. | 585 DCHECK_EQ(hideTimer_, timer); // This better be our hide timer. |
465 [hideTimer_ invalidate]; // Make sure it doesn't repeat. | 586 [hideTimer_ invalidate]; // Make sure it doesn't repeat. |
466 hideTimer_.reset(); // And get rid of it. | 587 hideTimer_.reset(); // And get rid of it. |
467 [self changeOverlayToFraction:0 withAnimation:YES]; | 588 shouldAnimateToolbarOut_ = YES; |
erikchen
2016/08/26 00:56:58
should this be set at line 563, to mirror the loca
spqchan
2016/08/26 01:23:21
Actually...now that you mention I think it makes m
erikchen
2016/08/26 01:27:26
Since a currentAnimation_ exists, doesn't the cond
| |
589 [self animateToolbarVisibility:NO]; | |
468 } | 590 } |
469 | 591 |
470 - (void)cleanup { | 592 - (void)cleanup { |
471 [self cancelAnimationAndTimer]; | 593 [self cancelAnimationAndTimer]; |
472 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 594 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
473 | 595 |
474 // This isn't tracked when not in fullscreen mode. | 596 [self removeTrackingAreaIfNecessary]; |
475 [browserController_ releaseBarVisibilityForOwner:self withAnimation:NO]; | |
476 | 597 |
477 // Call the main status resignation code to perform the associated cleanup, | 598 // Call the main status resignation code to perform the associated cleanup, |
478 // since we will no longer be receiving actual status resignation | 599 // since we will no longer be receiving actual status resignation |
479 // notifications. | 600 // notifications. |
480 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; | 601 [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; |
481 | 602 |
482 // No more calls back up to the BWC. | 603 // No more calls back up to the BWC. |
483 browserController_ = nil; | 604 browserController_ = nil; |
484 } | 605 } |
485 | 606 |
486 - (void)showActiveWindowUI { | |
487 [self updateMenuBarAndDockVisibility]; | |
488 } | |
489 | |
490 - (void)hideActiveWindowUI { | |
491 [self updateMenuBarAndDockVisibility]; | |
492 } | |
493 | |
494 - (BOOL)shouldShowMenubarInImmersiveFullscreen { | 607 - (BOOL)shouldShowMenubarInImmersiveFullscreen { |
495 return [self doesScreenHaveMenuBar] && toolbarFraction_ > 0.99; | 608 return [self doesScreenHaveMenuBar] && [self toolbarFraction] > 0.99; |
496 } | 609 } |
497 | 610 |
498 @end | 611 @end |
OLD | NEW |