Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / xpfe / appshell / nsAppShellService.cpp
blob5da29064e39cb3abefb9ef4302d0379de7660e83
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsIAppShellService.h"
8 #include "nsIComponentManager.h"
9 #include "nsIURL.h"
10 #include "nsNetUtil.h"
11 #include "nsIServiceManager.h"
12 #include "nsIObserverService.h"
13 #include "nsIObserver.h"
14 #include "nsIXPConnect.h"
15 #include "nsIXULRuntime.h"
17 #include "nsIWindowMediator.h"
18 #include "nsIWindowWatcher.h"
19 #include "nsPIWindowWatcher.h"
20 #include "nsIDOMWindow.h"
21 #include "nsPIDOMWindow.h"
22 #include "nsWebShellWindow.h"
24 #include "prprf.h"
26 #include "nsWidgetInitData.h"
27 #include "nsWidgetsCID.h"
28 #include "nsIWidget.h"
29 #include "nsIRequestObserver.h"
31 /* For implementing GetHiddenWindowAndJSContext */
32 #include "nsIScriptGlobalObject.h"
33 #include "nsIScriptContext.h"
35 #include "nsAppShellService.h"
36 #include "nsISupportsPrimitives.h"
37 #include "nsIChromeRegistry.h"
38 #include "nsILoadContext.h"
39 #include "nsIWebNavigation.h"
41 #include "mozilla/Attributes.h"
42 #include "mozilla/Preferences.h"
43 #include "mozilla/StartupTimeline.h"
45 #include "nsEmbedCID.h"
46 #include "nsIWebBrowser.h"
47 #include "nsIDocShell.h"
49 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
50 #include "EventTracer.h"
51 #endif
53 using namespace mozilla;
55 // Default URL for the hidden window, can be overridden by a pref on Mac
56 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
58 class nsIAppShell;
60 nsAppShellService::nsAppShellService() :
61 mXPCOMWillShutDown(false),
62 mXPCOMShuttingDown(false),
63 mModalWindowCount(0),
64 mApplicationProvidedHiddenWindow(false)
66 nsCOMPtr<nsIObserverService> obs
67 (do_GetService("@mozilla.org/observer-service;1"));
69 if (obs) {
70 obs->AddObserver(this, "xpcom-will-shutdown", false);
71 obs->AddObserver(this, "xpcom-shutdown", false);
75 nsAppShellService::~nsAppShellService()
81 * Implement the nsISupports methods...
83 NS_IMPL_ISUPPORTS(nsAppShellService,
84 nsIAppShellService,
85 nsIObserver)
87 NS_IMETHODIMP
88 nsAppShellService::CreateHiddenWindow()
90 return CreateHiddenWindowHelper(false);
93 void
94 nsAppShellService::EnsurePrivateHiddenWindow()
96 if (!mHiddenPrivateWindow) {
97 CreateHiddenWindowHelper(true);
101 nsresult
102 nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate)
104 nsresult rv;
105 int32_t initialHeight = 100, initialWidth = 100;
107 #ifdef XP_MACOSX
108 uint32_t chromeMask = 0;
109 nsAdoptingCString prefVal =
110 Preferences::GetCString("browser.hiddenWindowChromeURL");
111 const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
112 if (aIsPrivate) {
113 hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL;
114 } else {
115 mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
117 #else
118 static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
119 uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL;
120 #endif
122 nsCOMPtr<nsIURI> url;
123 rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
124 NS_ENSURE_SUCCESS(rv, rv);
126 nsRefPtr<nsWebShellWindow> newWindow;
127 if (!aIsPrivate) {
128 rv = JustCreateTopWindow(nullptr, url,
129 chromeMask, initialWidth, initialHeight,
130 true, nullptr, getter_AddRefs(newWindow));
131 NS_ENSURE_SUCCESS(rv, rv);
133 mHiddenWindow.swap(newWindow);
134 } else {
135 // Create the hidden private window
136 chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
138 rv = JustCreateTopWindow(nullptr, url,
139 chromeMask, initialWidth, initialHeight,
140 true, nullptr, getter_AddRefs(newWindow));
141 NS_ENSURE_SUCCESS(rv, rv);
143 nsCOMPtr<nsIDocShell> docShell;
144 newWindow->GetDocShell(getter_AddRefs(docShell));
145 if (docShell) {
146 docShell->SetAffectPrivateSessionLifetime(false);
149 mHiddenPrivateWindow.swap(newWindow);
152 // RegisterTopLevelWindow(newWindow); -- Mac only
154 return NS_OK;
157 NS_IMETHODIMP
158 nsAppShellService::DestroyHiddenWindow()
160 if (mHiddenWindow) {
161 mHiddenWindow->Destroy();
163 mHiddenWindow = nullptr;
166 if (mHiddenPrivateWindow) {
167 mHiddenPrivateWindow->Destroy();
169 mHiddenPrivateWindow = nullptr;
172 return NS_OK;
176 * Create a new top level window and display the given URL within it...
178 NS_IMETHODIMP
179 nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent,
180 nsIURI *aUrl,
181 uint32_t aChromeMask,
182 int32_t aInitialWidth,
183 int32_t aInitialHeight,
184 nsITabParent *aOpeningTab,
185 nsIXULWindow **aResult)
188 nsresult rv;
190 StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
192 nsWebShellWindow *newWindow = nullptr;
193 rv = JustCreateTopWindow(aParent, aUrl,
194 aChromeMask, aInitialWidth, aInitialHeight,
195 false, aOpeningTab, &newWindow); // addrefs
197 *aResult = newWindow; // transfer ref
199 if (NS_SUCCEEDED(rv)) {
200 // the addref resulting from this is the owning addref for this window
201 RegisterTopLevelWindow(*aResult);
202 nsCOMPtr<nsIXULWindow> parent;
203 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
204 parent = aParent;
205 (*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
208 return rv;
212 * This class provides a stub implementation of nsIWebBrowserChrome2, as needed
213 * by nsAppShellService::CreateWindowlessBrowser
215 class WebBrowserChrome2Stub : public nsIWebBrowserChrome2,
216 public nsIInterfaceRequestor,
217 public nsSupportsWeakReference {
218 protected:
219 virtual ~WebBrowserChrome2Stub() {}
220 public:
221 NS_DECL_ISUPPORTS
222 NS_DECL_NSIWEBBROWSERCHROME
223 NS_DECL_NSIWEBBROWSERCHROME2
224 NS_DECL_NSIINTERFACEREQUESTOR
227 NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
228 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
229 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
230 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
231 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
232 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
233 NS_INTERFACE_MAP_END
235 NS_IMPL_ADDREF(WebBrowserChrome2Stub)
236 NS_IMPL_RELEASE(WebBrowserChrome2Stub)
238 NS_IMETHODIMP
239 WebBrowserChrome2Stub::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
241 return NS_OK;
244 NS_IMETHODIMP
245 WebBrowserChrome2Stub::GetWebBrowser(nsIWebBrowser** aWebBrowser)
247 NS_NOTREACHED("WebBrowserChrome2Stub::GetWebBrowser is not supported");
248 return NS_ERROR_NOT_IMPLEMENTED;
251 NS_IMETHODIMP
252 WebBrowserChrome2Stub::SetWebBrowser(nsIWebBrowser* aWebBrowser)
254 NS_NOTREACHED("WebBrowserChrome2Stub::SetWebBrowser is not supported");
255 return NS_ERROR_NOT_IMPLEMENTED;
258 NS_IMETHODIMP
259 WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags)
261 *aChromeFlags = 0;
262 return NS_OK;
265 NS_IMETHODIMP
266 WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags)
268 NS_NOTREACHED("WebBrowserChrome2Stub::SetChromeFlags is not supported");
269 return NS_ERROR_NOT_IMPLEMENTED;
272 NS_IMETHODIMP
273 WebBrowserChrome2Stub::DestroyBrowserWindow()
275 NS_NOTREACHED("WebBrowserChrome2Stub::DestroyBrowserWindow is not supported");
276 return NS_ERROR_NOT_IMPLEMENTED;
279 NS_IMETHODIMP
280 WebBrowserChrome2Stub::SizeBrowserTo(int32_t aCX, int32_t aCY)
282 NS_NOTREACHED("WebBrowserChrome2Stub::SizeBrowserTo is not supported");
283 return NS_ERROR_NOT_IMPLEMENTED;
286 NS_IMETHODIMP
287 WebBrowserChrome2Stub::ShowAsModal()
289 NS_NOTREACHED("WebBrowserChrome2Stub::ShowAsModal is not supported");
290 return NS_ERROR_NOT_IMPLEMENTED;
293 NS_IMETHODIMP
294 WebBrowserChrome2Stub::IsWindowModal(bool* aResult)
296 *aResult = false;
297 return NS_OK;
300 NS_IMETHODIMP
301 WebBrowserChrome2Stub::ExitModalEventLoop(nsresult aStatus)
303 NS_NOTREACHED("WebBrowserChrome2Stub::ExitModalEventLoop is not supported");
304 return NS_ERROR_NOT_IMPLEMENTED;
307 NS_IMETHODIMP
308 WebBrowserChrome2Stub::SetStatusWithContext(uint32_t aStatusType,
309 const nsAString& aStatusText,
310 nsISupports* aStatusContext)
312 return NS_OK;
315 NS_IMETHODIMP
316 WebBrowserChrome2Stub::GetInterface(const nsIID & aIID, void **aSink)
318 return QueryInterface(aIID, aSink);
321 // This is the "stub" we return from CreateWindowlessBrowser - it exists
322 // purely to keep a strong reference to the browser and the container to
323 // prevent the container being collected while the stub remains alive.
324 class WindowlessBrowserStub MOZ_FINAL : public nsIWebNavigation,
325 public nsIInterfaceRequestor {
326 public:
327 WindowlessBrowserStub(nsIWebBrowser *aBrowser, nsISupports *aContainer) {
328 mBrowser = aBrowser;
329 mWebNavigation = do_QueryInterface(aBrowser);
330 mInterfaceRequestor = do_QueryInterface(aBrowser);
331 mContainer = aContainer;
333 NS_DECL_ISUPPORTS
334 NS_FORWARD_NSIWEBNAVIGATION(mWebNavigation->)
335 NS_FORWARD_NSIINTERFACEREQUESTOR(mInterfaceRequestor->)
336 private:
337 ~WindowlessBrowserStub() {}
338 nsCOMPtr<nsIWebBrowser> mBrowser;
339 nsCOMPtr<nsIWebNavigation> mWebNavigation;
340 nsCOMPtr<nsIInterfaceRequestor> mInterfaceRequestor;
341 // we don't use the container but just hold a reference to it.
342 nsCOMPtr<nsISupports> mContainer;
345 NS_INTERFACE_MAP_BEGIN(WindowlessBrowserStub)
346 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebNavigation)
347 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
348 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
349 NS_INTERFACE_MAP_END
351 NS_IMPL_ADDREF(WindowlessBrowserStub)
352 NS_IMPL_RELEASE(WindowlessBrowserStub)
355 NS_IMETHODIMP
356 nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWebNavigation **aResult)
358 /* First, we create an instance of nsWebBrowser. Instances of this class have
359 * an associated doc shell, which is what we're interested in.
361 nsCOMPtr<nsIWebBrowser> browser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
362 if (!browser) {
363 NS_ERROR("Couldn't create instance of nsWebBrowser!");
364 return NS_ERROR_FAILURE;
367 /* Next, we set the container window for our instance of nsWebBrowser. Since
368 * we don't actually have a window, we instead set the container window to be
369 * an instance of WebBrowserChrome2Stub, which provides a stub implementation
370 * of nsIWebBrowserChrome2.
372 nsRefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub();
373 if (!stub) {
374 NS_ERROR("Couldn't create instance of WebBrowserChrome2Stub!");
375 return NS_ERROR_FAILURE;
377 browser->SetContainerWindow(stub);
379 nsCOMPtr<nsIWebNavigation> navigation = do_QueryInterface(browser);
381 nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(navigation);
382 item->SetItemType(aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
383 : nsIDocShellTreeItem::typeContentWrapper);
385 /* A windowless web browser doesn't have an associated OS level window. To
386 * accomplish this, we initialize the window associated with our instance of
387 * nsWebBrowser with an instance of PuppetWidget, which provides a stub
388 * implementation of nsIWidget.
390 nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(nullptr);
391 if (!widget) {
392 NS_ERROR("Couldn't create instance of PuppetWidget");
393 return NS_ERROR_FAILURE;
395 widget->Create(nullptr, 0, nsIntRect(nsIntPoint(0, 0), nsIntSize(0, 0)),
396 nullptr, nullptr);
397 nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(navigation);
398 window->InitWindow(0, widget, 0, 0, 0, 0);
399 window->Create();
401 nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub);
402 nsRefPtr<nsIWebNavigation> result = new WindowlessBrowserStub(browser, isstub);
403 nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
404 docshell->SetInvisible(true);
406 result.forget(aResult);
407 return NS_OK;
410 uint32_t
411 nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
412 uint32_t aChromeMask)
414 uint32_t zLevel;
416 zLevel = nsIXULWindow::normalZ;
417 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
418 zLevel = nsIXULWindow::raisedZ;
419 else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
420 zLevel = nsIXULWindow::loweredZ;
422 #ifdef XP_MACOSX
423 /* Platforms on which modal windows are always application-modal, not
424 window-modal (that's just the Mac, right?) want modal windows to
425 be stacked on top of everyone else.
427 On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
429 uint32_t modalDepMask = nsIWebBrowserChrome::CHROME_MODAL |
430 nsIWebBrowserChrome::CHROME_DEPENDENT;
431 if (aParent && (aChromeMask & modalDepMask)) {
432 aParent->GetZLevel(&zLevel);
434 #else
435 /* Platforms with native support for dependent windows (that's everyone
436 but pre-Mac OS X, right?) know how to stack dependent windows. On these
437 platforms, give the dependent window the same level as its parent,
438 so we won't try to override the normal platform behaviour. */
439 if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent)
440 aParent->GetZLevel(&zLevel);
441 #endif
443 return zLevel;
446 #ifdef XP_WIN
448 * Checks to see if any existing window is currently in fullscreen mode.
450 static bool
451 CheckForFullscreenWindow()
453 nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
454 if (!wm)
455 return false;
457 nsCOMPtr<nsISimpleEnumerator> windowList;
458 wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList));
459 if (!windowList)
460 return false;
462 for (;;) {
463 bool more = false;
464 windowList->HasMoreElements(&more);
465 if (!more)
466 return false;
468 nsCOMPtr<nsISupports> supportsWindow;
469 windowList->GetNext(getter_AddRefs(supportsWindow));
470 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
471 if (baseWin) {
472 nsCOMPtr<nsIWidget> widget;
473 baseWin->GetMainWidget(getter_AddRefs(widget));
474 if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) {
475 return true;
479 return false;
481 #endif
484 * Just do the window-making part of CreateTopLevelWindow
486 nsresult
487 nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent,
488 nsIURI *aUrl,
489 uint32_t aChromeMask,
490 int32_t aInitialWidth,
491 int32_t aInitialHeight,
492 bool aIsHiddenWindow,
493 nsITabParent *aOpeningTab,
494 nsWebShellWindow **aResult)
496 *aResult = nullptr;
497 NS_ENSURE_STATE(!mXPCOMWillShutDown);
499 nsCOMPtr<nsIXULWindow> parent;
500 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
501 parent = aParent;
503 nsRefPtr<nsWebShellWindow> window = new nsWebShellWindow(aChromeMask);
504 NS_ENSURE_TRUE(window, NS_ERROR_OUT_OF_MEMORY);
506 #ifdef XP_WIN
507 // If the parent is currently fullscreen, tell the child to ignore persisted
508 // full screen states. This way new browser windows open on top of fullscreen
509 // windows normally.
510 if (window && CheckForFullscreenWindow())
511 window->IgnoreXULSizeMode(true);
512 #endif
514 nsWidgetInitData widgetInitData;
516 if (aIsHiddenWindow)
517 widgetInitData.mWindowType = eWindowType_invisible;
518 else
519 widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ?
520 eWindowType_dialog : eWindowType_toplevel;
522 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
523 widgetInitData.mWindowType = eWindowType_popup;
525 if (aChromeMask & nsIWebBrowserChrome::CHROME_MAC_SUPPRESS_ANIMATION)
526 widgetInitData.mIsAnimationSuppressed = true;
528 if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW)
529 widgetInitData.mRequireOffMainThreadCompositing = true;
531 #ifdef XP_MACOSX
532 // Mac OS X sheet support
533 // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
534 // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
535 // windows opened from nsPromptService::DoDialog() still are sheets. This
536 // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
537 // nsCocoaWindow::SetModal()).
538 uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
539 nsIWebBrowserChrome::CHROME_MODAL |
540 nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
541 if (parent &&
542 (parent != mHiddenWindow && parent != mHiddenPrivateWindow) &&
543 ((aChromeMask & sheetMask) == sheetMask)) {
544 widgetInitData.mWindowType = eWindowType_sheet;
546 #endif
548 #if defined(XP_WIN)
549 if (widgetInitData.mWindowType == eWindowType_toplevel ||
550 widgetInitData.mWindowType == eWindowType_dialog)
551 widgetInitData.clipChildren = true;
552 #endif
554 // note default chrome overrides other OS chrome settings, but
555 // not internal chrome
556 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT)
557 widgetInitData.mBorderStyle = eBorderStyle_default;
558 else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
559 widgetInitData.mBorderStyle = eBorderStyle_all;
560 else {
561 widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00
562 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS)
563 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_border);
564 if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR)
565 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_title);
566 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
567 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_close);
568 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
569 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_resizeh);
570 // only resizable windows get the maximize button (but not dialogs)
571 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
572 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_maximize);
574 // all windows (except dialogs) get minimize buttons and the system menu
575 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
576 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize | eBorderStyle_menu);
577 // but anyone can explicitly ask for a minimize button
578 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) {
579 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize);
583 if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
584 aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
585 aInitialWidth = 1;
586 aInitialHeight = 1;
587 window->SetIntrinsicallySized(true);
590 bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
592 nsCOMPtr<nsIXULChromeRegistry> reg =
593 mozilla::services::GetXULChromeRegistryService();
594 if (reg) {
595 nsAutoCString package;
596 package.AssignLiteral("global");
597 bool isRTL = false;
598 reg->IsLocaleRTL(package, &isRTL);
599 widgetInitData.mRTL = isRTL;
602 nsresult rv = window->Initialize(parent, center ? aParent : nullptr,
603 aUrl, aInitialWidth, aInitialHeight,
604 aIsHiddenWindow, aOpeningTab, widgetInitData);
606 NS_ENSURE_SUCCESS(rv, rv);
608 // Enforce the Private Browsing autoStart pref first.
609 bool isPrivateBrowsingWindow =
610 Preferences::GetBool("browser.privatebrowsing.autostart");
611 bool isUsingRemoteTabs = mozilla::BrowserTabsRemoteAutostart();
613 if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
614 // Caller requested a private window
615 isPrivateBrowsingWindow = true;
617 if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
618 isUsingRemoteTabs = true;
621 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aParent);
622 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(domWin);
623 nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(webNav);
625 if (!isPrivateBrowsingWindow && parentContext) {
626 // Ensure that we propagate any existing private browsing status
627 // from the parent, even if it will not actually be used
628 // as a parent value.
629 isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
632 if (parentContext) {
633 isUsingRemoteTabs = parentContext->UseRemoteTabs();
636 nsCOMPtr<nsIDOMWindow> newDomWin =
637 do_GetInterface(NS_ISUPPORTS_CAST(nsIBaseWindow*, window));
638 nsCOMPtr<nsIWebNavigation> newWebNav = do_GetInterface(newDomWin);
639 nsCOMPtr<nsILoadContext> thisContext = do_GetInterface(newWebNav);
640 if (thisContext) {
641 thisContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
642 thisContext->SetRemoteTabs(isUsingRemoteTabs);
645 window.swap(*aResult); // transfer reference
646 if (parent)
647 parent->AddChildWindow(*aResult);
649 if (center)
650 rv = (*aResult)->Center(parent, parent ? false : true, false);
652 return rv;
655 NS_IMETHODIMP
656 nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow)
658 NS_ENSURE_ARG_POINTER(aWindow);
660 *aWindow = mHiddenWindow;
661 NS_IF_ADDREF(*aWindow);
662 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
665 NS_IMETHODIMP
666 nsAppShellService::GetHiddenDOMWindow(nsIDOMWindow **aWindow)
668 nsresult rv;
669 nsCOMPtr<nsIDocShell> docShell;
670 NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
672 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
673 NS_ENSURE_SUCCESS(rv, rv);
674 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
676 nsCOMPtr<nsIDOMWindow> hiddenDOMWindow(docShell->GetWindow());
677 hiddenDOMWindow.forget(aWindow);
678 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
681 NS_IMETHODIMP
682 nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow)
684 NS_ENSURE_ARG_POINTER(aWindow);
686 EnsurePrivateHiddenWindow();
688 *aWindow = mHiddenPrivateWindow;
689 NS_IF_ADDREF(*aWindow);
690 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
693 NS_IMETHODIMP
694 nsAppShellService::GetHiddenPrivateDOMWindow(nsIDOMWindow **aWindow)
696 EnsurePrivateHiddenWindow();
698 nsresult rv;
699 nsCOMPtr<nsIDocShell> docShell;
700 NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE);
702 rv = mHiddenPrivateWindow->GetDocShell(getter_AddRefs(docShell));
703 NS_ENSURE_SUCCESS(rv, rv);
704 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
706 nsCOMPtr<nsIDOMWindow> hiddenPrivateDOMWindow(docShell->GetWindow());
707 hiddenPrivateDOMWindow.forget(aWindow);
708 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
711 NS_IMETHODIMP
712 nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow)
714 NS_ENSURE_ARG_POINTER(aHasPrivateWindow);
716 *aHasPrivateWindow = !!mHiddenPrivateWindow;
717 return NS_OK;
720 NS_IMETHODIMP
721 nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindow **aWindow,
722 JSContext **aJSContext)
724 nsresult rv = NS_OK;
725 if ( aWindow && aJSContext ) {
726 *aWindow = nullptr;
727 *aJSContext = nullptr;
729 if ( mHiddenWindow ) {
730 // Convert hidden window to nsIDOMWindow and extract its JSContext.
731 do {
732 // 1. Get doc for hidden window.
733 nsCOMPtr<nsIDocShell> docShell;
734 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
735 if (NS_FAILED(rv)) break;
736 if (!docShell) {
737 break;
740 // 2. Convert that to an nsIDOMWindow.
741 nsCOMPtr<nsIDOMWindow> hiddenDOMWindow(docShell->GetWindow());
742 if(!hiddenDOMWindow) break;
744 // 3. Get script global object for the window.
745 nsCOMPtr<nsIScriptGlobalObject> sgo = docShell->GetScriptGlobalObject();
746 if (!sgo) { rv = NS_ERROR_FAILURE; break; }
748 // 4. Get script context from that.
749 nsIScriptContext *scriptContext = sgo->GetContext();
750 if (!scriptContext) { rv = NS_ERROR_FAILURE; break; }
752 // 5. Get JSContext from the script context.
753 JSContext *jsContext = scriptContext->GetNativeContext();
754 if (!jsContext) { rv = NS_ERROR_FAILURE; break; }
756 // Now, give results to caller.
757 *aWindow = hiddenDOMWindow.get();
758 NS_IF_ADDREF( *aWindow );
759 *aJSContext = jsContext;
760 } while (0);
761 } else {
762 rv = NS_ERROR_FAILURE;
764 } else {
765 rv = NS_ERROR_NULL_POINTER;
767 return rv;
770 NS_IMETHODIMP
771 nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW)
773 *aAPHW = mApplicationProvidedHiddenWindow;
774 return NS_OK;
778 * Register a new top level window (created elsewhere)
780 NS_IMETHODIMP
781 nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
783 NS_ENSURE_ARG_POINTER(aWindow);
785 nsCOMPtr<nsIDocShell> docShell;
786 aWindow->GetDocShell(getter_AddRefs(docShell));
787 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
789 nsCOMPtr<nsPIDOMWindow> domWindow(docShell->GetWindow());
790 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
791 domWindow->SetInitialPrincipalToSubject();
793 // tell the window mediator about the new window
794 nsCOMPtr<nsIWindowMediator> mediator
795 ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
796 NS_ASSERTION(mediator, "Couldn't get window mediator.");
798 if (mediator)
799 mediator->RegisterWindow(aWindow);
801 // tell the window watcher about the new window
802 nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
803 NS_ASSERTION(wwatcher, "No windowwatcher?");
804 if (wwatcher && domWindow) {
805 wwatcher->AddWindow(domWindow, 0);
808 // an ongoing attempt to quit is stopped by a newly opened window
809 nsCOMPtr<nsIObserverService> obssvc =
810 do_GetService("@mozilla.org/observer-service;1");
811 NS_ASSERTION(obssvc, "Couldn't get observer service.");
813 if (obssvc)
814 obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
816 return NS_OK;
820 NS_IMETHODIMP
821 nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
823 if (mXPCOMShuttingDown) {
824 /* return an error code in order to:
825 - avoid doing anything with other member variables while we are in
826 the destructor
827 - notify the caller not to release the AppShellService after
828 unregistering the window
829 (we don't want to be deleted twice consecutively to
830 mHiddenWindow->Destroy() in our destructor)
832 return NS_ERROR_FAILURE;
835 NS_ENSURE_ARG_POINTER(aWindow);
837 if (aWindow == mHiddenWindow) {
838 // CreateHiddenWindow() does not register the window, so we're done.
839 return NS_OK;
841 if (aWindow == mHiddenPrivateWindow) {
842 // CreateHiddenWindow() does not register the window, so we're done.
843 return NS_OK;
846 // tell the window mediator
847 nsCOMPtr<nsIWindowMediator> mediator
848 ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
849 NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
851 if (mediator)
852 mediator->UnregisterWindow(aWindow);
854 // tell the window watcher
855 nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
856 NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
857 if (wwatcher) {
858 nsCOMPtr<nsIDocShell> docShell;
859 aWindow->GetDocShell(getter_AddRefs(docShell));
860 if (docShell) {
861 nsCOMPtr<nsIDOMWindow> domWindow(docShell->GetWindow());
862 if (domWindow)
863 wwatcher->RemoveWindow(domWindow);
867 return NS_OK;
871 NS_IMETHODIMP
872 nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic,
873 const char16_t *aData)
875 if (!strcmp(aTopic, "xpcom-will-shutdown")) {
876 mXPCOMWillShutDown = true;
877 } else if (!strcmp(aTopic, "xpcom-shutdown")) {
878 mXPCOMShuttingDown = true;
879 if (mHiddenWindow) {
880 mHiddenWindow->Destroy();
882 if (mHiddenPrivateWindow) {
883 mHiddenPrivateWindow->Destroy();
885 } else {
886 NS_ERROR("Unexpected observer topic!");
889 return NS_OK;
892 NS_IMETHODIMP
893 nsAppShellService::StartEventLoopLagTracking(bool* aResult)
895 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
896 *aResult = mozilla::InitEventTracing(true);
897 #endif
898 return NS_OK;
901 NS_IMETHODIMP
902 nsAppShellService::StopEventLoopLagTracking()
904 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
905 mozilla::ShutdownEventTracing();
906 #endif
907 return NS_OK;