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