diff options
author | spqchan <spqchan@chromium.org> | 2016-03-25 15:12:53 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-25 22:14:08 +0000 |
commit | 38ac6be27a783853f6a8fec136d2f4d3235a34d6 (patch) | |
tree | 3c42f28ce87cfb9d9b8f403689eee031c089accc | |
parent | 5e436974bc54c2e3007d6a1a421e1009ace44068 (diff) | |
download | chromium_src-38ac6be27a783853f6a8fec136d2f4d3235a34d6.zip chromium_src-38ac6be27a783853f6a8fec136d2f4d3235a34d6.tar.gz chromium_src-38ac6be27a783853f6a8fec136d2f4d3235a34d6.tar.bz2 |
Fixed a fullscreen race condition on OSX
Ensure that |windowDidExitFullscreen| gets called after the fullscreen
transition is completed. Slightly speed up the animations on Yosemite.
BUG=593419
Review URL: https://codereview.chromium.org/1813693003
Cr-Commit-Position: refs/heads/master@{#383381}
5 files changed, 86 insertions, 36 deletions
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h index e305c5e..53b179a 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.h +++ b/chrome/browser/ui/cocoa/browser_window_controller.h @@ -164,6 +164,11 @@ class Command; // True if the toolbar needs to be shown in fullscreen. BOOL shouldShowFullscreenToolbar_; + // True if AppKit has finished exiting fullscreen before the exit animation + // is completed. This flag is used to ensure that |windowDidExitFullscreen| + // is called after the exit fullscreen animation is complete. + BOOL appKitDidExitFullscreen_; + // The size of the original (non-fullscreen) window. This is saved just // before entering fullscreen mode and is only valid when |-isFullscreen| // returns YES. @@ -424,6 +429,9 @@ class Command; // deprecated. - (BOOL)isTabbedWindow; +// Returns the size of the original (non-fullscreen) window. +- (NSRect)savedRegularWindowFrame; + @end // @interface BrowserWindowController(WindowType) // Fullscreen terminology: @@ -564,6 +572,10 @@ class Command; // Whether the toolbar should be shown in fullscreen. - (BOOL)shouldShowFullscreenToolbar; +// Called by BrowserWindowFullscreenTransition when the exit animation is +// finished. +- (void)exitFullscreenAnimationFinished; + // Resizes the fullscreen window to fit the screen it's currently on. Called by // the PresentationModeController when there is a change in monitor placement or // resolution. diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index e3e5683d..7eec240 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm @@ -2019,6 +2019,13 @@ willAnimateFromState:(BookmarkBar::State)oldState return shouldShowFullscreenToolbar_; } +- (void)exitFullscreenAnimationFinished { + if (appKitDidExitFullscreen_) { + [self windowDidExitFullScreen:nil]; + appKitDidExitFullscreen_ = NO; + } +} + - (void)resizeFullscreenWindow { DCHECK([self isInAnyFullscreenMode]); if (![self isInAnyFullscreenMode]) @@ -2103,4 +2110,8 @@ willAnimateFromState:(BookmarkBar::State)oldState return browser_->is_type_tabbed(); } +- (NSRect)savedRegularWindowFrame { + return savedRegularWindowFrame_; +} + @end // @implementation BrowserWindowController(WindowType) diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index ebb3bd4..ef42630 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm @@ -778,6 +778,15 @@ willPositionSheet:(NSWindow*)sheet - (void)windowDidExitFullScreen:(NSNotification*)notification { DCHECK(exitingAppKitFullscreen_); + // If the custom transition isn't complete, then just set the flag and + // return. Once the transition is completed, windowDidExitFullscreen will + // be called again. + if (isUsingCustomAnimation_ && + ![fullscreenTransition_ isTransitionCompleted]) { + appKitDidExitFullscreen_ = YES; + return; + } + if (notification) // For System Fullscreen when non-nil. [self deregisterForContentViewResizeNotifications]; @@ -1175,10 +1184,8 @@ willPositionSheet:(NSWindow*)sheet if (![self shouldUseCustomAppKitFullscreenTransition:YES]) return nil; - FramedBrowserWindow* framedBrowserWindow = - base::mac::ObjCCast<FramedBrowserWindow>([self window]); - fullscreenTransition_.reset([[BrowserWindowFullscreenTransition alloc] - initEnterWithWindow:framedBrowserWindow]); + fullscreenTransition_.reset( + [[BrowserWindowFullscreenTransition alloc] initEnterWithController:self]); NSArray* customWindows = [fullscreenTransition_ customWindowsForFullScreenTransition]; @@ -1192,12 +1199,8 @@ willPositionSheet:(NSWindow*)sheet if (![self shouldUseCustomAppKitFullscreenTransition:NO]) return nil; - FramedBrowserWindow* framedBrowserWindow = - base::mac::ObjCCast<FramedBrowserWindow>([self window]); - fullscreenTransition_.reset([[BrowserWindowFullscreenTransition alloc] - initExitWithWindow:framedBrowserWindow - frame:savedRegularWindowFrame_ - tabStripBackgroundView:[self tabStripBackgroundView]]); + fullscreenTransition_.reset( + [[BrowserWindowFullscreenTransition alloc] initExitWithController:self]); NSArray* customWindows = [fullscreenTransition_ customWindowsForFullScreenTransition]; diff --git a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h index 332bd94..a92a1b7 100644 --- a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h +++ b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h @@ -7,7 +7,7 @@ #import <Cocoa/Cocoa.h> -@class FramedBrowserWindow; +@class BrowserWindowController; // This class is responsible for managing the custom transition of a // BrowserWindow from its normal state into an AppKit Fullscreen state @@ -94,20 +94,17 @@ @interface BrowserWindowFullscreenTransition : NSObject -// Designated initializers. |window| is the NSWindow that is going to be moved -// into a fullscreen Space (virtual desktop), and resized to have the same size -// as the screen. |window|'s root view must be layer backed. -// initEnterWithWindow will create a BrowserWindowFullscreenTransition that -// enters fullscreen. initExitWithWindow will create one that exits fullscreen, -// using |frame| as the frame that |window| is going to transition into. -- (instancetype)initEnterWithWindow:(FramedBrowserWindow*)window; -- (instancetype)initExitWithWindow:(FramedBrowserWindow*)window - frame:(NSRect)frame - tabStripBackgroundView:(NSView*)view; +// Designated initializers. |controller| is the BrowserWindowController of the +// window that's going to be moved into a fullscreen Space. +- (instancetype)initEnterWithController:(BrowserWindowController*)controller; +- (instancetype)initExitWithController:(BrowserWindowController*)controller; // Returns the windows to be used in the custom fullscreen transition. - (NSArray*)customWindowsForFullScreenTransition; +// Returns true if the fullscreen transition is completed. +- (BOOL)isTransitionCompleted; + // This method begins animation for exit or enter fullscreen transition. // In this method, the following happens: // - Animates the snapshot to the expected final size of the window while diff --git a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm index 409c422..1a0792a 100644 --- a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm +++ b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm @@ -12,6 +12,7 @@ #import "base/mac/sdk_forward_declarations.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/framed_browser_window.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h" @@ -22,8 +23,10 @@ NSString* const kSnapshotWindowAnimationID = @"SnapshotWindowAnimationID"; NSString* const kAnimationIDKey = @"AnimationIDKey"; // The fraction of the duration from AppKit's startCustomAnimation methods -// that we want our animation to run in. +// that we want our animation to run in. Yosemite's fraction is smaller +// since its fullscreen transition is significantly slower. CGFloat const kAnimationDurationFraction = 0.5; +CGFloat const kAnimationDurationFractionYosemite = 0.3; // This class has two simultaneous animations to resize and reposition layers. // These animations must use the same timing function, otherwise there will be @@ -91,6 +94,9 @@ class FrameAndStyleLock { // The window which is undergoing the fullscreen transition. base::scoped_nsobject<FramedBrowserWindow> primaryWindow_; + // The window which is undergoing the fullscreen transition. + BrowserWindowController* controller_; // weak + // A layer that holds a snapshot of the original state of |primaryWindow_|. base::scoped_nsobject<CALayer> snapshotLayer_; @@ -131,6 +137,10 @@ class FrameAndStyleLock { // Locks and unlocks the FullSizeContentWindow. scoped_ptr<FrameAndStyleLock> lock_; + + // Flag that indicates if the animation was completed. Sets to true at the + // end of the animation. + BOOL completedTransition_; } // Takes a snapshot of |primaryWindow_| and puts it in |snapshotLayer_|. @@ -180,11 +190,14 @@ class FrameAndStyleLock { // -------------------------Public Methods---------------------------- -- (instancetype)initEnterWithWindow:(FramedBrowserWindow*)window { - DCHECK(window); - DCHECK([self rootLayerOfWindow:window]); +- (instancetype)initEnterWithController:(BrowserWindowController*)controller { + DCHECK(controller); + DCHECK([self rootLayerOfWindow:[controller window]]); if ((self = [super init])) { - primaryWindow_.reset([window retain]); + controller_ = controller; + FramedBrowserWindow* framedBrowserWindow = + base::mac::ObjCCast<FramedBrowserWindow>([controller window]); + primaryWindow_.reset([framedBrowserWindow retain]); isEnteringFullscreen_ = YES; initialFrame_ = [primaryWindow_ frame]; @@ -193,19 +206,21 @@ class FrameAndStyleLock { return self; } -- (instancetype)initExitWithWindow:(FramedBrowserWindow*)window - frame:(NSRect)frame - tabStripBackgroundView:(NSView*)view { - DCHECK(window); - DCHECK([self rootLayerOfWindow:window]); +- (instancetype)initExitWithController:(BrowserWindowController*)controller { + DCHECK(controller); + DCHECK([self rootLayerOfWindow:[controller window]]); if ((self = [super init])) { - primaryWindow_.reset([window retain]); - tabStripBackgroundView_.reset([view retain]); + controller_ = controller; + FramedBrowserWindow* framedBrowserWindow = + base::mac::ObjCCast<FramedBrowserWindow>([controller window]); + primaryWindow_.reset([framedBrowserWindow retain]); + isEnteringFullscreen_ = NO; - finalFrame_ = frame; initialFrame_ = [[primaryWindow_ screen] frame]; + finalFrame_ = [controller savedRegularWindowFrame]; + tabStripBackgroundView_.reset([[controller tabStripBackgroundView] retain]); - lock_.reset(new FrameAndStyleLock(window)); + lock_.reset(new FrameAndStyleLock(framedBrowserWindow)); } return self; } @@ -216,8 +231,15 @@ class FrameAndStyleLock { return @[ primaryWindow_.get(), snapshotWindow_.get() ]; } +- (BOOL)isTransitionCompleted { + return completedTransition_; +} + - (void)startCustomFullScreenAnimationWithDuration:(NSTimeInterval)duration { - CGFloat animationDuration = duration * kAnimationDurationFraction; + CGFloat durationFraction = base::mac::IsOSYosemite() + ? kAnimationDurationFractionYosemite + : kAnimationDurationFraction; + CGFloat animationDuration = duration * durationFraction; [self preparePrimaryWindowForAnimation]; [self animatePrimaryWindowWithDuration:animationDuration]; [self animateSnapshotWindowWithDuration:animationDuration]; @@ -501,7 +523,12 @@ class FrameAndStyleLock { CALayer* root = [self rootLayerOfWindow:primaryWindow_]; [root removeAnimationForKey:kPrimaryWindowAnimationID]; root.opacity = 1; + + if (!isEnteringFullscreen_) + [controller_ exitFullscreenAnimationFinished]; } + + completedTransition_ = YES; } - (CALayer*)rootLayerOfWindow:(NSWindow*)window { |