From 2f54796673c894a064ba32ea873964e4c710fce3 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Mon, 17 Jun 2013 14:50:32 +1200 Subject: [PATCH] Bug 877534 - Use a shutdown listener to destroy the compositor from nsBaseWidget. r=roc This prevents a case where the nsBaseWidget isn't destroyed until the cycle collector is shutdown, and we are too late in the shutdown sequence to process the events that get queued during Compositor teardown. --- widget/xpwidgets/nsBaseWidget.cpp | 33 +++++++++++++++++++++++++++++++ widget/xpwidgets/nsBaseWidget.h | 20 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/widget/xpwidgets/nsBaseWidget.cpp b/widget/xpwidgets/nsBaseWidget.cpp index ad8b62752b5e..22f50b3d0624 100644 --- a/widget/xpwidgets/nsBaseWidget.cpp +++ b/widget/xpwidgets/nsBaseWidget.cpp @@ -118,8 +118,31 @@ nsBaseWidget::nsBaseWidget() #ifdef DEBUG debug_RegisterPrefCallbacks(); #endif + + mShutdownObserver = new WidgetShutdownObserver(this); + nsContentUtils::RegisterShutdownObserver(mShutdownObserver); } +NS_IMPL_ISUPPORTS1(WidgetShutdownObserver, nsIObserver) + +NS_IMETHODIMP +WidgetShutdownObserver::Observe(nsISupports *aSubject, + const char *aTopic, + const PRUnichar *aData) +{ + if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { + mWidget->Shutdown(); + nsContentUtils::UnregisterShutdownObserver(this); + } + return NS_OK; +} + +void +nsBaseWidget::Shutdown() +{ + DestroyCompositor(); + mShutdownObserver = nullptr; +} static void DeferredDestroyCompositor(CompositorParent* aCompositorParent, CompositorChild* aCompositorChild) @@ -171,6 +194,10 @@ nsBaseWidget::~nsBaseWidget() mLayerManager = nullptr; } + if (mShutdownObserver) { + nsContentUtils::UnregisterShutdownObserver(mShutdownObserver); + } + DestroyCompositor(); #ifdef NOISY_WIDGET_LEAKS @@ -893,6 +920,12 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight) // Recreating this is tricky, as we may still have an old and we need // to make sure it's properly destroyed by calling DestroyCompositor! + // If we've already received a shutdown notification, don't try + // create a new compositor. + if (!mShutdownObserver) { + return; + } + mCompositorParent = NewCompositorParent(aWidth, aHeight); AsyncChannel *parentChannel = mCompositorParent->GetIPCChannel(); LayerManager* lm = new ClientLayerManager(this); diff --git a/widget/xpwidgets/nsBaseWidget.h b/widget/xpwidgets/nsBaseWidget.h index 87ff5eedc752..d3efcb931b39 100644 --- a/widget/xpwidgets/nsBaseWidget.h +++ b/widget/xpwidgets/nsBaseWidget.h @@ -15,6 +15,7 @@ #include "nsGUIEvent.h" #include "nsAutoPtr.h" #include "nsIRollupListener.h" +#include "nsIObserver.h" #include class nsIContent; class nsAutoRollup; @@ -38,6 +39,22 @@ namespace base { class Thread; } +class nsBaseWidget; + +class WidgetShutdownObserver MOZ_FINAL : public nsIObserver +{ +public: + WidgetShutdownObserver(nsBaseWidget* aWidget) + : mWidget(aWidget) + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + +private: + nsBaseWidget *mWidget; +}; + /** * Common widget implementation used as base class for native * or crossplatform implementations of Widgets. @@ -254,6 +271,8 @@ public: static nsIRollupListener* GetActiveRollupListener(); + void Shutdown(); + protected: virtual void ResolveIconName(const nsAString &aIconName, @@ -356,6 +375,7 @@ protected: nsRefPtr mBasicLayerManager; nsRefPtr mCompositorChild; nsRefPtr mCompositorParent; + nsCOMPtr mShutdownObserver; nscolor mBackground; nscolor mForeground; nsCursor mCursor;