michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: #include "nsIAppShellService.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIURL.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIObserver.h" michael@0: #include "nsIXPConnect.h" michael@0: michael@0: #include "nsIWindowMediator.h" michael@0: #include "nsIWindowWatcher.h" michael@0: #include "nsPIWindowWatcher.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsWebShellWindow.h" michael@0: michael@0: #include "nsCRT.h" michael@0: #include "prprf.h" michael@0: michael@0: #include "nsWidgetInitData.h" michael@0: #include "nsWidgetsCID.h" michael@0: #include "nsIWidget.h" michael@0: #include "nsIRequestObserver.h" michael@0: michael@0: /* For implementing GetHiddenWindowAndJSContext */ michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsIScriptContext.h" michael@0: michael@0: #include "nsAppShellService.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsIChromeRegistry.h" michael@0: #include "nsILoadContext.h" michael@0: #include "nsIWebNavigation.h" michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/StartupTimeline.h" michael@0: michael@0: #include "nsEmbedCID.h" michael@0: #include "nsIWebBrowser.h" michael@0: #include "nsIDocShell.h" michael@0: michael@0: #ifdef MOZ_INSTRUMENT_EVENT_LOOP michael@0: #include "EventTracer.h" michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: michael@0: // Default URL for the hidden window, can be overridden by a pref on Mac michael@0: #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html" michael@0: michael@0: class nsIAppShell; michael@0: michael@0: nsAppShellService::nsAppShellService() : michael@0: mXPCOMWillShutDown(false), michael@0: mXPCOMShuttingDown(false), michael@0: mModalWindowCount(0), michael@0: mApplicationProvidedHiddenWindow(false) michael@0: { michael@0: nsCOMPtr obs michael@0: (do_GetService("@mozilla.org/observer-service;1")); michael@0: michael@0: if (obs) { michael@0: obs->AddObserver(this, "xpcom-will-shutdown", false); michael@0: obs->AddObserver(this, "xpcom-shutdown", false); michael@0: } michael@0: } michael@0: michael@0: nsAppShellService::~nsAppShellService() michael@0: { michael@0: } michael@0: michael@0: michael@0: /* michael@0: * Implement the nsISupports methods... michael@0: */ michael@0: NS_IMPL_ISUPPORTS(nsAppShellService, michael@0: nsIAppShellService, michael@0: nsIObserver) michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::CreateHiddenWindow() michael@0: { michael@0: return CreateHiddenWindowHelper(false); michael@0: } michael@0: michael@0: void michael@0: nsAppShellService::EnsurePrivateHiddenWindow() michael@0: { michael@0: if (!mHiddenPrivateWindow) { michael@0: CreateHiddenWindowHelper(true); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate) michael@0: { michael@0: nsresult rv; michael@0: int32_t initialHeight = 100, initialWidth = 100; michael@0: michael@0: #ifdef XP_MACOSX michael@0: uint32_t chromeMask = 0; michael@0: nsAdoptingCString prefVal = michael@0: Preferences::GetCString("browser.hiddenWindowChromeURL"); michael@0: const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL; michael@0: if (aIsPrivate) { michael@0: hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL; michael@0: } else { michael@0: mApplicationProvidedHiddenWindow = prefVal.get() ? true : false; michael@0: } michael@0: #else michael@0: static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL; michael@0: uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL; michael@0: #endif michael@0: michael@0: nsCOMPtr url; michael@0: rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsRefPtr newWindow; michael@0: if (!aIsPrivate) { michael@0: rv = JustCreateTopWindow(nullptr, url, michael@0: chromeMask, initialWidth, initialHeight, michael@0: true, getter_AddRefs(newWindow)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mHiddenWindow.swap(newWindow); michael@0: } else { michael@0: // Create the hidden private window michael@0: chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW; michael@0: michael@0: rv = JustCreateTopWindow(nullptr, url, michael@0: chromeMask, initialWidth, initialHeight, michael@0: true, getter_AddRefs(newWindow)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr docShell; michael@0: newWindow->GetDocShell(getter_AddRefs(docShell)); michael@0: if (docShell) { michael@0: docShell->SetAffectPrivateSessionLifetime(false); michael@0: } michael@0: michael@0: mHiddenPrivateWindow.swap(newWindow); michael@0: } michael@0: michael@0: // RegisterTopLevelWindow(newWindow); -- Mac only michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::DestroyHiddenWindow() michael@0: { michael@0: if (mHiddenWindow) { michael@0: mHiddenWindow->Destroy(); michael@0: michael@0: mHiddenWindow = nullptr; michael@0: } michael@0: michael@0: if (mHiddenPrivateWindow) { michael@0: mHiddenPrivateWindow->Destroy(); michael@0: michael@0: mHiddenPrivateWindow = nullptr; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* michael@0: * Create a new top level window and display the given URL within it... michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent, michael@0: nsIURI *aUrl, michael@0: uint32_t aChromeMask, michael@0: int32_t aInitialWidth, michael@0: int32_t aInitialHeight, michael@0: nsIXULWindow **aResult) michael@0: michael@0: { michael@0: nsresult rv; michael@0: michael@0: StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW); michael@0: michael@0: nsWebShellWindow *newWindow = nullptr; michael@0: rv = JustCreateTopWindow(aParent, aUrl, michael@0: aChromeMask, aInitialWidth, aInitialHeight, michael@0: false, &newWindow); // addrefs michael@0: michael@0: *aResult = newWindow; // transfer ref michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // the addref resulting from this is the owning addref for this window michael@0: RegisterTopLevelWindow(*aResult); michael@0: nsCOMPtr parent; michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) michael@0: parent = aParent; michael@0: (*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask)); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* michael@0: * This class provides a stub implementation of nsIWebBrowserChrome2, as needed michael@0: * by nsAppShellService::CreateWindowlessBrowser michael@0: */ michael@0: class WebBrowserChrome2Stub : public nsIWebBrowserChrome2, michael@0: public nsIInterfaceRequestor, michael@0: public nsSupportsWeakReference { michael@0: public: michael@0: virtual ~WebBrowserChrome2Stub() {} michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIWEBBROWSERCHROME michael@0: NS_DECL_NSIWEBBROWSERCHROME2 michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: }; michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome) michael@0: NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome) michael@0: NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2) michael@0: NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_ADDREF(WebBrowserChrome2Stub) michael@0: NS_IMPL_RELEASE(WebBrowserChrome2Stub) michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::SetStatus(uint32_t aStatusType, const char16_t* aStatus) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::GetWebBrowser(nsIWebBrowser** aWebBrowser) michael@0: { michael@0: NS_NOTREACHED("WebBrowserChrome2Stub::GetWebBrowser is not supported"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::SetWebBrowser(nsIWebBrowser* aWebBrowser) michael@0: { michael@0: NS_NOTREACHED("WebBrowserChrome2Stub::SetWebBrowser is not supported"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags) michael@0: { michael@0: *aChromeFlags = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags) michael@0: { michael@0: NS_NOTREACHED("WebBrowserChrome2Stub::SetChromeFlags is not supported"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::DestroyBrowserWindow() michael@0: { michael@0: NS_NOTREACHED("WebBrowserChrome2Stub::DestroyBrowserWindow is not supported"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::SizeBrowserTo(int32_t aCX, int32_t aCY) michael@0: { michael@0: NS_NOTREACHED("WebBrowserChrome2Stub::SizeBrowserTo is not supported"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::ShowAsModal() michael@0: { michael@0: NS_NOTREACHED("WebBrowserChrome2Stub::ShowAsModal is not supported"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::IsWindowModal(bool* aResult) michael@0: { michael@0: *aResult = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::ExitModalEventLoop(nsresult aStatus) michael@0: { michael@0: NS_NOTREACHED("WebBrowserChrome2Stub::ExitModalEventLoop is not supported"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::SetStatusWithContext(uint32_t aStatusType, michael@0: const nsAString& aStatusText, michael@0: nsISupports* aStatusContext) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebBrowserChrome2Stub::GetInterface(const nsIID & aIID, void **aSink) michael@0: { michael@0: return QueryInterface(aIID, aSink); michael@0: } michael@0: michael@0: // This is the "stub" we return from CreateWindowlessBrowser - it exists michael@0: // purely to keep a strong reference to the browser and the container to michael@0: // prevent the container being collected while the stub remains alive. michael@0: class WindowlessBrowserStub MOZ_FINAL : public nsIWebNavigation, michael@0: public nsIInterfaceRequestor { michael@0: public: michael@0: WindowlessBrowserStub(nsIWebBrowser *aBrowser, nsISupports *aContainer) { michael@0: mBrowser = aBrowser; michael@0: mWebNavigation = do_QueryInterface(aBrowser); michael@0: mInterfaceRequestor = do_QueryInterface(aBrowser); michael@0: mContainer = aContainer; michael@0: } michael@0: NS_DECL_ISUPPORTS michael@0: NS_FORWARD_NSIWEBNAVIGATION(mWebNavigation->) michael@0: NS_FORWARD_NSIINTERFACEREQUESTOR(mInterfaceRequestor->) michael@0: private: michael@0: nsCOMPtr mBrowser; michael@0: nsCOMPtr mWebNavigation; michael@0: nsCOMPtr mInterfaceRequestor; michael@0: // we don't use the container but just hold a reference to it. michael@0: nsCOMPtr mContainer; michael@0: }; michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(WindowlessBrowserStub) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebNavigation) michael@0: NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) michael@0: NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_ADDREF(WindowlessBrowserStub) michael@0: NS_IMPL_RELEASE(WindowlessBrowserStub) michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWebNavigation **aResult) michael@0: { michael@0: /* First, we create an instance of nsWebBrowser. Instances of this class have michael@0: * an associated doc shell, which is what we're interested in. michael@0: */ michael@0: nsCOMPtr browser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID); michael@0: if (!browser) { michael@0: NS_ERROR("Couldn't create instance of nsWebBrowser!"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* Next, we set the container window for our instance of nsWebBrowser. Since michael@0: * we don't actually have a window, we instead set the container window to be michael@0: * an instance of WebBrowserChrome2Stub, which provides a stub implementation michael@0: * of nsIWebBrowserChrome2. michael@0: */ michael@0: nsRefPtr stub = new WebBrowserChrome2Stub(); michael@0: if (!stub) { michael@0: NS_ERROR("Couldn't create instance of WebBrowserChrome2Stub!"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: browser->SetContainerWindow(stub); michael@0: michael@0: nsCOMPtr navigation = do_QueryInterface(browser); michael@0: michael@0: nsCOMPtr item = do_QueryInterface(navigation); michael@0: item->SetItemType(aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper michael@0: : nsIDocShellTreeItem::typeContentWrapper); michael@0: michael@0: /* A windowless web browser doesn't have an associated OS level window. To michael@0: * accomplish this, we initialize the window associated with our instance of michael@0: * nsWebBrowser with an instance of PuppetWidget, which provides a stub michael@0: * implementation of nsIWidget. michael@0: */ michael@0: nsCOMPtr widget = nsIWidget::CreatePuppetWidget(nullptr); michael@0: if (!widget) { michael@0: NS_ERROR("Couldn't create instance of PuppetWidget"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: widget->Create(nullptr, 0, nsIntRect(nsIntPoint(0, 0), nsIntSize(0, 0)), michael@0: nullptr, nullptr); michael@0: nsCOMPtr window = do_QueryInterface(navigation); michael@0: window->InitWindow(0, widget, 0, 0, 0, 0); michael@0: window->Create(); michael@0: michael@0: nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub); michael@0: nsRefPtr result = new WindowlessBrowserStub(browser, isstub); michael@0: nsCOMPtr docshell = do_GetInterface(result); michael@0: docshell->SetInvisible(true); michael@0: michael@0: result.forget(aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint32_t michael@0: nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent, michael@0: uint32_t aChromeMask) michael@0: { michael@0: uint32_t zLevel; michael@0: michael@0: zLevel = nsIXULWindow::normalZ; michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED) michael@0: zLevel = nsIXULWindow::raisedZ; michael@0: else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED) michael@0: zLevel = nsIXULWindow::loweredZ; michael@0: michael@0: #ifdef XP_MACOSX michael@0: /* Platforms on which modal windows are always application-modal, not michael@0: window-modal (that's just the Mac, right?) want modal windows to michael@0: be stacked on top of everyone else. michael@0: michael@0: On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9) michael@0: */ michael@0: uint32_t modalDepMask = nsIWebBrowserChrome::CHROME_MODAL | michael@0: nsIWebBrowserChrome::CHROME_DEPENDENT; michael@0: if (aParent && (aChromeMask & modalDepMask)) { michael@0: aParent->GetZLevel(&zLevel); michael@0: } michael@0: #else michael@0: /* Platforms with native support for dependent windows (that's everyone michael@0: but pre-Mac OS X, right?) know how to stack dependent windows. On these michael@0: platforms, give the dependent window the same level as its parent, michael@0: so we won't try to override the normal platform behaviour. */ michael@0: if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent) michael@0: aParent->GetZLevel(&zLevel); michael@0: #endif michael@0: michael@0: return zLevel; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: /* michael@0: * Checks to see if any existing window is currently in fullscreen mode. michael@0: */ michael@0: static bool michael@0: CheckForFullscreenWindow() michael@0: { michael@0: nsCOMPtr wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (!wm) michael@0: return false; michael@0: michael@0: nsCOMPtr windowList; michael@0: wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList)); michael@0: if (!windowList) michael@0: return false; michael@0: michael@0: for (;;) { michael@0: bool more = false; michael@0: windowList->HasMoreElements(&more); michael@0: if (!more) michael@0: return false; michael@0: michael@0: nsCOMPtr supportsWindow; michael@0: windowList->GetNext(getter_AddRefs(supportsWindow)); michael@0: nsCOMPtr baseWin(do_QueryInterface(supportsWindow)); michael@0: if (baseWin) { michael@0: nsCOMPtr widget; michael@0: baseWin->GetMainWidget(getter_AddRefs(widget)); michael@0: if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) { michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: #endif michael@0: michael@0: /* michael@0: * Just do the window-making part of CreateTopLevelWindow michael@0: */ michael@0: nsresult michael@0: nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent, michael@0: nsIURI *aUrl, michael@0: uint32_t aChromeMask, michael@0: int32_t aInitialWidth, michael@0: int32_t aInitialHeight, michael@0: bool aIsHiddenWindow, michael@0: nsWebShellWindow **aResult) michael@0: { michael@0: *aResult = nullptr; michael@0: NS_ENSURE_STATE(!mXPCOMWillShutDown); michael@0: michael@0: nsCOMPtr parent; michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) michael@0: parent = aParent; michael@0: michael@0: nsRefPtr window = new nsWebShellWindow(aChromeMask); michael@0: NS_ENSURE_TRUE(window, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: #ifdef XP_WIN michael@0: // If the parent is currently fullscreen, tell the child to ignore persisted michael@0: // full screen states. This way new browser windows open on top of fullscreen michael@0: // windows normally. michael@0: if (window && CheckForFullscreenWindow()) michael@0: window->IgnoreXULSizeMode(true); michael@0: #endif michael@0: michael@0: nsWidgetInitData widgetInitData; michael@0: michael@0: if (aIsHiddenWindow) michael@0: widgetInitData.mWindowType = eWindowType_invisible; michael@0: else michael@0: widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ? michael@0: eWindowType_dialog : eWindowType_toplevel; michael@0: michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP) michael@0: widgetInitData.mWindowType = eWindowType_popup; michael@0: michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_MAC_SUPPRESS_ANIMATION) michael@0: widgetInitData.mIsAnimationSuppressed = true; michael@0: michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) michael@0: widgetInitData.mRequireOffMainThreadCompositing = true; michael@0: michael@0: #ifdef XP_MACOSX michael@0: // Mac OS X sheet support michael@0: // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from michael@0: // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal michael@0: // windows opened from nsPromptService::DoDialog() still are sheets. This michael@0: // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and michael@0: // nsCocoaWindow::SetModal()). michael@0: uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | michael@0: nsIWebBrowserChrome::CHROME_MODAL | michael@0: nsIWebBrowserChrome::CHROME_OPENAS_CHROME; michael@0: if (parent && michael@0: (parent != mHiddenWindow && parent != mHiddenPrivateWindow) && michael@0: ((aChromeMask & sheetMask) == sheetMask)) { michael@0: widgetInitData.mWindowType = eWindowType_sheet; michael@0: } michael@0: #endif michael@0: michael@0: #if defined(XP_WIN) michael@0: if (widgetInitData.mWindowType == eWindowType_toplevel || michael@0: widgetInitData.mWindowType == eWindowType_dialog) michael@0: widgetInitData.clipChildren = true; michael@0: #endif michael@0: michael@0: // note default chrome overrides other OS chrome settings, but michael@0: // not internal chrome michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT) michael@0: widgetInitData.mBorderStyle = eBorderStyle_default; michael@0: else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL) michael@0: widgetInitData.mBorderStyle = eBorderStyle_all; michael@0: else { michael@0: widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00 michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS) michael@0: widgetInitData.mBorderStyle = static_cast(widgetInitData.mBorderStyle | eBorderStyle_border); michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR) michael@0: widgetInitData.mBorderStyle = static_cast(widgetInitData.mBorderStyle | eBorderStyle_title); michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE) michael@0: widgetInitData.mBorderStyle = static_cast(widgetInitData.mBorderStyle | eBorderStyle_close); michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) { michael@0: widgetInitData.mBorderStyle = static_cast(widgetInitData.mBorderStyle | eBorderStyle_resizeh); michael@0: // only resizable windows get the maximize button (but not dialogs) michael@0: if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG)) michael@0: widgetInitData.mBorderStyle = static_cast(widgetInitData.mBorderStyle | eBorderStyle_maximize); michael@0: } michael@0: // all windows (except dialogs) get minimize buttons and the system menu michael@0: if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG)) michael@0: widgetInitData.mBorderStyle = static_cast(widgetInitData.mBorderStyle | eBorderStyle_minimize | eBorderStyle_menu); michael@0: // but anyone can explicitly ask for a minimize button michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) { michael@0: widgetInitData.mBorderStyle = static_cast(widgetInitData.mBorderStyle | eBorderStyle_minimize); michael@0: } michael@0: } michael@0: michael@0: if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT || michael@0: aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) { michael@0: aInitialWidth = 1; michael@0: aInitialHeight = 1; michael@0: window->SetIntrinsicallySized(true); michael@0: } michael@0: michael@0: bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN; michael@0: michael@0: nsCOMPtr reg = michael@0: mozilla::services::GetXULChromeRegistryService(); michael@0: if (reg) { michael@0: nsAutoCString package; michael@0: package.AssignLiteral("global"); michael@0: bool isRTL = false; michael@0: reg->IsLocaleRTL(package, &isRTL); michael@0: widgetInitData.mRTL = isRTL; michael@0: } michael@0: michael@0: nsresult rv = window->Initialize(parent, center ? aParent : nullptr, michael@0: aUrl, aInitialWidth, aInitialHeight, michael@0: aIsHiddenWindow, widgetInitData); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Enforce the Private Browsing autoStart pref first. michael@0: bool isPrivateBrowsingWindow = michael@0: Preferences::GetBool("browser.privatebrowsing.autostart"); michael@0: if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) { michael@0: // Caller requested a private window michael@0: isPrivateBrowsingWindow = true; michael@0: } michael@0: if (!isPrivateBrowsingWindow) { michael@0: // Ensure that we propagate any existing private browsing status michael@0: // from the parent, even if it will not actually be used michael@0: // as a parent value. michael@0: nsCOMPtr domWin = do_GetInterface(aParent); michael@0: nsCOMPtr webNav = do_GetInterface(domWin); michael@0: nsCOMPtr parentContext = do_QueryInterface(webNav); michael@0: if (parentContext) { michael@0: isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing(); michael@0: } michael@0: } michael@0: nsCOMPtr newDomWin = michael@0: do_GetInterface(NS_ISUPPORTS_CAST(nsIBaseWindow*, window)); michael@0: nsCOMPtr newWebNav = do_GetInterface(newDomWin); michael@0: nsCOMPtr thisContext = do_GetInterface(newWebNav); michael@0: if (thisContext) { michael@0: thisContext->SetPrivateBrowsing(isPrivateBrowsingWindow); michael@0: } michael@0: michael@0: window.swap(*aResult); // transfer reference michael@0: if (parent) michael@0: parent->AddChildWindow(*aResult); michael@0: michael@0: if (center) michael@0: rv = (*aResult)->Center(parent, parent ? false : true, false); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aWindow); michael@0: michael@0: *aWindow = mHiddenWindow; michael@0: NS_IF_ADDREF(*aWindow); michael@0: return *aWindow ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::GetHiddenDOMWindow(nsIDOMWindow **aWindow) michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr docShell; michael@0: NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE); michael@0: michael@0: rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr hiddenDOMWindow(do_GetInterface(docShell, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aWindow = hiddenDOMWindow; michael@0: NS_IF_ADDREF(*aWindow); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aWindow); michael@0: michael@0: EnsurePrivateHiddenWindow(); michael@0: michael@0: *aWindow = mHiddenPrivateWindow; michael@0: NS_IF_ADDREF(*aWindow); michael@0: return *aWindow ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::GetHiddenPrivateDOMWindow(nsIDOMWindow **aWindow) michael@0: { michael@0: EnsurePrivateHiddenWindow(); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr docShell; michael@0: NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE); michael@0: michael@0: rv = mHiddenPrivateWindow->GetDocShell(getter_AddRefs(docShell)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr hiddenPrivateDOMWindow(do_GetInterface(docShell, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aWindow = hiddenPrivateDOMWindow; michael@0: NS_IF_ADDREF(*aWindow); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aHasPrivateWindow); michael@0: michael@0: *aHasPrivateWindow = !!mHiddenPrivateWindow; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindow **aWindow, michael@0: JSContext **aJSContext) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: if ( aWindow && aJSContext ) { michael@0: *aWindow = nullptr; michael@0: *aJSContext = nullptr; michael@0: michael@0: if ( mHiddenWindow ) { michael@0: // Convert hidden window to nsIDOMWindow and extract its JSContext. michael@0: do { michael@0: // 1. Get doc for hidden window. michael@0: nsCOMPtr docShell; michael@0: rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell)); michael@0: if (NS_FAILED(rv)) break; michael@0: michael@0: // 2. Convert that to an nsIDOMWindow. michael@0: nsCOMPtr hiddenDOMWindow(do_GetInterface(docShell)); michael@0: if(!hiddenDOMWindow) break; michael@0: michael@0: // 3. Get script global object for the window. michael@0: nsCOMPtr sgo; michael@0: sgo = do_QueryInterface( hiddenDOMWindow ); michael@0: if (!sgo) { rv = NS_ERROR_FAILURE; break; } michael@0: michael@0: // 4. Get script context from that. michael@0: nsIScriptContext *scriptContext = sgo->GetContext(); michael@0: if (!scriptContext) { rv = NS_ERROR_FAILURE; break; } michael@0: michael@0: // 5. Get JSContext from the script context. michael@0: JSContext *jsContext = scriptContext->GetNativeContext(); michael@0: if (!jsContext) { rv = NS_ERROR_FAILURE; break; } michael@0: michael@0: // Now, give results to caller. michael@0: *aWindow = hiddenDOMWindow.get(); michael@0: NS_IF_ADDREF( *aWindow ); michael@0: *aJSContext = jsContext; michael@0: } while (0); michael@0: } else { michael@0: rv = NS_ERROR_FAILURE; michael@0: } michael@0: } else { michael@0: rv = NS_ERROR_NULL_POINTER; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW) michael@0: { michael@0: *aAPHW = mApplicationProvidedHiddenWindow; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* michael@0: * Register a new top level window (created elsewhere) michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aWindow); michael@0: michael@0: nsCOMPtr docShell; michael@0: aWindow->GetDocShell(getter_AddRefs(docShell)); michael@0: nsCOMPtr domWindow(do_GetInterface(docShell)); michael@0: NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); michael@0: domWindow->SetInitialPrincipalToSubject(); michael@0: michael@0: // tell the window mediator about the new window michael@0: nsCOMPtr mediator michael@0: ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) ); michael@0: NS_ASSERTION(mediator, "Couldn't get window mediator."); michael@0: michael@0: if (mediator) michael@0: mediator->RegisterWindow(aWindow); michael@0: michael@0: // tell the window watcher about the new window michael@0: nsCOMPtr wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) ); michael@0: NS_ASSERTION(wwatcher, "No windowwatcher?"); michael@0: if (wwatcher && domWindow) { michael@0: wwatcher->AddWindow(domWindow, 0); michael@0: } michael@0: michael@0: // an ongoing attempt to quit is stopped by a newly opened window michael@0: nsCOMPtr obssvc = michael@0: do_GetService("@mozilla.org/observer-service;1"); michael@0: NS_ASSERTION(obssvc, "Couldn't get observer service."); michael@0: michael@0: if (obssvc) michael@0: obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow) michael@0: { michael@0: if (mXPCOMShuttingDown) { michael@0: /* return an error code in order to: michael@0: - avoid doing anything with other member variables while we are in michael@0: the destructor michael@0: - notify the caller not to release the AppShellService after michael@0: unregistering the window michael@0: (we don't want to be deleted twice consecutively to michael@0: mHiddenWindow->Destroy() in our destructor) michael@0: */ michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_ENSURE_ARG_POINTER(aWindow); michael@0: michael@0: if (aWindow == mHiddenWindow) { michael@0: // CreateHiddenWindow() does not register the window, so we're done. michael@0: return NS_OK; michael@0: } michael@0: if (aWindow == mHiddenPrivateWindow) { michael@0: // CreateHiddenWindow() does not register the window, so we're done. michael@0: return NS_OK; michael@0: } michael@0: michael@0: // tell the window mediator michael@0: nsCOMPtr mediator michael@0: ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) ); michael@0: NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?"); michael@0: michael@0: if (mediator) michael@0: mediator->UnregisterWindow(aWindow); michael@0: michael@0: // tell the window watcher michael@0: nsCOMPtr wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) ); michael@0: NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?"); michael@0: if (wwatcher) { michael@0: nsCOMPtr docShell; michael@0: aWindow->GetDocShell(getter_AddRefs(docShell)); michael@0: if (docShell) { michael@0: nsCOMPtr domWindow(do_GetInterface(docShell)); michael@0: if (domWindow) michael@0: wwatcher->RemoveWindow(domWindow); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic, michael@0: const char16_t *aData) michael@0: { michael@0: if (!strcmp(aTopic, "xpcom-will-shutdown")) { michael@0: mXPCOMWillShutDown = true; michael@0: } else if (!strcmp(aTopic, "xpcom-shutdown")) { michael@0: mXPCOMShuttingDown = true; michael@0: if (mHiddenWindow) { michael@0: mHiddenWindow->Destroy(); michael@0: } michael@0: if (mHiddenPrivateWindow) { michael@0: mHiddenPrivateWindow->Destroy(); michael@0: } michael@0: } else { michael@0: NS_ERROR("Unexpected observer topic!"); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::StartEventLoopLagTracking(bool* aResult) michael@0: { michael@0: #ifdef MOZ_INSTRUMENT_EVENT_LOOP michael@0: *aResult = mozilla::InitEventTracing(true); michael@0: #endif michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAppShellService::StopEventLoopLagTracking() michael@0: { michael@0: #ifdef MOZ_INSTRUMENT_EVENT_LOOP michael@0: mozilla::ShutdownEventTracing(); michael@0: #endif michael@0: return NS_OK; michael@0: }