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/. */
6 #include "nsIAppShellService.h"
8 #include "nsIObserverService.h"
9 #include "nsIObserver.h"
10 #include "nsIXULRuntime.h"
12 #include "nsIWindowMediator.h"
13 #include "nsPIWindowWatcher.h"
14 #include "nsPIDOMWindow.h"
15 #include "AppWindow.h"
17 #include "mozilla/widget/InitData.h"
18 #include "nsWidgetsCID.h"
19 #include "nsIWidget.h"
21 #include "nsAppDirectoryServiceDefs.h"
22 #include "nsAppShellService.h"
23 #include "nsContentUtils.h"
24 #include "nsDirectoryServiceUtils.h"
25 #include "nsThreadUtils.h"
26 #include "nsILoadContext.h"
27 #include "nsIWebNavigation.h"
28 #include "nsIWindowlessBrowser.h"
30 #include "mozilla/Attributes.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/Services.h"
33 #include "mozilla/StartupTimeline.h"
34 #include "mozilla/StaticPrefs_browser.h"
35 #include "mozilla/Try.h"
36 #include "mozilla/intl/LocaleService.h"
37 #include "mozilla/dom/BrowsingContext.h"
38 #include "mozilla/dom/Document.h"
40 #include "nsEmbedCID.h"
41 #include "nsIWebBrowser.h"
42 #include "nsIDocShell.h"
43 #include "gfxPlatform.h"
45 #include "nsWebBrowser.h"
46 #include "nsDocShell.h"
47 #include "nsDocShellLoadState.h"
49 using namespace mozilla
;
50 using mozilla::dom::BrowsingContext
;
51 using mozilla::intl::LocaleService
;
55 nsAppShellService::nsAppShellService()
56 : mXPCOMWillShutDown(false),
57 mXPCOMShuttingDown(false),
60 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
63 obs
->AddObserver(this, "xpcom-will-shutdown", false);
64 obs
->AddObserver(this, "xpcom-shutdown", false);
68 nsAppShellService::~nsAppShellService() {}
71 * Implement the nsISupports methods...
73 NS_IMPL_ISUPPORTS(nsAppShellService
, nsIAppShellService
, nsIObserver
)
76 nsAppShellService::SetScreenId(uint32_t aScreenId
) {
77 mScreenId
= aScreenId
;
82 nsAppShellService::CreateHiddenWindow() {
83 #if defined(XP_MACOSX)
84 if (!XRE_IsParentProcess()) {
85 return NS_ERROR_NOT_IMPLEMENTED
;
88 if (mXPCOMShuttingDown
) {
89 return NS_ERROR_FAILURE
;
96 nsCOMPtr
<nsIFile
> profileDir
;
97 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
98 getter_AddRefs(profileDir
));
100 // This is too early on startup to create the hidden window
101 return NS_ERROR_FAILURE
;
105 int32_t initialHeight
= 100, initialWidth
= 100;
107 uint32_t chromeMask
= 0;
108 nsAutoCString prefVal
;
109 rv
= Preferences::GetCString("browser.hiddenWindowChromeURL", prefVal
);
113 const char* hiddenWindowURL
= prefVal
.get();
115 nsCOMPtr
<nsIURI
> url
;
116 rv
= NS_NewURI(getter_AddRefs(url
), hiddenWindowURL
);
117 NS_ENSURE_SUCCESS(rv
, rv
);
119 RefPtr
<AppWindow
> newWindow
;
120 rv
= JustCreateTopWindow(nullptr, url
, chromeMask
, initialWidth
,
121 initialHeight
, true, getter_AddRefs(newWindow
));
122 NS_ENSURE_SUCCESS(rv
, rv
);
124 nsCOMPtr
<nsIDocShell
> docShell
;
125 newWindow
->GetDocShell(getter_AddRefs(docShell
));
127 Unused
<< docShell
->GetBrowsingContext()->SetExplicitActive(
128 dom::ExplicitActiveStatus::Inactive
);
131 mHiddenWindow
.swap(newWindow
);
138 nsAppShellService::DestroyHiddenWindow() {
140 mHiddenWindow
->Destroy();
142 mHiddenWindow
= nullptr;
149 * Create a new top level window and display the given URL within it...
152 nsAppShellService::CreateTopLevelWindow(nsIAppWindow
* aParent
, nsIURI
* aUrl
,
153 uint32_t aChromeMask
,
154 int32_t aInitialWidth
,
155 int32_t aInitialHeight
,
156 nsIAppWindow
** aResult
) {
159 StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW
);
161 RefPtr
<AppWindow
> newWindow
;
162 rv
= JustCreateTopWindow(aParent
, aUrl
, aChromeMask
, aInitialWidth
,
163 aInitialHeight
, false, getter_AddRefs(newWindow
));
164 newWindow
.forget(aResult
);
166 if (NS_SUCCEEDED(rv
)) {
167 // the addref resulting from this is the owning addref for this window
168 RegisterTopLevelWindow(*aResult
);
175 * This class provides a stub implementation of nsIWebBrowserChrome, as needed
176 * by nsAppShellService::CreateWindowlessBrowser
178 class WebBrowserChrome2Stub final
: public nsIWebBrowserChrome
,
179 public nsIInterfaceRequestor
,
180 public nsSupportsWeakReference
{
182 nsCOMPtr
<nsIWebBrowser
> mBrowser
;
183 virtual ~WebBrowserChrome2Stub() = default;
186 void SetBrowser(nsIWebBrowser
* aBrowser
) { mBrowser
= aBrowser
; }
189 NS_DECL_NSIWEBBROWSERCHROME
190 NS_DECL_NSIINTERFACEREQUESTOR
193 NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub
)
194 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIWebBrowserChrome
)
195 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome
)
196 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
197 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
200 NS_IMPL_ADDREF(WebBrowserChrome2Stub
)
201 NS_IMPL_RELEASE(WebBrowserChrome2Stub
)
204 WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags
) {
210 WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags
) {
211 MOZ_ASSERT_UNREACHABLE(
212 "WebBrowserChrome2Stub::SetChromeFlags is "
214 return NS_ERROR_NOT_IMPLEMENTED
;
218 WebBrowserChrome2Stub::ShowAsModal() {
219 MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::ShowAsModal is not supported");
220 return NS_ERROR_NOT_IMPLEMENTED
;
224 WebBrowserChrome2Stub::IsWindowModal(bool* aResult
) {
230 WebBrowserChrome2Stub::SetLinkStatus(const nsAString
& aStatusText
) {
235 WebBrowserChrome2Stub::GetInterface(const nsIID
& aIID
, void** aSink
) {
236 return QueryInterface(aIID
, aSink
);
240 WebBrowserChrome2Stub::GetDimensions(DimensionKind aDimensionKind
, int32_t* aX
,
241 int32_t* aY
, int32_t* aCX
, int32_t* aCY
) {
258 WebBrowserChrome2Stub::SetDimensions(DimensionRequest
&& aRequest
) {
259 nsCOMPtr
<nsIBaseWindow
> window(do_QueryInterface(mBrowser
));
260 NS_ENSURE_STATE(window
);
261 // Inner and outer dimensions are equal.
262 aRequest
.mDimensionKind
= DimensionKind::Outer
;
263 MOZ_TRY(aRequest
.SupplementFrom(window
));
264 return aRequest
.ApplyOuterTo(window
);
268 WebBrowserChrome2Stub::Blur() { return NS_ERROR_NOT_IMPLEMENTED
; }
270 class BrowserDestroyer final
: public Runnable
{
272 BrowserDestroyer(nsIWebBrowser
* aBrowser
, nsISupports
* aContainer
)
273 : mozilla::Runnable("BrowserDestroyer"),
275 mContainer(aContainer
) {}
277 static nsresult
Destroy(nsIWebBrowser
* aBrowser
) {
278 nsCOMPtr
<nsIBaseWindow
> window(do_QueryInterface(aBrowser
));
279 return window
->Destroy();
284 // Explicitly destroy the browser, in case this isn't the last reference.
285 return Destroy(mBrowser
);
289 virtual ~BrowserDestroyer() {}
292 nsCOMPtr
<nsIWebBrowser
> mBrowser
;
293 nsCOMPtr
<nsISupports
> mContainer
;
296 // This is the "stub" we return from CreateWindowlessBrowser - it exists
297 // to manage the lifetimes of the nsIWebBrowser and container window.
298 // In particular, it keeps a strong reference to both, to prevent them from
299 // being collected while this object remains alive, and ensures that they
300 // aren't destroyed when it's not safe to run scripts.
301 class WindowlessBrowser final
: public nsIWindowlessBrowser
,
302 public nsIInterfaceRequestor
{
304 WindowlessBrowser(nsIWebBrowser
* aBrowser
, nsISupports
* aContainer
)
305 : mBrowser(aBrowser
), mContainer(aContainer
), mClosed(false) {
306 mWebNavigation
= do_QueryInterface(aBrowser
);
307 mInterfaceRequestor
= do_QueryInterface(aBrowser
);
310 NS_DECL_NSIWINDOWLESSBROWSER
311 NS_FORWARD_SAFE_NSIWEBNAVIGATION(RefPtr
{mWebNavigation
.get()})
312 NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor
)
315 ~WindowlessBrowser() {
320 NS_WARNING("Windowless browser was not closed prior to destruction");
322 // The docshell destructor needs to dispatch events, and can only run
323 // when it's safe to run scripts. If this was triggered by GC, it may
324 // not always be safe to run scripts, in which cases we need to delay
325 // destruction until it is.
326 auto runnable
= MakeRefPtr
<BrowserDestroyer
>(mBrowser
, mContainer
);
327 nsContentUtils::AddScriptRunner(runnable
.forget());
330 nsCOMPtr
<nsIWebBrowser
> mBrowser
;
331 nsCOMPtr
<nsIWebNavigation
> mWebNavigation
;
332 nsCOMPtr
<nsIInterfaceRequestor
> mInterfaceRequestor
;
333 // we don't use the container but just hold a reference to it.
334 nsCOMPtr
<nsISupports
> mContainer
;
339 NS_IMPL_ISUPPORTS(WindowlessBrowser
, nsIWindowlessBrowser
, nsIWebNavigation
,
340 nsIInterfaceRequestor
)
343 WindowlessBrowser::Close() {
344 NS_ENSURE_TRUE(!mClosed
, NS_ERROR_UNEXPECTED
);
345 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
346 "WindowlessBrowser::Close called when not safe to run scripts");
350 mWebNavigation
= nullptr;
351 mInterfaceRequestor
= nullptr;
352 return BrowserDestroyer::Destroy(mBrowser
);
356 WindowlessBrowser::GetBrowsingContext(BrowsingContext
** aBrowsingContext
) {
357 nsCOMPtr
<nsIDocShellTreeItem
> docShellTreeItem
= do_QueryInterface(mBrowser
);
358 if (!docShellTreeItem
) {
359 return NS_ERROR_NOT_INITIALIZED
;
361 return docShellTreeItem
->GetBrowsingContextXPCOM(aBrowsingContext
);
365 WindowlessBrowser::GetDocShell(nsIDocShell
** aDocShell
) {
366 nsCOMPtr
<nsIDocShell
> docShell
= do_GetInterface(mInterfaceRequestor
);
368 return NS_ERROR_NOT_INITIALIZED
;
370 docShell
.forget(aDocShell
);
375 nsAppShellService::CreateWindowlessBrowser(bool aIsChrome
, uint32_t aChromeMask
,
376 nsIWindowlessBrowser
** aResult
) {
378 MOZ_DIAGNOSTIC_ASSERT(aIsChrome
, "Got chrome flags for non-chrome browser");
379 if (aChromeMask
& ~(nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
|
380 nsIWebBrowserChrome::CHROME_FISSION_WINDOW
|
381 nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
)) {
382 NS_ERROR("Received unexpected chrome flags");
383 return NS_ERROR_FAILURE
;
387 /* First, we set the container window for our instance of nsWebBrowser. Since
388 * we don't actually have a window, we instead set the container window to be
389 * an instance of WebBrowserChrome2Stub, which provides a stub implementation
390 * of nsIWebBrowserChrome.
392 RefPtr
<WebBrowserChrome2Stub
> stub
= new WebBrowserChrome2Stub();
394 /* A windowless web browser doesn't have an associated OS level window. To
395 * accomplish this, we initialize the window associated with our instance of
396 * nsWebBrowser with an instance of HeadlessWidget/PuppetWidget, which provide
397 * a stub implementation of nsIWidget.
399 nsCOMPtr
<nsIWidget
> widget
;
400 if (gfxPlatform::IsHeadless()) {
401 widget
= nsIWidget::CreateHeadlessWidget();
403 widget
= nsIWidget::CreatePuppetWidget(nullptr);
406 NS_ERROR("Couldn't create instance of stub widget");
407 return NS_ERROR_FAILURE
;
411 widget
->Create(nullptr, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
412 NS_ENSURE_SUCCESS(rv
, rv
);
414 // Create a BrowsingContext for our windowless browser.
415 RefPtr
<BrowsingContext
> browsingContext
= BrowsingContext::CreateIndependent(
416 aIsChrome
? BrowsingContext::Type::Chrome
417 : BrowsingContext::Type::Content
);
419 if (aChromeMask
& nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
) {
420 browsingContext
->SetRemoteTabs(true);
422 if (aChromeMask
& nsIWebBrowserChrome::CHROME_FISSION_WINDOW
) {
423 browsingContext
->SetRemoteSubframes(true);
425 if (aChromeMask
& nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
) {
426 browsingContext
->SetPrivateBrowsing(true);
429 /* Next, we create an instance of nsWebBrowser. Instances of this class have
430 * an associated doc shell, which is what we're interested in.
432 nsCOMPtr
<nsIWebBrowser
> browser
= nsWebBrowser::Create(
433 stub
, widget
, browsingContext
, nullptr /* initialWindowChild */);
435 if (NS_WARN_IF(!browser
)) {
436 NS_ERROR("Couldn't create instance of nsWebBrowser!");
437 return NS_ERROR_FAILURE
;
440 // Make sure the container window owns the the nsWebBrowser instance.
441 stub
->SetBrowser(browser
);
443 nsISupports
* isstub
= NS_ISUPPORTS_CAST(nsIWebBrowserChrome
*, stub
);
444 RefPtr
<nsIWindowlessBrowser
> result
= new WindowlessBrowser(browser
, isstub
);
445 nsCOMPtr
<nsIDocShell
> docshell
= do_GetInterface(result
);
446 docshell
->SetInvisible(true);
448 result
.forget(aResult
);
453 * Just do the window-making part of CreateTopLevelWindow
455 nsresult
nsAppShellService::JustCreateTopWindow(
456 nsIAppWindow
* aParent
, nsIURI
* aUrl
, uint32_t aChromeMask
,
457 int32_t aInitialWidth
, int32_t aInitialHeight
, bool aIsHiddenWindow
,
458 AppWindow
** aResult
) {
459 using BorderStyle
= widget::BorderStyle
;
461 NS_ENSURE_STATE(!mXPCOMWillShutDown
);
463 nsCOMPtr
<nsIAppWindow
> parent
;
464 if (aChromeMask
& nsIWebBrowserChrome::CHROME_DEPENDENT
) parent
= aParent
;
466 RefPtr
<AppWindow
> window
= new AppWindow(aChromeMask
);
469 // If the parent is currently fullscreen, tell the child to ignore persisted
470 // full screen states. This way new browser windows open on top of fullscreen
472 if (nsCOMPtr
<nsIBaseWindow
> baseWin
= do_QueryInterface(aParent
)) {
473 nsCOMPtr
<nsIWidget
> widget
;
474 baseWin
->GetMainWidget(getter_AddRefs(widget
));
475 if (widget
&& widget
->SizeMode() == nsSizeMode_Fullscreen
) {
476 window
->IgnoreXULSizeMode(true);
481 widget::InitData widgetInitData
;
482 if (aIsHiddenWindow
) {
483 widgetInitData
.mWindowType
= widget::WindowType::Invisible
;
485 widgetInitData
.mWindowType
=
486 aChromeMask
& nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
487 ? widget::WindowType::Dialog
488 : widget::WindowType::TopLevel
;
491 if (aChromeMask
& nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION
) {
492 widgetInitData
.mIsAnimationSuppressed
= true;
495 if (aChromeMask
& nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP
) {
496 widgetInitData
.mAlwaysOnTop
= true;
499 if (aChromeMask
& nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
) {
500 widgetInitData
.mHasRemoteContent
= true;
503 #if defined(MOZ_WIDGET_GTK) || defined(XP_WIN)
504 // Windows/Gtk PIP window support. It's Chrome dialog window, always on top
505 // and without any bar.
506 uint32_t pipMask
= nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP
|
507 nsIWebBrowserChrome::CHROME_OPENAS_CHROME
|
508 nsIWebBrowserChrome::CHROME_WINDOW_RESIZE
;
509 uint32_t barMask
= nsIWebBrowserChrome::CHROME_MENUBAR
|
510 nsIWebBrowserChrome::CHROME_TOOLBAR
|
511 nsIWebBrowserChrome::CHROME_LOCATIONBAR
|
512 nsIWebBrowserChrome::CHROME_TITLEBAR
|
513 nsIWebBrowserChrome::CHROME_STATUSBAR
;
514 if (widgetInitData
.mWindowType
== widget::WindowType::Dialog
&&
515 ((aChromeMask
& pipMask
) == pipMask
) && !(aChromeMask
& barMask
)) {
516 widgetInitData
.mPIPWindow
= true;
520 // alert=yes is expected to be used along with dialogs, not other window
522 MOZ_ASSERT_IF(aChromeMask
& nsIWebBrowserChrome::CHROME_ALERT
,
523 widgetInitData
.mWindowType
== widget::WindowType::Dialog
);
524 widgetInitData
.mIsAlert
=
525 !!(aChromeMask
& nsIWebBrowserChrome::CHROME_ALERT
) &&
526 widgetInitData
.mWindowType
== widget::WindowType::Dialog
;
529 if (widgetInitData
.mWindowType
== widget::WindowType::TopLevel
||
530 widgetInitData
.mWindowType
== widget::WindowType::Dialog
) {
531 widgetInitData
.mClipChildren
= true;
535 // note default chrome overrides other OS chrome settings, but
536 // not internal chrome
537 if (aChromeMask
& nsIWebBrowserChrome::CHROME_DEFAULT
) {
538 widgetInitData
.mBorderStyle
= BorderStyle::Default
;
539 } else if ((aChromeMask
& nsIWebBrowserChrome::CHROME_ALL
) ==
540 nsIWebBrowserChrome::CHROME_ALL
) {
541 widgetInitData
.mBorderStyle
= BorderStyle::All
;
543 widgetInitData
.mBorderStyle
= BorderStyle::None
; // assumes none == 0x00
544 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_BORDERS
) {
545 widgetInitData
.mBorderStyle
|= BorderStyle::Border
;
547 if (aChromeMask
& nsIWebBrowserChrome::CHROME_TITLEBAR
) {
548 widgetInitData
.mBorderStyle
|= BorderStyle::Title
;
550 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_CLOSE
) {
551 widgetInitData
.mBorderStyle
|= BorderStyle::Close
;
553 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_RESIZE
) {
554 widgetInitData
.mResizable
= true;
555 widgetInitData
.mBorderStyle
|= BorderStyle::ResizeH
;
556 // only resizable windows get the maximize button (but not dialogs)
557 if (!(aChromeMask
& nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
)) {
558 widgetInitData
.mBorderStyle
|= BorderStyle::Maximize
;
561 // all windows (except dialogs) get minimize buttons and the system menu
562 if (!(aChromeMask
& nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
)) {
563 widgetInitData
.mBorderStyle
|= BorderStyle::Minimize
| BorderStyle::Menu
;
565 // but anyone can explicitly ask for a minimize button
566 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_MINIMIZE
) {
567 widgetInitData
.mBorderStyle
|= BorderStyle::Minimize
;
571 if (aInitialWidth
== nsIAppShellService::SIZE_TO_CONTENT
||
572 aInitialHeight
== nsIAppShellService::SIZE_TO_CONTENT
) {
575 window
->SetIntrinsicallySized(true);
578 bool center
= aChromeMask
& nsIWebBrowserChrome::CHROME_CENTER_SCREEN
;
580 widgetInitData
.mRTL
= LocaleService::GetInstance()->IsAppLocaleRTL();
582 // Enforce the Private Browsing autoStart pref first.
583 bool isPrivateBrowsingWindow
=
584 StaticPrefs::browser_privatebrowsing_autostart();
585 if (aChromeMask
& nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
) {
586 // Caller requested a private window
587 isPrivateBrowsingWindow
= true;
589 widgetInitData
.mIsPrivate
= isPrivateBrowsingWindow
;
592 window
->Initialize(parent
, center
? aParent
: nullptr, aInitialWidth
,
593 aInitialHeight
, aIsHiddenWindow
, widgetInitData
);
595 NS_ENSURE_SUCCESS(rv
, rv
);
597 nsCOMPtr
<mozIDOMWindowProxy
> domWin
= do_GetInterface(aParent
);
598 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(domWin
);
599 nsCOMPtr
<nsILoadContext
> parentContext
= do_QueryInterface(webNav
);
601 if (!isPrivateBrowsingWindow
&& parentContext
) {
602 // Ensure that we propagate any existing private browsing status
603 // from the parent, even if it will not actually be used
604 // as a parent value.
605 isPrivateBrowsingWindow
= parentContext
->UsePrivateBrowsing();
608 if (RefPtr
<nsDocShell
> docShell
= window
->GetDocShell()) {
609 MOZ_ASSERT(docShell
->GetBrowsingContext()->IsChrome());
611 docShell
->SetPrivateBrowsing(isPrivateBrowsingWindow
);
612 docShell
->SetRemoteTabs(aChromeMask
&
613 nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
);
614 docShell
->SetRemoteSubframes(aChromeMask
&
615 nsIWebBrowserChrome::CHROME_FISSION_WINDOW
);
617 // Eagerly create an about:blank content viewer with the right principal
618 // here, rather than letting it happen in the upcoming call to
619 // SetInitialPrincipal. This avoids creating the about:blank document and
620 // then blowing it away with a second one, which can cause problems for the
621 // top-level chrome window case. See bug 789773.
622 // Toplevel chrome windows always have a system principal, so ensure the
623 // initial window is created with that principal.
624 // We need to do this even when creating a chrome window to load a content
625 // window, see bug 799348 comment 13 for details about what previously
626 // happened here due to it using the subject principal.
627 if (nsContentUtils::IsInitialized()) { // Sometimes this happens really
628 // early. See bug 793370.
629 MOZ_DIAGNOSTIC_ASSERT(
630 nsContentUtils::LegacyIsCallerChromeOrNativeCode(),
631 "Previously, this method would use the subject principal rather than "
632 "hardcoding the system principal");
633 // Use the system principal as the storage principal too until the new
634 // window finishes navigating and gets a real storage principal.
635 rv
= docShell
->CreateAboutBlankDocumentViewer(
636 nsContentUtils::GetSystemPrincipal(),
637 nsContentUtils::GetSystemPrincipal(),
638 /* aCsp = */ nullptr, /* aBaseURI = */ nullptr,
639 /* aIsInitialDocument = */ true);
640 NS_ENSURE_SUCCESS(rv
, rv
);
641 RefPtr
<dom::Document
> doc
= docShell
->GetDocument();
642 NS_ENSURE_TRUE(!!doc
, NS_ERROR_FAILURE
);
643 MOZ_ASSERT(doc
->IsInitialDocument(),
644 "Document should be an initial document");
647 // Begin loading the URL provided.
649 RefPtr
<nsDocShellLoadState
> loadState
= new nsDocShellLoadState(aUrl
);
650 loadState
->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
651 loadState
->SetFirstParty(true);
652 rv
= docShell
->LoadURI(loadState
, /* aSetNavigating */ true);
653 NS_ENSURE_SUCCESS(rv
, rv
);
657 window
.forget(aResult
);
659 if (center
) rv
= (*aResult
)->Center(parent
, parent
? false : true, false);
665 nsAppShellService::GetHiddenWindow(nsIAppWindow
** aWindow
) {
666 NS_ENSURE_ARG_POINTER(aWindow
);
668 *aWindow
= mHiddenWindow
;
669 NS_IF_ADDREF(*aWindow
);
670 return *aWindow
? NS_OK
: NS_ERROR_FAILURE
;
674 nsAppShellService::GetHiddenDOMWindow(mozIDOMWindowProxy
** aWindow
) {
675 NS_ENSURE_ARG_POINTER(aWindow
);
678 nsCOMPtr
<nsIDocShell
> docShell
;
679 NS_ENSURE_TRUE(mHiddenWindow
, NS_ERROR_FAILURE
);
681 rv
= mHiddenWindow
->GetDocShell(getter_AddRefs(docShell
));
682 NS_ENSURE_SUCCESS(rv
, rv
);
683 NS_ENSURE_TRUE(docShell
, NS_ERROR_FAILURE
);
685 nsCOMPtr
<nsPIDOMWindowOuter
> hiddenDOMWindow(docShell
->GetWindow());
686 hiddenDOMWindow
.forget(aWindow
);
687 return *aWindow
? NS_OK
: NS_ERROR_FAILURE
;
691 nsAppShellService::GetHasHiddenWindow(bool* aHasHiddenWindow
) {
692 NS_ENSURE_ARG_POINTER(aHasHiddenWindow
);
694 *aHasHiddenWindow
= !!mHiddenWindow
;
699 * Register a new top level window (created elsewhere)
702 nsAppShellService::RegisterTopLevelWindow(nsIAppWindow
* aWindow
) {
703 NS_ENSURE_ARG_POINTER(aWindow
);
705 nsCOMPtr
<nsIDocShell
> docShell
;
706 aWindow
->GetDocShell(getter_AddRefs(docShell
));
707 NS_ENSURE_TRUE(docShell
, NS_ERROR_FAILURE
);
709 nsCOMPtr
<nsPIDOMWindowOuter
> domWindow(docShell
->GetWindow());
710 NS_ENSURE_TRUE(domWindow
, NS_ERROR_FAILURE
);
712 // Toplevel chrome windows always have a system principal, so ensure the
713 // initial window is created with that principal.
714 // We need to do this even when creating a chrome window to load a content
715 // window, see bug 799348 comment 13 for details about what previously
716 // happened here due to it using the subject principal.
717 MOZ_DIAGNOSTIC_ASSERT(
718 nsContentUtils::LegacyIsCallerChromeOrNativeCode(),
719 "Previously, this method would use the subject principal rather than "
720 "hardcoding the system principal");
721 domWindow
->SetInitialPrincipal(nsContentUtils::GetSystemPrincipal(), nullptr,
724 // tell the window mediator about the new window
725 nsCOMPtr
<nsIWindowMediator
> mediator(
726 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
727 NS_ASSERTION(mediator
, "Couldn't get window mediator.");
729 if (mediator
) mediator
->RegisterWindow(aWindow
);
731 // tell the window watcher about the new window
732 nsCOMPtr
<nsPIWindowWatcher
> wwatcher(
733 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
734 NS_ASSERTION(wwatcher
, "No windowwatcher?");
735 if (wwatcher
&& domWindow
) {
736 wwatcher
->AddWindow(domWindow
, 0);
739 // an ongoing attempt to quit is stopped by a newly opened window
740 nsCOMPtr
<nsIObserverService
> obssvc
= services::GetObserverService();
741 NS_ASSERTION(obssvc
, "Couldn't get observer service.");
744 obssvc
->NotifyObservers(aWindow
, "xul-window-registered", nullptr);
745 AppWindow
* appWindow
= static_cast<AppWindow
*>(aWindow
);
746 appWindow
->WasRegistered();
753 nsAppShellService::UnregisterTopLevelWindow(nsIAppWindow
* aWindow
) {
754 if (mXPCOMShuttingDown
) {
755 /* return an error code in order to:
756 - avoid doing anything with other member variables while we are in
758 - notify the caller not to release the AppShellService after
759 unregistering the window
760 (we don't want to be deleted twice consecutively to
761 mHiddenWindow->Destroy() in our destructor)
763 return NS_ERROR_FAILURE
;
766 NS_ENSURE_ARG_POINTER(aWindow
);
768 if (aWindow
== mHiddenWindow
) {
769 // CreateHiddenWindow() does not register the window, so we're done.
773 // tell the window mediator
774 nsCOMPtr
<nsIWindowMediator
> mediator(
775 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
776 NS_ASSERTION(mediator
, "Couldn't get window mediator. Doing xpcom shutdown?");
778 if (mediator
) mediator
->UnregisterWindow(aWindow
);
780 // tell the window watcher
781 nsCOMPtr
<nsPIWindowWatcher
> wwatcher(
782 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
783 NS_ASSERTION(wwatcher
, "Couldn't get windowwatcher, doing xpcom shutdown?");
785 nsCOMPtr
<nsIDocShell
> docShell
;
786 aWindow
->GetDocShell(getter_AddRefs(docShell
));
788 nsCOMPtr
<nsPIDOMWindowOuter
> domWindow(docShell
->GetWindow());
789 if (domWindow
) wwatcher
->RemoveWindow(domWindow
);
797 nsAppShellService::Observe(nsISupports
* aSubject
, const char* aTopic
,
798 const char16_t
* aData
) {
799 if (!strcmp(aTopic
, "xpcom-will-shutdown")) {
800 mXPCOMWillShutDown
= true;
801 } else if (!strcmp(aTopic
, "xpcom-shutdown")) {
802 mXPCOMShuttingDown
= true;
804 mHiddenWindow
->Destroy();
807 NS_ERROR("Unexpected observer topic!");