Bug 1893155 - Part 6: Correct constant for minimum epoch day. r=spidermonkey-reviewer...
[gecko.git] / xpfe / appshell / nsAppShellService.cpp
blob06f2476c25081fc7feca2fc09d9317b437571e06
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"
7 #include "nsNetUtil.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 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
50 # include "EventTracer.h"
51 #endif
53 using namespace mozilla;
54 using mozilla::dom::BrowsingContext;
55 using mozilla::intl::LocaleService;
57 // Default URL for the hidden window, can be overridden by a pref on Mac
58 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
60 class nsIAppShell;
62 nsAppShellService::nsAppShellService()
63 : mXPCOMWillShutDown(false),
64 mXPCOMShuttingDown(false),
65 mModalWindowCount(0),
66 mApplicationProvidedHiddenWindow(false),
67 mScreenId(0) {
68 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
70 if (obs) {
71 obs->AddObserver(this, "xpcom-will-shutdown", false);
72 obs->AddObserver(this, "xpcom-shutdown", false);
76 nsAppShellService::~nsAppShellService() {}
79 * Implement the nsISupports methods...
81 NS_IMPL_ISUPPORTS(nsAppShellService, nsIAppShellService, nsIObserver)
83 NS_IMETHODIMP
84 nsAppShellService::SetScreenId(uint32_t aScreenId) {
85 mScreenId = aScreenId;
86 return NS_OK;
89 void nsAppShellService::EnsureHiddenWindow() {
90 if (!mHiddenWindow) {
91 (void)CreateHiddenWindow();
95 NS_IMETHODIMP
96 nsAppShellService::CreateHiddenWindow() {
97 if (!XRE_IsParentProcess()) {
98 return NS_ERROR_NOT_IMPLEMENTED;
101 if (mXPCOMShuttingDown) {
102 return NS_ERROR_FAILURE;
105 if (mHiddenWindow) {
106 return NS_OK;
109 nsCOMPtr<nsIFile> profileDir;
110 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
111 getter_AddRefs(profileDir));
112 if (!profileDir) {
113 // This is too early on startup to create the hidden window
114 return NS_ERROR_FAILURE;
117 nsresult rv;
118 int32_t initialHeight = 100, initialWidth = 100;
120 #ifdef XP_MACOSX
121 uint32_t chromeMask = 0;
122 nsAutoCString prefVal;
123 rv = Preferences::GetCString("browser.hiddenWindowChromeURL", prefVal);
124 const char* hiddenWindowURL =
125 NS_SUCCEEDED(rv) ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
126 mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
127 #else
128 static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
129 uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL;
130 #endif
132 nsCOMPtr<nsIURI> url;
133 rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
134 NS_ENSURE_SUCCESS(rv, rv);
136 RefPtr<AppWindow> newWindow;
137 rv = JustCreateTopWindow(nullptr, url, chromeMask, initialWidth,
138 initialHeight, true, getter_AddRefs(newWindow));
139 NS_ENSURE_SUCCESS(rv, rv);
141 nsCOMPtr<nsIDocShell> docShell;
142 newWindow->GetDocShell(getter_AddRefs(docShell));
143 if (docShell) {
144 Unused << docShell->GetBrowsingContext()->SetExplicitActive(
145 dom::ExplicitActiveStatus::Inactive);
148 mHiddenWindow.swap(newWindow);
150 return NS_OK;
153 NS_IMETHODIMP
154 nsAppShellService::DestroyHiddenWindow() {
155 if (mHiddenWindow) {
156 mHiddenWindow->Destroy();
158 mHiddenWindow = nullptr;
161 return NS_OK;
165 * Create a new top level window and display the given URL within it...
167 NS_IMETHODIMP
168 nsAppShellService::CreateTopLevelWindow(nsIAppWindow* aParent, nsIURI* aUrl,
169 uint32_t aChromeMask,
170 int32_t aInitialWidth,
171 int32_t aInitialHeight,
172 nsIAppWindow** aResult) {
173 nsresult rv;
175 StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
177 RefPtr<AppWindow> newWindow;
178 rv = JustCreateTopWindow(aParent, aUrl, aChromeMask, aInitialWidth,
179 aInitialHeight, false, getter_AddRefs(newWindow));
180 newWindow.forget(aResult);
182 if (NS_SUCCEEDED(rv)) {
183 // the addref resulting from this is the owning addref for this window
184 RegisterTopLevelWindow(*aResult);
185 nsCOMPtr<nsIAppWindow> parent;
186 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) parent = aParent;
187 (*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
190 return rv;
194 * This class provides a stub implementation of nsIWebBrowserChrome, as needed
195 * by nsAppShellService::CreateWindowlessBrowser
197 class WebBrowserChrome2Stub final : public nsIWebBrowserChrome,
198 public nsIInterfaceRequestor,
199 public nsSupportsWeakReference {
200 protected:
201 nsCOMPtr<nsIWebBrowser> mBrowser;
202 virtual ~WebBrowserChrome2Stub() = default;
204 public:
205 void SetBrowser(nsIWebBrowser* aBrowser) { mBrowser = aBrowser; }
207 NS_DECL_ISUPPORTS
208 NS_DECL_NSIWEBBROWSERCHROME
209 NS_DECL_NSIINTERFACEREQUESTOR
212 NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
213 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
214 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
215 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
216 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
217 NS_INTERFACE_MAP_END
219 NS_IMPL_ADDREF(WebBrowserChrome2Stub)
220 NS_IMPL_RELEASE(WebBrowserChrome2Stub)
222 NS_IMETHODIMP
223 WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags) {
224 *aChromeFlags = 0;
225 return NS_OK;
228 NS_IMETHODIMP
229 WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags) {
230 MOZ_ASSERT_UNREACHABLE(
231 "WebBrowserChrome2Stub::SetChromeFlags is "
232 "not supported");
233 return NS_ERROR_NOT_IMPLEMENTED;
236 NS_IMETHODIMP
237 WebBrowserChrome2Stub::ShowAsModal() {
238 MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::ShowAsModal is not supported");
239 return NS_ERROR_NOT_IMPLEMENTED;
242 NS_IMETHODIMP
243 WebBrowserChrome2Stub::IsWindowModal(bool* aResult) {
244 *aResult = false;
245 return NS_OK;
248 NS_IMETHODIMP
249 WebBrowserChrome2Stub::SetLinkStatus(const nsAString& aStatusText) {
250 return NS_OK;
253 NS_IMETHODIMP
254 WebBrowserChrome2Stub::GetInterface(const nsIID& aIID, void** aSink) {
255 return QueryInterface(aIID, aSink);
258 NS_IMETHODIMP
259 WebBrowserChrome2Stub::GetDimensions(DimensionKind aDimensionKind, int32_t* aX,
260 int32_t* aY, int32_t* aCX, int32_t* aCY) {
261 if (aX) {
262 *aX = 0;
264 if (aY) {
265 *aY = 0;
267 if (aCX) {
268 *aCX = 0;
270 if (aCY) {
271 *aCY = 0;
273 return NS_OK;
276 NS_IMETHODIMP
277 WebBrowserChrome2Stub::SetDimensions(DimensionRequest&& aRequest) {
278 nsCOMPtr<nsIBaseWindow> window(do_QueryInterface(mBrowser));
279 NS_ENSURE_STATE(window);
280 // Inner and outer dimensions are equal.
281 aRequest.mDimensionKind = DimensionKind::Outer;
282 MOZ_TRY(aRequest.SupplementFrom(window));
283 return aRequest.ApplyOuterTo(window);
286 NS_IMETHODIMP
287 WebBrowserChrome2Stub::Blur() { return NS_ERROR_NOT_IMPLEMENTED; }
289 class BrowserDestroyer final : public Runnable {
290 public:
291 BrowserDestroyer(nsIWebBrowser* aBrowser, nsISupports* aContainer)
292 : mozilla::Runnable("BrowserDestroyer"),
293 mBrowser(aBrowser),
294 mContainer(aContainer) {}
296 static nsresult Destroy(nsIWebBrowser* aBrowser) {
297 nsCOMPtr<nsIBaseWindow> window(do_QueryInterface(aBrowser));
298 return window->Destroy();
301 NS_IMETHOD
302 Run() override {
303 // Explicitly destroy the browser, in case this isn't the last reference.
304 return Destroy(mBrowser);
307 protected:
308 virtual ~BrowserDestroyer() {}
310 private:
311 nsCOMPtr<nsIWebBrowser> mBrowser;
312 nsCOMPtr<nsISupports> mContainer;
315 // This is the "stub" we return from CreateWindowlessBrowser - it exists
316 // to manage the lifetimes of the nsIWebBrowser and container window.
317 // In particular, it keeps a strong reference to both, to prevent them from
318 // being collected while this object remains alive, and ensures that they
319 // aren't destroyed when it's not safe to run scripts.
320 class WindowlessBrowser final : public nsIWindowlessBrowser,
321 public nsIInterfaceRequestor {
322 public:
323 WindowlessBrowser(nsIWebBrowser* aBrowser, nsISupports* aContainer)
324 : mBrowser(aBrowser), mContainer(aContainer), mClosed(false) {
325 mWebNavigation = do_QueryInterface(aBrowser);
326 mInterfaceRequestor = do_QueryInterface(aBrowser);
328 NS_DECL_ISUPPORTS
329 NS_DECL_NSIWINDOWLESSBROWSER
330 NS_FORWARD_SAFE_NSIWEBNAVIGATION(mWebNavigation)
331 NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor)
333 private:
334 ~WindowlessBrowser() {
335 if (mClosed) {
336 return;
339 NS_WARNING("Windowless browser was not closed prior to destruction");
341 // The docshell destructor needs to dispatch events, and can only run
342 // when it's safe to run scripts. If this was triggered by GC, it may
343 // not always be safe to run scripts, in which cases we need to delay
344 // destruction until it is.
345 auto runnable = MakeRefPtr<BrowserDestroyer>(mBrowser, mContainer);
346 nsContentUtils::AddScriptRunner(runnable.forget());
349 nsCOMPtr<nsIWebBrowser> mBrowser;
350 nsCOMPtr<nsIWebNavigation> mWebNavigation;
351 nsCOMPtr<nsIInterfaceRequestor> mInterfaceRequestor;
352 // we don't use the container but just hold a reference to it.
353 nsCOMPtr<nsISupports> mContainer;
355 bool mClosed;
358 NS_IMPL_ISUPPORTS(WindowlessBrowser, nsIWindowlessBrowser, nsIWebNavigation,
359 nsIInterfaceRequestor)
361 NS_IMETHODIMP
362 WindowlessBrowser::Close() {
363 NS_ENSURE_TRUE(!mClosed, NS_ERROR_UNEXPECTED);
364 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
365 "WindowlessBrowser::Close called when not safe to run scripts");
367 mClosed = true;
369 mWebNavigation = nullptr;
370 mInterfaceRequestor = nullptr;
371 return BrowserDestroyer::Destroy(mBrowser);
374 NS_IMETHODIMP
375 WindowlessBrowser::GetBrowsingContext(BrowsingContext** aBrowsingContext) {
376 nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(mBrowser);
377 if (!docShellTreeItem) {
378 return NS_ERROR_NOT_INITIALIZED;
380 return docShellTreeItem->GetBrowsingContextXPCOM(aBrowsingContext);
383 NS_IMETHODIMP
384 WindowlessBrowser::GetDocShell(nsIDocShell** aDocShell) {
385 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mInterfaceRequestor);
386 if (!docShell) {
387 return NS_ERROR_NOT_INITIALIZED;
389 docShell.forget(aDocShell);
390 return NS_OK;
393 NS_IMETHODIMP
394 nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, uint32_t aChromeMask,
395 nsIWindowlessBrowser** aResult) {
396 if (aChromeMask) {
397 MOZ_DIAGNOSTIC_ASSERT(aIsChrome, "Got chrome flags for non-chrome browser");
398 if (aChromeMask & ~(nsIWebBrowserChrome::CHROME_REMOTE_WINDOW |
399 nsIWebBrowserChrome::CHROME_FISSION_WINDOW |
400 nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW)) {
401 NS_ERROR("Received unexpected chrome flags");
402 return NS_ERROR_FAILURE;
406 /* First, we set the container window for our instance of nsWebBrowser. Since
407 * we don't actually have a window, we instead set the container window to be
408 * an instance of WebBrowserChrome2Stub, which provides a stub implementation
409 * of nsIWebBrowserChrome.
411 RefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub();
413 /* A windowless web browser doesn't have an associated OS level window. To
414 * accomplish this, we initialize the window associated with our instance of
415 * nsWebBrowser with an instance of HeadlessWidget/PuppetWidget, which provide
416 * a stub implementation of nsIWidget.
418 nsCOMPtr<nsIWidget> widget;
419 if (gfxPlatform::IsHeadless()) {
420 widget = nsIWidget::CreateHeadlessWidget();
421 } else {
422 widget = nsIWidget::CreatePuppetWidget(nullptr);
424 if (!widget) {
425 NS_ERROR("Couldn't create instance of stub widget");
426 return NS_ERROR_FAILURE;
429 nsresult rv =
430 widget->Create(nullptr, 0, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
431 NS_ENSURE_SUCCESS(rv, rv);
433 // Create a BrowsingContext for our windowless browser.
434 RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateIndependent(
435 aIsChrome ? BrowsingContext::Type::Chrome
436 : BrowsingContext::Type::Content);
438 if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
439 browsingContext->SetRemoteTabs(true);
441 if (aChromeMask & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) {
442 browsingContext->SetRemoteSubframes(true);
444 if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
445 browsingContext->SetPrivateBrowsing(true);
448 /* Next, we create an instance of nsWebBrowser. Instances of this class have
449 * an associated doc shell, which is what we're interested in.
451 nsCOMPtr<nsIWebBrowser> browser = nsWebBrowser::Create(
452 stub, widget, browsingContext, nullptr /* initialWindowChild */);
454 if (NS_WARN_IF(!browser)) {
455 NS_ERROR("Couldn't create instance of nsWebBrowser!");
456 return NS_ERROR_FAILURE;
459 // Make sure the container window owns the the nsWebBrowser instance.
460 stub->SetBrowser(browser);
462 nsISupports* isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome*, stub);
463 RefPtr<nsIWindowlessBrowser> result = new WindowlessBrowser(browser, isstub);
464 nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
465 docshell->SetInvisible(true);
467 result.forget(aResult);
468 return NS_OK;
471 uint32_t nsAppShellService::CalculateWindowZLevel(nsIAppWindow* aParent,
472 uint32_t aChromeMask) {
473 uint32_t zLevel;
475 zLevel = nsIAppWindow::normalZ;
476 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
477 zLevel = nsIAppWindow::raisedZ;
478 else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
479 zLevel = nsIAppWindow::loweredZ;
481 #ifdef XP_MACOSX
482 /* Platforms on which modal windows are always application-modal, not
483 window-modal (that's just the Mac, right?) want modal windows to
484 be stacked on top of everyone else.
486 On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
488 uint32_t modalDepMask =
489 nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT;
490 if (aParent && (aChromeMask & modalDepMask)) {
491 aParent->GetZLevel(&zLevel);
493 #else
494 /* Platforms with native support for dependent windows (that's everyone
495 but pre-Mac OS X, right?) know how to stack dependent windows. On these
496 platforms, give the dependent window the same level as its parent,
497 so we won't try to override the normal platform behaviour. */
498 if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent) {
499 aParent->GetZLevel(&zLevel);
501 #endif
503 return zLevel;
507 * Just do the window-making part of CreateTopLevelWindow
509 nsresult nsAppShellService::JustCreateTopWindow(
510 nsIAppWindow* aParent, nsIURI* aUrl, uint32_t aChromeMask,
511 int32_t aInitialWidth, int32_t aInitialHeight, bool aIsHiddenWindow,
512 AppWindow** aResult) {
513 using BorderStyle = widget::BorderStyle;
514 *aResult = nullptr;
515 NS_ENSURE_STATE(!mXPCOMWillShutDown);
517 nsCOMPtr<nsIAppWindow> parent;
518 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) parent = aParent;
520 RefPtr<AppWindow> window = new AppWindow(aChromeMask);
522 #ifdef XP_WIN
523 // If the parent is currently fullscreen, tell the child to ignore persisted
524 // full screen states. This way new browser windows open on top of fullscreen
525 // windows normally.
526 if (nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(aParent)) {
527 nsCOMPtr<nsIWidget> widget;
528 baseWin->GetMainWidget(getter_AddRefs(widget));
529 if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) {
530 window->IgnoreXULSizeMode(true);
533 #endif
535 widget::InitData widgetInitData;
536 if (aIsHiddenWindow) {
537 widgetInitData.mWindowType = widget::WindowType::Invisible;
538 } else {
539 widgetInitData.mWindowType =
540 aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
541 ? widget::WindowType::Dialog
542 : widget::WindowType::TopLevel;
545 if (aChromeMask & nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION) {
546 widgetInitData.mIsAnimationSuppressed = true;
549 if (aChromeMask & nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP) {
550 widgetInitData.mAlwaysOnTop = true;
553 if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
554 widgetInitData.mHasRemoteContent = true;
557 #if defined(MOZ_WIDGET_GTK) || defined(XP_WIN)
558 // Windows/Gtk PIP window support. It's Chrome dialog window, always on top
559 // and without any bar.
560 uint32_t pipMask = nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP |
561 nsIWebBrowserChrome::CHROME_OPENAS_CHROME |
562 nsIWebBrowserChrome::CHROME_WINDOW_RESIZE;
563 uint32_t barMask = nsIWebBrowserChrome::CHROME_MENUBAR |
564 nsIWebBrowserChrome::CHROME_TOOLBAR |
565 nsIWebBrowserChrome::CHROME_LOCATIONBAR |
566 nsIWebBrowserChrome::CHROME_TITLEBAR |
567 nsIWebBrowserChrome::CHROME_STATUSBAR;
568 if (widgetInitData.mWindowType == widget::WindowType::Dialog &&
569 ((aChromeMask & pipMask) == pipMask) && !(aChromeMask & barMask)) {
570 widgetInitData.mPIPWindow = true;
572 #endif
574 // alert=yes is expected to be used along with dialogs, not other window
575 // types.
576 MOZ_ASSERT_IF(aChromeMask & nsIWebBrowserChrome::CHROME_ALERT,
577 widgetInitData.mWindowType == widget::WindowType::Dialog);
578 widgetInitData.mIsAlert =
579 !!(aChromeMask & nsIWebBrowserChrome::CHROME_ALERT) &&
580 widgetInitData.mWindowType == widget::WindowType::Dialog;
582 #if defined(XP_WIN)
583 if (widgetInitData.mWindowType == widget::WindowType::TopLevel ||
584 widgetInitData.mWindowType == widget::WindowType::Dialog) {
585 widgetInitData.mClipChildren = true;
587 #endif
589 // note default chrome overrides other OS chrome settings, but
590 // not internal chrome
591 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT) {
592 widgetInitData.mBorderStyle = BorderStyle::Default;
593 } else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) ==
594 nsIWebBrowserChrome::CHROME_ALL) {
595 widgetInitData.mBorderStyle = BorderStyle::All;
596 } else {
597 widgetInitData.mBorderStyle = BorderStyle::None; // assumes none == 0x00
598 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS) {
599 widgetInitData.mBorderStyle |= BorderStyle::Border;
601 if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR) {
602 widgetInitData.mBorderStyle |= BorderStyle::Title;
604 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE) {
605 widgetInitData.mBorderStyle |= BorderStyle::Close;
607 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
608 widgetInitData.mResizable = true;
609 widgetInitData.mBorderStyle |= BorderStyle::ResizeH;
610 // only resizable windows get the maximize button (but not dialogs)
611 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG)) {
612 widgetInitData.mBorderStyle |= BorderStyle::Maximize;
615 // all windows (except dialogs) get minimize buttons and the system menu
616 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG)) {
617 widgetInitData.mBorderStyle |= BorderStyle::Minimize | BorderStyle::Menu;
619 // but anyone can explicitly ask for a minimize button
620 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MINIMIZE) {
621 widgetInitData.mBorderStyle |= BorderStyle::Minimize;
625 if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
626 aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
627 aInitialWidth = 1;
628 aInitialHeight = 1;
629 window->SetIntrinsicallySized(true);
632 bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
634 widgetInitData.mRTL = LocaleService::GetInstance()->IsAppLocaleRTL();
636 // Enforce the Private Browsing autoStart pref first.
637 bool isPrivateBrowsingWindow =
638 StaticPrefs::browser_privatebrowsing_autostart();
639 if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
640 // Caller requested a private window
641 isPrivateBrowsingWindow = true;
643 widgetInitData.mIsPrivate = isPrivateBrowsingWindow;
645 nsresult rv =
646 window->Initialize(parent, center ? aParent : nullptr, aInitialWidth,
647 aInitialHeight, aIsHiddenWindow, widgetInitData);
649 NS_ENSURE_SUCCESS(rv, rv);
651 nsCOMPtr<mozIDOMWindowProxy> domWin = do_GetInterface(aParent);
652 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(domWin);
653 nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(webNav);
655 if (!isPrivateBrowsingWindow && parentContext) {
656 // Ensure that we propagate any existing private browsing status
657 // from the parent, even if it will not actually be used
658 // as a parent value.
659 isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
662 if (RefPtr<nsDocShell> docShell = window->GetDocShell()) {
663 MOZ_ASSERT(docShell->GetBrowsingContext()->IsChrome());
665 docShell->SetPrivateBrowsing(isPrivateBrowsingWindow);
666 docShell->SetRemoteTabs(aChromeMask &
667 nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
668 docShell->SetRemoteSubframes(aChromeMask &
669 nsIWebBrowserChrome::CHROME_FISSION_WINDOW);
671 // Eagerly create an about:blank content viewer with the right principal
672 // here, rather than letting it happen in the upcoming call to
673 // SetInitialPrincipal. This avoids creating the about:blank document and
674 // then blowing it away with a second one, which can cause problems for the
675 // top-level chrome window case. See bug 789773.
676 // Toplevel chrome windows always have a system principal, so ensure the
677 // initial window is created with that principal.
678 // We need to do this even when creating a chrome window to load a content
679 // window, see bug 799348 comment 13 for details about what previously
680 // happened here due to it using the subject principal.
681 if (nsContentUtils::IsInitialized()) { // Sometimes this happens really
682 // early. See bug 793370.
683 MOZ_DIAGNOSTIC_ASSERT(
684 nsContentUtils::LegacyIsCallerChromeOrNativeCode(),
685 "Previously, this method would use the subject principal rather than "
686 "hardcoding the system principal");
687 // Use the system principal as the storage principal too until the new
688 // window finishes navigating and gets a real storage principal.
689 rv = docShell->CreateAboutBlankDocumentViewer(
690 nsContentUtils::GetSystemPrincipal(),
691 nsContentUtils::GetSystemPrincipal(),
692 /* aCsp = */ nullptr, /* aBaseURI = */ nullptr,
693 /* aIsInitialDocument = */ true);
694 NS_ENSURE_SUCCESS(rv, rv);
695 RefPtr<dom::Document> doc = docShell->GetDocument();
696 NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
697 MOZ_ASSERT(doc->IsInitialDocument(),
698 "Document should be an initial document");
701 // Begin loading the URL provided.
702 if (aUrl) {
703 RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aUrl);
704 loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
705 loadState->SetFirstParty(true);
706 rv = docShell->LoadURI(loadState, /* aSetNavigating */ true);
707 NS_ENSURE_SUCCESS(rv, rv);
711 window.forget(aResult);
713 if (center) rv = (*aResult)->Center(parent, parent ? false : true, false);
715 return rv;
718 NS_IMETHODIMP
719 nsAppShellService::GetHiddenWindow(nsIAppWindow** aWindow) {
720 NS_ENSURE_ARG_POINTER(aWindow);
722 EnsureHiddenWindow();
724 *aWindow = mHiddenWindow;
725 NS_IF_ADDREF(*aWindow);
726 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
729 NS_IMETHODIMP
730 nsAppShellService::GetHiddenDOMWindow(mozIDOMWindowProxy** aWindow) {
731 NS_ENSURE_ARG_POINTER(aWindow);
733 EnsureHiddenWindow();
735 nsresult rv;
736 nsCOMPtr<nsIDocShell> docShell;
737 NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
739 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
740 NS_ENSURE_SUCCESS(rv, rv);
741 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
743 nsCOMPtr<nsPIDOMWindowOuter> hiddenDOMWindow(docShell->GetWindow());
744 hiddenDOMWindow.forget(aWindow);
745 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
748 NS_IMETHODIMP
749 nsAppShellService::GetHasHiddenWindow(bool* aHasHiddenWindow) {
750 NS_ENSURE_ARG_POINTER(aHasHiddenWindow);
752 *aHasHiddenWindow = !!mHiddenWindow;
753 return NS_OK;
756 NS_IMETHODIMP
757 nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW) {
758 *aAPHW = mApplicationProvidedHiddenWindow;
759 return NS_OK;
763 * Register a new top level window (created elsewhere)
765 NS_IMETHODIMP
766 nsAppShellService::RegisterTopLevelWindow(nsIAppWindow* aWindow) {
767 NS_ENSURE_ARG_POINTER(aWindow);
769 nsCOMPtr<nsIDocShell> docShell;
770 aWindow->GetDocShell(getter_AddRefs(docShell));
771 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
773 nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
774 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
776 // Toplevel chrome windows always have a system principal, so ensure the
777 // initial window is created with that principal.
778 // We need to do this even when creating a chrome window to load a content
779 // window, see bug 799348 comment 13 for details about what previously
780 // happened here due to it using the subject principal.
781 MOZ_DIAGNOSTIC_ASSERT(
782 nsContentUtils::LegacyIsCallerChromeOrNativeCode(),
783 "Previously, this method would use the subject principal rather than "
784 "hardcoding the system principal");
785 domWindow->SetInitialPrincipal(nsContentUtils::GetSystemPrincipal(), nullptr,
786 Nothing());
788 // tell the window mediator about the new window
789 nsCOMPtr<nsIWindowMediator> mediator(
790 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
791 NS_ASSERTION(mediator, "Couldn't get window mediator.");
793 if (mediator) mediator->RegisterWindow(aWindow);
795 // tell the window watcher about the new window
796 nsCOMPtr<nsPIWindowWatcher> wwatcher(
797 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
798 NS_ASSERTION(wwatcher, "No windowwatcher?");
799 if (wwatcher && domWindow) {
800 wwatcher->AddWindow(domWindow, 0);
803 // an ongoing attempt to quit is stopped by a newly opened window
804 nsCOMPtr<nsIObserverService> obssvc = services::GetObserverService();
805 NS_ASSERTION(obssvc, "Couldn't get observer service.");
807 if (obssvc) {
808 obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
809 AppWindow* appWindow = static_cast<AppWindow*>(aWindow);
810 appWindow->WasRegistered();
813 return NS_OK;
816 NS_IMETHODIMP
817 nsAppShellService::UnregisterTopLevelWindow(nsIAppWindow* aWindow) {
818 if (mXPCOMShuttingDown) {
819 /* return an error code in order to:
820 - avoid doing anything with other member variables while we are in
821 the destructor
822 - notify the caller not to release the AppShellService after
823 unregistering the window
824 (we don't want to be deleted twice consecutively to
825 mHiddenWindow->Destroy() in our destructor)
827 return NS_ERROR_FAILURE;
830 NS_ENSURE_ARG_POINTER(aWindow);
832 if (aWindow == mHiddenWindow) {
833 // CreateHiddenWindow() does not register the window, so we're done.
834 return NS_OK;
837 // tell the window mediator
838 nsCOMPtr<nsIWindowMediator> mediator(
839 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
840 NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
842 if (mediator) mediator->UnregisterWindow(aWindow);
844 // tell the window watcher
845 nsCOMPtr<nsPIWindowWatcher> wwatcher(
846 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
847 NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
848 if (wwatcher) {
849 nsCOMPtr<nsIDocShell> docShell;
850 aWindow->GetDocShell(getter_AddRefs(docShell));
851 if (docShell) {
852 nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
853 if (domWindow) wwatcher->RemoveWindow(domWindow);
857 return NS_OK;
860 NS_IMETHODIMP
861 nsAppShellService::Observe(nsISupports* aSubject, const char* aTopic,
862 const char16_t* aData) {
863 if (!strcmp(aTopic, "xpcom-will-shutdown")) {
864 mXPCOMWillShutDown = true;
865 } else if (!strcmp(aTopic, "xpcom-shutdown")) {
866 mXPCOMShuttingDown = true;
867 if (mHiddenWindow) {
868 mHiddenWindow->Destroy();
870 } else {
871 NS_ERROR("Unexpected observer topic!");
874 return NS_OK;
877 NS_IMETHODIMP
878 nsAppShellService::StartEventLoopLagTracking(bool* aResult) {
879 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
880 *aResult = mozilla::InitEventTracing(true);
881 #endif
882 return NS_OK;
885 NS_IMETHODIMP
886 nsAppShellService::StopEventLoopLagTracking() {
887 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
888 mozilla::ShutdownEventTracing();
889 #endif
890 return NS_OK;