From e00fee0e9017a2aed66c79efdafbdb815da5dd61 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Tue, 14 Oct 2008 17:33:40 +0200 Subject: [PATCH] Bug 450944 - Implement -moz-window-shadow functionality on Mac OS X, r=hwaara sr=roc. This patch turns on window shadows for transparent windows by default, so the identity popup and the "edit bookmarks" popup will get a shadow, too. ui-r=faaborg --- layout/base/nsStyleConsts.h | 5 +- layout/generic/nsContainerFrame.cpp | 5 +- layout/xul/base/src/nsMenuPopupFrame.cpp | 5 +- widget/public/nsIWidget.h | 19 ++++++-- widget/src/cocoa/nsChildView.h | 3 ++ widget/src/cocoa/nsChildView.mm | 61 ++++++++++++++++++++++++ widget/src/cocoa/nsCocoaWindow.h | 1 + widget/src/cocoa/nsCocoaWindow.mm | 14 +++++- widget/src/xpwidgets/nsBaseWidget.cpp | 11 +++++ widget/src/xpwidgets/nsBaseWidget.h | 1 + 10 files changed, 115 insertions(+), 10 deletions(-) diff --git a/layout/base/nsStyleConsts.h b/layout/base/nsStyleConsts.h index 17be3a91a9cf..72d924195210 100644 --- a/layout/base/nsStyleConsts.h +++ b/layout/base/nsStyleConsts.h @@ -42,6 +42,7 @@ #define nsStyleConsts_h___ #include "nsFont.h" +#include "nsIWidget.h" // cairo doesn't support invert // #define GFX_HAS_INVERT @@ -710,10 +711,6 @@ #define NS_STYLE_IME_MODE_DISABLED 3 #define NS_STYLE_IME_MODE_INACTIVE 4 -// See nsStyleUIReset -#define NS_STYLE_WINDOW_SHADOW_NONE 0 -#define NS_STYLE_WINDOW_SHADOW_DEFAULT 1 - #ifdef MOZ_SVG // See nsStyleSVG diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index b7e744745c33..9c03d22c0785 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -508,7 +508,10 @@ SyncFrameViewGeometryDependentProperties(nsPresContext* aPresContext, nsIFrame *rootFrame = aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame(); if(rootFrame && NS_THEME_WIN_GLASS == rootFrame->GetStyleDisplay()->mAppearance) mode = eTransparencyGlass; - aView->GetWidget()->SetTransparencyMode(mode); + nsIWidget* widget = aView->GetWidget(); + widget->SetTransparencyMode(mode); + if (rootFrame) + widget->SetWindowShadowStyle(rootFrame->GetStyleUIReset()->mWindowShadow); } } } diff --git a/layout/xul/base/src/nsMenuPopupFrame.cpp b/layout/xul/base/src/nsMenuPopupFrame.cpp index c1ccf5a63df9..2105772b268a 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -280,7 +280,10 @@ nsMenuPopupFrame::CreateWidgetForView(nsIView* aView) aView->CreateWidget(kCChildCID, &widgetData, nsnull, PR_TRUE, PR_TRUE, eContentTypeInherit, parentWidget); #endif - aView->GetWidget()->SetTransparencyMode(mode); + nsIWidget* widget = aView->GetWidget(); + widget->SetTransparencyMode(viewHasTransparentContent ? + eTransparencyTransparent : eTransparencyOpaque); + widget->SetWindowShadowStyle(GetStyleUIReset()->mWindowShadow); return NS_OK; } diff --git a/widget/public/nsIWidget.h b/widget/public/nsIWidget.h index 2271da83f790..7296b70ada6f 100644 --- a/widget/public/nsIWidget.h +++ b/widget/public/nsIWidget.h @@ -93,16 +93,24 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event); #define NS_NATIVE_PLUGIN_PORT_CG 101 #endif -// 0e64821f-00a2-4adc-ac3b-3439d61f4491 +// 8c91457a-ef86-4da1-b4f9-36022dcc6c7e #define NS_IWIDGET_IID \ -{ 0x0e64821f, 0x00a2, 0x4adc, \ - { 0xac, 0x3b, 0x34, 0x39, 0xd6, 0x1f, 0x44, 0x91 } } +{ 0x8c91457a, 0xef86, 0x4da1, \ + { 0xb4, 0xf9, 0x36, 0x02, 0x2d, 0xcc, 0x6c, 0x7e } } // Hide the native window systems real window type so as to avoid // including native window system types and APIs. This is necessary // to ensure cross-platform code. typedef void* nsNativeWidget; +/* + * Window shadow styles + * Also used for the -moz-window-shadow CSS property + */ + +#define NS_STYLE_WINDOW_SHADOW_NONE 0 +#define NS_STYLE_WINDOW_SHADOW_DEFAULT 1 + /** * Border styles */ @@ -711,6 +719,11 @@ class nsIWidget : public nsISupports { */ virtual nsTransparencyMode GetTransparencyMode() = 0; + /** + * Set the shadow style of the window. + */ + NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle) = 0; + /** * Hide window chrome (borders, buttons) for this widget. * diff --git a/widget/src/cocoa/nsChildView.h b/widget/src/cocoa/nsChildView.h index c11a07223785..37375329c489 100644 --- a/widget/src/cocoa/nsChildView.h +++ b/widget/src/cocoa/nsChildView.h @@ -166,6 +166,8 @@ enum { // All views are always opaque (non-transparent). The only exception is when we're // the content view in a transparent XUL window. BOOL mIsTransparent; + PRIntervalTime mLastShadowInvalidation; + BOOL mNeedsShadowInvalidation; // Holds our drag service across multiple drag calls. The reference to the // service is obtained when the mouse enters the view and is released when @@ -366,6 +368,7 @@ public: virtual nsTransparencyMode GetTransparencyMode(); virtual void SetTransparencyMode(nsTransparencyMode aMode); + NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle); // Mac specific methods virtual PRBool PointInWidget(Point aThePoint); diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index aa8722af3de4..24d57d7dfe18 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -179,6 +179,9 @@ nsIWidget * gRollupWidget = nsnull; - (BOOL)isPaintingSuppressed; +- (void)maybeInvalidateShadow; +- (void)invalidateShadow; + #if USE_CLICK_HOLD_CONTEXTMENU // called on a timer two seconds after a mouse down to see if we should display // a context menu (click-hold) @@ -777,6 +780,28 @@ void nsChildView::SetTransparencyMode(nsTransparencyMode aMode) } +// This is called by nsContainerFrame on the root widget for all window types +// except popup windows (when nsCocoaWindow::SetWindowShadowStyle is used instead). +NS_IMETHODIMP nsChildView::SetWindowShadowStyle(PRInt32 aStyle) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + // Find out if this is a window we created by seeing if the delegate is WindowDelegate. If it is, + // tell the nsCocoaWindow to set the shadow style. + id windowDelegate = [[mView nativeWindow] delegate]; + if (windowDelegate && [windowDelegate isKindOfClass:[WindowDelegate class]]) { + nsCocoaWindow *widget = [(WindowDelegate *)windowDelegate geckoWidget]; + if (widget) { + widget->SetWindowShadowStyle(aStyle); + } + } + + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + + NS_IMETHODIMP nsChildView::IsVisible(PRBool& outState) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; @@ -2733,6 +2758,38 @@ NSEvent* gLastDragEvent = nil; } +// Limit shadow invalidation to 10 times per second. +static const PRInt32 sShadowInvalidationInterval = 100; +- (void)maybeInvalidateShadow +{ + if (!mIsTransparent || ![mWindow hasShadow]) + return; + + PRIntervalTime now = PR_IntervalNow(); + PRInt32 elapsed = PR_IntervalToMilliseconds(now - mLastShadowInvalidation); + if (!mLastShadowInvalidation || + elapsed >= sShadowInvalidationInterval) { + [mWindow invalidateShadow]; + mLastShadowInvalidation = now; + mNeedsShadowInvalidation = NO; + } else if (!mNeedsShadowInvalidation) { + mNeedsShadowInvalidation = YES; + [self performSelector:@selector(invalidateShadow) + withObject:nil + afterDelay:(sShadowInvalidationInterval - elapsed) / 1000.0]; + } +} + + +- (void)invalidateShadow +{ + if (!mNeedsShadowInvalidation) + return; + [mWindow invalidateShadow]; + mNeedsShadowInvalidation = NO; +} + + - (BOOL)isPaintingSuppressed { NSWindow* win = [self window]; @@ -2811,6 +2868,10 @@ NSEvent* gLastDragEvent = nil; if (!mGeckoChild) return; + // If we're a transparent window, and our contents have changed, we need + // to make sure the shadow is updated to the new contents. + [self maybeInvalidateShadow]; + paintEvent.renderingContext = nsnull; paintEvent.region = nsnull; diff --git a/widget/src/cocoa/nsCocoaWindow.h b/widget/src/cocoa/nsCocoaWindow.h index 8c59903d7b36..b549341a61e3 100644 --- a/widget/src/cocoa/nsCocoaWindow.h +++ b/widget/src/cocoa/nsCocoaWindow.h @@ -276,6 +276,7 @@ public: NS_IMETHOD GetAttention(PRInt32 aCycleCount); virtual nsTransparencyMode GetTransparencyMode(); virtual void SetTransparencyMode(nsTransparencyMode aMode); + NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle); NS_IMETHOD SetWindowTitlebarColor(nscolor aColor, PRBool aActive); // dispatch an NS_SIZEMODE event on miniaturize or deminiaturize diff --git a/widget/src/cocoa/nsCocoaWindow.mm b/widget/src/cocoa/nsCocoaWindow.mm index c6fe916558d0..8f570ab431e9 100644 --- a/widget/src/cocoa/nsCocoaWindow.mm +++ b/widget/src/cocoa/nsCocoaWindow.mm @@ -65,6 +65,7 @@ #include "nsIDOMElement.h" #include "nsMenuBarX.h" #include "nsMenuUtilsX.h" +#include "nsStyleConsts.h" #include "gfxPlatform.h" #include "lcms.h" @@ -800,7 +801,6 @@ void nsCocoaWindow::MakeBackgroundTransparent(PRBool aTransparent) } [mWindow setOpaque:!aTransparent]; [mWindow setBackgroundColor:(aTransparent ? [NSColor clearColor] : [NSColor whiteColor])]; - [mWindow setHasShadow:!aTransparent]; } NS_OBJC_END_TRY_ABORT_BLOCK; @@ -1317,6 +1317,18 @@ NS_IMETHODIMP nsCocoaWindow::GetAttention(PRInt32 aCycleCount) } +NS_IMETHODIMP nsCocoaWindow::SetWindowShadowStyle(PRInt32 aStyle) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + if ([mWindow hasShadow] != (aStyle != NS_STYLE_WINDOW_SHADOW_NONE)) + [mWindow setHasShadow:(aStyle != NS_STYLE_WINDOW_SHADOW_NONE)]; + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + + NS_IMETHODIMP nsCocoaWindow::SetWindowTitlebarColor(nscolor aColor, PRBool aActive) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index 01a46159cb97..576233a4c9d2 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -568,6 +568,17 @@ nsTransparencyMode nsBaseWidget::GetTransparencyMode() { return eTransparencyOpaque; } +//------------------------------------------------------------------------- +// +// Set window shadow style +// +//------------------------------------------------------------------------- + +NS_IMETHODIMP nsBaseWidget::SetWindowShadowStyle(PRInt32 aMode) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + //------------------------------------------------------------------------- // // Hide window borders/decorations for this widget diff --git a/widget/src/xpwidgets/nsBaseWidget.h b/widget/src/xpwidgets/nsBaseWidget.h index e15d1b9fd55c..2770d1dcdb70 100644 --- a/widget/src/xpwidgets/nsBaseWidget.h +++ b/widget/src/xpwidgets/nsBaseWidget.h @@ -106,6 +106,7 @@ public: NS_IMETHOD SetWindowType(nsWindowType aWindowType); virtual void SetTransparencyMode(nsTransparencyMode aMode); virtual nsTransparencyMode GetTransparencyMode(); + NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle); NS_IMETHOD HideWindowChrome(PRBool aShouldHide); NS_IMETHOD MakeFullScreen(PRBool aFullScreen); virtual nsIRenderingContext* GetRenderingContext();