From 19f4b6e9a3118506041287bd61973eb0f295da0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Tue, 20 Mar 2012 16:21:14 -0700 Subject: [PATCH] Bug 639705 (Lion Full Screen) Part 2: Support Lion Full Screen when fullscreenbutton=true [r=josh,mstange] --HG-- extra : rebase_source : ce2751e4b32cf0d4344b5ca6a642e1e172c04e3b --- widget/cocoa/nsCocoaWindow.h | 19 +++++++ widget/cocoa/nsCocoaWindow.mm | 101 ++++++++++++++++++++++++++++++---- 2 files changed, 108 insertions(+), 12 deletions(-) diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index f01aebe2697..c9450d9d652 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -53,6 +53,21 @@ class nsCocoaWindow; class nsChildView; class nsMenuBarX; +// If we are using an SDK older than 10.7, define bits we need that are missing +// from it. +#if !defined(MAC_OS_X_VERSION_10_7) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 + +enum { + NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7, +}; + +@interface NSWindow (NewInMacOS107) +- (void)toggleFullScreen:(id)sender; +@end + +#endif + typedef struct _nsCocoaWindowList { _nsCocoaWindowList() : prev(NULL), window(NULL) {} struct _nsCocoaWindowList *prev; @@ -255,6 +270,7 @@ public: nsIWidget *aWidget, bool aActivate); NS_IMETHOD SetSizeMode(PRInt32 aMode); NS_IMETHOD HideWindowChrome(bool aShouldHide); + void EnteredFullScreen(bool aFullScreen); NS_IMETHOD MakeFullScreen(bool aFullScreen); NS_IMETHOD Resize(PRInt32 aWidth,PRInt32 aHeight, bool aRepaint); NS_IMETHOD Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, bool aRepaint); @@ -281,6 +297,7 @@ public: virtual void SetTransparencyMode(nsTransparencyMode aMode); NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle); virtual void SetShowsToolbarButton(bool aShow); + virtual void SetShowsFullScreenButton(bool aShow); virtual void SetWindowAnimationType(WindowAnimationType aType); NS_IMETHOD SetWindowTitlebarColor(nscolor aColor, bool aActive); virtual void SetDrawsInTitlebar(bool aState); @@ -359,6 +376,8 @@ protected: bool mFullScreen; bool mModal; + bool mUsesNativeFullScreen; // only true on Lion if SetShowsFullScreenButton(true); + bool mIsAnimationSuppressed; bool mInReportMoveEvent; // true if in a call to ReportMoveEvent(). diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm index 7175679bc08..80fc621d7f6 100644 --- a/widget/cocoa/nsCocoaWindow.mm +++ b/widget/cocoa/nsCocoaWindow.mm @@ -140,6 +140,7 @@ nsCocoaWindow::nsCocoaWindow() , mSheetNeedsShow(false) , mFullScreen(false) , mModal(false) +, mUsesNativeFullScreen(false) , mIsAnimationSuppressed(false) , mInReportMoveEvent(false) , mNumModalDescendents(0) @@ -513,7 +514,10 @@ NS_IMETHODIMP nsCocoaWindow::Destroy() nsBaseWidget::Destroy(); nsBaseWidget::OnDestroy(); - if (mFullScreen) { + // On Lion we do not have to mess with the OS chrome when in Full Screen mode. So we + // can simply skip that. When the Window is destroyed, the OS will take care of removing + // the full screen 'Space' that was setup for us. + if (!mUsesNativeFullScreen && mFullScreen) { nsCocoaUtils::HideOSChromeOnScreen(false, [mWindow screen]); } @@ -1180,24 +1184,40 @@ NS_IMETHODIMP nsCocoaWindow::HideWindowChrome(bool aShouldHide) NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } +void nsCocoaWindow::EnteredFullScreen(bool aFullScreen) +{ + mFullScreen = aFullScreen; + DispatchSizeModeEvent(); +} NS_METHOD nsCocoaWindow::MakeFullScreen(bool aFullScreen) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ASSERTION(mFullScreen != aFullScreen, "Unnecessary MakeFullScreen call"); + // We will call into MakeFullScreen redundantly when entering/exiting + // fullscreen mode via OS X controls. When that happens we should just handle + // it gracefully - no need to ASSERT. + if (mFullScreen == aFullScreen) { + return NS_OK; + } - NSDisableScreenUpdates(); - // The order here matters. When we exit full screen mode, we need to show the - // Dock first, otherwise the newly-created window won't have its minimize - // button enabled. See bug 526282. - nsCocoaUtils::HideOSChromeOnScreen(aFullScreen, [mWindow screen]); - nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen); - NSEnableScreenUpdates(); - NS_ENSURE_SUCCESS(rv, rv); + if (mUsesNativeFullScreen) { + // Calling toggleFullScreen will result in windowDid(Enter|Exit)FullScreen + // to be called from the OS. We will call EnteredFullScreen from those methods, + // where mFullScreen will be set and a sizemode event will be dispatched. + [mWindow toggleFullScreen:nil]; + } else { + NSDisableScreenUpdates(); + // The order here matters. When we exit full screen mode, we need to show the + // Dock first, otherwise the newly-created window won't have its minimize + // button enabled. See bug 526282. + nsCocoaUtils::HideOSChromeOnScreen(aFullScreen, [mWindow screen]); + nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen); + NSEnableScreenUpdates(); + NS_ENSURE_SUCCESS(rv, rv); - mFullScreen = aFullScreen; - DispatchSizeModeEvent(); + EnteredFullScreen(aFullScreen); + } return NS_OK; @@ -1642,6 +1662,42 @@ void nsCocoaWindow::SetShowsToolbarButton(bool aShow) NS_OBJC_END_TRY_ABORT_BLOCK; } +void nsCocoaWindow::SetShowsFullScreenButton(bool aShow) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + if (![mWindow respondsToSelector:@selector(toggleFullScreen:)] || + mUsesNativeFullScreen == aShow) { + return; + } + + // If the window is currently in fullscreen mode, then we're going to + // transition out first, then set the collection behavior & toggle + // mUsesNativeFullScreen, then transtion back into fullscreen mode. This + // prevents us from getting into a conflicting state with MakeFullScreen + // where mUsesNativeFullScreen would lead us down the wrong path. + bool wasFullScreen = mFullScreen; + + if (wasFullScreen) { + MakeFullScreen(false); + } + + NSWindowCollectionBehavior newBehavior = [mWindow collectionBehavior]; + if (aShow) { + newBehavior |= NSWindowCollectionBehaviorFullScreenPrimary; + } else { + newBehavior &= ~NSWindowCollectionBehaviorFullScreenPrimary; + } + [mWindow setCollectionBehavior:newBehavior]; + mUsesNativeFullScreen = aShow; + + if (wasFullScreen) { + MakeFullScreen(true); + } + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + void nsCocoaWindow::SetWindowAnimationType(nsIWidget::WindowAnimationType aType) { mAnimationType = aType; @@ -1875,6 +1931,27 @@ bool nsCocoaWindow::ShouldFocusPlugin() mGeckoWindow->ReportMoveEvent(); } +// Lion's full screen mode will bypass our internal fullscreen tracking, so +// we need to catch it when we transition and call our own methods, which in +// turn will fire "fullscreen" events. +- (void)windowDidEnterFullScreen:(NSNotification *)notification +{ + if (!mGeckoWindow) { + return; + } + + mGeckoWindow->EnteredFullScreen(true); +} + +- (void)windowDidExitFullScreen:(NSNotification *)notification +{ + if (!mGeckoWindow) { + return; + } + + mGeckoWindow->EnteredFullScreen(false); +} + - (void)windowDidBecomeMain:(NSNotification *)aNotification { NS_OBJC_BEGIN_TRY_ABORT_BLOCK;