#include <cmath>
#include "base/command_line.h"
+#include "base/mac/mac_util.h"
#import "base/mac/scoped_nsobject.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/fullscreen.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_info_util.h"
+#include "chrome/browser/profiles/profile_avatar_icon_util.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/avatar_button_controller.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"
#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"
#import "chrome/browser/ui/cocoa/status_bubble_mac.h"
#import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
-#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
#import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
+#import "chrome/browser/ui/cocoa/version_independent_window.h"
+#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h"
#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
#import "ui/base/cocoa/focus_tracker.h"
#include "ui/base/ui_base_types.h"
// 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.
DictionaryPrefUpdate update(
prefs,
chrome::GetWindowPlacementKey(browser_.get()).c_str());
- DictionaryValue* windowPreferences = update.Get();
+ base::DictionaryValue* windowPreferences = update.Get();
windowPreferences->SetInteger("left", bounds.x());
windowPreferences->SetInteger("top", bounds.y());
windowPreferences->SetInteger("right", bounds.right());
maxY -= tabStripHeight;
[tabStripView setFrame:NSMakeRect(0, maxY, width, tabStripHeight)];
+ // In Yosemite fullscreen, manually add the fullscreen controls to the tab
+ // strip.
+ BOOL isInAppKitFullscreen =
+ [self isInSystemFullscreen] || enteringSystemFullscreen_;
+ BOOL addControlsInFullscreen =
+ isInAppKitFullscreen && base::mac::IsOSYosemiteOrLater();
+
// Set left indentation based on fullscreen mode status.
- [tabStripController_ setLeftIndentForControls:(fullscreen ? 0 :
- [[tabStripController_ class] defaultLeftIndentForControls])];
+ CGFloat leftIndent = 0;
+ if (!fullscreen || addControlsInFullscreen)
+ leftIndent = [[tabStripController_ class] defaultLeftIndentForControls];
+ [tabStripController_ setLeftIndentForControls:leftIndent];
+
+ if (addControlsInFullscreen)
+ [tabStripController_ addWindowControls];
+ else
+ [tabStripController_ removeWindowControls];
// Lay out the icognito/avatar badge because calculating the indentation on
// the right depends on it.
+ NSView* avatarButton = [avatarButtonController_ view];
if ([self shouldShowAvatar]) {
- NSView* avatarButton = [avatarButtonController_ view];
- CGFloat buttonHeight = std::min(
- static_cast<CGFloat>(profiles::kAvatarIconHeight), tabStripHeight);
- [avatarButton setFrameSize:NSMakeSize(NSWidth([avatarButton frame]),
- buttonHeight)];
-
- // Actually place the badge *above* |maxY|, by +2 to miss the divider.
CGFloat badgeXOffset = -kAvatarRightOffset;
- CGFloat badgeYOffset = 2 * [[avatarButton superview] cr_lineWidth];
+ CGFloat badgeYOffset = 0;
+ CGFloat buttonHeight = NSHeight([avatarButton frame]);
+
+ if ([self shouldUseNewAvatarButton]) {
+ // The fullscreen icon is displayed to the right of the avatar button.
+ if (![self isFullscreen])
+ badgeXOffset -= kFullscreenIconWidth;
+ // Center the button vertically on the tabstrip.
+ badgeYOffset = (tabStripHeight - buttonHeight) / 2;
+ } else {
+ // Actually place the badge *above* |maxY|, by +2 to miss the divider.
+ badgeYOffset = 2 * [[avatarButton superview] cr_lineWidth];
+ }
+
+ [avatarButton setFrameSize:NSMakeSize(NSWidth([avatarButton frame]),
+ std::min(buttonHeight, tabStripHeight))];
NSPoint origin =
NSMakePoint(width - NSWidth([avatarButton frame]) + badgeXOffset,
maxY + badgeYOffset);
FramedBrowserWindow* window =
static_cast<FramedBrowserWindow*>([self window]);
rightIndent += -[window fullScreenButtonOriginAdjustment].x;
+
+ 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;
+ }
} else if ([self shouldShowAvatar]) {
- rightIndent += kAvatarTabStripShrink;
- NSButton* labelButton = [avatarButtonController_ labelButtonView];
- if (labelButton)
- rightIndent += NSWidth([labelButton frame]) + kAvatarRightOffset;
+ rightIndent += kAvatarTabStripShrink +
+ NSWidth([avatarButton frame]) + kAvatarRightOffset;
}
[tabStripController_ setRightIndentForControls:rightIndent];
}
}
+- (void)updateRoundedBottomCorners {
+ [[self tabContentArea] setRoundedBottomCorners:![self isFullscreen]];
+}
+
- (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression {
CGFloat newHeight =
[toolbarController_ desiredHeightForCompression:compression];
// Fullscreen and presentation mode methods
-- (BOOL)shouldShowPresentationModeToggle {
- return chrome::mac::SupportsSystemFullscreen() && [self isFullscreen];
-}
-
-- (void)moveViewsForFullscreenForSnowLeopard:(BOOL)fullscreen
- regularWindow:(NSWindow*)regularWindow
- fullscreenWindow:(NSWindow*)fullscreenWindow {
- // This method is only for systems without fullscreen support.
- DCHECK(!chrome::mac::SupportsSystemFullscreen());
-
+- (void)moveViewsForImmersiveFullscreen:(BOOL)fullscreen
+ regularWindow:(NSWindow*)regularWindow
+ fullscreenWindow:(NSWindow*)fullscreenWindow {
NSWindow* sourceWindow = fullscreen ? regularWindow : fullscreenWindow;
NSWindow* destWindow = fullscreen ? fullscreenWindow : regularWindow;
// Move the incognito badge if present.
if ([self shouldShowAvatar]) {
- [[avatarButtonController_ view] removeFromSuperview];
- [[avatarButtonController_ view] setHidden:YES]; // Will be shown in layout.
- [[[destWindow contentView] superview] addSubview:
- [avatarButtonController_ view]];
+ NSView* avatarButtonView = [avatarButtonController_ view];
+
+ [avatarButtonView removeFromSuperview];
+ [avatarButtonView setHidden:YES]; // Will be shown in layout.
+ [[destWindow cr_windowView] addSubview:avatarButtonView];
}
// Add the tab strip after setting the content view and moving the incognito
// badge (if any), so that the tab strip will be on top (in the z-order).
if ([self hasTabStrip])
- [[[destWindow contentView] superview] addSubview:tabStripView];
+ [[destWindow cr_windowView] addSubview:tabStripView];
[sourceWindow setWindowController:nil];
[self setWindow:destWindow];
[destWindow makeKeyAndOrderFront:self];
[destWindow setCollectionBehavior:behavior];
- [focusTracker restoreFocusInWindow:destWindow];
+ if (![focusTracker restoreFocusInWindow:destWindow]) {
+ // During certain types of fullscreen transitions, the view that had focus
+ // may have gone away (e.g., the one for a Flash FS widget). In this case,
+ // FocusTracker will fail to restore focus to anything, so we set the focus
+ // to the tab contents as a reasonable fall-back.
+ [self focusTabContents];
+ }
[sourceWindow orderOut:self];
// We're done moving focus, so re-enable bar visibility changes.
[self enableBarVisibilityUpdates];
}
+- (void)permissionBubbleWindowWillClose:(NSNotification*)notification {
+ DCHECK(permissionBubbleCocoa_);
+
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center removeObserver:self
+ name:NSWindowWillCloseNotification
+ object:[notification object]];
+ [self releaseBarVisibilityForOwner:[notification object]
+ withAnimation:YES
+ delay:YES];
+}
+
- (void)setPresentationModeInternal:(BOOL)presentationMode
forceDropdown:(BOOL)forceDropdown {
if (presentationMode == [self inPresentationMode])
if (presentationMode) {
BOOL fullscreen_for_tab =
- browser_->fullscreen_controller()->IsFullscreenForTabOrPending();
+ browser_->fullscreen_controller()->IsWindowFullscreenForTabOrPending();
BOOL kiosk_mode =
CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode);
BOOL showDropdown = !fullscreen_for_tab &&
!kiosk_mode &&
(forceDropdown || [self floatingBarHasFocus]);
- NSView* contentView = [[self window] contentView];
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];
} else {
[self layoutSubviews];
}
-// TODO(rohitrao): This method is misnamed now, since there is a flag that
-// enables 10.6-style fullscreen on newer OSes.
-- (void)enterFullscreenForSnowLeopard {
+- (void)enterImmersiveFullscreen {
+ // |-isFullscreen:| will return YES from here onwards.
+ enteringFullscreen_ = YES; // Set to NO by |-windowDidEnterFullScreen:|.
+
// Fade to black.
const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
Boolean didFadeOut = NO;
kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true);
}
- // Create the fullscreen window. After this line, isFullscreen will return
- // YES.
+ // Create the fullscreen window.
fullscreenWindow_.reset([[self createFullscreenWindow] retain]);
savedRegularWindow_ = [[self window] retain];
savedRegularWindowFrame_ = [savedRegularWindow_ frame];
- [self moveViewsForFullscreenForSnowLeopard:YES
- regularWindow:[self window]
- fullscreenWindow:fullscreenWindow_.get()];
+ [self moveViewsForImmersiveFullscreen:YES
+ regularWindow:[self window]
+ fullscreenWindow:fullscreenWindow_.get()];
// When simplified fullscreen is enabled, do not enter presentation mode.
const CommandLine* command_line = CommandLine::ForCurrentProcess();
}
}
-- (void)exitFullscreenForSnowLeopard {
- // TODO(rohitrao): This method is misnamed now, since there is a flag that
- // enables 10.6-style fullscreen on newer OSes.
- DCHECK(!chrome::mac::SupportsSystemFullscreen());
-
+- (void)exitImmersiveFullscreen {
// Fade to black.
const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
Boolean didFadeOut = NO;
[self windowWillExitFullScreen:nil];
- [self moveViewsForFullscreenForSnowLeopard:NO
- regularWindow:savedRegularWindow_
- fullscreenWindow:fullscreenWindow_.get()];
+ [self moveViewsForImmersiveFullscreen:NO
+ regularWindow:savedRegularWindow_
+ fullscreenWindow:fullscreenWindow_.get()];
// When exiting fullscreen mode, we need to call layoutSubviews manually.
[savedRegularWindow_ autorelease];
- (void)showFullscreenExitBubbleIfNecessary {
// This method is called in response to
- // |-updateFullscreenExitBubbleURL:bubbleType:|. If on Lion the system is
- // transitioning, do not show the bubble because it will cause visual jank
- // <http://crbug.com/130649>. This will be called again as part of
+ // |-updateFullscreenExitBubbleURL:bubbleType:|. If we're in the middle of the
+ // transition into fullscreen (i.e., using the System 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_)
return;
- [presentationModeController_ ensureOverlayHiddenWithAnimation:NO delay:NO];
+ [self hideOverlayIfPossibleWithAnimation:NO delay:NO];
if (fullscreenBubbleType_ == FEB_TYPE_NONE ||
fullscreenBubbleType_ == FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION) {
}
- (void)windowWillEnterFullScreen:(NSNotification*)notification {
- [self registerForContentViewResizeNotifications];
+ if (notification) // For System Fullscreen when non-nil.
+ [self registerForContentViewResizeNotifications];
NSWindow* window = [self window];
savedRegularWindowFrame_ = [window frame];
BOOL mode = enteringPresentationMode_ ||
- browser_->fullscreen_controller()->IsFullscreenForTabOrPending();
+ browser_->fullscreen_controller()->IsWindowFullscreenForTabOrPending();
enteringFullscreen_ = YES;
+ enteringSystemFullscreen_ = YES;
[self setPresentationModeInternal:mode forceDropdown:NO];
}
- (void)windowDidEnterFullScreen:(NSNotification*)notification {
- if (chrome::mac::SupportsSystemFullscreen())
+ // In Yosemite, some combination of the titlebar and toolbar always show in
+ // full-screen mode. We do not want either to show. Search for the window that
+ // contains the views, and hide it. There is no need to ever unhide the view.
+ // http://crbug.com/380235
+ if (base::mac::IsOSYosemiteOrLater()) {
+ for (NSWindow* window in [[NSApplication sharedApplication] windows]) {
+ if ([window
+ isKindOfClass:NSClassFromString(@"NSToolbarFullScreenWindow")]) {
+ [window.contentView setHidden:YES];
+ }
+ }
+ }
+
+ if (notification) // For System Fullscreen when non-nil.
[self deregisterForContentViewResizeNotifications];
enteringFullscreen_ = NO;
+ enteringSystemFullscreen_ = NO;
enteringPresentationMode_ = NO;
const CommandLine* command_line = CommandLine::ForCurrentProcess();
[self showFullscreenExitBubbleIfNecessary];
browser_->WindowFullscreenStateChanged();
+ [[[self window] cr_windowView] setWantsLayer:NO];
+ [self updateRoundedBottomCorners];
}
- (void)windowWillExitFullScreen:(NSNotification*)notification {
- if (chrome::mac::SupportsSystemFullscreen())
+ if (notification) // For System Fullscreen when non-nil.
[self registerForContentViewResizeNotifications];
fullscreenModeController_.reset();
[self destroyFullscreenExitBubbleIfNecessary];
}
- (void)windowDidExitFullScreen:(NSNotification*)notification {
- if (chrome::mac::SupportsSystemFullscreen())
+ if (notification) // For System Fullscreen when non-nil.
[self deregisterForContentViewResizeNotifications];
browser_->WindowFullscreenStateChanged();
+ [self updateRoundedBottomCorners];
}
- (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.
[presentationModeController_ cancelAnimationAndTimers];
}
+- (void)hideOverlayIfPossibleWithAnimation:(BOOL)animation delay:(BOOL)delay {
+ if (!barVisibilityUpdatesEnabled_ || [barVisibilityLocks_ count])
+ return;
+ [presentationModeController_ ensureOverlayHiddenWithAnimation:animation
+ delay:delay];
+}
+
- (CGFloat)toolbarDividerOpacity {
return [bookmarkBarController_ toolbarDividerOpacity];
}
// transitioning between composited and non-composited mode.
// http://crbug.com/279472
allowOverlappingViews = YES;
+ contents->SetAllowOverlappingViews(allowOverlappingViews);
- if (allowOverlappingViews &&
- [self coreAnimationStatus] ==
- browser_window_controller::kCoreAnimationEnabledLazy) {
- [[[self window] contentView] setWantsLayer:YES];
- [[self tabStripView] setWantsLayer:YES];
- }
-
- contents->GetView()->SetAllowOverlappingViews(allowOverlappingViews);
-
- DevToolsWindow* devToolsWindow =
- DevToolsWindow::GetDockedInstanceForInspectedTab(contents);
- if (devToolsWindow) {
- devToolsWindow->web_contents()->GetView()->
- SetAllowOverlappingViews(allowOverlappingViews);
- }
+ WebContents* devTools = DevToolsWindow::GetInTabWebContents(contents, NULL);
+ if (devTools)
+ devTools->SetAllowOverlappingViews(allowOverlappingViews);
}
- (void)updateInfoBarTipVisibility {
setShouldSuppressTopInfoBarTip:![self hasToolbar]];
}
-- (browser_window_controller::CoreAnimationStatus)coreAnimationStatus {
- // TODO(sail) Remove this.
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseCoreAnimation)) {
- return browser_window_controller::kCoreAnimationDisabled;
- }
- if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kUseCoreAnimation) == "lazy") {
- return browser_window_controller::kCoreAnimationEnabledLazy;
- }
- if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kUseCoreAnimation) == "disabled") {
- return browser_window_controller::kCoreAnimationDisabled;
- }
- return browser_window_controller::kCoreAnimationEnabledAlways;
-}
-
@end // @implementation BrowserWindowController(Private)