1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/fullscreen_mode_controller.h"
7 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
8 #import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
9 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
11 @interface FullscreenModeController (Private)
12 - (void)startAnimationToState:(FullscreenToolbarState)state;
13 - (void)setMenuBarRevealProgress:(CGFloat)progress;
14 - (void)setRevealAnimationProgress:(NSAnimationProgress)progress;
19 OSStatus MenuBarRevealHandler(EventHandlerCallRef handler,
22 FullscreenModeController* self =
23 static_cast<FullscreenModeController*>(context);
24 CGFloat revealFraction = 0;
25 GetEventParameter(event, FOUR_CHAR_CODE('rvlf'), typeCGFloat, NULL,
26 sizeof(CGFloat), NULL, &revealFraction);
27 [self setMenuBarRevealProgress:revealFraction];
28 return CallNextEventHandler(handler, event);
31 // The duration of the animation to bring down the tabstrip.
32 const NSTimeInterval kAnimationDuration = 0.35;
34 // The height of the tracking area in which mouse entered/exit events will
35 // reveal the tabstrip.
36 const NSUInteger kTrackingAreaHeight = 100;
38 // There is a tiny gap between the window's max Y and the top of the screen,
39 // which will produce a mouse exit event when the menu bar should be revealed.
40 // This factor is the size of that gap plus padding.
41 const CGFloat kTrackingAreaMaxYEpsilon = 15;
45 // Animation ///////////////////////////////////////////////////////////////////
47 @interface FullscreenModeDropDownAnimation : NSAnimation {
48 FullscreenModeController* controller_;
52 @implementation FullscreenModeDropDownAnimation
54 - (id)initWithFullscreenModeController:(FullscreenModeController*)controller {
55 if ((self = [super initWithDuration:kAnimationDuration
56 animationCurve:NSAnimationEaseInOut])) {
57 controller_ = controller;
58 [self setAnimationBlockingMode:NSAnimationNonblocking];
59 [self setDelegate:controller_];
64 - (void)setCurrentProgress:(NSAnimationProgress)progress {
65 [controller_ setRevealAnimationProgress:progress];
70 // Implementation //////////////////////////////////////////////////////////////
72 @implementation FullscreenModeController
74 - (id)initWithBrowserWindowController:(BrowserWindowController*)bwc {
75 if ((self = [super init])) {
78 currentState_ = kFullscreenToolbarOnly;
79 destinationState_ = kFullscreenToolbarOnly;
81 // Create the tracking area at the top of the window.
82 NSRect windowFrame = [[bwc window] frame];
83 NSRect trackingRect = NSMakeRect(
84 0, NSHeight(windowFrame) - kTrackingAreaHeight,
85 NSWidth(windowFrame), kTrackingAreaHeight);
87 [[CrTrackingArea alloc] initWithRect:trackingRect
88 options:NSTrackingMouseEnteredAndExited |
89 NSTrackingActiveAlways
92 [[[bwc window] contentView] addTrackingArea:trackingArea_.get()];
94 // Install the Carbon event handler for the undocumented menu bar show/hide
96 EventTypeSpec eventSpec = { kEventClassMenu, 2004 };
97 InstallApplicationEventHandler(NewEventHandlerUPP(&MenuBarRevealHandler),
99 self, &menuBarTrackingHandler_);
105 RemoveEventHandler(menuBarTrackingHandler_);
106 [[[controller_ window] contentView] removeTrackingArea:trackingArea_.get()];
110 - (CGFloat)menuBarHeight {
111 // -[NSMenu menuBarHeight] will return 0 when the menu bar is hidden, so
112 // use the status bar API instead, which always returns a constant value.
113 return [[NSStatusBar systemStatusBar] thickness] * menuBarRevealFraction_;
116 - (void)mouseEntered:(NSEvent*)event {
117 if (animation_ || currentState_ == kFullscreenToolbarAndTabstrip)
120 [self startAnimationToState:kFullscreenToolbarAndTabstrip];
123 - (void)mouseExited:(NSEvent*)event {
124 if (animation_ || currentState_ == kFullscreenToolbarOnly)
127 // Take allowance for the small gap between the window max Y and top edge of
129 NSPoint mousePoint = [NSEvent mouseLocation];
130 NSRect screenRect = [[[controller_ window] screen] frame];
131 if (mousePoint.y >= NSMaxY(screenRect) - kTrackingAreaMaxYEpsilon)
134 [self startAnimationToState:kFullscreenToolbarOnly];
137 - (void)startAnimationToState:(FullscreenToolbarState)state {
138 DCHECK_NE(currentState_, state);
140 destinationState_ = state;
142 // Turn on fast resize mode to ensure a smooth web contents animation.
143 // TODO(rsesek): This makes the animation jump at the end.
144 [[controller_ tabContentArea] setFastResizeMode:YES];
146 animation_.reset([[FullscreenModeDropDownAnimation alloc]
147 initWithFullscreenModeController:self]);
148 [animation_ startAnimation];
151 - (void)setMenuBarRevealProgress:(CGFloat)progress {
152 menuBarRevealFraction_ = progress;
154 // If an animation is not running, then -layoutSubviews will not be called
155 // for each tick of the menu bar reveal. Do that manually.
156 // TODO(rsesek): This is kind of hacky and janky.
158 [controller_ layoutSubviews];
161 - (void)setRevealAnimationProgress:(NSAnimationProgress)progress {
162 // When hiding the tabstrip, invert the fraction.
163 if (destinationState_ == kFullscreenToolbarOnly)
164 progress = 1.0 - progress;
165 [controller_ setFloatingBarShownFraction:progress];
168 - (void)animationDidEnd:(NSAnimation*)animation {
169 DCHECK_EQ(animation_.get(), animation);
171 currentState_ = destinationState_;
173 [animation_ setDelegate:nil];
176 [[controller_ tabContentArea] setFastResizeMode:NO];