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 "nsWidgetInitData.h"
18 #include "nsWidgetsCID.h"
19 #include "nsIWidget.h"
20 #include "nsIEmbeddingSiteWindow.h"
22 #include "nsAppDirectoryServiceDefs.h"
23 #include "nsAppShellService.h"
24 #include "nsContentUtils.h"
25 #include "nsDirectoryServiceUtils.h"
26 #include "nsThreadUtils.h"
27 #include "nsILoadContext.h"
28 #include "nsIWebNavigation.h"
29 #include "nsIWindowlessBrowser.h"
31 #include "mozilla/Attributes.h"
32 #include "mozilla/Preferences.h"
33 #include "mozilla/Services.h"
34 #include "mozilla/StartupTimeline.h"
35 #include "mozilla/StaticPrefs_fission.h"
36 #include "mozilla/intl/LocaleService.h"
37 #include "mozilla/dom/BrowsingContext.h"
39 #include "nsEmbedCID.h"
40 #include "nsIWebBrowser.h"
41 #include "nsIDocShell.h"
42 #include "gfxPlatform.h"
44 #include "nsWebBrowser.h"
45 #include "nsDocShell.h"
46 #include "nsDocShellLoadState.h"
48 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
49 # include "EventTracer.h"
52 using namespace mozilla
;
53 using mozilla::dom::BrowsingContext
;
54 using mozilla::intl::LocaleService
;
56 // Default URL for the hidden window, can be overridden by a pref on Mac
57 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
61 nsAppShellService::nsAppShellService()
62 : mXPCOMWillShutDown(false),
63 mXPCOMShuttingDown(false),
65 mApplicationProvidedHiddenWindow(false),
67 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
70 obs
->AddObserver(this, "xpcom-will-shutdown", false);
71 obs
->AddObserver(this, "xpcom-shutdown", false);
75 nsAppShellService::~nsAppShellService() {}
78 * Implement the nsISupports methods...
80 NS_IMPL_ISUPPORTS(nsAppShellService
, nsIAppShellService
, nsIObserver
)
83 nsAppShellService::SetScreenId(uint32_t aScreenId
) {
84 mScreenId
= aScreenId
;
88 void nsAppShellService::EnsureHiddenWindow() {
90 (void)CreateHiddenWindow();
95 nsAppShellService::CreateHiddenWindow() {
96 if (!XRE_IsParentProcess()) {
97 return NS_ERROR_NOT_IMPLEMENTED
;
100 if (mXPCOMShuttingDown
) {
101 return NS_ERROR_FAILURE
;
108 nsCOMPtr
<nsIFile
> profileDir
;
109 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
110 getter_AddRefs(profileDir
));
112 // This is too early on startup to create the hidden window
113 return NS_ERROR_FAILURE
;
117 int32_t initialHeight
= 100, initialWidth
= 100;
120 uint32_t chromeMask
= 0;
121 nsAutoCString prefVal
;
122 rv
= Preferences::GetCString("browser.hiddenWindowChromeURL", prefVal
);
123 const char* hiddenWindowURL
=
124 NS_SUCCEEDED(rv
) ? prefVal
.get() : DEFAULT_HIDDENWINDOW_URL
;
125 mApplicationProvidedHiddenWindow
= prefVal
.get() ? true : false;
127 static const char hiddenWindowURL
[] = DEFAULT_HIDDENWINDOW_URL
;
128 uint32_t chromeMask
= nsIWebBrowserChrome::CHROME_ALL
;
131 nsCOMPtr
<nsIURI
> url
;
132 rv
= NS_NewURI(getter_AddRefs(url
), hiddenWindowURL
);
133 NS_ENSURE_SUCCESS(rv
, rv
);
135 RefPtr
<AppWindow
> newWindow
;
136 rv
= JustCreateTopWindow(nullptr, url
, chromeMask
, initialWidth
,
137 initialHeight
, true, getter_AddRefs(newWindow
));
138 NS_ENSURE_SUCCESS(rv
, rv
);
140 nsCOMPtr
<nsIDocShell
> docShell
;
141 newWindow
->GetDocShell(getter_AddRefs(docShell
));
143 Unused
<< docShell
->GetBrowsingContext()->SetExplicitActive(
144 dom::ExplicitActiveStatus::Inactive
);
147 mHiddenWindow
.swap(newWindow
);
153 nsAppShellService::DestroyHiddenWindow() {
155 mHiddenWindow
->Destroy();
157 mHiddenWindow
= nullptr;
164 * Create a new top level window and display the given URL within it...
167 nsAppShellService::CreateTopLevelWindow(nsIAppWindow
* aParent
, nsIURI
* aUrl
,
168 uint32_t aChromeMask
,
169 int32_t aInitialWidth
,
170 int32_t aInitialHeight
,
171 nsIAppWindow
** aResult
) {
174 StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW
);
176 RefPtr
<AppWindow
> newWindow
;
177 rv
= JustCreateTopWindow(aParent
, aUrl
, aChromeMask
, aInitialWidth
,
178 aInitialHeight
, false, getter_AddRefs(newWindow
));
179 newWindow
.forget(aResult
);
181 if (NS_SUCCEEDED(rv
)) {
182 // the addref resulting from this is the owning addref for this window
183 RegisterTopLevelWindow(*aResult
);
184 nsCOMPtr
<nsIAppWindow
> parent
;
185 if (aChromeMask
& nsIWebBrowserChrome::CHROME_DEPENDENT
) parent
= aParent
;
186 (*aResult
)->SetZLevel(CalculateWindowZLevel(parent
, aChromeMask
));
193 * This class provides a stub implementation of nsIWebBrowserChrome, as needed
194 * by nsAppShellService::CreateWindowlessBrowser
196 class WebBrowserChrome2Stub final
: public nsIWebBrowserChrome
,
197 public nsIEmbeddingSiteWindow
,
198 public nsIInterfaceRequestor
,
199 public nsSupportsWeakReference
{
201 nsCOMPtr
<nsIWebBrowser
> mBrowser
;
202 virtual ~WebBrowserChrome2Stub() {}
205 void SetBrowser(nsIWebBrowser
* aBrowser
) { mBrowser
= aBrowser
; }
208 NS_DECL_NSIWEBBROWSERCHROME
209 NS_DECL_NSIINTERFACEREQUESTOR
210 NS_DECL_NSIEMBEDDINGSITEWINDOW
213 NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub
)
214 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIWebBrowserChrome
)
215 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome
)
216 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
217 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
218 NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow
)
221 NS_IMPL_ADDREF(WebBrowserChrome2Stub
)
222 NS_IMPL_RELEASE(WebBrowserChrome2Stub
)
225 WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags
) {
231 WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags
) {
232 MOZ_ASSERT_UNREACHABLE(
233 "WebBrowserChrome2Stub::SetChromeFlags is "
235 return NS_ERROR_NOT_IMPLEMENTED
;
239 WebBrowserChrome2Stub::ShowAsModal() {
240 MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::ShowAsModal is not supported");
241 return NS_ERROR_NOT_IMPLEMENTED
;
245 WebBrowserChrome2Stub::IsWindowModal(bool* aResult
) {
251 WebBrowserChrome2Stub::SetLinkStatus(const nsAString
& aStatusText
) {
256 WebBrowserChrome2Stub::GetInterface(const nsIID
& aIID
, void** aSink
) {
257 return QueryInterface(aIID
, aSink
);
260 // nsIEmbeddingSiteWindow impl
262 WebBrowserChrome2Stub::GetDimensions(uint32_t flags
, int32_t* x
, int32_t* y
,
263 int32_t* cx
, int32_t* cy
) {
284 WebBrowserChrome2Stub::SetDimensions(uint32_t flags
, int32_t x
, int32_t y
,
285 int32_t cx
, int32_t cy
) {
286 nsCOMPtr
<nsIBaseWindow
> window
= do_QueryInterface(mBrowser
);
287 NS_ENSURE_TRUE(window
, NS_ERROR_FAILURE
);
288 window
->SetSize(cx
, cy
, true);
293 WebBrowserChrome2Stub::GetVisibility(bool* aVisibility
) {
294 return NS_ERROR_NOT_IMPLEMENTED
;
297 WebBrowserChrome2Stub::SetVisibility(bool aVisibility
) {
298 return NS_ERROR_NOT_IMPLEMENTED
;
302 WebBrowserChrome2Stub::GetTitle(nsAString
& aTitle
) {
303 return NS_ERROR_NOT_IMPLEMENTED
;
306 WebBrowserChrome2Stub::SetTitle(const nsAString
& aTitle
) {
307 return NS_ERROR_NOT_IMPLEMENTED
;
311 WebBrowserChrome2Stub::GetSiteWindow(void** aSiteWindow
) {
312 return NS_ERROR_NOT_IMPLEMENTED
;
316 WebBrowserChrome2Stub::Blur() { return NS_ERROR_NOT_IMPLEMENTED
; }
318 class BrowserDestroyer final
: public Runnable
{
320 BrowserDestroyer(nsIWebBrowser
* aBrowser
, nsISupports
* aContainer
)
321 : mozilla::Runnable("BrowserDestroyer"),
323 mContainer(aContainer
) {}
325 static nsresult
Destroy(nsIWebBrowser
* aBrowser
) {
326 nsCOMPtr
<nsIBaseWindow
> window(do_QueryInterface(aBrowser
));
327 return window
->Destroy();
332 // Explicitly destroy the browser, in case this isn't the last reference.
333 return Destroy(mBrowser
);
337 virtual ~BrowserDestroyer() {}
340 nsCOMPtr
<nsIWebBrowser
> mBrowser
;
341 nsCOMPtr
<nsISupports
> mContainer
;
344 // This is the "stub" we return from CreateWindowlessBrowser - it exists
345 // to manage the lifetimes of the nsIWebBrowser and container window.
346 // In particular, it keeps a strong reference to both, to prevent them from
347 // being collected while this object remains alive, and ensures that they
348 // aren't destroyed when it's not safe to run scripts.
349 class WindowlessBrowser final
: public nsIWindowlessBrowser
,
350 public nsIInterfaceRequestor
{
352 WindowlessBrowser(nsIWebBrowser
* aBrowser
, nsISupports
* aContainer
)
353 : mBrowser(aBrowser
), mContainer(aContainer
), mClosed(false) {
354 mWebNavigation
= do_QueryInterface(aBrowser
);
355 mInterfaceRequestor
= do_QueryInterface(aBrowser
);
358 NS_DECL_NSIWINDOWLESSBROWSER
359 NS_FORWARD_SAFE_NSIWEBNAVIGATION(mWebNavigation
)
360 NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor
)
363 ~WindowlessBrowser() {
368 NS_WARNING("Windowless browser was not closed prior to destruction");
370 // The docshell destructor needs to dispatch events, and can only run
371 // when it's safe to run scripts. If this was triggered by GC, it may
372 // not always be safe to run scripts, in which cases we need to delay
373 // destruction until it is.
374 auto runnable
= MakeRefPtr
<BrowserDestroyer
>(mBrowser
, mContainer
);
375 nsContentUtils::AddScriptRunner(runnable
.forget());
378 nsCOMPtr
<nsIWebBrowser
> mBrowser
;
379 nsCOMPtr
<nsIWebNavigation
> mWebNavigation
;
380 nsCOMPtr
<nsIInterfaceRequestor
> mInterfaceRequestor
;
381 // we don't use the container but just hold a reference to it.
382 nsCOMPtr
<nsISupports
> mContainer
;
387 NS_IMPL_ISUPPORTS(WindowlessBrowser
, nsIWindowlessBrowser
, nsIWebNavigation
,
388 nsIInterfaceRequestor
)
391 WindowlessBrowser::Close() {
392 NS_ENSURE_TRUE(!mClosed
, NS_ERROR_UNEXPECTED
);
393 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
394 "WindowlessBrowser::Close called when not safe to run scripts");
398 mWebNavigation
= nullptr;
399 mInterfaceRequestor
= nullptr;
400 return BrowserDestroyer::Destroy(mBrowser
);
404 WindowlessBrowser::GetBrowsingContext(BrowsingContext
** aBrowsingContext
) {
405 nsCOMPtr
<nsIDocShellTreeItem
> docShellTreeItem
= do_QueryInterface(mBrowser
);
406 if (!docShellTreeItem
) {
407 return NS_ERROR_NOT_INITIALIZED
;
409 return docShellTreeItem
->GetBrowsingContextXPCOM(aBrowsingContext
);
413 WindowlessBrowser::GetDocShell(nsIDocShell
** aDocShell
) {
414 nsCOMPtr
<nsIDocShell
> docShell
= do_GetInterface(mInterfaceRequestor
);
416 return NS_ERROR_NOT_INITIALIZED
;
418 docShell
.forget(aDocShell
);
423 nsAppShellService::CreateWindowlessBrowser(bool aIsChrome
, uint32_t aChromeMask
,
424 nsIWindowlessBrowser
** aResult
) {
426 MOZ_DIAGNOSTIC_ASSERT(aIsChrome
, "Got chrome flags for non-chrome browser");
427 if (aChromeMask
& ~(nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
|
428 nsIWebBrowserChrome::CHROME_FISSION_WINDOW
|
429 nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
)) {
430 NS_ERROR("Received unexpected chrome flags");
431 return NS_ERROR_FAILURE
;
435 /* First, we set the container window for our instance of nsWebBrowser. Since
436 * we don't actually have a window, we instead set the container window to be
437 * an instance of WebBrowserChrome2Stub, which provides a stub implementation
438 * of nsIWebBrowserChrome.
440 RefPtr
<WebBrowserChrome2Stub
> stub
= new WebBrowserChrome2Stub();
442 /* A windowless web browser doesn't have an associated OS level window. To
443 * accomplish this, we initialize the window associated with our instance of
444 * nsWebBrowser with an instance of HeadlessWidget/PuppetWidget, which provide
445 * a stub implementation of nsIWidget.
447 nsCOMPtr
<nsIWidget
> widget
;
448 if (gfxPlatform::IsHeadless()) {
449 widget
= nsIWidget::CreateHeadlessWidget();
451 widget
= nsIWidget::CreatePuppetWidget(nullptr);
454 NS_ERROR("Couldn't create instance of stub widget");
455 return NS_ERROR_FAILURE
;
459 widget
->Create(nullptr, 0, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
460 NS_ENSURE_SUCCESS(rv
, rv
);
462 // Create a BrowsingContext for our windowless browser.
463 RefPtr
<BrowsingContext
> browsingContext
= BrowsingContext::CreateIndependent(
464 aIsChrome
? BrowsingContext::Type::Chrome
465 : BrowsingContext::Type::Content
);
467 if (aChromeMask
& nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
) {
468 browsingContext
->SetRemoteTabs(true);
470 if (aChromeMask
& nsIWebBrowserChrome::CHROME_FISSION_WINDOW
) {
471 browsingContext
->SetRemoteSubframes(true);
473 if (aChromeMask
& nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
) {
474 browsingContext
->SetPrivateBrowsing(true);
477 /* Next, we create an instance of nsWebBrowser. Instances of this class have
478 * an associated doc shell, which is what we're interested in.
480 nsCOMPtr
<nsIWebBrowser
> browser
= nsWebBrowser::Create(
481 stub
, widget
, browsingContext
, nullptr /* initialWindowChild */);
483 if (NS_WARN_IF(!browser
)) {
484 NS_ERROR("Couldn't create instance of nsWebBrowser!");
485 return NS_ERROR_FAILURE
;
488 // Make sure the container window owns the the nsWebBrowser instance.
489 stub
->SetBrowser(browser
);
491 nsISupports
* isstub
= NS_ISUPPORTS_CAST(nsIWebBrowserChrome
*, stub
);
492 RefPtr
<nsIWindowlessBrowser
> result
= new WindowlessBrowser(browser
, isstub
);
493 nsCOMPtr
<nsIDocShell
> docshell
= do_GetInterface(result
);
494 docshell
->SetInvisible(true);
496 result
.forget(aResult
);
500 uint32_t nsAppShellService::CalculateWindowZLevel(nsIAppWindow
* aParent
,
501 uint32_t aChromeMask
) {
504 zLevel
= nsIAppWindow::normalZ
;
505 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_RAISED
)
506 zLevel
= nsIAppWindow::raisedZ
;
507 else if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_LOWERED
)
508 zLevel
= nsIAppWindow::loweredZ
;
511 /* Platforms on which modal windows are always application-modal, not
512 window-modal (that's just the Mac, right?) want modal windows to
513 be stacked on top of everyone else.
515 On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
517 uint32_t modalDepMask
=
518 nsIWebBrowserChrome::CHROME_MODAL
| nsIWebBrowserChrome::CHROME_DEPENDENT
;
519 if (aParent
&& (aChromeMask
& modalDepMask
)) {
520 aParent
->GetZLevel(&zLevel
);
523 /* Platforms with native support for dependent windows (that's everyone
524 but pre-Mac OS X, right?) know how to stack dependent windows. On these
525 platforms, give the dependent window the same level as its parent,
526 so we won't try to override the normal platform behaviour. */
527 if ((aChromeMask
& nsIWebBrowserChrome::CHROME_DEPENDENT
) && aParent
)
528 aParent
->GetZLevel(&zLevel
);
536 * Checks to see if any existing window is currently in fullscreen mode.
538 static bool CheckForFullscreenWindow() {
539 nsCOMPtr
<nsIWindowMediator
> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
540 if (!wm
) return false;
542 nsCOMPtr
<nsISimpleEnumerator
> windowList
;
543 wm
->GetAppWindowEnumerator(nullptr, getter_AddRefs(windowList
));
544 if (!windowList
) return false;
548 windowList
->HasMoreElements(&more
);
549 if (!more
) return false;
551 nsCOMPtr
<nsISupports
> supportsWindow
;
552 windowList
->GetNext(getter_AddRefs(supportsWindow
));
553 nsCOMPtr
<nsIBaseWindow
> baseWin(do_QueryInterface(supportsWindow
));
555 nsCOMPtr
<nsIWidget
> widget
;
556 baseWin
->GetMainWidget(getter_AddRefs(widget
));
557 if (widget
&& widget
->SizeMode() == nsSizeMode_Fullscreen
) {
567 * Just do the window-making part of CreateTopLevelWindow
569 nsresult
nsAppShellService::JustCreateTopWindow(
570 nsIAppWindow
* aParent
, nsIURI
* aUrl
, uint32_t aChromeMask
,
571 int32_t aInitialWidth
, int32_t aInitialHeight
, bool aIsHiddenWindow
,
572 AppWindow
** aResult
) {
574 NS_ENSURE_STATE(!mXPCOMWillShutDown
);
576 nsCOMPtr
<nsIAppWindow
> parent
;
577 if (aChromeMask
& nsIWebBrowserChrome::CHROME_DEPENDENT
) parent
= aParent
;
579 RefPtr
<AppWindow
> window
= new AppWindow(aChromeMask
);
582 // If the parent is currently fullscreen, tell the child to ignore persisted
583 // full screen states. This way new browser windows open on top of fullscreen
585 if (window
&& CheckForFullscreenWindow()) window
->IgnoreXULSizeMode(true);
588 nsWidgetInitData widgetInitData
;
591 widgetInitData
.mWindowType
= eWindowType_invisible
;
593 widgetInitData
.mWindowType
=
594 aChromeMask
& nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
596 : eWindowType_toplevel
;
598 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_POPUP
)
599 widgetInitData
.mWindowType
= eWindowType_popup
;
601 if (aChromeMask
& nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION
)
602 widgetInitData
.mIsAnimationSuppressed
= true;
604 if (aChromeMask
& nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP
)
605 widgetInitData
.mAlwaysOnTop
= true;
607 if (aChromeMask
& nsIWebBrowserChrome::CHROME_FISSION_WINDOW
)
608 widgetInitData
.mFissionWindow
= true;
610 if (aChromeMask
& nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
)
611 widgetInitData
.mHasRemoteContent
= true;
613 #ifdef MOZ_WIDGET_GTK
614 // Linux/Gtk PIP window support. It's Chrome Toplevel window, always on top
615 // and without any bar.
616 uint32_t pipMask
= nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP
|
617 nsIWebBrowserChrome::CHROME_OPENAS_CHROME
;
618 uint32_t barMask
= nsIWebBrowserChrome::CHROME_MENUBAR
|
619 nsIWebBrowserChrome::CHROME_TOOLBAR
|
620 nsIWebBrowserChrome::CHROME_LOCATIONBAR
|
621 nsIWebBrowserChrome::CHROME_STATUSBAR
;
622 if (widgetInitData
.mWindowType
== eWindowType_toplevel
&&
623 ((aChromeMask
& pipMask
) == pipMask
) && !(aChromeMask
& barMask
)) {
624 widgetInitData
.mPIPWindow
= true;
626 #elif defined(XP_WIN)
627 // Windows PIP window support. It's Chrome dialog window, always on top
628 // and without any bar.
629 uint32_t pipMask
= nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP
|
630 nsIWebBrowserChrome::CHROME_OPENAS_CHROME
;
631 uint32_t barMask
= nsIWebBrowserChrome::CHROME_MENUBAR
|
632 nsIWebBrowserChrome::CHROME_TOOLBAR
|
633 nsIWebBrowserChrome::CHROME_LOCATIONBAR
|
634 nsIWebBrowserChrome::CHROME_STATUSBAR
;
635 if (widgetInitData
.mWindowType
== eWindowType_dialog
&&
636 ((aChromeMask
& pipMask
) == pipMask
) && !(aChromeMask
& barMask
)) {
637 widgetInitData
.mPIPWindow
= true;
642 // Mac OS X sheet support
643 // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
644 // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
645 // windows opened from nsPromptService::DoDialog() still are sheets. This
646 // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
647 // nsCocoaWindow::SetModal()).
648 uint32_t sheetMask
= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
|
649 nsIWebBrowserChrome::CHROME_MODAL
|
650 nsIWebBrowserChrome::CHROME_OPENAS_CHROME
;
651 if (parent
&& (parent
!= mHiddenWindow
) &&
652 ((aChromeMask
& sheetMask
) == sheetMask
)) {
653 widgetInitData
.mWindowType
= eWindowType_sheet
;
658 if (widgetInitData
.mWindowType
== eWindowType_toplevel
||
659 widgetInitData
.mWindowType
== eWindowType_dialog
)
660 widgetInitData
.clipChildren
= true;
663 // note default chrome overrides other OS chrome settings, but
664 // not internal chrome
665 if (aChromeMask
& nsIWebBrowserChrome::CHROME_DEFAULT
)
666 widgetInitData
.mBorderStyle
= eBorderStyle_default
;
667 else if ((aChromeMask
& nsIWebBrowserChrome::CHROME_ALL
) ==
668 nsIWebBrowserChrome::CHROME_ALL
)
669 widgetInitData
.mBorderStyle
= eBorderStyle_all
;
671 widgetInitData
.mBorderStyle
= eBorderStyle_none
; // assumes none == 0x00
672 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_BORDERS
)
673 widgetInitData
.mBorderStyle
= static_cast<enum nsBorderStyle
>(
674 widgetInitData
.mBorderStyle
| eBorderStyle_border
);
675 if (aChromeMask
& nsIWebBrowserChrome::CHROME_TITLEBAR
)
676 widgetInitData
.mBorderStyle
= static_cast<enum nsBorderStyle
>(
677 widgetInitData
.mBorderStyle
| eBorderStyle_title
);
678 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_CLOSE
)
679 widgetInitData
.mBorderStyle
= static_cast<enum nsBorderStyle
>(
680 widgetInitData
.mBorderStyle
| eBorderStyle_close
);
681 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_RESIZE
) {
682 widgetInitData
.mResizable
= true;
683 widgetInitData
.mBorderStyle
= static_cast<enum nsBorderStyle
>(
684 widgetInitData
.mBorderStyle
| eBorderStyle_resizeh
);
685 // only resizable windows get the maximize button (but not dialogs)
686 if (!(aChromeMask
& nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
))
687 widgetInitData
.mBorderStyle
= static_cast<enum nsBorderStyle
>(
688 widgetInitData
.mBorderStyle
| eBorderStyle_maximize
);
690 // all windows (except dialogs) get minimize buttons and the system menu
691 if (!(aChromeMask
& nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
))
692 widgetInitData
.mBorderStyle
= static_cast<enum nsBorderStyle
>(
693 widgetInitData
.mBorderStyle
| eBorderStyle_minimize
|
695 // but anyone can explicitly ask for a minimize button
696 if (aChromeMask
& nsIWebBrowserChrome::CHROME_WINDOW_MIN
) {
697 widgetInitData
.mBorderStyle
= static_cast<enum nsBorderStyle
>(
698 widgetInitData
.mBorderStyle
| eBorderStyle_minimize
);
702 if (aInitialWidth
== nsIAppShellService::SIZE_TO_CONTENT
||
703 aInitialHeight
== nsIAppShellService::SIZE_TO_CONTENT
) {
706 window
->SetIntrinsicallySized(true);
709 bool center
= aChromeMask
& nsIWebBrowserChrome::CHROME_CENTER_SCREEN
;
711 widgetInitData
.mRTL
= LocaleService::GetInstance()->IsAppLocaleRTL();
714 window
->Initialize(parent
, center
? aParent
: nullptr, aInitialWidth
,
715 aInitialHeight
, aIsHiddenWindow
, widgetInitData
);
717 NS_ENSURE_SUCCESS(rv
, rv
);
719 // Enforce the Private Browsing autoStart pref first.
720 bool isPrivateBrowsingWindow
=
721 Preferences::GetBool("browser.privatebrowsing.autostart");
723 if (aChromeMask
& nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
) {
724 // Caller requested a private window
725 isPrivateBrowsingWindow
= true;
727 nsCOMPtr
<mozIDOMWindowProxy
> domWin
= do_GetInterface(aParent
);
728 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(domWin
);
729 nsCOMPtr
<nsILoadContext
> parentContext
= do_QueryInterface(webNav
);
731 if (!isPrivateBrowsingWindow
&& parentContext
) {
732 // Ensure that we propagate any existing private browsing status
733 // from the parent, even if it will not actually be used
734 // as a parent value.
735 isPrivateBrowsingWindow
= parentContext
->UsePrivateBrowsing();
738 if (nsDocShell
* docShell
= window
->GetDocShell()) {
739 MOZ_ASSERT(docShell
->GetBrowsingContext()->IsChrome());
741 docShell
->SetPrivateBrowsing(isPrivateBrowsingWindow
);
742 docShell
->SetRemoteTabs(aChromeMask
&
743 nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
);
744 docShell
->SetRemoteSubframes(aChromeMask
&
745 nsIWebBrowserChrome::CHROME_FISSION_WINDOW
);
747 // Eagerly create an about:blank content viewer with the right principal
748 // here, rather than letting it happening in the upcoming call to
749 // SetInitialPrincipalToSubject. This avoids creating the about:blank
750 // document and then blowing it away with a second one, which can cause
751 // problems for the top-level chrome window case. See bug 789773. Note that
752 // we don't accept expanded principals here, similar to
753 // SetInitialPrincipalToSubject.
754 if (nsContentUtils::IsInitialized()) { // Sometimes this happens really
755 // early. See bug 793370.
756 nsCOMPtr
<nsIPrincipal
> principal
=
757 nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
758 if (nsContentUtils::IsExpandedPrincipal(principal
)) {
761 // Use the subject (or system) principal as the storage principal too
762 // until the new window finishes navigating and gets a real storage
764 rv
= docShell
->CreateAboutBlankContentViewer(
765 principal
, principal
, /* aCsp = */ nullptr, /* aBaseURI = */ nullptr,
766 /* aIsInitialDocument = */ true);
767 NS_ENSURE_SUCCESS(rv
, rv
);
768 RefPtr
<Document
> doc
= docShell
->GetDocument();
769 NS_ENSURE_TRUE(!!doc
, NS_ERROR_FAILURE
);
770 MOZ_ASSERT(doc
->IsInitialDocument(),
771 "Document should be an initial document");
774 // Begin loading the URL provided.
776 RefPtr
<nsDocShellLoadState
> loadState
= new nsDocShellLoadState(aUrl
);
777 loadState
->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
778 loadState
->SetFirstParty(true);
779 rv
= docShell
->LoadURI(loadState
, /* aSetNavigating */ true);
780 NS_ENSURE_SUCCESS(rv
, rv
);
784 window
.forget(aResult
);
785 if (parent
) parent
->AddChildWindow(*aResult
);
787 if (center
) rv
= (*aResult
)->Center(parent
, parent
? false : true, false);
793 nsAppShellService::GetHiddenWindow(nsIAppWindow
** aWindow
) {
794 NS_ENSURE_ARG_POINTER(aWindow
);
796 EnsureHiddenWindow();
798 *aWindow
= mHiddenWindow
;
799 NS_IF_ADDREF(*aWindow
);
800 return *aWindow
? NS_OK
: NS_ERROR_FAILURE
;
804 nsAppShellService::GetHiddenDOMWindow(mozIDOMWindowProxy
** aWindow
) {
805 NS_ENSURE_ARG_POINTER(aWindow
);
807 EnsureHiddenWindow();
810 nsCOMPtr
<nsIDocShell
> docShell
;
811 NS_ENSURE_TRUE(mHiddenWindow
, NS_ERROR_FAILURE
);
813 rv
= mHiddenWindow
->GetDocShell(getter_AddRefs(docShell
));
814 NS_ENSURE_SUCCESS(rv
, rv
);
815 NS_ENSURE_TRUE(docShell
, NS_ERROR_FAILURE
);
817 nsCOMPtr
<nsPIDOMWindowOuter
> hiddenDOMWindow(docShell
->GetWindow());
818 hiddenDOMWindow
.forget(aWindow
);
819 return *aWindow
? NS_OK
: NS_ERROR_FAILURE
;
823 nsAppShellService::GetHasHiddenWindow(bool* aHasHiddenWindow
) {
824 NS_ENSURE_ARG_POINTER(aHasHiddenWindow
);
826 *aHasHiddenWindow
= !!mHiddenWindow
;
831 nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW
) {
832 *aAPHW
= mApplicationProvidedHiddenWindow
;
837 * Register a new top level window (created elsewhere)
840 nsAppShellService::RegisterTopLevelWindow(nsIAppWindow
* aWindow
) {
841 NS_ENSURE_ARG_POINTER(aWindow
);
843 nsCOMPtr
<nsIDocShell
> docShell
;
844 aWindow
->GetDocShell(getter_AddRefs(docShell
));
845 NS_ENSURE_TRUE(docShell
, NS_ERROR_FAILURE
);
847 nsCOMPtr
<nsPIDOMWindowOuter
> domWindow(docShell
->GetWindow());
848 NS_ENSURE_TRUE(domWindow
, NS_ERROR_FAILURE
);
849 domWindow
->SetInitialPrincipalToSubject(nullptr, Nothing());
851 // tell the window mediator about the new window
852 nsCOMPtr
<nsIWindowMediator
> mediator(
853 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
854 NS_ASSERTION(mediator
, "Couldn't get window mediator.");
856 if (mediator
) mediator
->RegisterWindow(aWindow
);
858 // tell the window watcher about the new window
859 nsCOMPtr
<nsPIWindowWatcher
> wwatcher(
860 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
861 NS_ASSERTION(wwatcher
, "No windowwatcher?");
862 if (wwatcher
&& domWindow
) {
863 wwatcher
->AddWindow(domWindow
, 0);
866 // an ongoing attempt to quit is stopped by a newly opened window
867 nsCOMPtr
<nsIObserverService
> obssvc
= services::GetObserverService();
868 NS_ASSERTION(obssvc
, "Couldn't get observer service.");
871 obssvc
->NotifyObservers(aWindow
, "xul-window-registered", nullptr);
872 AppWindow
* appWindow
= static_cast<AppWindow
*>(aWindow
);
873 appWindow
->WasRegistered();
880 nsAppShellService::UnregisterTopLevelWindow(nsIAppWindow
* aWindow
) {
881 if (mXPCOMShuttingDown
) {
882 /* return an error code in order to:
883 - avoid doing anything with other member variables while we are in
885 - notify the caller not to release the AppShellService after
886 unregistering the window
887 (we don't want to be deleted twice consecutively to
888 mHiddenWindow->Destroy() in our destructor)
890 return NS_ERROR_FAILURE
;
893 NS_ENSURE_ARG_POINTER(aWindow
);
895 if (aWindow
== mHiddenWindow
) {
896 // CreateHiddenWindow() does not register the window, so we're done.
900 // tell the window mediator
901 nsCOMPtr
<nsIWindowMediator
> mediator(
902 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
903 NS_ASSERTION(mediator
, "Couldn't get window mediator. Doing xpcom shutdown?");
905 if (mediator
) mediator
->UnregisterWindow(aWindow
);
907 // tell the window watcher
908 nsCOMPtr
<nsPIWindowWatcher
> wwatcher(
909 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
910 NS_ASSERTION(wwatcher
, "Couldn't get windowwatcher, doing xpcom shutdown?");
912 nsCOMPtr
<nsIDocShell
> docShell
;
913 aWindow
->GetDocShell(getter_AddRefs(docShell
));
915 nsCOMPtr
<nsPIDOMWindowOuter
> domWindow(docShell
->GetWindow());
916 if (domWindow
) wwatcher
->RemoveWindow(domWindow
);
924 nsAppShellService::Observe(nsISupports
* aSubject
, const char* aTopic
,
925 const char16_t
* aData
) {
926 if (!strcmp(aTopic
, "xpcom-will-shutdown")) {
927 mXPCOMWillShutDown
= true;
928 } else if (!strcmp(aTopic
, "xpcom-shutdown")) {
929 mXPCOMShuttingDown
= true;
931 mHiddenWindow
->Destroy();
934 NS_ERROR("Unexpected observer topic!");
941 nsAppShellService::StartEventLoopLagTracking(bool* aResult
) {
942 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
943 *aResult
= mozilla::InitEventTracing(true);
949 nsAppShellService::StopEventLoopLagTracking() {
950 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
951 mozilla::ShutdownEventTracing();