1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/ui/cocoa/presentation_mode_controller.h"
#include <algorithm>
#include "base/command_line.h"
#import "base/mac/mac_util.h"
#include "base/mac/sdk_forward_declarations.h"
#include "chrome/browser/fullscreen.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
#include "chrome/common/chrome_switches.h"
#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h"
#import "ui/base/cocoa/nsview_additions.h"
NSString* const kWillEnterFullscreenNotification =
@"WillEnterFullscreenNotification";
NSString* const kWillLeaveFullscreenNotification =
@"WillLeaveFullscreenNotification";
namespace {
// The activation zone for the main menu is 4 pixels high; if we make it any
// smaller, then the menu can be made to appear without the bar sliding down.
const CGFloat kDropdownActivationZoneHeight = 4;
const NSTimeInterval kDropdownAnimationDuration = 0.12;
const NSTimeInterval kMouseExitCheckDelay = 0.1;
// This show delay attempts to match the delay for the main menu.
const NSTimeInterval kDropdownShowDelay = 0.3;
const NSTimeInterval kDropdownHideDelay = 0.2;
// The amount by which the floating bar is offset downwards (to avoid the menu)
// in presentation mode. (We can't use |-[NSMenu menuBarHeight]| since it
// returns 0 when the menu bar is hidden.)
const CGFloat kFloatingBarVerticalOffset = 22;
OSStatus MenuBarRevealHandler(EventHandlerCallRef handler,
EventRef event,
void* context) {
PresentationModeController* self =
static_cast<PresentationModeController*>(context);
CGFloat revealFraction = 0;
GetEventParameter(event,
FOUR_CHAR_CODE('rvlf'),
typeCGFloat,
NULL,
sizeof(CGFloat),
NULL,
&revealFraction);
[self setMenuBarRevealProgress:revealFraction];
return CallNextEventHandler(handler, event);
}
} // end namespace
// Helper class to manage animations for the dropdown bar. Calls
// [PresentationModeController changeToolbarFraction] once per
// animation step.
@interface DropdownAnimation : NSAnimation {
@private
PresentationModeController* controller_;
CGFloat startFraction_;
CGFloat endFraction_;
}
@property(readonly, nonatomic) CGFloat startFraction;
@property(readonly, nonatomic) CGFloat endFraction;
// Designated initializer. Asks |controller| for the current shown fraction, so
// if the bar is already partially shown or partially hidden, the animation
// duration may be less than |fullDuration|.
- (id)initWithFraction:(CGFloat)fromFraction
fullDuration:(CGFloat)fullDuration
animationCurve:(NSAnimationCurve)animationCurve
controller:(PresentationModeController*)controller;
@end
@implementation DropdownAnimation
@synthesize startFraction = startFraction_;
@synthesize endFraction = endFraction_;
- (id)initWithFraction:(CGFloat)toFraction
fullDuration:(CGFloat)fullDuration
animationCurve:(NSAnimationCurve)animationCurve
controller:(PresentationModeController*)controller {
// Calculate the effective duration, based on the current shown fraction.
DCHECK(controller);
CGFloat fromFraction = controller.toolbarFraction;
CGFloat effectiveDuration = fabs(fullDuration * (fromFraction - toFraction));
if ((self = [super gtm_initWithDuration:effectiveDuration
eventMask:NSLeftMouseDownMask
animationCurve:animationCurve])) {
startFraction_ = fromFraction;
endFraction_ = toFraction;
controller_ = controller;
}
return self;
}
// Called once per animation step. Overridden to change the floating bar's
// position based on the animation's progress.
- (void)setCurrentProgress:(NSAnimationProgress)progress {
CGFloat fraction =
startFraction_ + (progress * (endFraction_ - startFraction_));
[controller_ changeToolbarFraction:fraction];
}
@end
@interface PresentationModeController (PrivateMethods)
// Updates the visibility of the menu bar and the dock.
- (void)updateMenuBarAndDockVisibility;
// Whether the current screen is expected to have a menu bar, regardless of
// current visibility of the menu bar.
- (BOOL)doesScreenHaveMenuBar;
// Returns YES if the window is on the primary screen.
- (BOOL)isWindowOnPrimaryScreen;
// Returns |kFullScreenModeHideAll| when the overlay is hidden and
// |kFullScreenModeHideDock| when the overlay is shown.
- (base::mac::FullScreenMode)desiredSystemFullscreenMode;
// Change the overlay to the given fraction, with or without animation. Only
// guaranteed to work properly with |fraction == 0| or |fraction == 1|. This
// performs the show/hide (animation) immediately. It does not touch the timers.
- (void)changeOverlayToFraction:(CGFloat)fraction
withAnimation:(BOOL)animate;
// Schedule the floating bar to be shown/hidden because of mouse position.
- (void)scheduleShowForMouse;
- (void)scheduleHideForMouse;
// Set up the tracking area used to activate the sliding bar or keep it active
// using with the rectangle in |trackingAreaBounds_|, or remove the tracking
// area if one was previously set up.
- (void)setupTrackingArea;
- (void)removeTrackingAreaIfNecessary;
// Returns YES if the mouse is currently in any current tracking rectangle, NO
// otherwise.
- (BOOL)mouseInsideTrackingRect;
// The tracking area can "falsely" report exits when the menu slides down over
// it. In that case, we have to monitor for a "real" mouse exit on a timer.
// |-setupMouseExitCheck| schedules a check; |-cancelMouseExitCheck| cancels any
// scheduled check.
- (void)setupMouseExitCheck;
- (void)cancelMouseExitCheck;
// Called (after a delay) by |-setupMouseExitCheck|, to check whether the mouse
// has exited or not; if it hasn't, it will schedule another check.
- (void)checkForMouseExit;
// Start timers for showing/hiding the floating bar.
- (void)startShowTimer;
- (void)startHideTimer;
- (void)cancelShowTimer;
- (void)cancelHideTimer;
- (void)cancelAllTimers;
// Methods called when the show/hide timers fire. Do not call directly.
- (void)showTimerFire:(NSTimer*)timer;
- (void)hideTimerFire:(NSTimer*)timer;
// Stops any running animations, removes tracking areas, etc.
- (void)cleanup;
// Shows and hides the UI associated with this window being active (having main
// status). This includes hiding the menu bar. These functions are called when
// the window gains or loses main status as well as in |-cleanup|.
- (void)showActiveWindowUI;
- (void)hideActiveWindowUI;
// Whether the menu bar should be shown in immersive fullscreen for the screen
// that contains the window.
- (BOOL)shouldShowMenubarInImmersiveFullscreen;
@end
@implementation PresentationModeController
@synthesize inPresentationMode = inPresentationMode_;
@synthesize slidingStyle = slidingStyle_;
@synthesize toolbarFraction = toolbarFraction_;
- (id)initWithBrowserController:(BrowserWindowController*)controller
style:(fullscreen_mac::SlidingStyle)style {
if ((self = [super init])) {
browserController_ = controller;
systemFullscreenMode_ = base::mac::kFullScreenModeNormal;
slidingStyle_ = style;
}
// Let the world know what we're up to.
[[NSNotificationCenter defaultCenter]
postNotificationName:kWillEnterFullscreenNotification
object:nil];
// Install the Carbon event handler for the undocumented menu bar show/hide
// event.
EventTypeSpec eventSpec = {kEventClassMenu, 2004};
InstallApplicationEventHandler(NewEventHandlerUPP(&MenuBarRevealHandler),
1,
&eventSpec,
self,
&menuBarTrackingHandler_);
return self;
}
- (void)dealloc {
RemoveEventHandler(menuBarTrackingHandler_);
DCHECK(!inPresentationMode_);
DCHECK(!trackingArea_);
[super dealloc];
}
- (void)enterPresentationModeForContentView:(NSView*)contentView
showDropdown:(BOOL)showDropdown {
DCHECK(!inPresentationMode_);
enteringPresentationMode_ = YES;
inPresentationMode_ = YES;
contentView_ = contentView;
[self changeToolbarFraction:(showDropdown ? 1 : 0)];
[self updateMenuBarAndDockVisibility];
// Register for notifications. Self is removed as an observer in |-cleanup|.
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
NSWindow* window = [browserController_ window];
// Disable these notifications on Lion as they cause crashes.
// TODO(rohitrao): Figure out what happens if a fullscreen window changes
// monitors on Lion.
if (base::mac::IsOSSnowLeopard()) {
[nc addObserver:self
selector:@selector(windowDidChangeScreen:)
name:NSWindowDidChangeScreenNotification
object:window];
[nc addObserver:self
selector:@selector(windowDidMove:)
name:NSWindowDidMoveNotification
object:window];
}
[nc addObserver:self
selector:@selector(windowDidBecomeMain:)
name:NSWindowDidBecomeMainNotification
object:window];
[nc addObserver:self
selector:@selector(windowDidResignMain:)
name:NSWindowDidResignMainNotification
object:window];
enteringPresentationMode_ = NO;
}
- (void)exitPresentationMode {
[[NSNotificationCenter defaultCenter]
postNotificationName:kWillLeaveFullscreenNotification
object:nil];
DCHECK(inPresentationMode_);
inPresentationMode_ = NO;
[self cleanup];
}
- (void)windowDidChangeScreen:(NSNotification*)notification {
[browserController_ resizeFullscreenWindow];
}
- (void)windowDidMove:(NSNotification*)notification {
[browserController_ resizeFullscreenWindow];
}
- (void)windowDidBecomeMain:(NSNotification*)notification {
[self showActiveWindowUI];
}
- (void)windowDidResignMain:(NSNotification*)notification {
[self hideActiveWindowUI];
}
// On OSX 10.8+, the menu bar shows on the secondary screen in fullscreen.
// On OSX 10.7, fullscreen never fills the secondary screen.
// On OSX 10.6, the menu bar never shows on the secondary screen in fullscreen.
// See http://crbug.com/388906 for full details.
- (CGFloat)floatingBarVerticalOffset {
if (base::mac::IsOSMountainLionOrLater())
return kFloatingBarVerticalOffset;
return [self isWindowOnPrimaryScreen] ? kFloatingBarVerticalOffset : 0;
}
- (void)overlayFrameChanged:(NSRect)frame {
if (!inPresentationMode_)
return;
// Make sure |trackingAreaBounds_| always reflects either the tracking area or
// the desired tracking area.
trackingAreaBounds_ = frame;
// The tracking area should always be at least the height of activation zone.
NSRect contentBounds = [contentView_ bounds];
trackingAreaBounds_.origin.y =
std::min(trackingAreaBounds_.origin.y,
NSMaxY(contentBounds) - kDropdownActivationZoneHeight);
trackingAreaBounds_.size.height =
NSMaxY(contentBounds) - trackingAreaBounds_.origin.y + 1;
// If an animation is currently running, do not set up a tracking area now.
// Instead, leave it to be created it in |-animationDidEnd:|.
if (currentAnimation_)
return;
// If this is part of the initial setup, lock bar visibility if the mouse is
// within the tracking area bounds.
if (enteringPresentationMode_ && [self mouseInsideTrackingRect])
[browserController_ lockBarVisibilityForOwner:self
withAnimation:NO
delay:NO];
[self setupTrackingArea];
}
- (void)ensureOverlayShownWithAnimation:(BOOL)animate delay:(BOOL)delay {
if (!inPresentationMode_)
return;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
return;
if (self.slidingStyle == fullscreen_mac::OMNIBOX_TABS_PRESENT)
return;
if (animate) {
if (delay) {
[self startShowTimer];
} else {
[self cancelAllTimers];
[self changeOverlayToFraction:1 withAnimation:YES];
}
} else {
DCHECK(!delay);
[self cancelAllTimers];
[self changeOverlayToFraction:1 withAnimation:NO];
}
}
- (void)ensureOverlayHiddenWithAnimation:(BOOL)animate delay:(BOOL)delay {
if (!inPresentationMode_)
return;
if (self.slidingStyle == fullscreen_mac::OMNIBOX_TABS_PRESENT)
return;
if (animate) {
if (delay) {
[self startHideTimer];
} else {
[self cancelAllTimers];
[self changeOverlayToFraction:0 withAnimation:YES];
}
} else {
DCHECK(!delay);
[self cancelAllTimers];
[self changeOverlayToFraction:0 withAnimation:NO];
}
}
- (void)cancelAnimationAndTimers {
[self cancelAllTimers];
[currentAnimation_ stopAnimation];
currentAnimation_.reset();
}
- (void)setSystemFullscreenModeTo:(base::mac::FullScreenMode)mode {
if (mode == systemFullscreenMode_)
return;
if (systemFullscreenMode_ == base::mac::kFullScreenModeNormal)
base::mac::RequestFullScreen(mode);
else if (mode == base::mac::kFullScreenModeNormal)
base::mac::ReleaseFullScreen(systemFullscreenMode_);
else
base::mac::SwitchFullScreenModes(systemFullscreenMode_, mode);
systemFullscreenMode_ = mode;
}
- (void)changeToolbarFraction:(CGFloat)fraction {
toolbarFraction_ = fraction;
[browserController_ layoutSubviews];
// In AppKit fullscreen, moving the mouse to the top of the screen toggles
// menu visibility. Replicate the same effect for immersive fullscreen.
if ([browserController_ isInImmersiveFullscreen])
[self updateMenuBarAndDockVisibility];
}
// This method works, but is fragile.
//
// It gets used during view layout, which sometimes needs to be done at the
// beginning of an animation. As such, this method needs to reflect the
// menubarOffset expected at the end of the animation. This information is not
// readily available. (The layout logic needs a refactor).
//
// For AppKit Fullscreen, the menubar always starts hidden, and
// menubarFraction_ always starts at 0, so the logic happens to work. For
// Immersive Fullscreen, this class controls the visibility of the menu bar, so
// the logic is correct and not fragile.
- (CGFloat)menubarOffset {
if ([browserController_ isInAppKitFullscreen])
return -std::floor(menubarFraction_ * [self floatingBarVerticalOffset]);
return [self shouldShowMenubarInImmersiveFullscreen]
? -[self floatingBarVerticalOffset]
: 0;
}
// Used to activate the floating bar in presentation mode.
- (void)mouseEntered:(NSEvent*)event {
DCHECK(inPresentationMode_);
// Having gotten a mouse entered, we no longer need to do exit checks.
[self cancelMouseExitCheck];
NSTrackingArea* trackingArea = [event trackingArea];
if (trackingArea == trackingArea_) {
// The tracking area shouldn't be active during animation.
DCHECK(!currentAnimation_);
[self scheduleShowForMouse];
}
}
// Used to deactivate the floating bar in presentation mode.
- (void)mouseExited:(NSEvent*)event {
DCHECK(inPresentationMode_);
NSTrackingArea* trackingArea = [event trackingArea];
if (trackingArea == trackingArea_) {
// The tracking area shouldn't be active during animation.
DCHECK(!currentAnimation_);
// We can get a false mouse exit when the menu slides down, so if the mouse
// is still actually over the tracking area, we ignore the mouse exit, but
// we set up to check the mouse position again after a delay.
if ([self mouseInsideTrackingRect]) {
[self setupMouseExitCheck];
return;
}
[self scheduleHideForMouse];
}
}
- (void)animationDidStop:(NSAnimation*)animation {
// Reset the |currentAnimation_| pointer now that the animation is over.
currentAnimation_.reset();
// Invariant says that the tracking area is not installed while animations are
// in progress. Ensure this is true.
DCHECK(!trackingArea_);
[self removeTrackingAreaIfNecessary]; // For paranoia.
// Don't automatically set up a new tracking area. When explicitly stopped,
// either another animation is going to start immediately or the state will be
// changed immediately.
}
- (void)animationDidEnd:(NSAnimation*)animation {
[self animationDidStop:animation];
// |trackingAreaBounds_| contains the correct tracking area bounds, including
// |any updates that may have come while the animation was running. Install a
// new tracking area with these bounds.
[self setupTrackingArea];
// TODO(viettrungluu): Better would be to check during the animation; doing it
// here means that the timing is slightly off.
if (![self mouseInsideTrackingRect])
[self scheduleHideForMouse];
}
- (void)setMenuBarRevealProgress:(CGFloat)progress {
menubarFraction_ = progress;
// If an animation is not running, then -layoutSubviews will not be called
// for each tick of the menu bar reveal. Do that manually.
// TODO(erikchen): The animation is janky. layoutSubviews need a refactor so
// that it calls setFrameOffset: instead of setFrame: if the frame's size has
// not changed.
if (!currentAnimation_.get())
[browserController_ layoutSubviews];
}
@end
@implementation PresentationModeController (PrivateMethods)
- (void)updateMenuBarAndDockVisibility {
if (![[browserController_ window] isMainWindow] ||
![browserController_ isInImmersiveFullscreen]) {
[self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal];
return;
}
// The screen does not have a menu bar, so there's no need to hide it.
if (![self doesScreenHaveMenuBar]) {
[self setSystemFullscreenModeTo:base::mac::kFullScreenModeHideDock];
return;
}
[self setSystemFullscreenModeTo:[self desiredSystemFullscreenMode]];
}
- (BOOL)doesScreenHaveMenuBar {
if (![[NSScreen class]
respondsToSelector:@selector(screensHaveSeparateSpaces)])
return [self isWindowOnPrimaryScreen];
BOOL eachScreenShouldHaveMenuBar = [NSScreen screensHaveSeparateSpaces];
return eachScreenShouldHaveMenuBar ?: [self isWindowOnPrimaryScreen];
}
- (BOOL)isWindowOnPrimaryScreen {
NSScreen* screen = [[browserController_ window] screen];
NSScreen* primaryScreen = [[NSScreen screens] objectAtIndex:0];
return (screen == primaryScreen);
}
- (base::mac::FullScreenMode)desiredSystemFullscreenMode {
if ([self shouldShowMenubarInImmersiveFullscreen])
return base::mac::kFullScreenModeHideDock;
return base::mac::kFullScreenModeHideAll;
}
- (void)changeOverlayToFraction:(CGFloat)fraction
withAnimation:(BOOL)animate {
// The non-animated case is really simple, so do it and return.
if (!animate) {
[currentAnimation_ stopAnimation];
[self changeToolbarFraction:fraction];
return;
}
// If we're already animating to the given fraction, then there's nothing more
// to do.
if (currentAnimation_ && [currentAnimation_ endFraction] == fraction)
return;
// In all other cases, we want to cancel any running animation (which may be
// to show or to hide).
[currentAnimation_ stopAnimation];
// Create the animation and set it up.
currentAnimation_.reset(
[[DropdownAnimation alloc] initWithFraction:fraction
fullDuration:kDropdownAnimationDuration
animationCurve:NSAnimationEaseOut
controller:self]);
DCHECK(currentAnimation_);
[currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
[currentAnimation_ setDelegate:self];
// If there is an existing tracking area, remove it. We do not track mouse
// movements during animations (see class comment in the header file).
[self removeTrackingAreaIfNecessary];
[currentAnimation_ startAnimation];
}
- (void)scheduleShowForMouse {
[browserController_ lockBarVisibilityForOwner:self
withAnimation:YES
delay:YES];
}
- (void)scheduleHideForMouse {
[browserController_ releaseBarVisibilityForOwner:self
withAnimation:YES
delay:YES];
}
- (void)setupTrackingArea {
if (trackingArea_) {
// If the tracking rectangle is already |trackingAreaBounds_|, quit early.
NSRect oldRect = [trackingArea_ rect];
if (NSEqualRects(trackingAreaBounds_, oldRect))
return;
// Otherwise, remove it.
[self removeTrackingAreaIfNecessary];
}
// Create and add a new tracking area for |frame|.
trackingArea_.reset(
[[NSTrackingArea alloc] initWithRect:trackingAreaBounds_
options:NSTrackingMouseEnteredAndExited |
NSTrackingActiveInKeyWindow
owner:self
userInfo:nil]);
DCHECK(contentView_);
[contentView_ addTrackingArea:trackingArea_];
}
- (void)removeTrackingAreaIfNecessary {
if (trackingArea_) {
DCHECK(contentView_); // |contentView_| better be valid.
[contentView_ removeTrackingArea:trackingArea_];
trackingArea_.reset();
}
}
- (BOOL)mouseInsideTrackingRect {
NSWindow* window = [browserController_ window];
NSPoint mouseLoc = [window mouseLocationOutsideOfEventStream];
NSPoint mousePos = [contentView_ convertPoint:mouseLoc fromView:nil];
return NSMouseInRect(mousePos, trackingAreaBounds_, [contentView_ isFlipped]);
}
- (void)setupMouseExitCheck {
[self performSelector:@selector(checkForMouseExit)
withObject:nil
afterDelay:kMouseExitCheckDelay];
}
- (void)cancelMouseExitCheck {
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(checkForMouseExit) object:nil];
}
- (void)checkForMouseExit {
if ([self mouseInsideTrackingRect])
[self setupMouseExitCheck];
else
[self scheduleHideForMouse];
}
- (void)startShowTimer {
// If there's already a show timer going, just keep it.
if (showTimer_) {
DCHECK([showTimer_ isValid]);
DCHECK(!hideTimer_);
return;
}
// Cancel the hide timer (if necessary) and set up the new show timer.
[self cancelHideTimer];
showTimer_.reset(
[[NSTimer scheduledTimerWithTimeInterval:kDropdownShowDelay
target:self
selector:@selector(showTimerFire:)
userInfo:nil
repeats:NO] retain]);
DCHECK([showTimer_ isValid]); // This also checks that |showTimer_ != nil|.
}
- (void)startHideTimer {
// If there's already a hide timer going, just keep it.
if (hideTimer_) {
DCHECK([hideTimer_ isValid]);
DCHECK(!showTimer_);
return;
}
// Cancel the show timer (if necessary) and set up the new hide timer.
[self cancelShowTimer];
hideTimer_.reset(
[[NSTimer scheduledTimerWithTimeInterval:kDropdownHideDelay
target:self
selector:@selector(hideTimerFire:)
userInfo:nil
repeats:NO] retain]);
DCHECK([hideTimer_ isValid]); // This also checks that |hideTimer_ != nil|.
}
- (void)cancelShowTimer {
[showTimer_ invalidate];
showTimer_.reset();
}
- (void)cancelHideTimer {
[hideTimer_ invalidate];
hideTimer_.reset();
}
- (void)cancelAllTimers {
[self cancelShowTimer];
[self cancelHideTimer];
}
- (void)showTimerFire:(NSTimer*)timer {
DCHECK_EQ(showTimer_, timer); // This better be our show timer.
[showTimer_ invalidate]; // Make sure it doesn't repeat.
showTimer_.reset(); // And get rid of it.
[self changeOverlayToFraction:1 withAnimation:YES];
}
- (void)hideTimerFire:(NSTimer*)timer {
DCHECK_EQ(hideTimer_, timer); // This better be our hide timer.
[hideTimer_ invalidate]; // Make sure it doesn't repeat.
hideTimer_.reset(); // And get rid of it.
[self changeOverlayToFraction:0 withAnimation:YES];
}
- (void)cleanup {
[self cancelMouseExitCheck];
[self cancelAnimationAndTimers];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self removeTrackingAreaIfNecessary];
contentView_ = nil;
// This isn't tracked when not in presentation mode.
[browserController_ releaseBarVisibilityForOwner:self
withAnimation:NO
delay:NO];
// Call the main status resignation code to perform the associated cleanup,
// since we will no longer be receiving actual status resignation
// notifications.
[self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal];
// No more calls back up to the BWC.
browserController_ = nil;
}
- (void)showActiveWindowUI {
[self updateMenuBarAndDockVisibility];
// TODO(rohitrao): Insert the Exit Fullscreen button. http://crbug.com/35956
}
- (void)hideActiveWindowUI {
[self updateMenuBarAndDockVisibility];
// TODO(rohitrao): Remove the Exit Fullscreen button. http://crbug.com/35956
}
- (BOOL)shouldShowMenubarInImmersiveFullscreen {
return [self doesScreenHaveMenuBar] && toolbarFraction_ > 0.99;
}
@end
|