Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsIAppShellService.h"
8 #include "nsIComponentManager.h"
9 #include "nsIURL.h"
10 #include "nsNetUtil.h"
11 #include "nsIServiceManager.h"
12 #include "nsIObserverService.h"
13 #include "nsIObserver.h"
14 #include "nsIXPConnect.h"
16 #include "nsIWindowMediator.h"
17 #include "nsIWindowWatcher.h"
18 #include "nsPIWindowWatcher.h"
19 #include "nsIDOMWindow.h"
20 #include "nsPIDOMWindow.h"
21 #include "nsWebShellWindow.h"
23 #include "nsCRT.h"
24 #include "prprf.h"
26 #include "nsWidgetInitData.h"
27 #include "nsWidgetsCID.h"
28 #include "nsIWidget.h"
29 #include "nsIRequestObserver.h"
31 /* For implementing GetHiddenWindowAndJSContext */
32 #include "nsIScriptGlobalObject.h"
33 #include "nsIScriptContext.h"
35 #include "nsAppShellService.h"
36 #include "nsISupportsPrimitives.h"
37 #include "nsIChromeRegistry.h"
38 #include "nsILoadContext.h"
39 #include "nsIWebNavigation.h"
41 #include "mozilla/Attributes.h"
42 #include "mozilla/Preferences.h"
43 #include "mozilla/StartupTimeline.h"
45 #include "nsEmbedCID.h"
46 #include "nsIWebBrowser.h"
47 #include "nsIDocShell.h"
49 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
50 #include "EventTracer.h"
51 #endif
53 using namespace mozilla;
55 // Default URL for the hidden window, can be overridden by a pref on Mac
56 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
58 class nsIAppShell;
60 nsAppShellService::nsAppShellService() :
61 mXPCOMWillShutDown(false),
62 mXPCOMShuttingDown(false),
63 mModalWindowCount(0),
64 mApplicationProvidedHiddenWindow(false)
65 {
66 nsCOMPtr<nsIObserverService> obs
67 (do_GetService("@mozilla.org/observer-service;1"));
69 if (obs) {
70 obs->AddObserver(this, "xpcom-will-shutdown", false);
71 obs->AddObserver(this, "xpcom-shutdown", false);
72 }
73 }
75 nsAppShellService::~nsAppShellService()
76 {
77 }
80 /*
81 * Implement the nsISupports methods...
82 */
83 NS_IMPL_ISUPPORTS(nsAppShellService,
84 nsIAppShellService,
85 nsIObserver)
87 NS_IMETHODIMP
88 nsAppShellService::CreateHiddenWindow()
89 {
90 return CreateHiddenWindowHelper(false);
91 }
93 void
94 nsAppShellService::EnsurePrivateHiddenWindow()
95 {
96 if (!mHiddenPrivateWindow) {
97 CreateHiddenWindowHelper(true);
98 }
99 }
101 nsresult
102 nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate)
103 {
104 nsresult rv;
105 int32_t initialHeight = 100, initialWidth = 100;
107 #ifdef XP_MACOSX
108 uint32_t chromeMask = 0;
109 nsAdoptingCString prefVal =
110 Preferences::GetCString("browser.hiddenWindowChromeURL");
111 const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
112 if (aIsPrivate) {
113 hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL;
114 } else {
115 mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
116 }
117 #else
118 static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
119 uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL;
120 #endif
122 nsCOMPtr<nsIURI> url;
123 rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
124 NS_ENSURE_SUCCESS(rv, rv);
126 nsRefPtr<nsWebShellWindow> newWindow;
127 if (!aIsPrivate) {
128 rv = JustCreateTopWindow(nullptr, url,
129 chromeMask, initialWidth, initialHeight,
130 true, getter_AddRefs(newWindow));
131 NS_ENSURE_SUCCESS(rv, rv);
133 mHiddenWindow.swap(newWindow);
134 } else {
135 // Create the hidden private window
136 chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
138 rv = JustCreateTopWindow(nullptr, url,
139 chromeMask, initialWidth, initialHeight,
140 true, getter_AddRefs(newWindow));
141 NS_ENSURE_SUCCESS(rv, rv);
143 nsCOMPtr<nsIDocShell> docShell;
144 newWindow->GetDocShell(getter_AddRefs(docShell));
145 if (docShell) {
146 docShell->SetAffectPrivateSessionLifetime(false);
147 }
149 mHiddenPrivateWindow.swap(newWindow);
150 }
152 // RegisterTopLevelWindow(newWindow); -- Mac only
154 return NS_OK;
155 }
157 NS_IMETHODIMP
158 nsAppShellService::DestroyHiddenWindow()
159 {
160 if (mHiddenWindow) {
161 mHiddenWindow->Destroy();
163 mHiddenWindow = nullptr;
164 }
166 if (mHiddenPrivateWindow) {
167 mHiddenPrivateWindow->Destroy();
169 mHiddenPrivateWindow = nullptr;
170 }
172 return NS_OK;
173 }
175 /*
176 * Create a new top level window and display the given URL within it...
177 */
178 NS_IMETHODIMP
179 nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent,
180 nsIURI *aUrl,
181 uint32_t aChromeMask,
182 int32_t aInitialWidth,
183 int32_t aInitialHeight,
184 nsIXULWindow **aResult)
186 {
187 nsresult rv;
189 StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
191 nsWebShellWindow *newWindow = nullptr;
192 rv = JustCreateTopWindow(aParent, aUrl,
193 aChromeMask, aInitialWidth, aInitialHeight,
194 false, &newWindow); // addrefs
196 *aResult = newWindow; // transfer ref
198 if (NS_SUCCEEDED(rv)) {
199 // the addref resulting from this is the owning addref for this window
200 RegisterTopLevelWindow(*aResult);
201 nsCOMPtr<nsIXULWindow> parent;
202 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
203 parent = aParent;
204 (*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
205 }
207 return rv;
208 }
210 /*
211 * This class provides a stub implementation of nsIWebBrowserChrome2, as needed
212 * by nsAppShellService::CreateWindowlessBrowser
213 */
214 class WebBrowserChrome2Stub : public nsIWebBrowserChrome2,
215 public nsIInterfaceRequestor,
216 public nsSupportsWeakReference {
217 public:
218 virtual ~WebBrowserChrome2Stub() {}
219 NS_DECL_ISUPPORTS
220 NS_DECL_NSIWEBBROWSERCHROME
221 NS_DECL_NSIWEBBROWSERCHROME2
222 NS_DECL_NSIINTERFACEREQUESTOR
223 };
225 NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
226 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
227 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
228 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
229 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
230 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
231 NS_INTERFACE_MAP_END
233 NS_IMPL_ADDREF(WebBrowserChrome2Stub)
234 NS_IMPL_RELEASE(WebBrowserChrome2Stub)
236 NS_IMETHODIMP
237 WebBrowserChrome2Stub::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
238 {
239 return NS_OK;
240 }
242 NS_IMETHODIMP
243 WebBrowserChrome2Stub::GetWebBrowser(nsIWebBrowser** aWebBrowser)
244 {
245 NS_NOTREACHED("WebBrowserChrome2Stub::GetWebBrowser is not supported");
246 return NS_ERROR_NOT_IMPLEMENTED;
247 }
249 NS_IMETHODIMP
250 WebBrowserChrome2Stub::SetWebBrowser(nsIWebBrowser* aWebBrowser)
251 {
252 NS_NOTREACHED("WebBrowserChrome2Stub::SetWebBrowser is not supported");
253 return NS_ERROR_NOT_IMPLEMENTED;
254 }
256 NS_IMETHODIMP
257 WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags)
258 {
259 *aChromeFlags = 0;
260 return NS_OK;
261 }
263 NS_IMETHODIMP
264 WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags)
265 {
266 NS_NOTREACHED("WebBrowserChrome2Stub::SetChromeFlags is not supported");
267 return NS_ERROR_NOT_IMPLEMENTED;
268 }
270 NS_IMETHODIMP
271 WebBrowserChrome2Stub::DestroyBrowserWindow()
272 {
273 NS_NOTREACHED("WebBrowserChrome2Stub::DestroyBrowserWindow is not supported");
274 return NS_ERROR_NOT_IMPLEMENTED;
275 }
277 NS_IMETHODIMP
278 WebBrowserChrome2Stub::SizeBrowserTo(int32_t aCX, int32_t aCY)
279 {
280 NS_NOTREACHED("WebBrowserChrome2Stub::SizeBrowserTo is not supported");
281 return NS_ERROR_NOT_IMPLEMENTED;
282 }
284 NS_IMETHODIMP
285 WebBrowserChrome2Stub::ShowAsModal()
286 {
287 NS_NOTREACHED("WebBrowserChrome2Stub::ShowAsModal is not supported");
288 return NS_ERROR_NOT_IMPLEMENTED;
289 }
291 NS_IMETHODIMP
292 WebBrowserChrome2Stub::IsWindowModal(bool* aResult)
293 {
294 *aResult = false;
295 return NS_OK;
296 }
298 NS_IMETHODIMP
299 WebBrowserChrome2Stub::ExitModalEventLoop(nsresult aStatus)
300 {
301 NS_NOTREACHED("WebBrowserChrome2Stub::ExitModalEventLoop is not supported");
302 return NS_ERROR_NOT_IMPLEMENTED;
303 }
305 NS_IMETHODIMP
306 WebBrowserChrome2Stub::SetStatusWithContext(uint32_t aStatusType,
307 const nsAString& aStatusText,
308 nsISupports* aStatusContext)
309 {
310 return NS_OK;
311 }
313 NS_IMETHODIMP
314 WebBrowserChrome2Stub::GetInterface(const nsIID & aIID, void **aSink)
315 {
316 return QueryInterface(aIID, aSink);
317 }
319 // This is the "stub" we return from CreateWindowlessBrowser - it exists
320 // purely to keep a strong reference to the browser and the container to
321 // prevent the container being collected while the stub remains alive.
322 class WindowlessBrowserStub MOZ_FINAL : public nsIWebNavigation,
323 public nsIInterfaceRequestor {
324 public:
325 WindowlessBrowserStub(nsIWebBrowser *aBrowser, nsISupports *aContainer) {
326 mBrowser = aBrowser;
327 mWebNavigation = do_QueryInterface(aBrowser);
328 mInterfaceRequestor = do_QueryInterface(aBrowser);
329 mContainer = aContainer;
330 }
331 NS_DECL_ISUPPORTS
332 NS_FORWARD_NSIWEBNAVIGATION(mWebNavigation->)
333 NS_FORWARD_NSIINTERFACEREQUESTOR(mInterfaceRequestor->)
334 private:
335 nsCOMPtr<nsIWebBrowser> mBrowser;
336 nsCOMPtr<nsIWebNavigation> mWebNavigation;
337 nsCOMPtr<nsIInterfaceRequestor> mInterfaceRequestor;
338 // we don't use the container but just hold a reference to it.
339 nsCOMPtr<nsISupports> mContainer;
340 };
342 NS_INTERFACE_MAP_BEGIN(WindowlessBrowserStub)
343 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebNavigation)
344 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
345 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
346 NS_INTERFACE_MAP_END
348 NS_IMPL_ADDREF(WindowlessBrowserStub)
349 NS_IMPL_RELEASE(WindowlessBrowserStub)
352 NS_IMETHODIMP
353 nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWebNavigation **aResult)
354 {
355 /* First, we create an instance of nsWebBrowser. Instances of this class have
356 * an associated doc shell, which is what we're interested in.
357 */
358 nsCOMPtr<nsIWebBrowser> browser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
359 if (!browser) {
360 NS_ERROR("Couldn't create instance of nsWebBrowser!");
361 return NS_ERROR_FAILURE;
362 }
364 /* Next, we set the container window for our instance of nsWebBrowser. Since
365 * we don't actually have a window, we instead set the container window to be
366 * an instance of WebBrowserChrome2Stub, which provides a stub implementation
367 * of nsIWebBrowserChrome2.
368 */
369 nsRefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub();
370 if (!stub) {
371 NS_ERROR("Couldn't create instance of WebBrowserChrome2Stub!");
372 return NS_ERROR_FAILURE;
373 }
374 browser->SetContainerWindow(stub);
376 nsCOMPtr<nsIWebNavigation> navigation = do_QueryInterface(browser);
378 nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(navigation);
379 item->SetItemType(aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
380 : nsIDocShellTreeItem::typeContentWrapper);
382 /* A windowless web browser doesn't have an associated OS level window. To
383 * accomplish this, we initialize the window associated with our instance of
384 * nsWebBrowser with an instance of PuppetWidget, which provides a stub
385 * implementation of nsIWidget.
386 */
387 nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(nullptr);
388 if (!widget) {
389 NS_ERROR("Couldn't create instance of PuppetWidget");
390 return NS_ERROR_FAILURE;
391 }
392 widget->Create(nullptr, 0, nsIntRect(nsIntPoint(0, 0), nsIntSize(0, 0)),
393 nullptr, nullptr);
394 nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(navigation);
395 window->InitWindow(0, widget, 0, 0, 0, 0);
396 window->Create();
398 nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub);
399 nsRefPtr<nsIWebNavigation> result = new WindowlessBrowserStub(browser, isstub);
400 nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
401 docshell->SetInvisible(true);
403 result.forget(aResult);
404 return NS_OK;
405 }
407 uint32_t
408 nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
409 uint32_t aChromeMask)
410 {
411 uint32_t zLevel;
413 zLevel = nsIXULWindow::normalZ;
414 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
415 zLevel = nsIXULWindow::raisedZ;
416 else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
417 zLevel = nsIXULWindow::loweredZ;
419 #ifdef XP_MACOSX
420 /* Platforms on which modal windows are always application-modal, not
421 window-modal (that's just the Mac, right?) want modal windows to
422 be stacked on top of everyone else.
424 On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
425 */
426 uint32_t modalDepMask = nsIWebBrowserChrome::CHROME_MODAL |
427 nsIWebBrowserChrome::CHROME_DEPENDENT;
428 if (aParent && (aChromeMask & modalDepMask)) {
429 aParent->GetZLevel(&zLevel);
430 }
431 #else
432 /* Platforms with native support for dependent windows (that's everyone
433 but pre-Mac OS X, right?) know how to stack dependent windows. On these
434 platforms, give the dependent window the same level as its parent,
435 so we won't try to override the normal platform behaviour. */
436 if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent)
437 aParent->GetZLevel(&zLevel);
438 #endif
440 return zLevel;
441 }
443 #ifdef XP_WIN
444 /*
445 * Checks to see if any existing window is currently in fullscreen mode.
446 */
447 static bool
448 CheckForFullscreenWindow()
449 {
450 nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
451 if (!wm)
452 return false;
454 nsCOMPtr<nsISimpleEnumerator> windowList;
455 wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList));
456 if (!windowList)
457 return false;
459 for (;;) {
460 bool more = false;
461 windowList->HasMoreElements(&more);
462 if (!more)
463 return false;
465 nsCOMPtr<nsISupports> supportsWindow;
466 windowList->GetNext(getter_AddRefs(supportsWindow));
467 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
468 if (baseWin) {
469 nsCOMPtr<nsIWidget> widget;
470 baseWin->GetMainWidget(getter_AddRefs(widget));
471 if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) {
472 return true;
473 }
474 }
475 }
476 return false;
477 }
478 #endif
480 /*
481 * Just do the window-making part of CreateTopLevelWindow
482 */
483 nsresult
484 nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent,
485 nsIURI *aUrl,
486 uint32_t aChromeMask,
487 int32_t aInitialWidth,
488 int32_t aInitialHeight,
489 bool aIsHiddenWindow,
490 nsWebShellWindow **aResult)
491 {
492 *aResult = nullptr;
493 NS_ENSURE_STATE(!mXPCOMWillShutDown);
495 nsCOMPtr<nsIXULWindow> parent;
496 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
497 parent = aParent;
499 nsRefPtr<nsWebShellWindow> window = new nsWebShellWindow(aChromeMask);
500 NS_ENSURE_TRUE(window, NS_ERROR_OUT_OF_MEMORY);
502 #ifdef XP_WIN
503 // If the parent is currently fullscreen, tell the child to ignore persisted
504 // full screen states. This way new browser windows open on top of fullscreen
505 // windows normally.
506 if (window && CheckForFullscreenWindow())
507 window->IgnoreXULSizeMode(true);
508 #endif
510 nsWidgetInitData widgetInitData;
512 if (aIsHiddenWindow)
513 widgetInitData.mWindowType = eWindowType_invisible;
514 else
515 widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ?
516 eWindowType_dialog : eWindowType_toplevel;
518 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
519 widgetInitData.mWindowType = eWindowType_popup;
521 if (aChromeMask & nsIWebBrowserChrome::CHROME_MAC_SUPPRESS_ANIMATION)
522 widgetInitData.mIsAnimationSuppressed = true;
524 if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW)
525 widgetInitData.mRequireOffMainThreadCompositing = true;
527 #ifdef XP_MACOSX
528 // Mac OS X sheet support
529 // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
530 // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
531 // windows opened from nsPromptService::DoDialog() still are sheets. This
532 // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
533 // nsCocoaWindow::SetModal()).
534 uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
535 nsIWebBrowserChrome::CHROME_MODAL |
536 nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
537 if (parent &&
538 (parent != mHiddenWindow && parent != mHiddenPrivateWindow) &&
539 ((aChromeMask & sheetMask) == sheetMask)) {
540 widgetInitData.mWindowType = eWindowType_sheet;
541 }
542 #endif
544 #if defined(XP_WIN)
545 if (widgetInitData.mWindowType == eWindowType_toplevel ||
546 widgetInitData.mWindowType == eWindowType_dialog)
547 widgetInitData.clipChildren = true;
548 #endif
550 // note default chrome overrides other OS chrome settings, but
551 // not internal chrome
552 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT)
553 widgetInitData.mBorderStyle = eBorderStyle_default;
554 else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
555 widgetInitData.mBorderStyle = eBorderStyle_all;
556 else {
557 widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00
558 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS)
559 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_border);
560 if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR)
561 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_title);
562 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
563 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_close);
564 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
565 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_resizeh);
566 // only resizable windows get the maximize button (but not dialogs)
567 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
568 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_maximize);
569 }
570 // all windows (except dialogs) get minimize buttons and the system menu
571 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
572 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize | eBorderStyle_menu);
573 // but anyone can explicitly ask for a minimize button
574 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) {
575 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize);
576 }
577 }
579 if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
580 aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
581 aInitialWidth = 1;
582 aInitialHeight = 1;
583 window->SetIntrinsicallySized(true);
584 }
586 bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
588 nsCOMPtr<nsIXULChromeRegistry> reg =
589 mozilla::services::GetXULChromeRegistryService();
590 if (reg) {
591 nsAutoCString package;
592 package.AssignLiteral("global");
593 bool isRTL = false;
594 reg->IsLocaleRTL(package, &isRTL);
595 widgetInitData.mRTL = isRTL;
596 }
598 nsresult rv = window->Initialize(parent, center ? aParent : nullptr,
599 aUrl, aInitialWidth, aInitialHeight,
600 aIsHiddenWindow, widgetInitData);
602 NS_ENSURE_SUCCESS(rv, rv);
604 // Enforce the Private Browsing autoStart pref first.
605 bool isPrivateBrowsingWindow =
606 Preferences::GetBool("browser.privatebrowsing.autostart");
607 if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
608 // Caller requested a private window
609 isPrivateBrowsingWindow = true;
610 }
611 if (!isPrivateBrowsingWindow) {
612 // Ensure that we propagate any existing private browsing status
613 // from the parent, even if it will not actually be used
614 // as a parent value.
615 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aParent);
616 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(domWin);
617 nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(webNav);
618 if (parentContext) {
619 isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
620 }
621 }
622 nsCOMPtr<nsIDOMWindow> newDomWin =
623 do_GetInterface(NS_ISUPPORTS_CAST(nsIBaseWindow*, window));
624 nsCOMPtr<nsIWebNavigation> newWebNav = do_GetInterface(newDomWin);
625 nsCOMPtr<nsILoadContext> thisContext = do_GetInterface(newWebNav);
626 if (thisContext) {
627 thisContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
628 }
630 window.swap(*aResult); // transfer reference
631 if (parent)
632 parent->AddChildWindow(*aResult);
634 if (center)
635 rv = (*aResult)->Center(parent, parent ? false : true, false);
637 return rv;
638 }
640 NS_IMETHODIMP
641 nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow)
642 {
643 NS_ENSURE_ARG_POINTER(aWindow);
645 *aWindow = mHiddenWindow;
646 NS_IF_ADDREF(*aWindow);
647 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
648 }
650 NS_IMETHODIMP
651 nsAppShellService::GetHiddenDOMWindow(nsIDOMWindow **aWindow)
652 {
653 nsresult rv;
654 nsCOMPtr<nsIDocShell> docShell;
655 NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
657 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
658 NS_ENSURE_SUCCESS(rv, rv);
660 nsCOMPtr<nsIDOMWindow> hiddenDOMWindow(do_GetInterface(docShell, &rv));
661 NS_ENSURE_SUCCESS(rv, rv);
663 *aWindow = hiddenDOMWindow;
664 NS_IF_ADDREF(*aWindow);
665 return NS_OK;
666 }
668 NS_IMETHODIMP
669 nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow)
670 {
671 NS_ENSURE_ARG_POINTER(aWindow);
673 EnsurePrivateHiddenWindow();
675 *aWindow = mHiddenPrivateWindow;
676 NS_IF_ADDREF(*aWindow);
677 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
678 }
680 NS_IMETHODIMP
681 nsAppShellService::GetHiddenPrivateDOMWindow(nsIDOMWindow **aWindow)
682 {
683 EnsurePrivateHiddenWindow();
685 nsresult rv;
686 nsCOMPtr<nsIDocShell> docShell;
687 NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE);
689 rv = mHiddenPrivateWindow->GetDocShell(getter_AddRefs(docShell));
690 NS_ENSURE_SUCCESS(rv, rv);
692 nsCOMPtr<nsIDOMWindow> hiddenPrivateDOMWindow(do_GetInterface(docShell, &rv));
693 NS_ENSURE_SUCCESS(rv, rv);
695 *aWindow = hiddenPrivateDOMWindow;
696 NS_IF_ADDREF(*aWindow);
697 return NS_OK;
698 }
700 NS_IMETHODIMP
701 nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow)
702 {
703 NS_ENSURE_ARG_POINTER(aHasPrivateWindow);
705 *aHasPrivateWindow = !!mHiddenPrivateWindow;
706 return NS_OK;
707 }
709 NS_IMETHODIMP
710 nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindow **aWindow,
711 JSContext **aJSContext)
712 {
713 nsresult rv = NS_OK;
714 if ( aWindow && aJSContext ) {
715 *aWindow = nullptr;
716 *aJSContext = nullptr;
718 if ( mHiddenWindow ) {
719 // Convert hidden window to nsIDOMWindow and extract its JSContext.
720 do {
721 // 1. Get doc for hidden window.
722 nsCOMPtr<nsIDocShell> docShell;
723 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
724 if (NS_FAILED(rv)) break;
726 // 2. Convert that to an nsIDOMWindow.
727 nsCOMPtr<nsIDOMWindow> hiddenDOMWindow(do_GetInterface(docShell));
728 if(!hiddenDOMWindow) break;
730 // 3. Get script global object for the window.
731 nsCOMPtr<nsIScriptGlobalObject> sgo;
732 sgo = do_QueryInterface( hiddenDOMWindow );
733 if (!sgo) { rv = NS_ERROR_FAILURE; break; }
735 // 4. Get script context from that.
736 nsIScriptContext *scriptContext = sgo->GetContext();
737 if (!scriptContext) { rv = NS_ERROR_FAILURE; break; }
739 // 5. Get JSContext from the script context.
740 JSContext *jsContext = scriptContext->GetNativeContext();
741 if (!jsContext) { rv = NS_ERROR_FAILURE; break; }
743 // Now, give results to caller.
744 *aWindow = hiddenDOMWindow.get();
745 NS_IF_ADDREF( *aWindow );
746 *aJSContext = jsContext;
747 } while (0);
748 } else {
749 rv = NS_ERROR_FAILURE;
750 }
751 } else {
752 rv = NS_ERROR_NULL_POINTER;
753 }
754 return rv;
755 }
757 NS_IMETHODIMP
758 nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW)
759 {
760 *aAPHW = mApplicationProvidedHiddenWindow;
761 return NS_OK;
762 }
764 /*
765 * Register a new top level window (created elsewhere)
766 */
767 NS_IMETHODIMP
768 nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
769 {
770 NS_ENSURE_ARG_POINTER(aWindow);
772 nsCOMPtr<nsIDocShell> docShell;
773 aWindow->GetDocShell(getter_AddRefs(docShell));
774 nsCOMPtr<nsPIDOMWindow> domWindow(do_GetInterface(docShell));
775 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
776 domWindow->SetInitialPrincipalToSubject();
778 // tell the window mediator about the new window
779 nsCOMPtr<nsIWindowMediator> mediator
780 ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
781 NS_ASSERTION(mediator, "Couldn't get window mediator.");
783 if (mediator)
784 mediator->RegisterWindow(aWindow);
786 // tell the window watcher about the new window
787 nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
788 NS_ASSERTION(wwatcher, "No windowwatcher?");
789 if (wwatcher && domWindow) {
790 wwatcher->AddWindow(domWindow, 0);
791 }
793 // an ongoing attempt to quit is stopped by a newly opened window
794 nsCOMPtr<nsIObserverService> obssvc =
795 do_GetService("@mozilla.org/observer-service;1");
796 NS_ASSERTION(obssvc, "Couldn't get observer service.");
798 if (obssvc)
799 obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
801 return NS_OK;
802 }
805 NS_IMETHODIMP
806 nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
807 {
808 if (mXPCOMShuttingDown) {
809 /* return an error code in order to:
810 - avoid doing anything with other member variables while we are in
811 the destructor
812 - notify the caller not to release the AppShellService after
813 unregistering the window
814 (we don't want to be deleted twice consecutively to
815 mHiddenWindow->Destroy() in our destructor)
816 */
817 return NS_ERROR_FAILURE;
818 }
820 NS_ENSURE_ARG_POINTER(aWindow);
822 if (aWindow == mHiddenWindow) {
823 // CreateHiddenWindow() does not register the window, so we're done.
824 return NS_OK;
825 }
826 if (aWindow == mHiddenPrivateWindow) {
827 // CreateHiddenWindow() does not register the window, so we're done.
828 return NS_OK;
829 }
831 // tell the window mediator
832 nsCOMPtr<nsIWindowMediator> mediator
833 ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
834 NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
836 if (mediator)
837 mediator->UnregisterWindow(aWindow);
839 // tell the window watcher
840 nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
841 NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
842 if (wwatcher) {
843 nsCOMPtr<nsIDocShell> docShell;
844 aWindow->GetDocShell(getter_AddRefs(docShell));
845 if (docShell) {
846 nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
847 if (domWindow)
848 wwatcher->RemoveWindow(domWindow);
849 }
850 }
852 return NS_OK;
853 }
856 NS_IMETHODIMP
857 nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic,
858 const char16_t *aData)
859 {
860 if (!strcmp(aTopic, "xpcom-will-shutdown")) {
861 mXPCOMWillShutDown = true;
862 } else if (!strcmp(aTopic, "xpcom-shutdown")) {
863 mXPCOMShuttingDown = true;
864 if (mHiddenWindow) {
865 mHiddenWindow->Destroy();
866 }
867 if (mHiddenPrivateWindow) {
868 mHiddenPrivateWindow->Destroy();
869 }
870 } else {
871 NS_ERROR("Unexpected observer topic!");
872 }
874 return NS_OK;
875 }
877 NS_IMETHODIMP
878 nsAppShellService::StartEventLoopLagTracking(bool* aResult)
879 {
880 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
881 *aResult = mozilla::InitEventTracing(true);
882 #endif
883 return NS_OK;
884 }
886 NS_IMETHODIMP
887 nsAppShellService::StopEventLoopLagTracking()
888 {
889 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
890 mozilla::ShutdownEventTracing();
891 #endif
892 return NS_OK;
893 }