Bug 1883867 [wpt PR 44930] - Update wpt metadata, a=testonly
[gecko.git] / xpfe / appshell / nsAppShellService.cpp
blob1ac989aaa3265c36f581e9d573b55378c55e95c8
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 #ifdef XP_MACOSX
583 // Mac OS X sheet support
584 // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
585 // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
586 // windows opened from nsPromptService::DoDialog() still are sheets. This
587 // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
588 // nsCocoaWindow::SetModal()).
589 uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
590 nsIWebBrowserChrome::CHROME_MODAL |
591 nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
592 if (parent && (parent != mHiddenWindow) &&
593 ((aChromeMask & sheetMask) == sheetMask)) {
594 widgetInitData.mWindowType = widget::WindowType::Sheet;
596 #endif
598 #if defined(XP_WIN)
599 if (widgetInitData.mWindowType == widget::WindowType::TopLevel ||
600 widgetInitData.mWindowType == widget::WindowType::Dialog)
601 widgetInitData.mClipChildren = true;
602 #endif
604 // note default chrome overrides other OS chrome settings, but
605 // not internal chrome
606 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT) {
607 widgetInitData.mBorderStyle = BorderStyle::Default;
608 } else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) ==
609 nsIWebBrowserChrome::CHROME_ALL) {
610 widgetInitData.mBorderStyle = BorderStyle::All;
611 } else {
612 widgetInitData.mBorderStyle = BorderStyle::None; // assumes none == 0x00
613 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS) {
614 widgetInitData.mBorderStyle |= BorderStyle::Border;
616 if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR) {
617 widgetInitData.mBorderStyle |= BorderStyle::Title;
619 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE) {
620 widgetInitData.mBorderStyle |= BorderStyle::Close;
622 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
623 widgetInitData.mResizable = true;
624 widgetInitData.mBorderStyle |= BorderStyle::ResizeH;
625 // only resizable windows get the maximize button (but not dialogs)
626 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG)) {
627 widgetInitData.mBorderStyle |= BorderStyle::Maximize;
630 // all windows (except dialogs) get minimize buttons and the system menu
631 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG)) {
632 widgetInitData.mBorderStyle |= BorderStyle::Minimize | BorderStyle::Menu;
634 // but anyone can explicitly ask for a minimize button
635 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MINIMIZE) {
636 widgetInitData.mBorderStyle |= BorderStyle::Minimize;
640 if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
641 aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
642 aInitialWidth = 1;
643 aInitialHeight = 1;
644 window->SetIntrinsicallySized(true);
647 bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
649 widgetInitData.mRTL = LocaleService::GetInstance()->IsAppLocaleRTL();
651 // Enforce the Private Browsing autoStart pref first.
652 bool isPrivateBrowsingWindow =
653 StaticPrefs::browser_privatebrowsing_autostart();
654 if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
655 // Caller requested a private window
656 isPrivateBrowsingWindow = true;
658 widgetInitData.mIsPrivate = isPrivateBrowsingWindow;
660 nsresult rv =
661 window->Initialize(parent, center ? aParent : nullptr, aInitialWidth,
662 aInitialHeight, aIsHiddenWindow, widgetInitData);
664 NS_ENSURE_SUCCESS(rv, rv);
666 nsCOMPtr<mozIDOMWindowProxy> domWin = do_GetInterface(aParent);
667 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(domWin);
668 nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(webNav);
670 if (!isPrivateBrowsingWindow && parentContext) {
671 // Ensure that we propagate any existing private browsing status
672 // from the parent, even if it will not actually be used
673 // as a parent value.
674 isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
677 if (RefPtr<nsDocShell> docShell = window->GetDocShell()) {
678 MOZ_ASSERT(docShell->GetBrowsingContext()->IsChrome());
680 docShell->SetPrivateBrowsing(isPrivateBrowsingWindow);
681 docShell->SetRemoteTabs(aChromeMask &
682 nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
683 docShell->SetRemoteSubframes(aChromeMask &
684 nsIWebBrowserChrome::CHROME_FISSION_WINDOW);
686 // Eagerly create an about:blank content viewer with the right principal
687 // here, rather than letting it happen in the upcoming call to
688 // SetInitialPrincipal. This avoids creating the about:blank document and
689 // then blowing it away with a second one, which can cause problems for the
690 // top-level chrome window case. See bug 789773.
691 // Toplevel chrome windows always have a system principal, so ensure the
692 // initial window is created with that principal.
693 // We need to do this even when creating a chrome window to load a content
694 // window, see bug 799348 comment 13 for details about what previously
695 // happened here due to it using the subject principal.
696 if (nsContentUtils::IsInitialized()) { // Sometimes this happens really
697 // early. See bug 793370.
698 MOZ_DIAGNOSTIC_ASSERT(
699 nsContentUtils::LegacyIsCallerChromeOrNativeCode(),
700 "Previously, this method would use the subject principal rather than "
701 "hardcoding the system principal");
702 // Use the system principal as the storage principal too until the new
703 // window finishes navigating and gets a real storage principal.
704 rv = docShell->CreateAboutBlankDocumentViewer(
705 nsContentUtils::GetSystemPrincipal(),
706 nsContentUtils::GetSystemPrincipal(),
707 /* aCsp = */ nullptr, /* aBaseURI = */ nullptr,
708 /* aIsInitialDocument = */ true);
709 NS_ENSURE_SUCCESS(rv, rv);
710 RefPtr<dom::Document> doc = docShell->GetDocument();
711 NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
712 MOZ_ASSERT(doc->IsInitialDocument(),
713 "Document should be an initial document");
716 // Begin loading the URL provided.
717 if (aUrl) {
718 RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aUrl);
719 loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
720 loadState->SetFirstParty(true);
721 rv = docShell->LoadURI(loadState, /* aSetNavigating */ true);
722 NS_ENSURE_SUCCESS(rv, rv);
726 window.forget(aResult);
728 if (center) rv = (*aResult)->Center(parent, parent ? false : true, false);
730 return rv;
733 NS_IMETHODIMP
734 nsAppShellService::GetHiddenWindow(nsIAppWindow** aWindow) {
735 NS_ENSURE_ARG_POINTER(aWindow);
737 EnsureHiddenWindow();
739 *aWindow = mHiddenWindow;
740 NS_IF_ADDREF(*aWindow);
741 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
744 NS_IMETHODIMP
745 nsAppShellService::GetHiddenDOMWindow(mozIDOMWindowProxy** aWindow) {
746 NS_ENSURE_ARG_POINTER(aWindow);
748 EnsureHiddenWindow();
750 nsresult rv;
751 nsCOMPtr<nsIDocShell> docShell;
752 NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
754 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
755 NS_ENSURE_SUCCESS(rv, rv);
756 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
758 nsCOMPtr<nsPIDOMWindowOuter> hiddenDOMWindow(docShell->GetWindow());
759 hiddenDOMWindow.forget(aWindow);
760 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
763 NS_IMETHODIMP
764 nsAppShellService::GetHasHiddenWindow(bool* aHasHiddenWindow) {
765 NS_ENSURE_ARG_POINTER(aHasHiddenWindow);
767 *aHasHiddenWindow = !!mHiddenWindow;
768 return NS_OK;
771 NS_IMETHODIMP
772 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(nsIAppWindow* aWindow) {
782 NS_ENSURE_ARG_POINTER(aWindow);
784 nsCOMPtr<nsIDocShell> docShell;
785 aWindow->GetDocShell(getter_AddRefs(docShell));
786 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
788 nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
789 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
791 // Toplevel chrome windows always have a system principal, so ensure the
792 // initial window is created with that principal.
793 // We need to do this even when creating a chrome window to load a content
794 // window, see bug 799348 comment 13 for details about what previously
795 // happened here due to it using the subject principal.
796 MOZ_DIAGNOSTIC_ASSERT(
797 nsContentUtils::LegacyIsCallerChromeOrNativeCode(),
798 "Previously, this method would use the subject principal rather than "
799 "hardcoding the system principal");
800 domWindow->SetInitialPrincipal(nsContentUtils::GetSystemPrincipal(), nullptr,
801 Nothing());
803 // tell the window mediator about the new window
804 nsCOMPtr<nsIWindowMediator> mediator(
805 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
806 NS_ASSERTION(mediator, "Couldn't get window mediator.");
808 if (mediator) mediator->RegisterWindow(aWindow);
810 // tell the window watcher about the new window
811 nsCOMPtr<nsPIWindowWatcher> wwatcher(
812 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
813 NS_ASSERTION(wwatcher, "No windowwatcher?");
814 if (wwatcher && domWindow) {
815 wwatcher->AddWindow(domWindow, 0);
818 // an ongoing attempt to quit is stopped by a newly opened window
819 nsCOMPtr<nsIObserverService> obssvc = services::GetObserverService();
820 NS_ASSERTION(obssvc, "Couldn't get observer service.");
822 if (obssvc) {
823 obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
824 AppWindow* appWindow = static_cast<AppWindow*>(aWindow);
825 appWindow->WasRegistered();
828 return NS_OK;
831 NS_IMETHODIMP
832 nsAppShellService::UnregisterTopLevelWindow(nsIAppWindow* aWindow) {
833 if (mXPCOMShuttingDown) {
834 /* return an error code in order to:
835 - avoid doing anything with other member variables while we are in
836 the destructor
837 - notify the caller not to release the AppShellService after
838 unregistering the window
839 (we don't want to be deleted twice consecutively to
840 mHiddenWindow->Destroy() in our destructor)
842 return NS_ERROR_FAILURE;
845 NS_ENSURE_ARG_POINTER(aWindow);
847 if (aWindow == mHiddenWindow) {
848 // CreateHiddenWindow() does not register the window, so we're done.
849 return NS_OK;
852 // tell the window mediator
853 nsCOMPtr<nsIWindowMediator> mediator(
854 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
855 NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
857 if (mediator) mediator->UnregisterWindow(aWindow);
859 // tell the window watcher
860 nsCOMPtr<nsPIWindowWatcher> wwatcher(
861 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
862 NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
863 if (wwatcher) {
864 nsCOMPtr<nsIDocShell> docShell;
865 aWindow->GetDocShell(getter_AddRefs(docShell));
866 if (docShell) {
867 nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
868 if (domWindow) wwatcher->RemoveWindow(domWindow);
872 return NS_OK;
875 NS_IMETHODIMP
876 nsAppShellService::Observe(nsISupports* aSubject, const char* aTopic,
877 const char16_t* aData) {
878 if (!strcmp(aTopic, "xpcom-will-shutdown")) {
879 mXPCOMWillShutDown = true;
880 } else if (!strcmp(aTopic, "xpcom-shutdown")) {
881 mXPCOMShuttingDown = true;
882 if (mHiddenWindow) {
883 mHiddenWindow->Destroy();
885 } else {
886 NS_ERROR("Unexpected observer topic!");
889 return NS_OK;
892 NS_IMETHODIMP
893 nsAppShellService::StartEventLoopLagTracking(bool* aResult) {
894 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
895 *aResult = mozilla::InitEventTracing(true);
896 #endif
897 return NS_OK;
900 NS_IMETHODIMP
901 nsAppShellService::StopEventLoopLagTracking() {
902 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
903 mozilla::ShutdownEventTracing();
904 #endif
905 return NS_OK;