Chromium Code Reviews| Index: chrome/browser/ui/cocoa/browser_window_controller.mm |
| =================================================================== |
| --- chrome/browser/ui/cocoa/browser_window_controller.mm (revision 95287) |
| +++ chrome/browser/ui/cocoa/browser_window_controller.mm (working copy) |
| @@ -39,13 +39,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" |
| @@ -196,6 +196,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; |
| @@ -262,6 +271,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. |
| @@ -407,8 +422,6 @@ |
| if ([self hasToolbar]) // Do not create the buttons in popups. |
| [toolbarController_ createBrowserActionButtons]; |
| - [self setUpOSFullScreenButton]; |
| - |
| // We are done initializing now. |
| initializing_ = NO; |
| } |
| @@ -426,11 +439,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) |
| @@ -1018,9 +1031,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()); |
| @@ -1399,7 +1425,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]); |
| @@ -1431,7 +1458,7 @@ |
| } |
| - (NSRect)regularWindowFrame { |
| - return [self isFullscreen] ? [savedRegularWindow_ frame] : |
| + return [self isFullscreen] ? savedRegularWindowFrame_ : |
| [[self window] frame]; |
| } |
| @@ -2014,171 +2041,106 @@ |
| @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] respondsToSelector:@selector(toggleSystemFullScreen)]) |
|
Mark Mentovai
2011/08/04 19:18:17
Can you do this as an isKindOfClass check with a c
rohitrao (ping after 24h)
2011/08/04 19:49:17
Done. Why is this better?
Mark Mentovai
2011/08/04 19:56:53
rohitrao wrote:
|
| + [(id)[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)togglePresentationMode:(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:|. |
| + if ([[self window] respondsToSelector:@selector(toggleSystemFullScreen)]) |
| + [(id)[self 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). |
| + if ([[self window] respondsToSelector:@selector(toggleSystemFullScreen)]) |
| + [(id)[self 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 { |
| @@ -2212,10 +2174,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]; |
| } |
| } |
| } |
| @@ -2226,11 +2188,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]; |
| } |
| } |
| } |