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 |