From ab6809f229b14f01017ac2f5980b8b7554799ae2 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Mon, 4 Nov 2019 23:11:32 +0000 Subject: [PATCH] Bug 1470510 - Merge nsWebShellWindow into nsXULWindow r=smaug nsWebShellWindow is the only class that extends nsXULWindow and only nsWebShellWindows are ever instantiated. Differential Revision: https://phabricator.services.mozilla.com/D51155 --HG-- extra : moz-landing-system : lando --- dom/base/nsGlobalWindowOuter.cpp | 2 +- xpfe/appshell/moz.build | 1 - xpfe/appshell/nsAppShellService.cpp | 10 +- xpfe/appshell/nsAppShellService.h | 6 +- xpfe/appshell/nsWebShellWindow.cpp | 818 ---------------------------- xpfe/appshell/nsWebShellWindow.h | 133 ----- xpfe/appshell/nsXULWindow.cpp | 742 ++++++++++++++++++++++++- xpfe/appshell/nsXULWindow.h | 112 +++- 8 files changed, 855 insertions(+), 969 deletions(-) delete mode 100644 xpfe/appshell/nsWebShellWindow.cpp delete mode 100644 xpfe/appshell/nsWebShellWindow.h diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index 3b08bc2e2e34..9a22e8541293 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -1546,7 +1546,7 @@ void nsGlobalWindowOuter::SetInitialPrincipalToSubject( // We should never create windows with an expanded principal. // If we have a system principal, make sure we're not using it for a content // docshell. - // NOTE: Please keep this logic in sync with nsWebShellWindow::Initialize(). + // NOTE: Please keep this logic in sync with nsXULWindow::Initialize(). if (nsContentUtils::IsExpandedPrincipal(newWindowPrincipal) || (nsContentUtils::IsSystemPrincipal(newWindowPrincipal) && GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome)) { diff --git a/xpfe/appshell/moz.build b/xpfe/appshell/moz.build index ca09649e4fd9..200eb10881c3 100644 --- a/xpfe/appshell/moz.build +++ b/xpfe/appshell/moz.build @@ -30,7 +30,6 @@ UNIFIED_SOURCES += [ 'nsAppShellWindowEnumerator.cpp', 'nsChromeTreeOwner.cpp', 'nsContentTreeOwner.cpp', - 'nsWebShellWindow.cpp', 'nsWindowMediator.cpp', 'nsXULWindow.cpp', ] diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index 08375d295845..85c7f4bdbee0 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -17,7 +17,7 @@ #include "nsIWindowWatcher.h" #include "nsPIWindowWatcher.h" #include "nsPIDOMWindow.h" -#include "nsWebShellWindow.h" +#include "nsXULWindow.h" #include "nsWidgetInitData.h" #include "nsWidgetsCID.h" @@ -133,7 +133,7 @@ nsAppShellService::CreateHiddenWindow() { rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL); NS_ENSURE_SUCCESS(rv, rv); - RefPtr newWindow; + RefPtr newWindow; rv = JustCreateTopWindow(nullptr, url, chromeMask, initialWidth, initialHeight, true, nullptr, nullptr, getter_AddRefs(newWindow)); @@ -175,7 +175,7 @@ nsAppShellService::CreateTopLevelWindow( StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW); - RefPtr newWindow; + RefPtr newWindow; rv = JustCreateTopWindow(aParent, aUrl, aChromeMask, aInitialWidth, aInitialHeight, false, aOpeningTab, aOpenerWindow, getter_AddRefs(newWindow)); @@ -558,14 +558,14 @@ nsresult nsAppShellService::JustCreateTopWindow( nsIXULWindow* aParent, nsIURI* aUrl, uint32_t aChromeMask, int32_t aInitialWidth, int32_t aInitialHeight, bool aIsHiddenWindow, nsIRemoteTab* aOpeningTab, mozIDOMWindowProxy* aOpenerWindow, - nsWebShellWindow** aResult) { + nsXULWindow** aResult) { *aResult = nullptr; NS_ENSURE_STATE(!mXPCOMWillShutDown); nsCOMPtr parent; if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) parent = aParent; - RefPtr window = new nsWebShellWindow(aChromeMask); + RefPtr window = new nsXULWindow(aChromeMask); #ifdef XP_WIN // If the parent is currently fullscreen, tell the child to ignore persisted diff --git a/xpfe/appshell/nsAppShellService.h b/xpfe/appshell/nsAppShellService.h index 4db031520393..6a36a4e123e2 100644 --- a/xpfe/appshell/nsAppShellService.h +++ b/xpfe/appshell/nsAppShellService.h @@ -10,7 +10,7 @@ #include "nsIObserver.h" // Interfaces Needed -#include "nsWebShellWindow.h" +#include "nsXULWindow.h" #include "nsStringFwd.h" #include "nsAutoPtr.h" #include "nsIRemoteTab.h" @@ -42,10 +42,10 @@ class nsAppShellService final : public nsIAppShellService, public nsIObserver { int32_t aInitialHeight, bool aIsHiddenWindow, nsIRemoteTab* aOpeningTab, mozIDOMWindowProxy* aOpenerWindow, - nsWebShellWindow** aResult); + nsXULWindow** aResult); uint32_t CalculateWindowZLevel(nsIXULWindow* aParent, uint32_t aChromeMask); - RefPtr mHiddenWindow; + RefPtr mHiddenWindow; bool mXPCOMWillShutDown; bool mXPCOMShuttingDown; uint16_t mModalWindowCount; diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp deleted file mode 100644 index 06d082b2980f..000000000000 --- a/xpfe/appshell/nsWebShellWindow.cpp +++ /dev/null @@ -1,818 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsWebShellWindow.h" - -#include "nsLayoutCID.h" -#include "nsContentCID.h" -#include "nsContentList.h" -#include "nsIWeakReference.h" -#include "nsIContentViewer.h" -#include "nsIComponentManager.h" -#include "nsIServiceManager.h" -#include "nsIURL.h" -#include "nsIIOService.h" -#include "nsIURL.h" -#include "nsNetCID.h" -#include "nsIStringBundle.h" -#include "nsReadableUtils.h" - -#include "nsContentUtils.h" -#include "nsEscape.h" -#include "nsPIDOMWindow.h" -#include "nsIWebNavigation.h" -#include "nsIWindowWatcher.h" - -#include "nsWidgetInitData.h" -#include "nsWidgetsCID.h" -#include "nsIWidget.h" -#include "nsIWidgetListener.h" - -#include "nsINodeList.h" - -#include "nsITimer.h" -#include "nsXULPopupManager.h" - -#include "nsFocusManager.h" - -#include "nsIWebProgress.h" -#include "nsIWebProgressListener.h" - -#include "mozilla/dom/Document.h" -#include "nsIDocumentLoaderFactory.h" -#include "nsIObserverService.h" - -#include "nsIScreenManager.h" -#include "nsIScreen.h" - -#include "nsIContent.h" // for menus -#include "nsIScriptSecurityManager.h" - -// For calculating size -#include "nsPresContext.h" - -#include "nsIBaseWindow.h" -#include "nsIDocShellTreeItem.h" -#include "nsDocShell.h" - -#include "mozilla/Attributes.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/EventDispatcher.h" -#include "mozilla/MouseEvents.h" -#include "mozilla/PresShell.h" - -#include "mozilla/dom/BrowsingContext.h" -#include "mozilla/dom/LoadURIOptionsBinding.h" - -#include "nsPIWindowRoot.h" - -#include "gfxPlatform.h" - -#ifdef XP_MACOSX -# include "nsINativeMenuService.h" -# define USE_NATIVE_MENUS -#endif - -using namespace mozilla; -using namespace mozilla::dom; - -#define SIZE_PERSISTENCE_TIMEOUT 500 // msec - -nsWebShellWindow::nsWebShellWindow(uint32_t aChromeFlags) - : nsXULWindow(aChromeFlags), - mSPTimerLock("nsWebShellWindow.mSPTimerLock"), - mWidgetListenerDelegate(this) {} - -nsWebShellWindow::~nsWebShellWindow() { - MutexAutoLock lock(mSPTimerLock); - if (mSPTimer) mSPTimer->Cancel(); -} - -NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow) -NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow) - -NS_INTERFACE_MAP_BEGIN(nsWebShellWindow) - NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) -NS_INTERFACE_MAP_END_INHERITING(nsXULWindow) - -nsresult nsWebShellWindow::Initialize( - nsIXULWindow* aParent, nsIXULWindow* aOpener, nsIURI* aUrl, - int32_t aInitialWidth, int32_t aInitialHeight, bool aIsHiddenWindow, - nsIRemoteTab* aOpeningTab, mozIDOMWindowProxy* aOpenerWindow, - nsWidgetInitData& widgetInitData) { - nsresult rv; - nsCOMPtr parentWidget; - - mIsHiddenWindow = aIsHiddenWindow; - - int32_t initialX = 0, initialY = 0; - nsCOMPtr base(do_QueryInterface(aOpener)); - if (base) { - int32_t x, y, width, height; - rv = base->GetPositionAndSize(&x, &y, &width, &height); - if (NS_FAILED(rv)) { - mOpenerScreenRect.SetEmpty(); - } else { - double scale; - if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { - mOpenerScreenRect.SetRect( - NSToIntRound(x / scale), NSToIntRound(y / scale), - NSToIntRound(width / scale), NSToIntRound(height / scale)); - } else { - mOpenerScreenRect.SetRect(x, y, width, height); - } - initialX = mOpenerScreenRect.X(); - initialY = mOpenerScreenRect.Y(); - ConstrainToOpenerScreen(&initialX, &initialY); - } - } - - // XXX: need to get the default window size from prefs... - // Doesn't come from prefs... will come from CSS/XUL/RDF - DesktopIntRect deskRect(initialX, initialY, aInitialWidth, aInitialHeight); - - // Create top level window - if (gfxPlatform::IsHeadless()) { - mWindow = nsIWidget::CreateHeadlessWidget(); - } else { - mWindow = nsIWidget::CreateTopLevelWindow(); - } - if (!mWindow) { - return NS_ERROR_FAILURE; - } - - /* This next bit is troublesome. We carry two different versions of a pointer - to our parent window. One is the parent window's widget, which is passed - to our own widget. The other is a weak reference we keep here to our - parent WebShellWindow. The former is useful to the widget, and we can't - trust its treatment of the parent reference because they're platform- - specific. The latter is useful to this class. - A better implementation would be one in which the parent keeps strong - references to its children and closes them before it allows itself - to be closed. This would mimic the behaviour of OSes that support - top-level child windows in OSes that do not. Later. - */ - nsCOMPtr parentAsWin(do_QueryInterface(aParent)); - if (parentAsWin) { - parentAsWin->GetMainWidget(getter_AddRefs(parentWidget)); - mParentWindow = do_GetWeakReference(aParent); - } - - mWindow->SetWidgetListener(&mWidgetListenerDelegate); - rv = mWindow->Create((nsIWidget*)parentWidget, // Parent nsIWidget - nullptr, // Native parent widget - deskRect, // Widget dimensions - &widgetInitData); // Widget initialization data - NS_ENSURE_SUCCESS(rv, rv); - - LayoutDeviceIntRect r = mWindow->GetClientBounds(); - // Match the default background color of content. Important on windows - // since we no longer use content child widgets. - mWindow->SetBackgroundColor(NS_RGB(255, 255, 255)); - - // Create web shell - RefPtr openerContext = - aOpenerWindow - ? nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext() - : nullptr; - RefPtr browsingContext = - BrowsingContext::Create(/* aParent */ nullptr, openerContext, - EmptyString(), BrowsingContext::Type::Chrome); - mDocShell = nsDocShell::Create(browsingContext); - NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); - - // XXX(nika): This is used to handle propagating opener across remote tab - // creation. We should come up with a better system for doing this (probably - // based on BrowsingContext). - mDocShell->SetOpener(aOpeningTab); - - // Make sure to set the item type on the docshell _before_ calling - // Create() so it knows what type it is. - nsCOMPtr docShellAsItem(mDocShell); - NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); - NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE); - - docShellAsItem->SetTreeOwner(mChromeTreeOwner); - - r.MoveTo(0, 0); - nsCOMPtr docShellAsWin(do_QueryInterface(mDocShell)); - NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow, r.X(), r.Y(), - r.Width(), r.Height()), - NS_ERROR_FAILURE); - NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE); - - // Attach a WebProgress listener.during initialization... - nsCOMPtr webProgress(do_GetInterface(mDocShell, &rv)); - if (webProgress) { - webProgress->AddProgressListener(this, - nsIWebProgress::NOTIFY_STATE_NETWORK); - } - -#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED - if (aOpenerWindow) { - BrowsingContext* bc = mDocShell->GetBrowsingContext(); - BrowsingContext* openerBC = - nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext(); - MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == openerBC->Id()); - MOZ_DIAGNOSTIC_ASSERT(bc->HadOriginalOpener()); - } -#endif - - // Eagerly create an about:blank content viewer with the right principal here, - // rather than letting it happening in the upcoming call to - // SetInitialPrincipalToSubject. This avoids creating the about:blank document - // and then blowing it away with a second one, which can cause problems for - // the top-level chrome window case. See bug 789773. Note that we don't accept - // expanded principals here, similar to SetInitialPrincipalToSubject. - if (nsContentUtils::IsInitialized()) { // Sometimes this happens really early - // See bug 793370. - MOZ_ASSERT(mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome); - nsCOMPtr principal = - nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller(); - if (nsContentUtils::IsExpandedPrincipal(principal)) { - principal = nullptr; - } - // Use the subject (or system) principal as the storage principal too until - // the new window finishes navigating and gets a real storage principal. - rv = mDocShell->CreateAboutBlankContentViewer(principal, principal, - /* aCsp = */ nullptr); - NS_ENSURE_SUCCESS(rv, rv); - RefPtr doc = mDocShell->GetDocument(); - NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE); - doc->SetIsInitialDocument(true); - } - - if (nullptr != aUrl) { - nsCString tmpStr; - - rv = aUrl->GetSpec(tmpStr); - if (NS_FAILED(rv)) return rv; - - NS_ConvertUTF8toUTF16 urlString(tmpStr); - nsCOMPtr webNav(do_QueryInterface(mDocShell)); - NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); - - LoadURIOptions loadURIOptions; - loadURIOptions.mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal(); - - rv = webNav->LoadURI(urlString, loadURIOptions); - NS_ENSURE_SUCCESS(rv, rv); - } - - return rv; -} - -PresShell* nsWebShellWindow::GetPresShell() { - if (!mDocShell) { - return nullptr; - } - return mDocShell->GetPresShell(); -} - -bool nsWebShellWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) { - nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); - if (pm) { - nsCOMPtr window = - mDocShell ? mDocShell->GetWindow() : nullptr; - pm->AdjustPopupsOnWindowChange(window); - } - - // Notify all tabs that the widget moved. - if (mDocShell && mDocShell->GetWindow()) { - nsCOMPtr eventTarget = - mDocShell->GetWindow()->GetTopWindowRoot(); - nsContentUtils::DispatchChromeEvent(mDocShell->GetDocument(), eventTarget, - NS_LITERAL_STRING("MozUpdateWindowPos"), - CanBubble::eNo, Cancelable::eNo, - nullptr); - } - - // Persist position, but not immediately, in case this OS is firing - // repeated move events as the user drags the window - SetPersistenceTimer(PAD_POSITION); - return false; -} - -bool nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, - int32_t aHeight) { - nsCOMPtr shellAsWin(do_QueryInterface(mDocShell)); - if (shellAsWin) { - shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, 0); - } - // Persist size, but not immediately, in case this OS is firing - // repeated size events as the user drags the sizing handle - if (!IsLocked()) SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC); - return true; -} - -bool nsWebShellWindow::RequestWindowClose(nsIWidget* aWidget) { - // Maintain a reference to this as it is about to get destroyed. - nsCOMPtr xulWindow(this); - - nsCOMPtr window(mDocShell ? mDocShell->GetWindow() - : nullptr); - nsCOMPtr eventTarget = do_QueryInterface(window); - - RefPtr presShell = mDocShell->GetPresShell(); - if (!presShell) { - mozilla::DebugOnly dying; - MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying, - "No presShell, but window is not being destroyed"); - } else if (eventTarget) { - RefPtr presContext = presShell->GetPresContext(); - - nsEventStatus status = nsEventStatus_eIgnore; - WidgetMouseEvent event(true, eClose, nullptr, WidgetMouseEvent::eReal); - if (NS_SUCCEEDED(EventDispatcher::Dispatch(eventTarget, presContext, &event, - nullptr, &status)) && - status == nsEventStatus_eConsumeNoDefault) - return false; - } - - Destroy(); - return false; -} - -void nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode) { - // An alwaysRaised (or higher) window will hide any newly opened normal - // browser windows, so here we just drop a raised window to the normal - // zlevel if it's maximized. We make no provision for automatically - // re-raising it when restored. - if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) { - uint32_t zLevel; - GetZLevel(&zLevel); - if (zLevel > nsIXULWindow::normalZ) SetZLevel(nsIXULWindow::normalZ); - } - mWindow->SetSizeMode(sizeMode); - - // Persist mode, but not immediately, because in many (all?) - // cases this will merge with the similar call in NS_SIZE and - // write the attribute values only once. - SetPersistenceTimer(PAD_MISC); - nsCOMPtr ourWindow = - mDocShell ? mDocShell->GetWindow() : nullptr; - if (ourWindow) { - // Ensure that the fullscreen state is synchronized between - // the widget and the outer window object. - if (sizeMode == nsSizeMode_Fullscreen) { - ourWindow->SetFullScreen(true); - } else if (sizeMode != nsSizeMode_Minimized) { - if (ourWindow->GetFullScreen()) { - // The first SetFullscreenInternal call below ensures that we do - // not trigger any fullscreen transition even if the window was - // put in fullscreen only for the Fullscreen API. The second - // SetFullScreen call ensures that the window really exit from - // fullscreen even if it entered fullscreen for both Fullscreen - // Mode and Fullscreen API. - ourWindow->SetFullscreenInternal( - FullscreenReason::ForForceExitFullscreen, false); - ourWindow->SetFullScreen(false); - } - } - - // And always fire a user-defined sizemodechange event on the window - ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("sizemodechange")); - } - - if (PresShell* presShell = GetPresShell()) { - presShell->GetPresContext()->SizeModeChanged(sizeMode); - } - - // Note the current implementation of SetSizeMode just stores - // the new state; it doesn't actually resize. So here we store - // the state and pass the event on to the OS. The day is coming - // when we'll handle the event here, and the return result will - // then need to be different. -} - -void nsWebShellWindow::UIResolutionChanged() { - nsCOMPtr ourWindow = - mDocShell ? mDocShell->GetWindow() : nullptr; - if (ourWindow) { - ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("resolutionchange")); - } -} - -void nsWebShellWindow::FullscreenWillChange(bool aInFullscreen) { - if (mDocShell) { - if (nsCOMPtr ourWindow = mDocShell->GetWindow()) { - ourWindow->FullscreenWillChange(aInFullscreen); - } - } -} - -void nsWebShellWindow::FullscreenChanged(bool aInFullscreen) { - if (mDocShell) { - if (nsCOMPtr ourWindow = mDocShell->GetWindow()) { - ourWindow->FinishFullscreenChange(aInFullscreen); - } - } -} - -void nsWebShellWindow::OcclusionStateChanged(bool aIsFullyOccluded) { - nsCOMPtr ourWindow = - mDocShell ? mDocShell->GetWindow() : nullptr; - if (ourWindow) { - // And always fire a user-defined occlusionstatechange event on the window - ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("occlusionstatechange")); - } -} - -void nsWebShellWindow::OSToolbarButtonPressed() { - // Keep a reference as setting the chrome flags can fire events. - nsCOMPtr xulWindow(this); - - // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA" - // due to components with multiple sidebar components - // (such as Mail/News, Addressbook, etc)... and frankly, - // Mac IE, OmniWeb, and other Mac OS X apps all work this way - uint32_t chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR | - nsIWebBrowserChrome::CHROME_LOCATIONBAR | - nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR); - - nsCOMPtr wbc(do_GetInterface(xulWindow)); - if (!wbc) return; - - uint32_t chromeFlags, newChromeFlags = 0; - wbc->GetChromeFlags(&chromeFlags); - newChromeFlags = chromeFlags & chromeMask; - if (!newChromeFlags) - chromeFlags |= chromeMask; - else - chromeFlags &= (~newChromeFlags); - wbc->SetChromeFlags(chromeFlags); -} - -bool nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement, - nsIWidget* aRequestBelow, - nsIWidget** aActualBelow) { - if (aActualBelow) *aActualBelow = nullptr; - - return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow); -} - -void nsWebShellWindow::WindowActivated() { - nsCOMPtr xulWindow(this); - - // focusing the window could cause it to close, so keep a reference to it - nsCOMPtr window = - mDocShell ? mDocShell->GetWindow() : nullptr; - nsFocusManager* fm = nsFocusManager::GetFocusManager(); - if (fm && window) fm->WindowRaised(window); - - if (mChromeLoaded) { - PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC); - SavePersistentAttributes(); - } -} - -void nsWebShellWindow::WindowDeactivated() { - nsCOMPtr xulWindow(this); - - nsCOMPtr window = - mDocShell ? mDocShell->GetWindow() : nullptr; - nsFocusManager* fm = nsFocusManager::GetFocusManager(); - if (fm && window && !fm->IsTestMode()) fm->WindowLowered(window); -} - -#ifdef USE_NATIVE_MENUS -static void LoadNativeMenus(Document* aDoc, nsIWidget* aParentWindow) { - if (gfxPlatform::IsHeadless()) { - return; - } - nsCOMPtr nms = - do_GetService("@mozilla.org/widget/nativemenuservice;1"); - if (!nms) { - return; - } - - // Find the menubar tag (if there is more than one, we ignore all but - // the first). - nsCOMPtr menubarElements = aDoc->GetElementsByTagNameNS( - NS_LITERAL_STRING( - "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"), - NS_LITERAL_STRING("menubar")); - - nsCOMPtr menubarNode; - if (menubarElements) { - menubarNode = menubarElements->Item(0); - } - - if (menubarNode) { - nsCOMPtr menubarContent(do_QueryInterface(menubarNode)); - nms->CreateNativeMenuBar(aParentWindow, menubarContent); - } else { - nms->CreateNativeMenuBar(aParentWindow, nullptr); - } -} -#endif - -namespace mozilla { - -class WebShellWindowTimerCallback final : public nsITimerCallback, - public nsINamed { - public: - explicit WebShellWindowTimerCallback(nsWebShellWindow* aWindow) - : mWindow(aWindow) {} - - NS_DECL_THREADSAFE_ISUPPORTS - - NS_IMETHOD Notify(nsITimer* aTimer) override { - // Although this object participates in a refcount cycle (this -> mWindow - // -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this - // after it fires. So we don't need to release mWindow here. - - mWindow->FirePersistenceTimer(); - return NS_OK; - } - - NS_IMETHOD GetName(nsACString& aName) override { - aName.AssignLiteral("WebShellWindowTimerCallback"); - return NS_OK; - } - - private: - ~WebShellWindowTimerCallback() {} - - RefPtr mWindow; -}; - -NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback, nsINamed) - -} // namespace mozilla - -void nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags) { - MutexAutoLock lock(mSPTimerLock); - if (!mSPTimer) { - mSPTimer = NS_NewTimer(); - if (!mSPTimer) { - NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?"); - return; - } - } - - RefPtr callback = - new WebShellWindowTimerCallback(this); - mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT, - nsITimer::TYPE_ONE_SHOT); - - PersistentAttributesDirty(aDirtyFlags); -} - -void nsWebShellWindow::FirePersistenceTimer() { - MutexAutoLock lock(mSPTimerLock); - SavePersistentAttributes(); -} - -//---------------------------------------- -// nsIWebProgessListener implementation -//---------------------------------------- -NS_IMETHODIMP -nsWebShellWindow::OnProgressChange(nsIWebProgress* aProgress, - nsIRequest* aRequest, - int32_t aCurSelfProgress, - int32_t aMaxSelfProgress, - int32_t aCurTotalProgress, - int32_t aMaxTotalProgress) { - MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsWebShellWindow::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest, - uint32_t aStateFlags, nsresult aStatus) { - // If the notification is not about a document finishing, then just - // ignore it... - if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) || - !(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) { - return NS_OK; - } - - if (mChromeLoaded) return NS_OK; - - // If this document notification is for a frame then ignore it... - nsCOMPtr eventWin; - aProgress->GetDOMWindow(getter_AddRefs(eventWin)); - auto* eventPWin = nsPIDOMWindowOuter::From(eventWin); - if (eventPWin) { - nsPIDOMWindowOuter* rootPWin = eventPWin->GetPrivateRoot(); - if (eventPWin != rootPWin) return NS_OK; - } - - mChromeLoaded = true; - mLockedUntilChromeLoad = false; - -#ifdef USE_NATIVE_MENUS - /////////////////////////////// - // Find the Menubar DOM and Load the menus, hooking them up to the loaded - // commands - /////////////////////////////// - nsCOMPtr cv; - mDocShell->GetContentViewer(getter_AddRefs(cv)); - if (cv) { - RefPtr menubarDoc = cv->GetDocument(); - if (menubarDoc) LoadNativeMenus(menubarDoc, mWindow); - } -#endif // USE_NATIVE_MENUS - - OnChromeLoaded(); - - return NS_OK; -} - -NS_IMETHODIMP -nsWebShellWindow::OnLocationChange(nsIWebProgress* aProgress, - nsIRequest* aRequest, nsIURI* aURI, - uint32_t aFlags) { - MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsWebShellWindow::OnStatusChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, nsresult aStatus, - const char16_t* aMessage) { - MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsWebShellWindow::OnSecurityChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, uint32_t aState) { - MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -NS_IMETHODIMP -nsWebShellWindow::OnContentBlockingEvent(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - uint32_t aEvent) { - MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); - return NS_OK; -} - -/** - * ExecuteCloseHandler - Run the close handler, if any. - * @return true iff we found a close handler to run. - */ -bool nsWebShellWindow::ExecuteCloseHandler() { - /* If the event handler closes this window -- a likely scenario -- - things get deleted out of order without this death grip. - (The problem may be the death grip in nsWindow::windowProc, - which forces this window's widget to remain alive longer - than it otherwise would.) */ - nsCOMPtr kungFuDeathGrip(this); - - nsCOMPtr eventTarget; - if (mDocShell) { - eventTarget = do_QueryInterface(mDocShell->GetWindow()); - } - - if (eventTarget) { - nsCOMPtr contentViewer; - mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); - if (contentViewer) { - RefPtr presContext = contentViewer->GetPresContext(); - - nsEventStatus status = nsEventStatus_eIgnore; - WidgetMouseEvent event(true, eClose, nullptr, WidgetMouseEvent::eReal); - - nsresult rv = EventDispatcher::Dispatch(eventTarget, presContext, &event, - nullptr, &status); - if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault) - return true; - // else fall through and return false - } - } - - return false; -} // ExecuteCloseHandler - -void nsWebShellWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY) { - if (mOpenerScreenRect.IsEmpty()) { - *aX = *aY = 0; - return; - } - - int32_t left, top, width, height; - // Constrain initial positions to the same screen as opener - nsCOMPtr screenmgr = - do_GetService("@mozilla.org/gfx/screenmanager;1"); - if (screenmgr) { - nsCOMPtr screen; - screenmgr->ScreenForRect( - mOpenerScreenRect.X(), mOpenerScreenRect.Y(), mOpenerScreenRect.Width(), - mOpenerScreenRect.Height(), getter_AddRefs(screen)); - if (screen) { - screen->GetAvailRectDisplayPix(&left, &top, &width, &height); - if (*aX < left || *aX > left + width) { - *aX = left; - } - if (*aY < top || *aY > top + height) { - *aY = top; - } - } - } -} - -// nsIBaseWindow -NS_IMETHODIMP nsWebShellWindow::Destroy() { - nsresult rv; - nsCOMPtr webProgress(do_GetInterface(mDocShell, &rv)); - if (webProgress) { - webProgress->RemoveProgressListener(this); - } - - nsCOMPtr kungFuDeathGrip(this); - { - MutexAutoLock lock(mSPTimerLock); - if (mSPTimer) { - mSPTimer->Cancel(); - SavePersistentAttributes(); - mSPTimer = nullptr; - } - } - return nsXULWindow::Destroy(); -} - -nsIXULWindow* nsWebShellWindow::WidgetListenerDelegate::GetXULWindow() { - return mWebShellWindow->GetXULWindow(); -} - -PresShell* nsWebShellWindow::WidgetListenerDelegate::GetPresShell() { - return mWebShellWindow->GetPresShell(); -} - -bool nsWebShellWindow::WidgetListenerDelegate::WindowMoved(nsIWidget* aWidget, - int32_t aX, - int32_t aY) { - RefPtr holder = mWebShellWindow; - return holder->WindowMoved(aWidget, aX, aY); -} - -bool nsWebShellWindow::WidgetListenerDelegate::WindowResized(nsIWidget* aWidget, - int32_t aWidth, - int32_t aHeight) { - RefPtr holder = mWebShellWindow; - return holder->WindowResized(aWidget, aWidth, aHeight); -} - -bool nsWebShellWindow::WidgetListenerDelegate::RequestWindowClose( - nsIWidget* aWidget) { - RefPtr holder = mWebShellWindow; - return holder->RequestWindowClose(aWidget); -} - -void nsWebShellWindow::WidgetListenerDelegate::SizeModeChanged( - nsSizeMode aSizeMode) { - RefPtr holder = mWebShellWindow; - holder->SizeModeChanged(aSizeMode); -} - -void nsWebShellWindow::WidgetListenerDelegate::UIResolutionChanged() { - RefPtr holder = mWebShellWindow; - holder->UIResolutionChanged(); -} - -void nsWebShellWindow::WidgetListenerDelegate::FullscreenWillChange( - bool aInFullscreen) { - RefPtr holder = mWebShellWindow; - holder->FullscreenWillChange(aInFullscreen); -} - -void nsWebShellWindow::WidgetListenerDelegate::FullscreenChanged( - bool aInFullscreen) { - RefPtr holder = mWebShellWindow; - holder->FullscreenChanged(aInFullscreen); -} - -void nsWebShellWindow::WidgetListenerDelegate::OcclusionStateChanged( - bool aIsFullyOccluded) { - RefPtr holder = mWebShellWindow; - holder->OcclusionStateChanged(aIsFullyOccluded); -} - -void nsWebShellWindow::WidgetListenerDelegate::OSToolbarButtonPressed() { - RefPtr holder = mWebShellWindow; - holder->OSToolbarButtonPressed(); -} - -bool nsWebShellWindow::WidgetListenerDelegate::ZLevelChanged( - bool aImmediate, nsWindowZ* aPlacement, nsIWidget* aRequestBelow, - nsIWidget** aActualBelow) { - RefPtr holder = mWebShellWindow; - return holder->ZLevelChanged(aImmediate, aPlacement, aRequestBelow, - aActualBelow); -} - -void nsWebShellWindow::WidgetListenerDelegate::WindowActivated() { - RefPtr holder = mWebShellWindow; - holder->WindowActivated(); -} - -void nsWebShellWindow::WidgetListenerDelegate::WindowDeactivated() { - RefPtr holder = mWebShellWindow; - holder->WindowDeactivated(); -} diff --git a/xpfe/appshell/nsWebShellWindow.h b/xpfe/appshell/nsWebShellWindow.h deleted file mode 100644 index ededd65c5b20..000000000000 --- a/xpfe/appshell/nsWebShellWindow.h +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsWebShellWindow_h__ -#define nsWebShellWindow_h__ - -#include "mozilla/Mutex.h" -#include "nsIWebProgressListener.h" -#include "nsITimer.h" -#include "nsCOMPtr.h" -#include "nsXULWindow.h" -#include "nsIWidgetListener.h" -#include "nsIRemoteTab.h" - -/* Forward declarations.... */ -class nsIURI; - -struct nsWidgetInitData; - -namespace mozilla { -class PresShell; -class WebShellWindowTimerCallback; -} // namespace mozilla - -class nsWebShellWindow final : public nsXULWindow, - public nsIWebProgressListener { - public: - // The implementation of non-refcounted nsIWidgetListener, which would hold a - // strong reference on stack before calling nsWebShellWindow's - // MOZ_CAN_RUN_SCRIPT methods. - class WidgetListenerDelegate : public nsIWidgetListener { - public: - explicit WidgetListenerDelegate(nsWebShellWindow* aWebShellWindow) - : mWebShellWindow(aWebShellWindow) {} - - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual nsIXULWindow* GetXULWindow() override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual mozilla::PresShell* GetPresShell() override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual bool WindowResized(nsIWidget* aWidget, int32_t aWidth, - int32_t aHeight) override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual bool RequestWindowClose(nsIWidget* aWidget) override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void SizeModeChanged(nsSizeMode sizeMode) override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void UIResolutionChanged() override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void FullscreenWillChange(bool aInFullscreen) override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void FullscreenChanged(bool aInFullscreen) override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void OcclusionStateChanged(bool aIsFullyOccluded) override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void OSToolbarButtonPressed() override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement, - nsIWidget* aRequestBelow, - nsIWidget** aActualBelow) override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void WindowActivated() override; - MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void WindowDeactivated() override; - - private: - // The lifetime of WidgetListenerDelegate is bound to nsWebShellWindow so - // we just use a raw pointer here. - nsWebShellWindow* mWebShellWindow; - }; - - explicit nsWebShellWindow(uint32_t aChromeFlags); - - // nsISupports interface... - NS_DECL_ISUPPORTS_INHERITED - - // nsWebShellWindow methods... - nsresult Initialize(nsIXULWindow* aParent, nsIXULWindow* aOpener, - nsIURI* aUrl, int32_t aInitialWidth, - int32_t aInitialHeight, bool aIsHiddenWindow, - nsIRemoteTab* aOpeningTab, - mozIDOMWindowProxy* aOpenerWIndow, - nsWidgetInitData& widgetInitData); - - nsresult Toolbar(); - - // nsIWebProgressListener - NS_DECL_NSIWEBPROGRESSLISTENER - - // nsIBaseWindow - NS_IMETHOD Destroy() override; - - // nsIWidgetListener methods for WidgetListenerDelegate. - nsIXULWindow* GetXULWindow() { return this; } - mozilla::PresShell* GetPresShell(); - MOZ_CAN_RUN_SCRIPT - bool WindowMoved(nsIWidget* aWidget, int32_t aX, int32_t aY); - MOZ_CAN_RUN_SCRIPT - bool WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight); - MOZ_CAN_RUN_SCRIPT bool RequestWindowClose(nsIWidget* aWidget); - MOZ_CAN_RUN_SCRIPT void SizeModeChanged(nsSizeMode aSizeMode); - MOZ_CAN_RUN_SCRIPT void UIResolutionChanged(); - MOZ_CAN_RUN_SCRIPT void FullscreenWillChange(bool aInFullscreen); - MOZ_CAN_RUN_SCRIPT void FullscreenChanged(bool aInFullscreen); - MOZ_CAN_RUN_SCRIPT void OcclusionStateChanged(bool aIsFullyOccluded); - MOZ_CAN_RUN_SCRIPT void OSToolbarButtonPressed(); - MOZ_CAN_RUN_SCRIPT - bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement, - nsIWidget* aRequestBelow, nsIWidget** aActualBelow); - MOZ_CAN_RUN_SCRIPT void WindowActivated(); - MOZ_CAN_RUN_SCRIPT void WindowDeactivated(); - - protected: - friend class mozilla::WebShellWindowTimerCallback; - - virtual ~nsWebShellWindow(); - - bool ExecuteCloseHandler(); - void ConstrainToOpenerScreen(int32_t* aX, int32_t* aY); - - nsCOMPtr mSPTimer; - mozilla::Mutex mSPTimerLock; - WidgetListenerDelegate mWidgetListenerDelegate; - - void SetPersistenceTimer(uint32_t aDirtyFlags); - void FirePersistenceTimer(); -}; - -#endif /* nsWebShellWindow_h__ */ diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index dde80f40e26a..93474723dee9 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -46,9 +46,11 @@ #include "nsStyleConsts.h" #include "nsPresContext.h" #include "nsContentUtils.h" -#include "nsWebShellWindow.h" // get rid of this one, too... #include "nsGlobalWindow.h" #include "nsXULTooltipListener.h" +#include "nsXULPopupManager.h" +#include "nsFocusManager.h" +#include "nsContentList.h" #include "prenv.h" #include "mozilla/AutoRestore.h" @@ -60,13 +62,25 @@ #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/BrowserHost.h" #include "mozilla/dom/BrowserParent.h" +#include "mozilla/dom/LoadURIOptionsBinding.h" +#include "mozilla/EventDispatcher.h" #ifdef MOZ_NEW_XULSTORE # include "mozilla/XULStore.h" #endif +#ifdef XP_MACOSX +# include "nsINativeMenuService.h" +# define USE_NATIVE_MENUS +#endif + using namespace mozilla; using dom::AutoNoJSAPI; +using dom::BrowserHost; +using dom::BrowsingContext; +using dom::Document; +using dom::EventTarget; +using dom::LoadURIOptions; #define SIZEMODE_NORMAL NS_LITERAL_STRING("normal") #define SIZEMODE_MAXIMIZED NS_LITERAL_STRING("maximized") @@ -84,6 +98,8 @@ using dom::AutoNoJSAPI; #define TILED_ATTRIBUTE NS_LITERAL_STRING("gtktiledwindow") #define ZLEVEL_ATTRIBUTE NS_LITERAL_STRING("zlevel") +#define SIZE_PERSISTENCE_TIMEOUT 500 // msec + //***************************************************************************** //*** nsXULWindow: Object Management //***************************************************************************** @@ -111,9 +127,17 @@ nsXULWindow::nsXULWindow(uint32_t aChromeFlags) mPersistentAttributesDirty(0), mPersistentAttributesMask(0), mChromeFlags(aChromeFlags), - mNextRemoteTabId(0) {} + mNextRemoteTabId(0), + mSPTimerLock("nsXULWindow.mSPTimerLock"), + mWidgetListenerDelegate(this) {} -nsXULWindow::~nsXULWindow() { Destroy(); } +nsXULWindow::~nsXULWindow() { + { + MutexAutoLock lock(mSPTimerLock); + if (mSPTimer) mSPTimer->Cancel(); + } + Destroy(); +} //***************************************************************************** // nsXULWindow::nsISupports @@ -128,9 +152,178 @@ NS_INTERFACE_MAP_BEGIN(nsXULWindow) NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) NS_INTERFACE_MAP_ENTRY_CONCRETE(nsXULWindow) NS_INTERFACE_MAP_END +nsresult nsXULWindow::Initialize(nsIXULWindow* aParent, nsIXULWindow* aOpener, + nsIURI* aUrl, int32_t aInitialWidth, + int32_t aInitialHeight, bool aIsHiddenWindow, + nsIRemoteTab* aOpeningTab, + mozIDOMWindowProxy* aOpenerWindow, + nsWidgetInitData& widgetInitData) { + nsresult rv; + nsCOMPtr parentWidget; + + mIsHiddenWindow = aIsHiddenWindow; + + int32_t initialX = 0, initialY = 0; + nsCOMPtr base(do_QueryInterface(aOpener)); + if (base) { + int32_t x, y, width, height; + rv = base->GetPositionAndSize(&x, &y, &width, &height); + if (NS_FAILED(rv)) { + mOpenerScreenRect.SetEmpty(); + } else { + double scale; + if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { + mOpenerScreenRect.SetRect( + NSToIntRound(x / scale), NSToIntRound(y / scale), + NSToIntRound(width / scale), NSToIntRound(height / scale)); + } else { + mOpenerScreenRect.SetRect(x, y, width, height); + } + initialX = mOpenerScreenRect.X(); + initialY = mOpenerScreenRect.Y(); + ConstrainToOpenerScreen(&initialX, &initialY); + } + } + + // XXX: need to get the default window size from prefs... + // Doesn't come from prefs... will come from CSS/XUL/RDF + DesktopIntRect deskRect(initialX, initialY, aInitialWidth, aInitialHeight); + + // Create top level window + if (gfxPlatform::IsHeadless()) { + mWindow = nsIWidget::CreateHeadlessWidget(); + } else { + mWindow = nsIWidget::CreateTopLevelWindow(); + } + if (!mWindow) { + return NS_ERROR_FAILURE; + } + + /* This next bit is troublesome. We carry two different versions of a pointer + to our parent window. One is the parent window's widget, which is passed + to our own widget. The other is a weak reference we keep here to our + parent nsXULWindow. The former is useful to the widget, and we can't + trust its treatment of the parent reference because they're platform- + specific. The latter is useful to this class. + A better implementation would be one in which the parent keeps strong + references to its children and closes them before it allows itself + to be closed. This would mimic the behaviour of OSes that support + top-level child windows in OSes that do not. Later. + */ + nsCOMPtr parentAsWin(do_QueryInterface(aParent)); + if (parentAsWin) { + parentAsWin->GetMainWidget(getter_AddRefs(parentWidget)); + mParentWindow = do_GetWeakReference(aParent); + } + + mWindow->SetWidgetListener(&mWidgetListenerDelegate); + rv = mWindow->Create((nsIWidget*)parentWidget, // Parent nsIWidget + nullptr, // Native parent widget + deskRect, // Widget dimensions + &widgetInitData); // Widget initialization data + NS_ENSURE_SUCCESS(rv, rv); + + LayoutDeviceIntRect r = mWindow->GetClientBounds(); + // Match the default background color of content. Important on windows + // since we no longer use content child widgets. + mWindow->SetBackgroundColor(NS_RGB(255, 255, 255)); + + // Create web shell + RefPtr openerContext = + aOpenerWindow + ? nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext() + : nullptr; + RefPtr browsingContext = + BrowsingContext::Create(/* aParent */ nullptr, openerContext, + EmptyString(), BrowsingContext::Type::Chrome); + mDocShell = nsDocShell::Create(browsingContext); + NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); + + // XXX(nika): This is used to handle propagating opener across remote tab + // creation. We should come up with a better system for doing this (probably + // based on BrowsingContext). + mDocShell->SetOpener(aOpeningTab); + + // Make sure to set the item type on the docshell _before_ calling + // Create() so it knows what type it is. + nsCOMPtr docShellAsItem(mDocShell); + NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE); + + docShellAsItem->SetTreeOwner(mChromeTreeOwner); + + r.MoveTo(0, 0); + nsCOMPtr docShellAsWin(do_QueryInterface(mDocShell)); + NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow, r.X(), r.Y(), + r.Width(), r.Height()), + NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE); + + // Attach a WebProgress listener.during initialization... + nsCOMPtr webProgress(do_GetInterface(mDocShell, &rv)); + if (webProgress) { + webProgress->AddProgressListener(this, + nsIWebProgress::NOTIFY_STATE_NETWORK); + } + +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + if (aOpenerWindow) { + BrowsingContext* bc = mDocShell->GetBrowsingContext(); + BrowsingContext* openerBC = + nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext(); + MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == openerBC->Id()); + MOZ_DIAGNOSTIC_ASSERT(bc->HadOriginalOpener()); + } +#endif + + // Eagerly create an about:blank content viewer with the right principal here, + // rather than letting it happening in the upcoming call to + // SetInitialPrincipalToSubject. This avoids creating the about:blank document + // and then blowing it away with a second one, which can cause problems for + // the top-level chrome window case. See bug 789773. Note that we don't accept + // expanded principals here, similar to SetInitialPrincipalToSubject. + if (nsContentUtils::IsInitialized()) { // Sometimes this happens really early + // See bug 793370. + MOZ_ASSERT(mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome); + nsCOMPtr principal = + nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller(); + if (nsContentUtils::IsExpandedPrincipal(principal)) { + principal = nullptr; + } + // Use the subject (or system) principal as the storage principal too until + // the new window finishes navigating and gets a real storage principal. + rv = mDocShell->CreateAboutBlankContentViewer(principal, principal, + /* aCsp = */ nullptr); + NS_ENSURE_SUCCESS(rv, rv); + RefPtr doc = mDocShell->GetDocument(); + NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE); + doc->SetIsInitialDocument(true); + } + + if (nullptr != aUrl) { + nsCString tmpStr; + + rv = aUrl->GetSpec(tmpStr); + if (NS_FAILED(rv)) return rv; + + NS_ConvertUTF8toUTF16 urlString(tmpStr); + nsCOMPtr webNav(do_QueryInterface(mDocShell)); + NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); + + LoadURIOptions loadURIOptions; + loadURIOptions.mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal(); + + rv = webNav->LoadURI(urlString, loadURIOptions); + NS_ENSURE_SUCCESS(rv, rv); + } + + return rv; +} + //***************************************************************************** // nsXULWindow::nsIIntefaceRequestor //***************************************************************************** @@ -421,6 +614,22 @@ NS_IMETHODIMP nsXULWindow::Create() { } NS_IMETHODIMP nsXULWindow::Destroy() { + nsresult rv; + nsCOMPtr webProgress(do_GetInterface(mDocShell, &rv)); + if (webProgress) { + webProgress->RemoveProgressListener(this); + } + + nsCOMPtr kungFuDeathGrip(this); + { + MutexAutoLock lock(mSPTimerLock); + if (mSPTimer) { + mSPTimer->Cancel(); + SavePersistentAttributes(); + mSPTimer = nullptr; + } + } + if (!mWindow) return NS_OK; // Ensure we don't reenter this code @@ -2496,3 +2705,530 @@ nsresult nsXULWindow::GetNextRemoteTabId(uint64_t* aNextRemoteTabId) { *aNextRemoteTabId = mNextRemoteTabId; return NS_OK; } + +PresShell* nsXULWindow::GetPresShell() { + if (!mDocShell) { + return nullptr; + } + return mDocShell->GetPresShell(); +} + +bool nsXULWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) { + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); + if (pm) { + nsCOMPtr window = + mDocShell ? mDocShell->GetWindow() : nullptr; + pm->AdjustPopupsOnWindowChange(window); + } + + // Notify all tabs that the widget moved. + if (mDocShell && mDocShell->GetWindow()) { + nsCOMPtr eventTarget = + mDocShell->GetWindow()->GetTopWindowRoot(); + nsContentUtils::DispatchChromeEvent(mDocShell->GetDocument(), eventTarget, + NS_LITERAL_STRING("MozUpdateWindowPos"), + CanBubble::eNo, Cancelable::eNo, + nullptr); + } + + // Persist position, but not immediately, in case this OS is firing + // repeated move events as the user drags the window + SetPersistenceTimer(PAD_POSITION); + return false; +} + +bool nsXULWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, + int32_t aHeight) { + nsCOMPtr shellAsWin(do_QueryInterface(mDocShell)); + if (shellAsWin) { + shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, 0); + } + // Persist size, but not immediately, in case this OS is firing + // repeated size events as the user drags the sizing handle + if (!IsLocked()) SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC); + return true; +} + +bool nsXULWindow::RequestWindowClose(nsIWidget* aWidget) { + // Maintain a reference to this as it is about to get destroyed. + nsCOMPtr xulWindow(this); + + nsCOMPtr window(mDocShell ? mDocShell->GetWindow() + : nullptr); + nsCOMPtr eventTarget = do_QueryInterface(window); + + RefPtr presShell = mDocShell->GetPresShell(); + if (!presShell) { + mozilla::DebugOnly dying; + MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying, + "No presShell, but window is not being destroyed"); + } else if (eventTarget) { + RefPtr presContext = presShell->GetPresContext(); + + nsEventStatus status = nsEventStatus_eIgnore; + WidgetMouseEvent event(true, eClose, nullptr, WidgetMouseEvent::eReal); + if (NS_SUCCEEDED(EventDispatcher::Dispatch(eventTarget, presContext, &event, + nullptr, &status)) && + status == nsEventStatus_eConsumeNoDefault) + return false; + } + + Destroy(); + return false; +} + +void nsXULWindow::SizeModeChanged(nsSizeMode sizeMode) { + // An alwaysRaised (or higher) window will hide any newly opened normal + // browser windows, so here we just drop a raised window to the normal + // zlevel if it's maximized. We make no provision for automatically + // re-raising it when restored. + if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) { + uint32_t zLevel; + GetZLevel(&zLevel); + if (zLevel > nsIXULWindow::normalZ) SetZLevel(nsIXULWindow::normalZ); + } + mWindow->SetSizeMode(sizeMode); + + // Persist mode, but not immediately, because in many (all?) + // cases this will merge with the similar call in NS_SIZE and + // write the attribute values only once. + SetPersistenceTimer(PAD_MISC); + nsCOMPtr ourWindow = + mDocShell ? mDocShell->GetWindow() : nullptr; + if (ourWindow) { + // Ensure that the fullscreen state is synchronized between + // the widget and the outer window object. + if (sizeMode == nsSizeMode_Fullscreen) { + ourWindow->SetFullScreen(true); + } else if (sizeMode != nsSizeMode_Minimized) { + if (ourWindow->GetFullScreen()) { + // The first SetFullscreenInternal call below ensures that we do + // not trigger any fullscreen transition even if the window was + // put in fullscreen only for the Fullscreen API. The second + // SetFullScreen call ensures that the window really exit from + // fullscreen even if it entered fullscreen for both Fullscreen + // Mode and Fullscreen API. + ourWindow->SetFullscreenInternal( + FullscreenReason::ForForceExitFullscreen, false); + ourWindow->SetFullScreen(false); + } + } + + // And always fire a user-defined sizemodechange event on the window + ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("sizemodechange")); + } + + if (PresShell* presShell = GetPresShell()) { + presShell->GetPresContext()->SizeModeChanged(sizeMode); + } + + // Note the current implementation of SetSizeMode just stores + // the new state; it doesn't actually resize. So here we store + // the state and pass the event on to the OS. The day is coming + // when we'll handle the event here, and the return result will + // then need to be different. +} + +void nsXULWindow::UIResolutionChanged() { + nsCOMPtr ourWindow = + mDocShell ? mDocShell->GetWindow() : nullptr; + if (ourWindow) { + ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("resolutionchange")); + } +} + +void nsXULWindow::FullscreenWillChange(bool aInFullscreen) { + if (mDocShell) { + if (nsCOMPtr ourWindow = mDocShell->GetWindow()) { + ourWindow->FullscreenWillChange(aInFullscreen); + } + } +} + +void nsXULWindow::FullscreenChanged(bool aInFullscreen) { + if (mDocShell) { + if (nsCOMPtr ourWindow = mDocShell->GetWindow()) { + ourWindow->FinishFullscreenChange(aInFullscreen); + } + } +} + +void nsXULWindow::OcclusionStateChanged(bool aIsFullyOccluded) { + nsCOMPtr ourWindow = + mDocShell ? mDocShell->GetWindow() : nullptr; + if (ourWindow) { + // And always fire a user-defined occlusionstatechange event on the window + ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("occlusionstatechange")); + } +} + +void nsXULWindow::OSToolbarButtonPressed() { + // Keep a reference as setting the chrome flags can fire events. + nsCOMPtr xulWindow(this); + + // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA" + // due to components with multiple sidebar components + // (such as Mail/News, Addressbook, etc)... and frankly, + // Mac IE, OmniWeb, and other Mac OS X apps all work this way + uint32_t chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR | + nsIWebBrowserChrome::CHROME_LOCATIONBAR | + nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR); + + nsCOMPtr wbc(do_GetInterface(xulWindow)); + if (!wbc) return; + + uint32_t chromeFlags, newChromeFlags = 0; + wbc->GetChromeFlags(&chromeFlags); + newChromeFlags = chromeFlags & chromeMask; + if (!newChromeFlags) + chromeFlags |= chromeMask; + else + chromeFlags &= (~newChromeFlags); + wbc->SetChromeFlags(chromeFlags); +} + +bool nsXULWindow::ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement, + nsIWidget* aRequestBelow, + nsIWidget** aActualBelow) { + if (aActualBelow) *aActualBelow = nullptr; + + return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow); +} + +void nsXULWindow::WindowActivated() { + nsCOMPtr xulWindow(this); + + // focusing the window could cause it to close, so keep a reference to it + nsCOMPtr window = + mDocShell ? mDocShell->GetWindow() : nullptr; + nsFocusManager* fm = nsFocusManager::GetFocusManager(); + if (fm && window) fm->WindowRaised(window); + + if (mChromeLoaded) { + PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC); + SavePersistentAttributes(); + } +} + +void nsXULWindow::WindowDeactivated() { + nsCOMPtr xulWindow(this); + + nsCOMPtr window = + mDocShell ? mDocShell->GetWindow() : nullptr; + nsFocusManager* fm = nsFocusManager::GetFocusManager(); + if (fm && window && !fm->IsTestMode()) fm->WindowLowered(window); +} + +#ifdef USE_NATIVE_MENUS +static void LoadNativeMenus(Document* aDoc, nsIWidget* aParentWindow) { + if (gfxPlatform::IsHeadless()) { + return; + } + nsCOMPtr nms = + do_GetService("@mozilla.org/widget/nativemenuservice;1"); + if (!nms) { + return; + } + + // Find the menubar tag (if there is more than one, we ignore all but + // the first). + nsCOMPtr menubarElements = aDoc->GetElementsByTagNameNS( + NS_LITERAL_STRING( + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"), + NS_LITERAL_STRING("menubar")); + + nsCOMPtr menubarNode; + if (menubarElements) { + menubarNode = menubarElements->Item(0); + } + + if (menubarNode) { + nsCOMPtr menubarContent(do_QueryInterface(menubarNode)); + nms->CreateNativeMenuBar(aParentWindow, menubarContent); + } else { + nms->CreateNativeMenuBar(aParentWindow, nullptr); + } +} +#endif + +namespace mozilla { + +class nsXULWindowTimerCallback final : public nsITimerCallback, + public nsINamed { + public: + explicit nsXULWindowTimerCallback(nsXULWindow* aWindow) : mWindow(aWindow) {} + + NS_DECL_THREADSAFE_ISUPPORTS + + NS_IMETHOD Notify(nsITimer* aTimer) override { + // Although this object participates in a refcount cycle (this -> mWindow + // -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this + // after it fires. So we don't need to release mWindow here. + + mWindow->FirePersistenceTimer(); + return NS_OK; + } + + NS_IMETHOD GetName(nsACString& aName) override { + aName.AssignLiteral("nsXULWindowTimerCallback"); + return NS_OK; + } + + private: + ~nsXULWindowTimerCallback() {} + + RefPtr mWindow; +}; + +NS_IMPL_ISUPPORTS(nsXULWindowTimerCallback, nsITimerCallback, nsINamed) + +} // namespace mozilla + +void nsXULWindow::SetPersistenceTimer(uint32_t aDirtyFlags) { + MutexAutoLock lock(mSPTimerLock); + if (!mSPTimer) { + mSPTimer = NS_NewTimer(); + if (!mSPTimer) { + NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?"); + return; + } + } + + RefPtr callback = + new nsXULWindowTimerCallback(this); + mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT, + nsITimer::TYPE_ONE_SHOT); + + PersistentAttributesDirty(aDirtyFlags); +} + +void nsXULWindow::FirePersistenceTimer() { + MutexAutoLock lock(mSPTimerLock); + SavePersistentAttributes(); +} + +//---------------------------------------- +// nsIWebProgessListener implementation +//---------------------------------------- +NS_IMETHODIMP +nsXULWindow::OnProgressChange(nsIWebProgress* aProgress, nsIRequest* aRequest, + int32_t aCurSelfProgress, + int32_t aMaxSelfProgress, + int32_t aCurTotalProgress, + int32_t aMaxTotalProgress) { + MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); + return NS_OK; +} + +NS_IMETHODIMP +nsXULWindow::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest, + uint32_t aStateFlags, nsresult aStatus) { + // If the notification is not about a document finishing, then just + // ignore it... + if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) || + !(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) { + return NS_OK; + } + + if (mChromeLoaded) return NS_OK; + + // If this document notification is for a frame then ignore it... + nsCOMPtr eventWin; + aProgress->GetDOMWindow(getter_AddRefs(eventWin)); + auto* eventPWin = nsPIDOMWindowOuter::From(eventWin); + if (eventPWin) { + nsPIDOMWindowOuter* rootPWin = eventPWin->GetPrivateRoot(); + if (eventPWin != rootPWin) return NS_OK; + } + + mChromeLoaded = true; + mLockedUntilChromeLoad = false; + +#ifdef USE_NATIVE_MENUS + /////////////////////////////// + // Find the Menubar DOM and Load the menus, hooking them up to the loaded + // commands + /////////////////////////////// + nsCOMPtr cv; + mDocShell->GetContentViewer(getter_AddRefs(cv)); + if (cv) { + RefPtr menubarDoc = cv->GetDocument(); + if (menubarDoc) LoadNativeMenus(menubarDoc, mWindow); + } +#endif // USE_NATIVE_MENUS + + OnChromeLoaded(); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULWindow::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest, + nsIURI* aURI, uint32_t aFlags) { + MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); + return NS_OK; +} + +NS_IMETHODIMP +nsXULWindow::OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, + nsresult aStatus, const char16_t* aMessage) { + MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); + return NS_OK; +} + +NS_IMETHODIMP +nsXULWindow::OnSecurityChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, uint32_t aState) { + MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); + return NS_OK; +} + +NS_IMETHODIMP +nsXULWindow::OnContentBlockingEvent(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, uint32_t aEvent) { + MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); + return NS_OK; +} + +/** + * ExecuteCloseHandler - Run the close handler, if any. + * @return true iff we found a close handler to run. + */ +bool nsXULWindow::ExecuteCloseHandler() { + /* If the event handler closes this window -- a likely scenario -- + things get deleted out of order without this death grip. + (The problem may be the death grip in nsWindow::windowProc, + which forces this window's widget to remain alive longer + than it otherwise would.) */ + nsCOMPtr kungFuDeathGrip(this); + + nsCOMPtr eventTarget; + if (mDocShell) { + eventTarget = do_QueryInterface(mDocShell->GetWindow()); + } + + if (eventTarget) { + nsCOMPtr contentViewer; + mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); + if (contentViewer) { + RefPtr presContext = contentViewer->GetPresContext(); + + nsEventStatus status = nsEventStatus_eIgnore; + WidgetMouseEvent event(true, eClose, nullptr, WidgetMouseEvent::eReal); + + nsresult rv = EventDispatcher::Dispatch(eventTarget, presContext, &event, + nullptr, &status); + if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault) + return true; + // else fall through and return false + } + } + + return false; +} // ExecuteCloseHandler + +void nsXULWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY) { + if (mOpenerScreenRect.IsEmpty()) { + *aX = *aY = 0; + return; + } + + int32_t left, top, width, height; + // Constrain initial positions to the same screen as opener + nsCOMPtr screenmgr = + do_GetService("@mozilla.org/gfx/screenmanager;1"); + if (screenmgr) { + nsCOMPtr screen; + screenmgr->ScreenForRect( + mOpenerScreenRect.X(), mOpenerScreenRect.Y(), mOpenerScreenRect.Width(), + mOpenerScreenRect.Height(), getter_AddRefs(screen)); + if (screen) { + screen->GetAvailRectDisplayPix(&left, &top, &width, &height); + if (*aX < left || *aX > left + width) { + *aX = left; + } + if (*aY < top || *aY > top + height) { + *aY = top; + } + } + } +} + +nsIXULWindow* nsXULWindow::WidgetListenerDelegate::GetXULWindow() { + return mXULWindow->GetXULWindow(); +} + +PresShell* nsXULWindow::WidgetListenerDelegate::GetPresShell() { + return mXULWindow->GetPresShell(); +} + +bool nsXULWindow::WidgetListenerDelegate::WindowMoved(nsIWidget* aWidget, + int32_t aX, int32_t aY) { + RefPtr holder = mXULWindow; + return holder->WindowMoved(aWidget, aX, aY); +} + +bool nsXULWindow::WidgetListenerDelegate::WindowResized(nsIWidget* aWidget, + int32_t aWidth, + int32_t aHeight) { + RefPtr holder = mXULWindow; + return holder->WindowResized(aWidget, aWidth, aHeight); +} + +bool nsXULWindow::WidgetListenerDelegate::RequestWindowClose( + nsIWidget* aWidget) { + RefPtr holder = mXULWindow; + return holder->RequestWindowClose(aWidget); +} + +void nsXULWindow::WidgetListenerDelegate::SizeModeChanged( + nsSizeMode aSizeMode) { + RefPtr holder = mXULWindow; + holder->SizeModeChanged(aSizeMode); +} + +void nsXULWindow::WidgetListenerDelegate::UIResolutionChanged() { + RefPtr holder = mXULWindow; + holder->UIResolutionChanged(); +} + +void nsXULWindow::WidgetListenerDelegate::FullscreenWillChange( + bool aInFullscreen) { + RefPtr holder = mXULWindow; + holder->FullscreenWillChange(aInFullscreen); +} + +void nsXULWindow::WidgetListenerDelegate::FullscreenChanged( + bool aInFullscreen) { + RefPtr holder = mXULWindow; + holder->FullscreenChanged(aInFullscreen); +} + +void nsXULWindow::WidgetListenerDelegate::OcclusionStateChanged( + bool aIsFullyOccluded) { + RefPtr holder = mXULWindow; + holder->OcclusionStateChanged(aIsFullyOccluded); +} + +void nsXULWindow::WidgetListenerDelegate::OSToolbarButtonPressed() { + RefPtr holder = mXULWindow; + holder->OSToolbarButtonPressed(); +} + +bool nsXULWindow::WidgetListenerDelegate::ZLevelChanged( + bool aImmediate, nsWindowZ* aPlacement, nsIWidget* aRequestBelow, + nsIWidget** aActualBelow) { + RefPtr holder = mXULWindow; + return holder->ZLevelChanged(aImmediate, aPlacement, aRequestBelow, + aActualBelow); +} + +void nsXULWindow::WidgetListenerDelegate::WindowActivated() { + RefPtr holder = mXULWindow; + holder->WindowActivated(); +} + +void nsXULWindow::WidgetListenerDelegate::WindowDeactivated() { + RefPtr holder = mXULWindow; + holder->WindowDeactivated(); +} diff --git a/xpfe/appshell/nsXULWindow.h b/xpfe/appshell/nsXULWindow.h index 43004dcc80ef..bdbef3124e7c 100644 --- a/xpfe/appshell/nsXULWindow.h +++ b/xpfe/appshell/nsXULWindow.h @@ -19,6 +19,7 @@ #include "nsCOMArray.h" #include "nsRect.h" #include "Units.h" +#include "mozilla/Mutex.h" // Interfaces needed #include "nsIBaseWindow.h" @@ -32,6 +33,8 @@ #include "nsIXULBrowserWindow.h" #include "nsIWidgetListener.h" #include "nsIRemoteTab.h" +#include "nsIWebProgressListener.h" +#include "nsITimer.h" #ifndef MOZ_NEW_XULSTORE # include "nsIXULStore.h" @@ -45,6 +48,12 @@ class Element; class nsAtom; class nsXULTooltipListener; +struct nsWidgetInitData; + +namespace mozilla { +class PresShell; +class nsXULWindowTimerCallback; +} // namespace mozilla // nsXULWindow @@ -57,14 +66,61 @@ class nsXULTooltipListener; class nsContentShellInfo; -class nsXULWindow : public nsIBaseWindow, - public nsIInterfaceRequestor, - public nsIXULWindow, - public nsSupportsWeakReference { +class nsXULWindow final : public nsIBaseWindow, + public nsIInterfaceRequestor, + public nsIXULWindow, + public nsSupportsWeakReference, + public nsIWebProgressListener { friend class nsChromeTreeOwner; friend class nsContentTreeOwner; public: + // The implementation of non-refcounted nsIWidgetListener, which would hold a + // strong reference on stack before calling nsXULWindow's + // MOZ_CAN_RUN_SCRIPT methods. + class WidgetListenerDelegate : public nsIWidgetListener { + public: + explicit WidgetListenerDelegate(nsXULWindow* aXULWindow) + : mXULWindow(aXULWindow) {} + + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual nsIXULWindow* GetXULWindow() override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual mozilla::PresShell* GetPresShell() override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual bool WindowResized(nsIWidget* aWidget, int32_t aWidth, + int32_t aHeight) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual bool RequestWindowClose(nsIWidget* aWidget) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void SizeModeChanged(nsSizeMode sizeMode) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void UIResolutionChanged() override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void FullscreenWillChange(bool aInFullscreen) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void FullscreenChanged(bool aInFullscreen) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void OcclusionStateChanged(bool aIsFullyOccluded) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void OSToolbarButtonPressed() override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement, + nsIWidget* aRequestBelow, + nsIWidget** aActualBelow) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void WindowActivated() override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void WindowDeactivated() override; + + private: + // The lifetime of WidgetListenerDelegate is bound to nsXULWindow so + // we just use a raw pointer here. + nsXULWindow* mXULWindow; + }; + NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIINTERFACEREQUESTOR @@ -78,6 +134,41 @@ class nsXULWindow : public nsIBaseWindow, void IgnoreXULSizeMode(bool aEnable) { mIgnoreXULSizeMode = aEnable; } void WasRegistered() { mRegistered = true; } + // nsXULWindow methods... + nsresult Initialize(nsIXULWindow* aParent, nsIXULWindow* aOpener, + nsIURI* aUrl, int32_t aInitialWidth, + int32_t aInitialHeight, bool aIsHiddenWindow, + nsIRemoteTab* aOpeningTab, + mozIDOMWindowProxy* aOpenerWIndow, + nsWidgetInitData& widgetInitData); + + nsresult Toolbar(); + + // nsIWebProgressListener + NS_DECL_NSIWEBPROGRESSLISTENER + + // nsIWidgetListener methods for WidgetListenerDelegate. + nsIXULWindow* GetXULWindow() { return this; } + mozilla::PresShell* GetPresShell(); + MOZ_CAN_RUN_SCRIPT + bool WindowMoved(nsIWidget* aWidget, int32_t aX, int32_t aY); + MOZ_CAN_RUN_SCRIPT + bool WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight); + MOZ_CAN_RUN_SCRIPT bool RequestWindowClose(nsIWidget* aWidget); + MOZ_CAN_RUN_SCRIPT void SizeModeChanged(nsSizeMode aSizeMode); + MOZ_CAN_RUN_SCRIPT void UIResolutionChanged(); + MOZ_CAN_RUN_SCRIPT void FullscreenWillChange(bool aInFullscreen); + MOZ_CAN_RUN_SCRIPT void FullscreenChanged(bool aInFullscreen); + MOZ_CAN_RUN_SCRIPT void OcclusionStateChanged(bool aIsFullyOccluded); + MOZ_CAN_RUN_SCRIPT void OSToolbarButtonPressed(); + MOZ_CAN_RUN_SCRIPT + bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement, + nsIWidget* aRequestBelow, nsIWidget** aActualBelow); + MOZ_CAN_RUN_SCRIPT void WindowActivated(); + MOZ_CAN_RUN_SCRIPT void WindowDeactivated(); + + explicit nsXULWindow(uint32_t aChromeFlags); + protected: enum persistentAttributes { PAD_MISC = 0x1, @@ -85,9 +176,16 @@ class nsXULWindow : public nsIBaseWindow, PAD_SIZE = 0x4 }; - explicit nsXULWindow(uint32_t aChromeFlags); virtual ~nsXULWindow(); + friend class mozilla::nsXULWindowTimerCallback; + + bool ExecuteCloseHandler(); + void ConstrainToOpenerScreen(int32_t* aX, int32_t* aY); + + void SetPersistenceTimer(uint32_t aDirtyFlags); + void FirePersistenceTimer(); + NS_IMETHOD EnsureChromeTreeOwner(); NS_IMETHOD EnsureContentTreeOwner(); NS_IMETHOD EnsurePrimaryContentTreeOwner(); @@ -189,6 +287,10 @@ class nsXULWindow : public nsIBaseWindow, nsCOMPtr mPrimaryBrowserParent; + nsCOMPtr mSPTimer; + mozilla::Mutex mSPTimerLock; + WidgetListenerDelegate mWidgetListenerDelegate; + private: // GetPrimaryBrowserParentSize is called from xpidl methods and we don't have // a good way to annotate those with MOZ_CAN_RUN_SCRIPT yet. It takes no