Home | History | Annotate | Download | only in cocoa
      1 // Copyright (c) 2011 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/browser_window_controller_private.h"
      6 
      7 #include "base/command_line.h"
      8 #import "base/memory/scoped_nsobject.h"
      9 #include "chrome/browser/browser_process.h"
     10 #include "chrome/browser/prefs/pref_service.h"
     11 #include "chrome/browser/prefs/scoped_user_pref_update.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/ui/browser_list.h"
     14 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
     15 #import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h"
     16 #import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
     17 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
     18 #import "chrome/browser/ui/cocoa/fullscreen_controller.h"
     19 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
     20 #import "chrome/browser/ui/cocoa/tab_contents/previewable_contents_controller.h"
     21 #import "chrome/browser/ui/cocoa/tabs/side_tab_strip_controller.h"
     22 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
     23 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
     24 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
     25 #include "chrome/common/chrome_switches.h"
     26 #include "chrome/common/pref_names.h"
     27 #include "content/browser/renderer_host/render_widget_host_view.h"
     28 #include "content/browser/tab_contents/tab_contents.h"
     29 #include "content/browser/tab_contents/tab_contents_view.h"
     30 
     31 // Provide the forward-declarations of new 10.7 SDK symbols so they can be
     32 // called when building with the 10.5 SDK.
     33 #if !defined(MAC_OS_X_VERSION_10_7) || \
     34     MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
     35 
     36 @interface NSWindow (LionSDKDeclarations)
     37 - (void)toggleFullScreen:(id)sender;
     38 @end
     39 
     40 enum {
     41   NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
     42   NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8
     43 };
     44 
     45 enum {
     46   NSWindowFullScreenButton = 7
     47 };
     48 
     49 #endif  // MAC_OS_X_VERSION_10_7
     50 
     51 namespace {
     52 
     53 // Space between the incognito badge and the right edge of the window.
     54 const CGFloat kIncognitoBadgeOffset = 4;
     55 
     56 // Insets for the location bar, used when the full toolbar is hidden.
     57 // TODO(viettrungluu): We can argue about the "correct" insetting; I like the
     58 // following best, though arguably 0 inset is better/more correct.
     59 const CGFloat kLocBarLeftRightInset = 1;
     60 const CGFloat kLocBarTopInset = 0;
     61 const CGFloat kLocBarBottomInset = 1;
     62 
     63 }  // namespace
     64 
     65 @implementation BrowserWindowController(Private)
     66 
     67 // Create the appropriate tab strip controller based on whether or not side
     68 // tabs are enabled.
     69 - (void)createTabStripController {
     70   Class factory = [TabStripController class];
     71   if ([self useVerticalTabs])
     72     factory = [SideTabStripController class];
     73 
     74   DCHECK([previewableContentsController_ activeContainer]);
     75   DCHECK([[previewableContentsController_ activeContainer] window]);
     76   tabStripController_.reset([[factory alloc]
     77       initWithView:[self tabStripView]
     78         switchView:[previewableContentsController_ activeContainer]
     79            browser:browser_.get()
     80           delegate:self]);
     81 }
     82 
     83 - (void)saveWindowPositionIfNeeded {
     84   if (browser_ != BrowserList::GetLastActive())
     85     return;
     86 
     87   if (!browser_->profile()->GetPrefs() ||
     88       !browser_->ShouldSaveWindowPlacement()) {
     89     return;
     90   }
     91 
     92   [self saveWindowPositionToPrefs:browser_->profile()->GetPrefs()];
     93 }
     94 
     95 - (void)saveWindowPositionToPrefs:(PrefService*)prefs {
     96   // If we're in fullscreen mode, save the position of the regular window
     97   // instead.
     98   NSWindow* window = [self isFullscreen] ? savedRegularWindow_ : [self window];
     99 
    100   // Window positions are stored relative to the origin of the primary monitor.
    101   NSRect monitorFrame = [[[NSScreen screens] objectAtIndex:0] frame];
    102   NSScreen* windowScreen = [window screen];
    103 
    104   // |windowScreen| can be nil (for example, if the monitor arrangement was
    105   // changed while in fullscreen mode).  If we see a nil screen, return without
    106   // saving.
    107   // TODO(rohitrao): We should just not save anything for fullscreen windows.
    108   // http://crbug.com/36479.
    109   if (!windowScreen)
    110     return;
    111 
    112   // Start with the window's frame, which is in virtual coordinates.
    113   // Do some y twiddling to flip the coordinate system.
    114   gfx::Rect bounds(NSRectToCGRect([window frame]));
    115   bounds.set_y(monitorFrame.size.height - bounds.y() - bounds.height());
    116 
    117   // We also need to save the current work area, in flipped coordinates.
    118   gfx::Rect workArea(NSRectToCGRect([windowScreen visibleFrame]));
    119   workArea.set_y(monitorFrame.size.height - workArea.y() - workArea.height());
    120 
    121   // Browser::SaveWindowPlacement is used for session restore.
    122   if (browser_->ShouldSaveWindowPlacement())
    123     browser_->SaveWindowPlacement(bounds, /*maximized=*/ false);
    124 
    125   DictionaryPrefUpdate update(prefs, browser_->GetWindowPlacementKey().c_str());
    126   DictionaryValue* windowPreferences = update.Get();
    127   windowPreferences->SetInteger("left", bounds.x());
    128   windowPreferences->SetInteger("top", bounds.y());
    129   windowPreferences->SetInteger("right", bounds.right());
    130   windowPreferences->SetInteger("bottom", bounds.bottom());
    131   windowPreferences->SetBoolean("maximized", false);
    132   windowPreferences->SetBoolean("always_on_top", false);
    133   windowPreferences->SetInteger("work_area_left", workArea.x());
    134   windowPreferences->SetInteger("work_area_top", workArea.y());
    135   windowPreferences->SetInteger("work_area_right", workArea.right());
    136   windowPreferences->SetInteger("work_area_bottom", workArea.bottom());
    137 }
    138 
    139 - (NSRect)window:(NSWindow*)window
    140 willPositionSheet:(NSWindow*)sheet
    141        usingRect:(NSRect)defaultSheetRect {
    142   // Position the sheet as follows:
    143   //  - If the bookmark bar is hidden or shown as a bubble (on the NTP when the
    144   //    bookmark bar is disabled), position the sheet immediately below the
    145   //    normal toolbar.
    146   //  - If the bookmark bar is shown (attached to the normal toolbar), position
    147   //    the sheet below the bookmark bar.
    148   //  - If the bookmark bar is currently animating, position the sheet according
    149   //    to where the bar will be when the animation ends.
    150   switch ([bookmarkBarController_ visualState]) {
    151     case bookmarks::kShowingState: {
    152       NSRect bookmarkBarFrame = [[bookmarkBarController_ view] frame];
    153       defaultSheetRect.origin.y = bookmarkBarFrame.origin.y;
    154       break;
    155     }
    156     case bookmarks::kHiddenState:
    157     case bookmarks::kDetachedState: {
    158       NSRect toolbarFrame = [[toolbarController_ view] frame];
    159       defaultSheetRect.origin.y = toolbarFrame.origin.y;
    160       break;
    161     }
    162     case bookmarks::kInvalidState:
    163     default:
    164       NOTREACHED();
    165   }
    166   return defaultSheetRect;
    167 }
    168 
    169 - (void)layoutSubviews {
    170   // With the exception of the top tab strip, the subviews which we lay out are
    171   // subviews of the content view, so we mainly work in the content view's
    172   // coordinate system. Note, however, that the content view's coordinate system
    173   // and the window's base coordinate system should coincide.
    174   NSWindow* window = [self window];
    175   NSView* contentView = [window contentView];
    176   NSRect contentBounds = [contentView bounds];
    177   CGFloat minX = NSMinX(contentBounds);
    178   CGFloat minY = NSMinY(contentBounds);
    179   CGFloat width = NSWidth(contentBounds);
    180 
    181   // Suppress title drawing if necessary.
    182   if ([window respondsToSelector:@selector(setShouldHideTitle:)])
    183     [(id)window setShouldHideTitle:![self hasTitleBar]];
    184 
    185   BOOL isFullscreen = [self isFullscreen];
    186   CGFloat floatingBarHeight = [self floatingBarHeight];
    187   // In fullscreen mode, |yOffset| accounts for the sliding position of the
    188   // floating bar and the extra offset needed to dodge the menu bar.
    189   CGFloat yOffset = isFullscreen ?
    190       (floor((1 - floatingBarShownFraction_) * floatingBarHeight) -
    191           [fullscreenController_ floatingBarVerticalOffset]) : 0;
    192   CGFloat maxY = NSMaxY(contentBounds) + yOffset;
    193   CGFloat startMaxY = maxY;
    194 
    195   if ([self hasTabStrip] && ![self useVerticalTabs]) {
    196     // If we need to lay out the top tab strip, replace |maxY| and |startMaxY|
    197     // with higher values, and then lay out the tab strip.
    198     NSRect windowFrame = [contentView convertRect:[window frame] fromView:nil];
    199     startMaxY = maxY = NSHeight(windowFrame) + yOffset;
    200     maxY = [self layoutTabStripAtMaxY:maxY width:width fullscreen:isFullscreen];
    201   }
    202 
    203   // Sanity-check |maxY|.
    204   DCHECK_GE(maxY, minY);
    205   DCHECK_LE(maxY, NSMaxY(contentBounds) + yOffset);
    206 
    207   // The base class already positions the side tab strip on the left side
    208   // of the window's content area and sizes it to take the entire vertical
    209   // height. All that's needed here is to push everything over to the right,
    210   // if necessary.
    211   if ([self useVerticalTabs]) {
    212     const CGFloat sideTabWidth = [[self tabStripView] bounds].size.width;
    213     minX += sideTabWidth;
    214     width -= sideTabWidth;
    215   }
    216 
    217   // Place the toolbar at the top of the reserved area.
    218   maxY = [self layoutToolbarAtMinX:minX maxY:maxY width:width];
    219 
    220   // If we're not displaying the bookmark bar below the infobar, then it goes
    221   // immediately below the toolbar.
    222   BOOL placeBookmarkBarBelowInfoBar = [self placeBookmarkBarBelowInfoBar];
    223   if (!placeBookmarkBarBelowInfoBar)
    224     maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
    225 
    226   // The floating bar backing view doesn't actually add any height.
    227   NSRect floatingBarBackingRect =
    228       NSMakeRect(minX, maxY, width, floatingBarHeight);
    229   [self layoutFloatingBarBackingView:floatingBarBackingRect
    230                           fullscreen:isFullscreen];
    231 
    232   // Place the find bar immediately below the toolbar/attached bookmark bar. In
    233   // fullscreen mode, it hangs off the top of the screen when the bar is hidden.
    234   // The find bar is unaffected by the side tab positioning.
    235   [findBarCocoaController_ positionFindBarViewAtMaxY:maxY maxWidth:width];
    236 
    237   // If in fullscreen mode, reset |maxY| to top of screen, so that the floating
    238   // bar slides over the things which appear to be in the content area.
    239   if (isFullscreen)
    240     maxY = NSMaxY(contentBounds);
    241 
    242   // Also place the infobar container immediate below the toolbar, except in
    243   // fullscreen mode in which case it's at the top of the visual content area.
    244   maxY = [self layoutInfoBarAtMinX:minX maxY:maxY width:width];
    245 
    246   // If the bookmark bar is detached, place it next in the visual content area.
    247   if (placeBookmarkBarBelowInfoBar)
    248     maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
    249 
    250   // Place the download shelf, if any, at the bottom of the view.
    251   minY = [self layoutDownloadShelfAtMinX:minX minY:minY width:width];
    252 
    253   // Finally, the content area takes up all of the remaining space.
    254   NSRect contentAreaRect = NSMakeRect(minX, minY, width, maxY - minY);
    255   [self layoutTabContentArea:contentAreaRect];
    256 
    257   // Normally, we don't need to tell the toolbar whether or not to show the
    258   // divider, but things break down during animation.
    259   [toolbarController_
    260       setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]];
    261 }
    262 
    263 - (CGFloat)floatingBarHeight {
    264   if (![self isFullscreen])
    265     return 0;
    266 
    267   CGFloat totalHeight = [fullscreenController_ floatingBarVerticalOffset];
    268 
    269   if ([self hasTabStrip])
    270     totalHeight += NSHeight([[self tabStripView] frame]);
    271 
    272   if ([self hasToolbar]) {
    273     totalHeight += NSHeight([[toolbarController_ view] frame]);
    274   } else if ([self hasLocationBar]) {
    275     totalHeight += NSHeight([[toolbarController_ view] frame]) +
    276                    kLocBarTopInset + kLocBarBottomInset;
    277   }
    278 
    279   if (![self placeBookmarkBarBelowInfoBar])
    280     totalHeight += NSHeight([[bookmarkBarController_ view] frame]);
    281 
    282   return totalHeight;
    283 }
    284 
    285 - (CGFloat)layoutTabStripAtMaxY:(CGFloat)maxY
    286                           width:(CGFloat)width
    287                      fullscreen:(BOOL)fullscreen {
    288   // Nothing to do if no tab strip.
    289   if (![self hasTabStrip])
    290     return maxY;
    291 
    292   NSView* tabStripView = [self tabStripView];
    293   CGFloat tabStripHeight = NSHeight([tabStripView frame]);
    294   maxY -= tabStripHeight;
    295   [tabStripView setFrame:NSMakeRect(0, maxY, width, tabStripHeight)];
    296 
    297   // Set indentation.
    298   [tabStripController_ setIndentForControls:(fullscreen ? 0 :
    299       [[tabStripController_ class] defaultIndentForControls])];
    300 
    301   // TODO(viettrungluu): Seems kind of bad -- shouldn't |-layoutSubviews| do
    302   // this? Moreover, |-layoutTabs| will try to animate....
    303   [tabStripController_ layoutTabs];
    304 
    305   // Now lay out incognito badge together with the tab strip.
    306   if (incognitoBadge_.get()) {
    307     // Avoid the full-screen button.
    308     CGFloat extraPadding = 0;
    309     if ([[self window] respondsToSelector:@selector(toggleFullScreen:)]) {
    310       NSButton* fullscreenButton =
    311           [[self window] standardWindowButton:NSWindowFullScreenButton];
    312       if (fullscreenButton)
    313         extraPadding += [fullscreenButton frame].size.width;
    314     }
    315 
    316     // Actually place the badge *above* |maxY|, by +2 to miss the divider.
    317     NSPoint origin = NSMakePoint(width - NSWidth([incognitoBadge_ frame]) -
    318                                      kIncognitoBadgeOffset - extraPadding,
    319                                  maxY + 2);
    320     [incognitoBadge_ setFrameOrigin:origin];
    321     [incognitoBadge_ setHidden:NO];  // Make sure it's shown.
    322   }
    323 
    324   return maxY;
    325 }
    326 
    327 - (CGFloat)layoutToolbarAtMinX:(CGFloat)minX
    328                           maxY:(CGFloat)maxY
    329                          width:(CGFloat)width {
    330   NSView* toolbarView = [toolbarController_ view];
    331   NSRect toolbarFrame = [toolbarView frame];
    332   if ([self hasToolbar]) {
    333     // The toolbar is present in the window, so we make room for it.
    334     DCHECK(![toolbarView isHidden]);
    335     toolbarFrame.origin.x = minX;
    336     toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame);
    337     toolbarFrame.size.width = width;
    338     maxY -= NSHeight(toolbarFrame);
    339   } else {
    340     if ([self hasLocationBar]) {
    341       // Location bar is present with no toolbar. Put a border of
    342       // |kLocBar...Inset| pixels around the location bar.
    343       // TODO(viettrungluu): This is moderately ridiculous. The toolbar should
    344       // really be aware of what its height should be (the way the toolbar
    345       // compression stuff is currently set up messes things up).
    346       DCHECK(![toolbarView isHidden]);
    347       toolbarFrame.origin.x = kLocBarLeftRightInset;
    348       toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame) - kLocBarTopInset;
    349       toolbarFrame.size.width = width - 2 * kLocBarLeftRightInset;
    350       maxY -= kLocBarTopInset + NSHeight(toolbarFrame) + kLocBarBottomInset;
    351     } else {
    352       DCHECK([toolbarView isHidden]);
    353     }
    354   }
    355   [toolbarView setFrame:toolbarFrame];
    356   return maxY;
    357 }
    358 
    359 - (BOOL)placeBookmarkBarBelowInfoBar {
    360   // If we are currently displaying the NTP detached bookmark bar or animating
    361   // to/from it (from/to anything else), we display the bookmark bar below the
    362   // infobar.
    363   return [bookmarkBarController_ isInState:bookmarks::kDetachedState] ||
    364       [bookmarkBarController_ isAnimatingToState:bookmarks::kDetachedState] ||
    365       [bookmarkBarController_ isAnimatingFromState:bookmarks::kDetachedState];
    366 }
    367 
    368 - (CGFloat)layoutBookmarkBarAtMinX:(CGFloat)minX
    369                               maxY:(CGFloat)maxY
    370                              width:(CGFloat)width {
    371   NSView* bookmarkBarView = [bookmarkBarController_ view];
    372   NSRect bookmarkBarFrame = [bookmarkBarView frame];
    373   BOOL oldHidden = [bookmarkBarView isHidden];
    374   BOOL newHidden = ![self isBookmarkBarVisible];
    375   if (oldHidden != newHidden)
    376     [bookmarkBarView setHidden:newHidden];
    377   bookmarkBarFrame.origin.x = minX;
    378   bookmarkBarFrame.origin.y = maxY - NSHeight(bookmarkBarFrame);
    379   bookmarkBarFrame.size.width = width;
    380   [bookmarkBarView setFrame:bookmarkBarFrame];
    381   maxY -= NSHeight(bookmarkBarFrame);
    382 
    383   // TODO(viettrungluu): Does this really belong here? Calling it shouldn't be
    384   // necessary in the non-NTP case.
    385   [bookmarkBarController_ layoutSubviews];
    386 
    387   return maxY;
    388 }
    389 
    390 - (void)layoutFloatingBarBackingView:(NSRect)frame
    391                           fullscreen:(BOOL)fullscreen {
    392   // Only display when in fullscreen mode.
    393   if (fullscreen) {
    394     // For certain window types such as app windows (e.g., the dev tools
    395     // window), there's no actual overlay. (Displaying one would result in an
    396     // overly sliding in only under the menu, which gives an ugly effect.)
    397     if (floatingBarBackingView_.get()) {
    398       BOOL aboveBookmarkBar = [self placeBookmarkBarBelowInfoBar];
    399 
    400       // Insert it into the view hierarchy if necessary.
    401       if (![floatingBarBackingView_ superview] ||
    402           aboveBookmarkBar != floatingBarAboveBookmarkBar_) {
    403         NSView* contentView = [[self window] contentView];
    404         // z-order gets messed up unless we explicitly remove the floatingbar
    405         // view and re-add it.
    406         [floatingBarBackingView_ removeFromSuperview];
    407         [contentView addSubview:floatingBarBackingView_
    408                      positioned:(aboveBookmarkBar ?
    409                                      NSWindowAbove : NSWindowBelow)
    410                      relativeTo:[bookmarkBarController_ view]];
    411         floatingBarAboveBookmarkBar_ = aboveBookmarkBar;
    412       }
    413 
    414       // Set its frame.
    415       [floatingBarBackingView_ setFrame:frame];
    416     }
    417 
    418     // But we want the logic to work as usual (for show/hide/etc. purposes).
    419     [fullscreenController_ overlayFrameChanged:frame];
    420   } else {
    421     // Okay to call even if |floatingBarBackingView_| is nil.
    422     if ([floatingBarBackingView_ superview])
    423       [floatingBarBackingView_ removeFromSuperview];
    424   }
    425 }
    426 
    427 - (CGFloat)layoutInfoBarAtMinX:(CGFloat)minX
    428                           maxY:(CGFloat)maxY
    429                          width:(CGFloat)width {
    430   NSView* containerView = [infoBarContainerController_ view];
    431   NSRect containerFrame = [containerView frame];
    432   maxY -= NSHeight(containerFrame);
    433   maxY += [infoBarContainerController_ antiSpoofHeight];
    434   containerFrame.origin.x = minX;
    435   containerFrame.origin.y = maxY;
    436   containerFrame.size.width = width;
    437   [containerView setFrame:containerFrame];
    438   return maxY;
    439 }
    440 
    441 - (CGFloat)layoutDownloadShelfAtMinX:(CGFloat)minX
    442                                 minY:(CGFloat)minY
    443                                width:(CGFloat)width {
    444   if (downloadShelfController_.get()) {
    445     NSView* downloadView = [downloadShelfController_ view];
    446     NSRect downloadFrame = [downloadView frame];
    447     downloadFrame.origin.x = minX;
    448     downloadFrame.origin.y = minY;
    449     downloadFrame.size.width = width;
    450     [downloadView setFrame:downloadFrame];
    451     minY += NSHeight(downloadFrame);
    452   }
    453   return minY;
    454 }
    455 
    456 - (void)layoutTabContentArea:(NSRect)newFrame {
    457   NSView* tabContentView = [self tabContentArea];
    458   NSRect tabContentFrame = [tabContentView frame];
    459 
    460   bool contentShifted =
    461       NSMaxY(tabContentFrame) != NSMaxY(newFrame) ||
    462       NSMinX(tabContentFrame) != NSMinX(newFrame);
    463 
    464   tabContentFrame = newFrame;
    465   [tabContentView setFrame:tabContentFrame];
    466 
    467   // If the relayout shifts the content area up or down, let the renderer know.
    468   if (contentShifted) {
    469     if (TabContents* contents = browser_->GetSelectedTabContents()) {
    470       if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
    471         rwhv->WindowFrameChanged();
    472     }
    473   }
    474 }
    475 
    476 - (BOOL)shouldShowBookmarkBar {
    477   DCHECK(browser_.get());
    478   return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ?
    479       YES : NO;
    480 }
    481 
    482 - (BOOL)shouldShowDetachedBookmarkBar {
    483   // NTP4 never detaches the bookmark bar.
    484   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNewTabPage4))
    485     return NO;
    486 
    487   DCHECK(browser_.get());
    488   TabContents* contents = browser_->GetSelectedTabContents();
    489   return (contents &&
    490           contents->ShouldShowBookmarkBar() &&
    491           ![previewableContentsController_ isShowingPreview]);
    492 }
    493 
    494 - (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression {
    495   CGFloat newHeight =
    496       [toolbarController_ desiredHeightForCompression:compression];
    497   NSRect toolbarFrame = [[toolbarController_ view] frame];
    498   CGFloat deltaH = newHeight - toolbarFrame.size.height;
    499 
    500   if (deltaH == 0)
    501     return;
    502 
    503   toolbarFrame.size.height = newHeight;
    504   NSRect bookmarkFrame = [[bookmarkBarController_ view] frame];
    505   bookmarkFrame.size.height = bookmarkFrame.size.height - deltaH;
    506   [[toolbarController_ view] setFrame:toolbarFrame];
    507   [[bookmarkBarController_ view] setFrame:bookmarkFrame];
    508   [self layoutSubviews];
    509 }
    510 
    511 // TODO(rohitrao): This function has shrunk into uselessness, and
    512 // |-setFullscreen:| has grown rather large.  Find a good way to break up
    513 // |-setFullscreen:| into smaller pieces.  http://crbug.com/36449
    514 - (void)adjustUIForFullscreen:(BOOL)fullscreen {
    515   // Create the floating bar backing view if necessary.
    516   if (fullscreen && !floatingBarBackingView_.get() &&
    517       ([self hasTabStrip] || [self hasToolbar] || [self hasLocationBar])) {
    518     floatingBarBackingView_.reset(
    519         [[FloatingBarBackingView alloc] initWithFrame:NSZeroRect]);
    520   }
    521 }
    522 
    523 - (void)enableBarVisibilityUpdates {
    524   // Early escape if there's nothing to do.
    525   if (barVisibilityUpdatesEnabled_)
    526     return;
    527 
    528   barVisibilityUpdatesEnabled_ = YES;
    529 
    530   if ([barVisibilityLocks_ count])
    531     [fullscreenController_ ensureOverlayShownWithAnimation:NO delay:NO];
    532   else
    533     [fullscreenController_ ensureOverlayHiddenWithAnimation:NO delay:NO];
    534 }
    535 
    536 - (void)disableBarVisibilityUpdates {
    537   // Early escape if there's nothing to do.
    538   if (!barVisibilityUpdatesEnabled_)
    539     return;
    540 
    541   barVisibilityUpdatesEnabled_ = NO;
    542   [fullscreenController_ cancelAnimationAndTimers];
    543 }
    544 
    545 - (void)setUpOSFullScreenButton {
    546   NSWindow* window = [self window];
    547   if ([window respondsToSelector:@selector(toggleFullScreen:)]) {
    548     NSWindowCollectionBehavior behavior = [window collectionBehavior];
    549     behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
    550     [window setCollectionBehavior:behavior];
    551 
    552     NSButton* fullscreenButton =
    553         [window standardWindowButton:NSWindowFullScreenButton];
    554     [fullscreenButton setAction:@selector(enterFullscreen:)];
    555     [fullscreenButton setTarget:self];
    556   }
    557 }
    558 
    559 @end  // @implementation BrowserWindowController(Private)
    560