Index: chrome/browser/ui/cocoa/browser_window_controller.mm |
=================================================================== |
--- chrome/browser/ui/cocoa/browser_window_controller.mm (revision 95517) |
+++ chrome/browser/ui/cocoa/browser_window_controller.mm (working copy) |
@@ -41,13 +41,13 @@ |
#import "chrome/browser/ui/cocoa/fast_resize_view.h" |
#import "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h" |
#import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h" |
-#import "chrome/browser/ui/cocoa/focus_tracker.h" |
-#import "chrome/browser/ui/cocoa/fullscreen_controller.h" |
+#import "chrome/browser/ui/cocoa/framed_browser_window.h" |
#import "chrome/browser/ui/cocoa/fullscreen_window.h" |
#import "chrome/browser/ui/cocoa/gesture_utils.h" |
#import "chrome/browser/ui/cocoa/image_utils.h" |
#import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" |
#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" |
+#import "chrome/browser/ui/cocoa/presentation_mode_controller.h" |
#import "chrome/browser/ui/cocoa/sidebar_controller.h" |
#import "chrome/browser/ui/cocoa/status_bubble_mac.h" |
#import "chrome/browser/ui/cocoa/tab_contents/previewable_contents_controller.h" |
@@ -198,6 +198,15 @@ |
}; |
typedef NSInteger NSWindowAnimationBehavior; |
+enum { |
+ NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7, |
+ NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8 |
+}; |
+ |
+enum { |
+ NSFullScreenWindowMask = 1 << 14 |
+}; |
+ |
@interface NSWindow (LionSDKDeclarations) |
- (void)setRestorable:(BOOL)flag; |
- (void)setAnimationBehavior:(NSWindowAnimationBehavior)newAnimationBehavior; |
@@ -264,6 +273,12 @@ |
if ([window respondsToSelector:@selector(setAnimationBehavior:)]) |
[window setAnimationBehavior:NSWindowAnimationBehaviorDocumentWindow]; |
+ // Set the window to participate in Lion Fullscreen mode. Setting this flag |
+ // has no effect on Snow Leopard or earlier. |
+ NSUInteger collectionBehavior = [window collectionBehavior]; |
+ collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary; |
+ [window setCollectionBehavior:collectionBehavior]; |
+ |
// Get the most appropriate size for the window, then enforce the |
// minimum width and height. The window shim will handle flipping |
// the coordinates for us so we can use it to save some code. |
@@ -409,8 +424,6 @@ |
if ([self hasToolbar]) // Do not create the buttons in popups. |
[toolbarController_ createBrowserActionButtons]; |
- [self setUpOSFullScreenButton]; |
- |
// We are done initializing now. |
initializing_ = NO; |
} |
@@ -428,11 +441,11 @@ |
browser_->CloseAllTabs(); |
[downloadShelfController_ exiting]; |
- // Explicitly release |fullscreenController_| here, as it may call back to |
- // this BWC in |-dealloc|. We are required to call |-exitFullscreen| before |
- // releasing the controller. |
- [fullscreenController_ exitFullscreen]; |
- fullscreenController_.reset(); |
+ // Explicitly release |presentationModeController_| here, as it may call back |
+ // to this BWC in |-dealloc|. We are required to call |-exitPresentationMode| |
+ // before releasing the controller. |
+ [presentationModeController_ exitPresentationMode]; |
+ presentationModeController_.reset(); |
// Under certain testing configurations we may not actually own the browser. |
if (ownsBrowser_ == NO) |
@@ -1020,9 +1033,22 @@ |
[self isFullscreen] ? IDS_EXIT_FULLSCREEN_MAC : |
IDS_ENTER_FULLSCREEN_MAC); |
[static_cast<NSMenuItem*>(item) setTitle:menuTitle]; |
+ |
+ if (base::mac::IsOSSnowLeopardOrEarlier()) |
+ [static_cast<NSMenuItem*>(item) setHidden:YES]; |
} |
break; |
} |
+ case IDC_PRESENTATION_MODE: { |
+ enable &= [self supportsFullscreen]; |
+ if ([static_cast<NSObject*>(item) isKindOfClass:[NSMenuItem class]]) { |
+ NSString* menuTitle = l10n_util::GetNSString( |
+ [self inPresentationMode] ? IDS_EXIT_PRESENTATION_MAC : |
+ IDS_ENTER_PRESENTATION_MAC); |
+ [static_cast<NSMenuItem*>(item) setTitle:menuTitle]; |
+ } |
+ break; |
+ } |
case IDC_SYNC_BOOKMARKS: |
enable &= browser_->profile()->IsSyncAccessible(); |
sync_ui_util::UpdateSyncItem(item, enable, browser_->profile()); |
@@ -1413,7 +1439,8 @@ |
relativeTo:[infoBarContainerController_ view]]; |
// Place the find bar immediately below the toolbar/attached bookmark bar. In |
- // fullscreen mode, it hangs off the top of the screen when the bar is hidden. |
+ // presentation mode, it hangs off the top of the screen when the bar is |
+ // hidden. |
CGFloat maxY = [self placeBookmarkBarBelowInfoBar] ? |
NSMinY([[toolbarController_ view] frame]) : |
NSMinY([[bookmarkBarController_ view] frame]); |
@@ -1445,7 +1472,7 @@ |
} |
- (NSRect)regularWindowFrame { |
- return [self isFullscreen] ? [savedRegularWindow_ frame] : |
+ return [self isFullscreen] ? savedRegularWindowFrame_ : |
[[self window] frame]; |
} |
@@ -2028,171 +2055,108 @@ |
@implementation BrowserWindowController(Fullscreen) |
-- (IBAction)enterFullscreen:(id)sender { |
+- (void)handleLionToggleFullscreen { |
+ DCHECK(base::mac::IsOSLionOrLater()); |
browser_->ExecuteCommand(IDC_FULLSCREEN); |
} |
+// On Lion, this method is called by either the Lion fullscreen button or the |
+// "Enter Full Screen" menu item. On Snow Leopard, this function is never |
+// called by the UI directly, but it provides the implementation for |
+// |-setPresentationMode:|. |
- (void)setFullscreen:(BOOL)fullscreen { |
- // The logic in this function is a bit complicated and very carefully |
- // arranged. See the below comments for more details. |
- |
if (fullscreen == [self isFullscreen]) |
return; |
if (![self supportsFullscreen]) |
return; |
- // Fade to black. |
- const CGDisplayReservationInterval kFadeDurationSeconds = 0.6; |
- Boolean didFadeOut = NO; |
- CGDisplayFadeReservationToken token; |
- if (CGAcquireDisplayFadeReservation(kFadeDurationSeconds, &token) |
- == kCGErrorSuccess) { |
- didFadeOut = YES; |
- CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendNormal, |
- kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true); |
+ if (base::mac::IsOSLionOrLater()) { |
+ enteredPresentationModeFromFullscreen_ = YES; |
+ if ([[self window] isKindOfClass:[FramedBrowserWindow class]]) |
+ [static_cast<FramedBrowserWindow*>([self window]) toggleSystemFullScreen]; |
+ return; |
} |
- // Close the bookmark bubble, if it's open. We use |-ok:| instead of |
- // |-cancel:| or |-close| because that matches the behavior when the bubble |
- // loses key status. |
- [bookmarkBubbleController_ ok:self]; |
+ if (fullscreen) |
+ [self enterFullscreenForSnowLeopardOrEarlier]; |
+ else |
+ [self exitFullscreenForSnowLeopardOrEarlier]; |
+} |
- // Save the current first responder so we can restore after views are moved. |
- NSWindow* window = [self window]; |
- scoped_nsobject<FocusTracker> focusTracker( |
- [[FocusTracker alloc] initWithWindow:window]); |
- BOOL showDropdown = [self floatingBarHasFocus]; |
+- (BOOL)isFullscreen { |
+ return (fullscreenWindow_.get() != nil) || |
+ ([[self window] styleMask] & NSFullScreenWindowMask); |
+} |
- // While we move views (and focus) around, disable any bar visibility changes. |
- [self disableBarVisibilityUpdates]; |
+- (void)togglePresentationModeForLionOrLater:(id)sender { |
+ // Called only by the presentation mode toggle button. |
+ DCHECK(base::mac::IsOSLionOrLater()); |
+ enteredPresentationModeFromFullscreen_ = YES; |
+ browser_->ExecuteCommand(IDC_PRESENTATION_MODE); |
+} |
- // If we're entering fullscreen, create the fullscreen controller. If we're |
- // exiting fullscreen, kill the controller. |
- if (fullscreen) { |
- fullscreenController_.reset([[FullscreenController alloc] |
- initWithBrowserController:self]); |
- } else { |
- [fullscreenController_ exitFullscreen]; |
- fullscreenController_.reset(); |
+// On Lion, this function is called by either the presentation mode toggle |
+// button or the "Enter Presentation Mode" menu item. In the latter case, this |
+// function also triggers the Lion machinery to enter fullscreen mode as well as |
+// set presentation mode. On Snow Leopard, this function is called by the |
+// "Enter Presentation Mode" menu item, and triggering presentation mode always |
+// moves the user into fullscreen mode. |
+- (void)setPresentationMode:(BOOL)presentationMode { |
+ // Presentation mode on Leopard and Snow Leopard maps directly to fullscreen |
+ // mode. |
+ if (base::mac::IsOSSnowLeopardOrEarlier()) { |
+ [self setFullscreen:presentationMode]; |
+ return; |
} |
- // Destroy the tab strip's sheet controller. We will recreate it in the new |
- // window when needed. |
- [tabStripController_ destroySheetController]; |
+ if (presentationMode) { |
+ BOOL fullscreen = [self isFullscreen]; |
+ [self setShouldUsePresentationModeWhenEnteringFullscreen:YES]; |
+ enteredPresentationModeFromFullscreen_ = fullscreen; |
- // Retain the tab strip view while we remove it from its superview. |
- scoped_nsobject<NSView> tabStripView; |
- if ([self hasTabStrip] && ![self useVerticalTabs]) { |
- tabStripView.reset([[self tabStripView] retain]); |
- [tabStripView removeFromSuperview]; |
- } |
- |
- // Ditto for the content view. |
- scoped_nsobject<NSView> contentView([[window contentView] retain]); |
- // Disable autoresizing of subviews while we move views around. This prevents |
- // spurious renderer resizes. |
- [contentView setAutoresizesSubviews:NO]; |
- [contentView removeFromSuperview]; |
- |
- NSWindow* destWindow = nil; |
- if (fullscreen) { |
- DCHECK(!savedRegularWindow_); |
- savedRegularWindow_ = [window retain]; |
- destWindow = [self createFullscreenWindow]; |
+ if (fullscreen) { |
+ // If already in fullscreen mode, just toggle the presentation mode |
+ // setting. Go through an elaborate dance to force the overlay to show, |
+ // then animate out once the mouse moves away. This helps draw attention |
+ // to the fact that the UI is in an overlay. Focus the tab contents |
+ // because the omnibox is the most likely source of bar visibility locks, |
+ // and taking focus away from the omnibox releases its lock. |
+ [self lockBarVisibilityForOwner:self withAnimation:NO delay:NO]; |
+ [self focusTabContents]; |
+ [self setPresentationModeInternal:YES forceDropdown:YES]; |
+ [self releaseBarVisibilityForOwner:self withAnimation:YES delay:YES]; |
+ } else { |
+ // If not in fullscreen mode, trigger the Lion fullscreen mode machinery. |
+ // Presentation mode will automatically be enabled in |
+ // |-windowWillEnterFullScreen:|. |
+ NSWindow* window = [self window]; |
+ if ([window isKindOfClass:[FramedBrowserWindow class]]) |
+ [static_cast<FramedBrowserWindow*>(window) toggleSystemFullScreen]; |
+ } |
} else { |
- DCHECK(savedRegularWindow_); |
- destWindow = [savedRegularWindow_ autorelease]; |
- savedRegularWindow_ = nil; |
+ if (enteredPresentationModeFromFullscreen_) { |
+ // The window is currently in fullscreen mode, but the user is choosing to |
+ // turn presentation mode off (choosing to always show the UI). Set the |
+ // preference to ensure that presentation mode will stay off for the next |
+ // window that goes fullscreen. |
+ [self setShouldUsePresentationModeWhenEnteringFullscreen:NO]; |
+ [self setPresentationModeInternal:NO forceDropdown:NO]; |
+ } else { |
+ // The user entered presentation mode directly from non-fullscreen mode |
+ // using the "Enter Presentation Mode" menu item and is using that same |
+ // menu item to exit presentation mode. In this case, exit fullscreen |
+ // mode as well (using the Lion machinery). |
+ NSWindow* window = [self window]; |
+ if ([window isKindOfClass:[FramedBrowserWindow class]]) |
+ [static_cast<FramedBrowserWindow*>(window) toggleSystemFullScreen]; |
+ } |
} |
- DCHECK(destWindow); |
- |
- // Have to do this here, otherwise later calls can crash because the window |
- // has no delegate. |
- [window setDelegate:nil]; |
- [destWindow setDelegate:self]; |
- |
- // With this call, valgrind complains that a "Conditional jump or move depends |
- // on uninitialised value(s)". The error happens in -[NSThemeFrame |
- // drawOverlayRect:]. I'm pretty convinced this is an Apple bug, but there is |
- // no visual impact. I have been unable to tickle it away with other window |
- // or view manipulation Cocoa calls. Stack added to suppressions_mac.txt. |
- [contentView setAutoresizesSubviews:YES]; |
- [destWindow setContentView:contentView]; |
- |
- // Move the incognito badge if present. |
- if (avatarButton_.get()) { |
- [avatarButton_ removeFromSuperview]; |
- [avatarButton_ setHidden:YES]; // Will be shown in layout. |
- [[[destWindow contentView] superview] addSubview:avatarButton_]; |
- } |
- |
- // 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] && ![self useVerticalTabs]) |
- [[[destWindow contentView] superview] addSubview:tabStripView]; |
- |
- [window setWindowController:nil]; |
- [self setWindow:destWindow]; |
- [destWindow setWindowController:self]; |
- [self adjustUIForFullscreen:fullscreen]; |
- |
- // Adjust the infobar container. In fullscreen, it needs to be below all |
- // top chrome elements so it only sits atop the web contents. When in normal |
- // mode, it needs to draw over the bookmark bar and part of the toolbar. |
- [[infoBarContainerController_ view] removeFromSuperview]; |
- NSView* infoBarDest = [[destWindow contentView] superview]; |
- [infoBarDest addSubview:[infoBarContainerController_ view] |
- positioned:fullscreen ? NSWindowBelow : NSWindowAbove |
- relativeTo:fullscreen ? floatingBarBackingView_ |
- : [bookmarkBarController_ view]]; |
- |
- // When entering fullscreen mode, the controller forces a layout for us. When |
- // exiting, we need to call layoutSubviews manually. |
- if (fullscreen) { |
- [fullscreenController_ enterFullscreenForContentView:contentView |
- showDropdown:showDropdown]; |
- } else { |
- [self layoutSubviews]; |
- } |
- |
- // Move the status bubble over, if we have one. |
- if (statusBubble_) |
- statusBubble_->SwitchParentWindow(destWindow); |
- |
- // Move the title over. |
- [destWindow setTitle:[window title]]; |
- |
- // The window needs to be onscreen before we can set its first responder. |
- // Ordering the window to the front can change the active Space (either to |
- // the window's old Space or to the application's assigned Space). To prevent |
- // this by temporarily change the collectionBehavior. |
- NSWindowCollectionBehavior behavior = [window collectionBehavior]; |
- [destWindow setCollectionBehavior: |
- NSWindowCollectionBehaviorMoveToActiveSpace]; |
- [destWindow makeKeyAndOrderFront:self]; |
- [destWindow setCollectionBehavior:behavior]; |
- |
- [focusTracker restoreFocusInWindow:destWindow]; |
- [window orderOut:self]; |
- |
- // We're done moving focus, so re-enable bar visibility changes. |
- [self enableBarVisibilityUpdates]; |
- |
- // This needs to be done when leaving full-screen mode to ensure that the |
- // button's action is set properly. |
- [self setUpOSFullScreenButton]; |
- |
- // Fade back in. |
- if (didFadeOut) { |
- CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendSolidColor, |
- kCGDisplayBlendNormal, 0.0, 0.0, 0.0, /*synchronous=*/false); |
- CGReleaseDisplayFadeReservation(token); |
- } |
} |
-- (BOOL)isFullscreen { |
- return fullscreenController_.get() && [fullscreenController_ isFullscreen]; |
+- (BOOL)inPresentationMode { |
+ return presentationModeController_.get() && |
+ [presentationModeController_ inPresentationMode]; |
} |
- (void)resizeFullscreenWindow { |
@@ -2226,10 +2190,10 @@ |
if (![self isBarVisibilityLockedForOwner:owner]) { |
[barVisibilityLocks_ addObject:owner]; |
- // If enabled, show the overlay if necessary (and if in fullscreen mode). |
+ // If enabled, show the overlay if necessary (and if in presentation mode). |
if (barVisibilityUpdatesEnabled_) { |
- [fullscreenController_ ensureOverlayShownWithAnimation:animate |
- delay:delay]; |
+ [presentationModeController_ ensureOverlayShownWithAnimation:animate |
+ delay:delay]; |
} |
} |
} |
@@ -2240,11 +2204,11 @@ |
if ([self isBarVisibilityLockedForOwner:owner]) { |
[barVisibilityLocks_ removeObject:owner]; |
- // If enabled, hide the overlay if necessary (and if in fullscreen mode). |
+ // If enabled, hide the overlay if necessary (and if in presentation mode). |
if (barVisibilityUpdatesEnabled_ && |
![barVisibilityLocks_ count]) { |
- [fullscreenController_ ensureOverlayHiddenWithAnimation:animate |
- delay:delay]; |
+ [presentationModeController_ ensureOverlayHiddenWithAnimation:animate |
+ delay:delay]; |
} |
} |
} |