#include "base/command_line.h"
#include "base/mac/mac_util.h"
#import "base/mac/scoped_nsobject.h"
+#import "base/mac/sdk_forward_declarations.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window_state.h"
+#import "chrome/browser/ui/cocoa/browser_window_layout.h"
#import "chrome/browser/ui/cocoa/dev_tools_controller.h"
#import "chrome/browser/ui/cocoa/fast_resize_view.h"
#import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h"
#import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
#import "chrome/browser/ui/cocoa/framed_browser_window.h"
-#import "chrome/browser/ui/cocoa/fullscreen_mode_controller.h"
#import "chrome/browser/ui/cocoa/fullscreen_window.h"
#import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
#include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
-#import "chrome/browser/ui/cocoa/nsview_additions.h"
#import "chrome/browser/ui/cocoa/presentation_mode_controller.h"
#import "chrome/browser/ui/cocoa/profiles/avatar_button_controller.h"
#import "chrome/browser/ui/cocoa/profiles/avatar_icon_controller.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#import "ui/base/cocoa/focus_tracker.h"
+#import "ui/base/cocoa/nsview_additions.h"
#include "ui/base/ui_base_types.h"
using content::RenderWidgetHostView;
// Space between the incognito badge and the right edge of the window.
const CGFloat kAvatarRightOffset = 4;
-// The amount by which to shrink the tab strip (on the right) when the
-// incognito badge is present.
-const CGFloat kAvatarTabStripShrink = 18;
-
-// Width of the full screen icon. Used to position the AvatarButton to the
-// left of the icon.
-const CGFloat kFullscreenIconWidth = 32;
-
-// Insets for the location bar, used when the full toolbar is hidden.
-// TODO(viettrungluu): We can argue about the "correct" insetting; I like the
-// following best, though arguably 0 inset is better/more correct.
-const CGFloat kLocBarLeftRightInset = 1;
-const CGFloat kLocBarTopInset = 0;
-const CGFloat kLocBarBottomInset = 1;
-
} // namespace
@implementation BrowserWindowController(Private)
// If we're in fullscreen mode, save the position of the regular window
// instead.
- NSWindow* window = [self isFullscreen] ? savedRegularWindow_ : [self window];
+ NSWindow* window =
+ [self isInAnyFullscreenMode] ? savedRegularWindow_ : [self window];
// Window positions are stored relative to the origin of the primary monitor.
NSRect monitorFrame = [[[NSScreen screens] objectAtIndex:0] frame];
ui::WindowShowState show_state = ui::SHOW_STATE_NORMAL;
if ([window isMiniaturized])
show_state = ui::SHOW_STATE_MINIMIZED;
- else if ([self isFullscreen])
+ else if ([self isInAnyFullscreenMode])
show_state = ui::SHOW_STATE_FULLSCREEN;
chrome::SaveWindowPlacement(browser_.get(), bounds, show_state);
gfx::Rect workArea(NSRectToCGRect([windowScreen visibleFrame]));
workArea.set_y(monitorFrame.size.height - workArea.y() - workArea.height());
- DictionaryPrefUpdate update(
- prefs,
- chrome::GetWindowPlacementKey(browser_.get()).c_str());
- base::DictionaryValue* windowPreferences = update.Get();
+ scoped_ptr<DictionaryPrefUpdate> update =
+ chrome::GetWindowPlacementDictionaryReadWrite(
+ chrome::GetWindowName(browser_.get()),
+ browser_->profile()->GetPrefs());
+ base::DictionaryValue* windowPreferences = update->Get();
windowPreferences->SetInteger("left", bounds.x());
windowPreferences->SetInteger("top", bounds.y());
windowPreferences->SetInteger("right", bounds.right());
}
- (void)layoutSubviews {
- // With the exception of the top tab strip, the subviews which we lay out are
- // subviews of the content view, so we mainly work in the content view's
- // coordinate system. Note, however, that the content view's coordinate system
- // and the window's base coordinate system should coincide.
- NSWindow* window = [self window];
- NSView* contentView = [window contentView];
- NSRect contentBounds = [contentView bounds];
- CGFloat minX = NSMinX(contentBounds);
- CGFloat minY = NSMinY(contentBounds);
- CGFloat width = NSWidth(contentBounds);
-
- BOOL useSimplifiedFullscreen = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableSimplifiedFullscreen);
-
// Suppress title drawing if necessary.
- if ([window respondsToSelector:@selector(setShouldHideTitle:)])
- [(id)window setShouldHideTitle:![self hasTitleBar]];
+ if ([self.window respondsToSelector:@selector(setShouldHideTitle:)])
+ [(id)self.window setShouldHideTitle:![self hasTitleBar]];
- // Update z-order. The code below depends on this.
- [self updateSubviewZOrder:[self inPresentationMode]];
-
- BOOL inPresentationMode = [self inPresentationMode];
- CGFloat floatingBarHeight = [self floatingBarHeight];
- // In presentation mode, |yOffset| accounts for the sliding position of the
- // floating bar and the extra offset needed to dodge the menu bar.
- CGFloat yOffset = inPresentationMode && !useSimplifiedFullscreen ?
- (std::floor((1 - floatingBarShownFraction_) * floatingBarHeight) -
- [presentationModeController_ floatingBarVerticalOffset]) : 0;
- CGFloat maxY = NSMaxY(contentBounds) + yOffset;
-
- if ([self hasTabStrip]) {
- // If we need to lay out the top tab strip, replace |maxY| with a higher
- // value, and then lay out the tab strip.
- NSRect windowFrame = [contentView convertRect:[window frame] fromView:nil];
- maxY = NSHeight(windowFrame) + yOffset;
- if (useSimplifiedFullscreen && [self isFullscreen]) {
- CGFloat tabStripHeight = NSHeight([[self tabStripView] frame]);
- CGFloat revealAmount = (1 - floatingBarShownFraction_) * tabStripHeight;
- // In simplified fullscreen, only the toolbar is visible by default, and
- // the tabstrip and menu bar come down (each separately) when the user
- // mouses near the top of the window. Push the maxY of the toolbar up by
- // the amount of the tabstrip that is revealed, while removing the amount
- // of space needed by the menu bar.
- maxY += std::floor(
- revealAmount - [fullscreenModeController_ menuBarHeight]);
- }
- maxY = [self layoutTabStripAtMaxY:maxY
- width:width
- fullscreen:[self isFullscreen]];
- }
-
- // Sanity-check |maxY|.
- DCHECK_GE(maxY, minY);
- DCHECK_LE(maxY, NSMaxY(contentBounds) + yOffset);
-
- // Place the toolbar at the top of the reserved area.
- maxY = [self layoutToolbarAtMinX:minX maxY:maxY width:width];
-
- // If we're not displaying the bookmark bar below the info bar, then it goes
- // immediately below the toolbar.
- BOOL placeBookmarkBarBelowInfoBar = [self placeBookmarkBarBelowInfoBar];
- if (!placeBookmarkBarBelowInfoBar)
- maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
-
- // The floating bar backing view doesn't actually add any height.
- NSRect floatingBarBackingRect =
- NSMakeRect(minX, maxY, width, floatingBarHeight);
- [self layoutFloatingBarBackingView:floatingBarBackingRect
- presentationMode:inPresentationMode];
-
- // Place the find bar immediately below the toolbar/attached bookmark bar. In
- // presentation mode, it hangs off the top of the screen when the bar is
- // hidden.
- [findBarCocoaController_ positionFindBarViewAtMaxY:maxY maxWidth:width];
- [fullscreenExitBubbleController_ positionInWindowAtTop:maxY width:width];
-
- // If in presentation mode, reset |maxY| to top of screen, so that the
- // floating bar slides over the things which appear to be in the content area.
- if (inPresentationMode ||
- (useSimplifiedFullscreen && !fullscreenUrl_.is_empty())) {
- maxY = NSMaxY(contentBounds);
- }
-
- // Also place the info bar container immediate below the toolbar, except in
- // presentation mode in which case it's at the top of the visual content area.
- maxY = [self layoutInfoBarAtMinX:minX maxY:maxY width:width];
-
- // If the bookmark bar is detached, place it next in the visual content area.
- if (placeBookmarkBarBelowInfoBar)
- maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
-
- // Place the download shelf, if any, at the bottom of the view.
- minY = [self layoutDownloadShelfAtMinX:minX minY:minY width:width];
+ [bookmarkBarController_ updateHiddenState];
+ [self updateSubviewZOrder];
- // Finally, the content area takes up all of the remaining space.
- NSRect contentAreaRect = NSMakeRect(minX, minY, width, maxY - minY);
- [self layoutTabContentArea:contentAreaRect];
+ base::scoped_nsobject<BrowserWindowLayout> layout(
+ [[BrowserWindowLayout alloc] init]);
+ [self updateLayoutParameters:layout];
+ [self applyLayout:layout];
- // Normally, we don't need to tell the toolbar whether or not to show the
- // divider, but things break down during animation.
[toolbarController_ setDividerOpacity:[self toolbarDividerOpacity]];
}
-- (CGFloat)floatingBarHeight {
- if (![self inPresentationMode])
- return 0;
-
- CGFloat totalHeight = [presentationModeController_ floatingBarVerticalOffset];
-
- if ([self hasTabStrip])
- totalHeight += NSHeight([[self tabStripView] frame]);
-
- if ([self hasToolbar]) {
- totalHeight += NSHeight([[toolbarController_ view] frame]);
- } else if ([self hasLocationBar]) {
- totalHeight += NSHeight([[toolbarController_ view] frame]) +
- kLocBarTopInset + kLocBarBottomInset;
- }
-
- if (![self placeBookmarkBarBelowInfoBar])
- totalHeight += NSHeight([[bookmarkBarController_ view] frame]);
-
- return totalHeight;
-}
-
- (CGFloat)layoutTabStripAtMaxY:(CGFloat)maxY
width:(CGFloat)width
fullscreen:(BOOL)fullscreen {
NSView* tabStripView = [self tabStripView];
CGFloat tabStripHeight = NSHeight([tabStripView frame]);
maxY -= tabStripHeight;
- [tabStripView setFrame:NSMakeRect(0, maxY, width, tabStripHeight)];
+ NSRect tabStripFrame = NSMakeRect(0, maxY, width, tabStripHeight);
+ BOOL requiresRelayout = !NSEqualRects(tabStripFrame, [tabStripView frame]);
// In Yosemite fullscreen, manually add the fullscreen controls to the tab
// strip.
- BOOL isInAppKitFullscreen =
- [self isInSystemFullscreen] || enteringSystemFullscreen_;
BOOL addControlsInFullscreen =
- isInAppKitFullscreen && base::mac::IsOSYosemiteOrLater();
+ [self isInAppKitFullscreen] && base::mac::IsOSYosemiteOrLater();
// Set left indentation based on fullscreen mode status.
CGFloat leftIndent = 0;
if (!fullscreen || addControlsInFullscreen)
leftIndent = [[tabStripController_ class] defaultLeftIndentForControls];
- [tabStripController_ setLeftIndentForControls:leftIndent];
+ if (leftIndent != [tabStripController_ leftIndentForControls]) {
+ [tabStripController_ setLeftIndentForControls:leftIndent];
+ requiresRelayout = YES;
+ }
if (addControlsInFullscreen)
[tabStripController_ addWindowControls];
else
[tabStripController_ removeWindowControls];
+ // fullScreenButton is non-nil when isInAnyFullscreenMode is NO, and OS
+ // version is in the range 10.7 <= version <= 10.9. Starting with 10.10, the
+ // zoom/maximize button acts as the fullscreen button.
+ NSButton* fullScreenButton =
+ [[self window] standardWindowButton:NSWindowFullScreenButton];
+
// Lay out the icognito/avatar badge because calculating the indentation on
// the right depends on it.
NSView* avatarButton = [avatarButtonController_ view];
if ([self shouldUseNewAvatarButton]) {
// The fullscreen icon is displayed to the right of the avatar button.
- if (![self isFullscreen])
- badgeXOffset -= kFullscreenIconWidth;
+ if (![self isInAnyFullscreenMode] && fullScreenButton)
+ badgeXOffset -= width - NSMinX([fullScreenButton frame]);
// Center the button vertically on the tabstrip.
badgeYOffset = (tabStripHeight - buttonHeight) / 2;
} else {
}
// Calculate the right indentation. The default indentation built into the
- // tabstrip leaves enough room for the fullscreen button or presentation mode
- // toggle button on Lion. On non-Lion systems, the right indent needs to be
+ // tabstrip leaves enough room for the fullscreen button on Lion (10.7) to
+ // Mavericks (10.9). On 10.6 and >=10.10, the right indent needs to be
// adjusted to make room for the new tab button when an avatar is present.
CGFloat rightIndent = 0;
- if (base::mac::IsOSLionOrLater() &&
- [[self window] isKindOfClass:[FramedBrowserWindow class]]) {
- FramedBrowserWindow* window =
- static_cast<FramedBrowserWindow*>([self window]);
- rightIndent += -[window fullScreenButtonOriginAdjustment].x;
+ if (![self isInAnyFullscreenMode] && fullScreenButton) {
+ rightIndent = width - NSMinX([fullScreenButton frame]);
if ([self shouldUseNewAvatarButton]) {
- // The new avatar is wider than the default indentation, so we need to
- // account for its width.
- rightIndent += NSWidth([avatarButton frame]) + kAvatarTabStripShrink;
-
- // When the fullscreen icon is not displayed, return its width to the
- // tabstrip.
- if ([self isFullscreen])
- rightIndent -= kFullscreenIconWidth;
+ // The new avatar button is to the left of the fullscreen button.
+ // (The old avatar button is to the right).
+ rightIndent += NSWidth([avatarButton frame]) + kAvatarRightOffset;
}
} else if ([self shouldShowAvatar]) {
- rightIndent += kAvatarTabStripShrink +
- NSWidth([avatarButton frame]) + kAvatarRightOffset;
+ rightIndent += NSWidth([avatarButton frame]) + kAvatarRightOffset;
}
- [tabStripController_ setRightIndentForControls:rightIndent];
-
- // Go ahead and layout the tabs.
- [tabStripController_ layoutTabsWithoutAnimation];
- return maxY;
-}
+ if (rightIndent != [tabStripController_ rightIndentForControls]) {
+ [tabStripController_ setRightIndentForControls:rightIndent];
+ requiresRelayout = YES;
+ }
-- (CGFloat)layoutToolbarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width {
- NSView* toolbarView = [toolbarController_ view];
- NSRect toolbarFrame = [toolbarView frame];
- if ([self hasToolbar]) {
- // The toolbar is present in the window, so we make room for it.
- DCHECK(![toolbarView isHidden]);
- toolbarFrame.origin.x = minX;
- toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame);
- toolbarFrame.size.width = width;
- maxY -= NSHeight(toolbarFrame);
- } else {
- if ([self hasLocationBar]) {
- // Location bar is present with no toolbar. Put a border of
- // |kLocBar...Inset| pixels around the location bar.
- // TODO(viettrungluu): This is moderately ridiculous. The toolbar should
- // really be aware of what its height should be (the way the toolbar
- // compression stuff is currently set up messes things up).
- DCHECK(![toolbarView isHidden]);
- toolbarFrame.origin.x = kLocBarLeftRightInset;
- toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame) - kLocBarTopInset;
- toolbarFrame.size.width = width - 2 * kLocBarLeftRightInset;
- maxY -= kLocBarTopInset + NSHeight(toolbarFrame) + kLocBarBottomInset;
- } else {
- DCHECK([toolbarView isHidden]);
- }
+ // It is undesirable to force tabs relayout when the tap strip's frame did
+ // not change, because it will interrupt tab animations in progress.
+ // In addition, there appears to be an AppKit bug on <10.9 where interrupting
+ // a tab animation resulted in the tab frame being the animator's target
+ // frame instead of the interrupting setFrame. (See http://crbug.com/415093)
+ if (requiresRelayout) {
+ [tabStripView setFrame:tabStripFrame];
+ [tabStripController_ layoutTabsWithoutAnimation];
}
- [toolbarView setFrame:toolbarFrame];
+
return maxY;
}
[bookmarkBarController_ isAnimatingFromState:BookmarkBar::DETACHED];
}
-- (CGFloat)layoutBookmarkBarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width {
- [bookmarkBarController_ updateHiddenState];
-
- NSView* bookmarkBarView = [bookmarkBarController_ view];
- NSRect frame = [bookmarkBarView frame];
- frame.origin.x = minX;
- frame.origin.y = maxY - NSHeight(frame);
- frame.size.width = width;
- [bookmarkBarView setFrame:frame];
- maxY -= NSHeight(frame);
-
- // Pin the bookmark bar to the top of the window and make the width flexible.
- [bookmarkBarView setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
-
- // TODO(viettrungluu): Does this really belong here? Calling it shouldn't be
- // necessary in the non-NTP case.
- [bookmarkBarController_ layoutSubviews];
-
- return maxY;
-}
-
-- (void)layoutFloatingBarBackingView:(NSRect)frame
- presentationMode:(BOOL)presentationMode {
- // Only display when in presentation mode.
- if (presentationMode) {
- // For certain window types such as app windows (e.g., the dev tools
- // window), there's no actual overlay. (Displaying one would result in an
- // overly sliding in only under the menu, which gives an ugly effect.)
- if (floatingBarBackingView_.get()) {
- // Set its frame.
- [floatingBarBackingView_ setFrame:frame];
- }
-
- // But we want the logic to work as usual (for show/hide/etc. purposes).
- [presentationModeController_ overlayFrameChanged:frame];
- } else {
- // Okay to call even if |floatingBarBackingView_| is nil.
- if ([floatingBarBackingView_ superview])
- [floatingBarBackingView_ removeFromSuperview];
- }
-}
-
-- (CGFloat)layoutInfoBarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width {
- NSView* containerView = [infoBarContainerController_ view];
- NSRect containerFrame = [containerView frame];
- maxY -= NSHeight(containerFrame);
- maxY += [infoBarContainerController_ overlappingTipHeight];
- containerFrame.origin.x = minX;
- containerFrame.origin.y = maxY;
- containerFrame.size.width = width;
- [containerView setFrame:containerFrame];
- return maxY;
-}
-
-- (CGFloat)layoutDownloadShelfAtMinX:(CGFloat)minX
- minY:(CGFloat)minY
- width:(CGFloat)width {
- if (downloadShelfController_.get()) {
- NSView* downloadView = [downloadShelfController_ view];
- NSRect downloadFrame = [downloadView frame];
- downloadFrame.origin.x = minX;
- downloadFrame.origin.y = minY;
- downloadFrame.size.width = width;
- [downloadView setFrame:downloadFrame];
- minY += NSHeight(downloadFrame);
- }
- return minY;
-}
-
- (void)layoutTabContentArea:(NSRect)newFrame {
NSView* tabContentView = [self tabContentArea];
NSRect tabContentFrame = [tabContentView frame];
delay:YES];
}
-- (void)setPresentationModeInternal:(BOOL)presentationMode
- forceDropdown:(BOOL)forceDropdown {
- if (presentationMode == [self inPresentationMode])
- return;
+- (void)configurePresentationModeController {
+ BOOL fullscreen_for_tab =
+ browser_->fullscreen_controller()->IsWindowFullscreenForTabOrPending();
+ BOOL kiosk_mode =
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode);
+ BOOL showDropdown =
+ !fullscreen_for_tab && !kiosk_mode && ([self floatingBarHasFocus]);
+ if (permissionBubbleCocoa_ && permissionBubbleCocoa_->IsVisible()) {
+ DCHECK(permissionBubbleCocoa_->window());
+ // A visible permission bubble will force the dropdown to remain visible.
+ [self lockBarVisibilityForOwner:permissionBubbleCocoa_->window()
+ withAnimation:NO
+ delay:NO];
+ showDropdown = YES;
+ // Register to be notified when the permission bubble is closed, to
+ // allow fullscreen to hide the dropdown.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(permissionBubbleWindowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:permissionBubbleCocoa_->window()];
+ }
+ if (showDropdown) {
+ // Turn on layered mode for the window's root view for the entry
+ // animation. Without this, the OS fullscreen animation for entering
+ // fullscreen mode does not correctly draw the tab strip.
+ // It will be turned off (set back to NO) when the animation finishes,
+ // in -windowDidEnterFullScreen:.
+ // Leaving wantsLayer on for the duration of presentation mode causes
+ // performance issues when the dropdown is animated in/out. It also does
+ // not seem to be required for the exit animation.
+ windowViewWantsLayer_ = [[[self window] cr_windowView] wantsLayer];
+ [[[self window] cr_windowView] setWantsLayer:YES];
+ }
+
+ NSView* contentView = [[self window] contentView];
+ [presentationModeController_
+ enterPresentationModeForContentView:contentView
+ showDropdown:showDropdown];
+}
+
+- (void)adjustUIForExitingFullscreenAndStopOmniboxSliding {
+ [presentationModeController_ exitPresentationMode];
+ presentationModeController_.reset();
+
+ // Force the bookmark bar z-order to update.
+ [[bookmarkBarController_ view] removeFromSuperview];
+ [self layoutSubviews];
+}
- if (presentationMode) {
- BOOL fullscreen_for_tab =
- browser_->fullscreen_controller()->IsWindowFullscreenForTabOrPending();
- BOOL kiosk_mode =
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode);
- BOOL showDropdown = !fullscreen_for_tab &&
- !kiosk_mode &&
- (forceDropdown || [self floatingBarHasFocus]);
+- (void)adjustUIForSlidingFullscreenStyle:(fullscreen_mac::SlidingStyle)style {
+ if (!presentationModeController_) {
presentationModeController_.reset(
- [[PresentationModeController alloc] initWithBrowserController:self]);
-
- if (permissionBubbleCocoa_ && permissionBubbleCocoa_->IsVisible()) {
- DCHECK(permissionBubbleCocoa_->window());
- // A visible permission bubble will force the dropdown to remain visible.
- [self lockBarVisibilityForOwner:permissionBubbleCocoa_->window()
- withAnimation:NO
- delay:NO];
- showDropdown = YES;
- // Register to be notified when the permission bubble is closed, to
- // allow fullscreen to hide the dropdown.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(permissionBubbleWindowWillClose:)
- name:NSWindowWillCloseNotification
- object:permissionBubbleCocoa_->window()];
- }
- if (showDropdown) {
- // Turn on layered mode for the window's root view for the entry
- // animation. Without this, the OS fullscreen animation for entering
- // fullscreen mode does not correctly draw the tab strip.
- // It will be turned off (set back to NO) when the animation finishes,
- // in -windowDidEnterFullScreen:.
- // Leaving wantsLayer on for the duration of presentation mode causes
- // performance issues when the dropdown is animated in/out. It also does
- // not seem to be required for the exit animation.
- [[[self window] cr_windowView] setWantsLayer:YES];
- }
- NSView* contentView = [[self window] contentView];
- [presentationModeController_ enterPresentationModeForContentView:contentView
- showDropdown:showDropdown];
+ [self newPresentationModeControllerWithStyle:style]);
+ [self configurePresentationModeController];
} else {
- [presentationModeController_ exitPresentationMode];
- presentationModeController_.reset();
+ presentationModeController_.get().slidingStyle = style;
+ }
+
+ if (!floatingBarBackingView_.get() &&
+ ([self hasTabStrip] || [self hasToolbar] || [self hasLocationBar])) {
+ floatingBarBackingView_.reset(
+ [[FloatingBarBackingView alloc] initWithFrame:NSZeroRect]);
+ [floatingBarBackingView_
+ setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
}
- [self adjustUIForPresentationMode:presentationMode];
+ // Force the bookmark bar z-order to update.
+ [[bookmarkBarController_ view] removeFromSuperview];
[self layoutSubviews];
}
+- (PresentationModeController*)newPresentationModeControllerWithStyle:
+ (fullscreen_mac::SlidingStyle)style {
+ return [[PresentationModeController alloc] initWithBrowserController:self
+ style:style];
+}
+
- (void)enterImmersiveFullscreen {
- // |-isFullscreen:| will return YES from here onwards.
- enteringFullscreen_ = YES; // Set to NO by |-windowDidEnterFullScreen:|.
+ // Set to NO by |-windowDidEnterFullScreen:|.
+ enteringImmersiveFullscreen_ = YES;
// Fade to black.
const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
regularWindow:[self window]
fullscreenWindow:fullscreenWindow_.get()];
- // When simplified fullscreen is enabled, do not enter presentation mode.
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen)) {
- // TODO(rohitrao): Add code to manage the menubar here.
- } else {
- [self adjustUIForPresentationMode:YES];
- [self setPresentationModeInternal:YES forceDropdown:NO];
- }
+ fullscreen_mac::SlidingStyle style = fullscreen_mac::OMNIBOX_TABS_HIDDEN;
+ [self adjustUIForSlidingFullscreenStyle:style];
+
+ // AppKit is helpful and prevents NSWindows from having the same height as
+ // the screen while the menu bar is showing. This only applies to windows on
+ // a secondary screen, in a separate space. Calling [NSWindow
+ // setFrame:display:] with the screen's height will always reduce the
+ // height by the height of the MenuBar. Calling the method with any other
+ // height works fine. The relevant method in the 10.10 AppKit SDK is called:
+ // _canAdjustSizeForScreensHaveSeparateSpacesIfFillingSecondaryScreen
+ //
+ // TODO(erikchen): Refactor the logic to allow the window to be shown after
+ // the menubar has been hidden. This would remove the need for this hack.
+ // http://crbug.com/403203
+ NSRect frame = [[[self window] screen] frame];
+ if (!NSEqualRects(frame, [fullscreenWindow_ frame]))
+ [fullscreenWindow_ setFrame:[[[self window] screen] frame] display:YES];
[self layoutSubviews];
kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true);
}
- // When simplified fullscreen is enabled, the menubar status is managed
- // directly by BWC.
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen)) {
- // TODO(rohitrao): Add code to manage the menubar here.
- }
-
[self windowWillExitFullScreen:nil];
[self moveViewsForImmersiveFullscreen:NO
}
}
-// TODO(rohitrao): This function has shrunk into uselessness, and
-// |-setFullscreen:| has grown rather large. Find a good way to break up
-// |-setFullscreen:| into smaller pieces. http://crbug.com/36449
-- (void)adjustUIForPresentationMode:(BOOL)fullscreen {
- // Create the floating bar backing view if necessary.
- if (fullscreen && !floatingBarBackingView_.get() &&
- ([self hasTabStrip] || [self hasToolbar] || [self hasLocationBar])) {
- floatingBarBackingView_.reset(
- [[FloatingBarBackingView alloc] initWithFrame:NSZeroRect]);
- [floatingBarBackingView_ setAutoresizingMask:(NSViewWidthSizable |
- NSViewMinYMargin)];
- }
-
- // Force the bookmark bar z-order to update.
- [[bookmarkBarController_ view] removeFromSuperview];
- [self updateSubviewZOrder:fullscreen];
- [self updateAllowOverlappingViews:fullscreen];
-}
-
- (void)showFullscreenExitBubbleIfNecessary {
// This method is called in response to
// |-updateFullscreenExitBubbleURL:bubbleType:|. If we're in the middle of the
- // transition into fullscreen (i.e., using the System Fullscreen API), do not
+ // transition into fullscreen (i.e., using the AppKit Fullscreen API), do not
// show the bubble because it will cause visual jank
// (http://crbug.com/130649). This will be called again as part of
// |-windowDidEnterFullScreen:|, so arrange to do that work then instead.
- if (enteringFullscreen_)
+ if (enteringAppKitFullscreen_)
return;
[self hideOverlayIfPossibleWithAnimation:NO delay:NO];
savedRegularWindowFrame_ = [window frame];
BOOL mode = enteringPresentationMode_ ||
browser_->fullscreen_controller()->IsWindowFullscreenForTabOrPending();
- enteringFullscreen_ = YES;
- enteringSystemFullscreen_ = YES;
- [self setPresentationModeInternal:mode forceDropdown:NO];
+ enteringAppKitFullscreen_ = YES;
+
+ fullscreen_mac::SlidingStyle style =
+ mode ? fullscreen_mac::OMNIBOX_TABS_HIDDEN
+ : fullscreen_mac::OMNIBOX_TABS_PRESENT;
+
+ [self adjustUIForSlidingFullscreenStyle:style];
}
- (void)windowDidEnterFullScreen:(NSNotification*)notification {
if (notification) // For System Fullscreen when non-nil.
[self deregisterForContentViewResizeNotifications];
- enteringFullscreen_ = NO;
- enteringSystemFullscreen_ = NO;
+ enteringAppKitFullscreen_ = NO;
+ enteringImmersiveFullscreen_ = NO;
enteringPresentationMode_ = NO;
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen) &&
- fullscreenUrl_.is_empty()) {
- fullscreenModeController_.reset([[FullscreenModeController alloc]
- initWithBrowserWindowController:self]);
- }
-
[self showFullscreenExitBubbleIfNecessary];
browser_->WindowFullscreenStateChanged();
- [[[self window] cr_windowView] setWantsLayer:NO];
+ [[[self window] cr_windowView] setWantsLayer:windowViewWantsLayer_];
}
- (void)windowWillExitFullScreen:(NSNotification*)notification {
if (notification) // For System Fullscreen when non-nil.
[self registerForContentViewResizeNotifications];
- fullscreenModeController_.reset();
[self destroyFullscreenExitBubbleIfNecessary];
- [self setPresentationModeInternal:NO forceDropdown:NO];
+ [self adjustUIForExitingFullscreenAndStopOmniboxSliding];
}
- (void)windowDidExitFullScreen:(NSNotification*)notification {
- (void)windowDidFailToEnterFullScreen:(NSWindow*)window {
[self deregisterForContentViewResizeNotifications];
- enteringFullscreen_ = NO;
- enteringSystemFullscreen_ = NO;
- [self setPresentationModeInternal:NO forceDropdown:NO];
-
- // Force a relayout to try and get the window back into a reasonable state.
- [self layoutSubviews];
+ enteringAppKitFullscreen_ = NO;
+ [self adjustUIForExitingFullscreenAndStopOmniboxSliding];
}
- (void)windowDidFailToExitFullScreen:(NSWindow*)window {
return [bookmarkBarController_ toolbarDividerOpacity];
}
-- (void)updateSubviewZOrder:(BOOL)inPresentationMode {
- NSView* contentView = [[self window] contentView];
- NSView* toolbarView = [toolbarController_ view];
-
- if (inPresentationMode) {
- // Toolbar is above tab contents so that it can slide down from top of
- // screen.
- [contentView cr_ensureSubview:toolbarView
- isPositioned:NSWindowAbove
- relativeTo:[self tabContentArea]];
- } else {
- // Toolbar is below tab contents so that the info bar arrow can appear above
- // it.
- [contentView cr_ensureSubview:toolbarView
- isPositioned:NSWindowBelow
- relativeTo:[self tabContentArea]];
- }
+- (void)updateLayerOrdering:(NSView*)view {
+ // Hold a reference to the view so that it doesn't accidentally get
+ // dealloc'ed.
+ base::scoped_nsobject<NSView> reference([view retain]);
- // The bookmark bar is always below the toolbar.
- [contentView cr_ensureSubview:[bookmarkBarController_ view]
- isPositioned:NSWindowBelow
- relativeTo:toolbarView];
+ // If the superview has a layer, then this hack isn't required.
+ NSView* superview = [view superview];
+ if ([superview layer])
+ return;
- if (inPresentationMode) {
- // In presentation mode the info bar is below all other views.
- [contentView cr_ensureSubview:[infoBarContainerController_ view]
- isPositioned:NSWindowBelow
- relativeTo:[self tabContentArea]];
+ // Get the current position of the view.
+ NSArray* subviews = [superview subviews];
+ NSInteger index = [subviews indexOfObject:view];
+ NSView* siblingBelow = nil;
+ if (index > 0)
+ siblingBelow = [subviews objectAtIndex:index - 1];
+
+ // Remove the view.
+ [view removeFromSuperview];
+
+ // Add it to the same position.
+ if (siblingBelow) {
+ [superview addSubview:view
+ positioned:NSWindowAbove
+ relativeTo:siblingBelow];
} else {
- // Above the toolbar but still below tab contents. Similar to the bookmark
- // bar, this allows Instant results to be above the info bar.
- [contentView cr_ensureSubview:[infoBarContainerController_ view]
- isPositioned:NSWindowAbove
- relativeTo:toolbarView];
+ [superview addSubview:view
+ positioned:NSWindowBelow
+ relativeTo:nil];
}
+}
+
+- (void)updateInfoBarTipVisibility {
+ // If there's no toolbar then hide the infobar tip.
+ [infoBarContainerController_
+ setShouldSuppressTopInfoBarTip:![self hasToolbar]];
+}
+
+- (NSInteger)pageInfoBubblePointY {
+ LocationBarViewMac* locationBarView = [self locationBarBridge];
+
+ // The point, in window coordinates.
+ NSPoint iconBottom = locationBarView->GetPageInfoBubblePoint();
- // The find bar is above everything.
- if (findBarCocoaController_) {
- NSView* relativeView = nil;
- if (inPresentationMode)
- relativeView = toolbarView;
- else
- relativeView = [self tabContentArea];
- [contentView cr_ensureSubview:[findBarCocoaController_ view]
- isPositioned:NSWindowAbove
- relativeTo:relativeView];
+ // The toolbar, in window coordinates.
+ NSView* toolbar = [toolbarController_ view];
+ CGFloat toolbarY = NSMinY([toolbar convertRect:[toolbar bounds] toView:nil]);
+
+ return iconBottom.y - toolbarY;
+}
+
+- (void)enterAppKitFullscreen {
+ DCHECK(base::mac::IsOSLionOrLater());
+ if (FramedBrowserWindow* framedBrowserWindow =
+ base::mac::ObjCCast<FramedBrowserWindow>([self window])) {
+ [framedBrowserWindow toggleSystemFullScreen];
}
+}
- if (floatingBarBackingView_) {
- if ([floatingBarBackingView_ cr_isBelowView:[self tabContentArea]])
- [floatingBarBackingView_ removeFromSuperview];
- if ([self placeBookmarkBarBelowInfoBar]) {
- [contentView cr_ensureSubview:floatingBarBackingView_
- isPositioned:NSWindowAbove
- relativeTo:[bookmarkBarController_ view]];
- } else {
- [contentView cr_ensureSubview:floatingBarBackingView_
- isPositioned:NSWindowBelow
- relativeTo:[bookmarkBarController_ view]];
- }
+- (void)exitAppKitFullscreen {
+ DCHECK(base::mac::IsOSLionOrLater());
+ if (FramedBrowserWindow* framedBrowserWindow =
+ base::mac::ObjCCast<FramedBrowserWindow>([self window])) {
+ [framedBrowserWindow toggleSystemFullScreen];
}
}
-- (BOOL)shouldAllowOverlappingViews:(BOOL)inPresentationMode {
- if (inPresentationMode)
- return YES;
+- (void)updateLayoutParameters:(BrowserWindowLayout*)layout {
+ [layout setContentViewSize:[[[self window] contentView] bounds].size];
+ [layout setWindowSize:[[self window] frame].size];
+
+ [layout setInAnyFullscreen:[self isInAnyFullscreenMode]];
+ [layout setFullscreenSlidingStyle:
+ presentationModeController_.get().slidingStyle];
+ [layout setFullscreenMenubarOffset:
+ [presentationModeController_ menubarOffset]];
+ [layout setFullscreenToolbarFraction:
+ [presentationModeController_ toolbarFraction]];
+
+ [layout setHasTabStrip:[self hasTabStrip]];
+
+ [layout setHasToolbar:[self hasToolbar]];
+ [layout setToolbarHeight:NSHeight([[toolbarController_ view] bounds])];
+
+ [layout setHasLocationBar:[self hasLocationBar]];
- if (findBarCocoaController_ &&
- ![[findBarCocoaController_ findBarView] isHidden]) {
- return YES;
+ [layout setPlaceBookmarkBarBelowInfoBar:[self placeBookmarkBarBelowInfoBar]];
+ [layout setBookmarkBarHidden:[bookmarkBarController_ view].isHidden];
+ [layout setBookmarkBarHeight:
+ NSHeight([[bookmarkBarController_ view] bounds])];
+
+ [layout setInfoBarHeight:[infoBarContainerController_ heightOfInfoBars]];
+ [layout setPageInfoBubblePointY:[self pageInfoBubblePointY]];
+
+ [layout setHasDownloadShelf:(downloadShelfController_.get() != nil)];
+ [layout setDownloadShelfHeight:
+ NSHeight([[downloadShelfController_ view] bounds])];
+}
+
+- (void)applyLayout:(BrowserWindowLayout*)layout {
+ chrome::LayoutOutput output = [layout computeLayout];
+
+ if (!NSIsEmptyRect(output.tabStripFrame)) {
+ // Note: The fullscreen parameter passed to the method is different from
+ // the field in |parameters| with the similar name.
+ [self layoutTabStripAtMaxY:NSMaxY(output.tabStripFrame)
+ width:NSWidth(output.tabStripFrame)
+ fullscreen:[self isInAnyFullscreenMode]];
+ }
+
+ if (!NSIsEmptyRect(output.toolbarFrame)) {
+ [[toolbarController_ view] setFrame:output.toolbarFrame];
+ }
+
+ if (!NSIsEmptyRect(output.bookmarkFrame)) {
+ NSView* bookmarkBarView = [bookmarkBarController_ view];
+ [bookmarkBarView setFrame:output.bookmarkFrame];
+
+ // Pin the bookmark bar to the top of the window and make the width
+ // flexible.
+ [bookmarkBarView setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
+
+ [bookmarkBarController_ layoutSubviews];
+ }
+
+ // The info bar is never hidden. Sometimes it has zero effective height.
+ [[infoBarContainerController_ view] setFrame:output.infoBarFrame];
+ [infoBarContainerController_
+ setMaxTopArrowHeight:output.infoBarMaxTopArrowHeight];
+
+ if (!NSIsEmptyRect(output.downloadShelfFrame))
+ [[downloadShelfController_ view] setFrame:output.downloadShelfFrame];
+
+ [self layoutTabContentArea:output.contentAreaFrame];
+
+ if (!NSIsEmptyRect(output.fullscreenBackingBarFrame)) {
+ [floatingBarBackingView_ setFrame:output.fullscreenBackingBarFrame];
+ [presentationModeController_
+ overlayFrameChanged:output.fullscreenBackingBarFrame];
}
- if (overlappedViewCount_)
- return YES;
+ [findBarCocoaController_
+ positionFindBarViewAtMaxY:output.findBarMaxY
+ maxWidth:NSWidth(output.contentAreaFrame)];
+
+ [fullscreenExitBubbleController_
+ positionInWindowAtTop:output.fullscreenExitButtonMaxY
+ width:NSWidth(output.contentAreaFrame)];
+}
+
+- (void)updateSubviewZOrder {
+ if ([self isInAnyFullscreenMode])
+ [self updateSubviewZOrderFullscreen];
+ else
+ [self updateSubviewZOrderNormal];
+
+ [self updateSubviewZOrderHack];
+}
+
+- (void)updateSubviewZOrderNormal {
+ base::scoped_nsobject<NSMutableArray> subviews([[NSMutableArray alloc] init]);
+ if ([downloadShelfController_ view])
+ [subviews addObject:[downloadShelfController_ view]];
+ if ([bookmarkBarController_ view])
+ [subviews addObject:[bookmarkBarController_ view]];
+ if ([toolbarController_ view])
+ [subviews addObject:[toolbarController_ view]];
+ if ([infoBarContainerController_ view])
+ [subviews addObject:[infoBarContainerController_ view]];
+ if ([self tabContentArea])
+ [subviews addObject:[self tabContentArea]];
+ if ([findBarCocoaController_ view])
+ [subviews addObject:[findBarCocoaController_ view]];
+
+ [self setContentViewSubviews:subviews];
+}
- return NO;
+- (void)updateSubviewZOrderFullscreen {
+ base::scoped_nsobject<NSMutableArray> subviews([[NSMutableArray alloc] init]);
+ if ([downloadShelfController_ view])
+ [subviews addObject:[downloadShelfController_ view]];
+ if ([self tabContentArea])
+ [subviews addObject:[self tabContentArea]];
+ if ([self placeBookmarkBarBelowInfoBar]) {
+ if ([bookmarkBarController_ view])
+ [subviews addObject:[bookmarkBarController_ view]];
+ if (floatingBarBackingView_)
+ [subviews addObject:floatingBarBackingView_];
+ } else {
+ if (floatingBarBackingView_)
+ [subviews addObject:floatingBarBackingView_];
+ if ([bookmarkBarController_ view])
+ [subviews addObject:[bookmarkBarController_ view]];
+ }
+ if ([toolbarController_ view])
+ [subviews addObject:[toolbarController_ view]];
+ if ([infoBarContainerController_ view])
+ [subviews addObject:[infoBarContainerController_ view]];
+ if ([findBarCocoaController_ view])
+ [subviews addObject:[findBarCocoaController_ view]];
+
+ [self setContentViewSubviews:subviews];
}
-- (void)updateAllowOverlappingViews:(BOOL)inPresentationMode {
- WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
- if (!contents)
+- (void)setContentViewSubviews:(NSArray*)subviews {
+ // Subviews already match.
+ if ([[self.window.contentView subviews] isEqual:subviews])
return;
- BOOL allowOverlappingViews =
- [self shouldAllowOverlappingViews:inPresentationMode];
+ // The tabContentArea isn't a subview, so just set all the subviews.
+ NSView* tabContentArea = [self tabContentArea];
+ if (![[self.window.contentView subviews] containsObject:tabContentArea]) {
+ [self.window.contentView setSubviews:subviews];
+ return;
+ }
+
+ // Remove all subviews that aren't the tabContentArea.
+ for (NSView* view in [[self.window.contentView subviews] copy]) {
+ if (view != tabContentArea)
+ [view removeFromSuperview];
+ }
- // The rendering path with overlapping views disabled causes bugs when
- // transitioning between composited and non-composited mode.
- // http://crbug.com/279472
- allowOverlappingViews = YES;
- contents->SetAllowOverlappingViews(allowOverlappingViews);
+ // Add in the subviews below the tabContentArea.
+ NSInteger index = [subviews indexOfObject:tabContentArea];
+ for (int i = index - 1; i >= 0; --i) {
+ NSView* view = [subviews objectAtIndex:i];
+ [self.window.contentView addSubview:view
+ positioned:NSWindowBelow
+ relativeTo:nil];
+ }
- WebContents* devTools = DevToolsWindow::GetInTabWebContents(contents, NULL);
- if (devTools)
- devTools->SetAllowOverlappingViews(allowOverlappingViews);
+ // Add in the subviews above the tabContentArea.
+ for (NSUInteger i = index + 1; i < [subviews count]; ++i) {
+ NSView* view = [subviews objectAtIndex:i];
+ [self.window.contentView addSubview:view
+ positioned:NSWindowAbove
+ relativeTo:nil];
+ }
}
-- (void)updateInfoBarTipVisibility {
- // If there's no toolbar then hide the infobar tip.
- [infoBarContainerController_
- setShouldSuppressTopInfoBarTip:![self hasToolbar]];
+- (void)updateSubviewZOrderHack {
+ // TODO(erikchen): Remove and then add the tabStripView to the root NSView.
+ // This fixes a layer ordering problem that occurs between the contentView
+ // and the tabStripView. This is a hack required because NSThemeFrame is not
+ // layer backed, and because Chrome adds subviews directly to the
+ // NSThemeFrame.
+ // http://crbug.com/407921
+ if (enteringAppKitFullscreen_) {
+ // The tabstrip frequently lies outside the bounds of its superview.
+ // Repeatedly adding/removing the tabstrip from its superview during the
+ // AppKit Fullscreen transition causes graphical glitches on 10.10. The
+ // correct solution is to use the AppKit fullscreen transition APIs added
+ // in 10.7+.
+ // http://crbug.com/408791
+ if (!hasAdjustedTabStripWhileEnteringAppKitFullscreen_) {
+ // Disable implicit animations.
+ [CATransaction begin];
+ [CATransaction setDisableActions:YES];
+
+ [self updateLayerOrdering:[self tabStripView]];
+ [self updateLayerOrdering:[avatarButtonController_ view]];
+
+ [CATransaction commit];
+ hasAdjustedTabStripWhileEnteringAppKitFullscreen_ = YES;
+ }
+ } else {
+ hasAdjustedTabStripWhileEnteringAppKitFullscreen_ = NO;
+ }
}
@end // @implementation BrowserWindowController(Private)