Line data Source code
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/. */
5 :
6 :
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"
15 : #include "nsIXULRuntime.h"
16 :
17 : #include "nsIWindowMediator.h"
18 : #include "nsIWindowWatcher.h"
19 : #include "nsPIWindowWatcher.h"
20 : #include "nsIDOMWindow.h"
21 : #include "nsPIDOMWindow.h"
22 : #include "nsWebShellWindow.h"
23 :
24 : #include "nsWidgetInitData.h"
25 : #include "nsWidgetsCID.h"
26 : #include "nsIWidget.h"
27 : #include "nsIRequestObserver.h"
28 : #include "nsIEmbeddingSiteWindow.h"
29 :
30 : #include "nsAppShellService.h"
31 : #include "nsContentUtils.h"
32 : #include "nsThreadUtils.h"
33 : #include "nsISupportsPrimitives.h"
34 : #include "nsILoadContext.h"
35 : #include "nsIWebNavigation.h"
36 : #include "nsIWindowlessBrowser.h"
37 :
38 : #include "mozilla/Attributes.h"
39 : #include "mozilla/Preferences.h"
40 : #include "mozilla/Services.h"
41 : #include "mozilla/StartupTimeline.h"
42 : #include "mozilla/intl/LocaleService.h"
43 :
44 : #include "nsEmbedCID.h"
45 : #include "nsIWebBrowser.h"
46 : #include "nsIDocShell.h"
47 : #include "gfxPlatform.h"
48 :
49 : #ifdef MOZ_INSTRUMENT_EVENT_LOOP
50 : #include "EventTracer.h"
51 : #endif
52 :
53 : using namespace mozilla;
54 : using mozilla::intl::LocaleService;
55 :
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"
58 :
59 : class nsIAppShell;
60 :
61 1 : nsAppShellService::nsAppShellService() :
62 : mXPCOMWillShutDown(false),
63 : mXPCOMShuttingDown(false),
64 : mModalWindowCount(0),
65 : mApplicationProvidedHiddenWindow(false),
66 1 : mScreenId(0)
67 : {
68 2 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
69 :
70 1 : if (obs) {
71 1 : obs->AddObserver(this, "xpcom-will-shutdown", false);
72 1 : obs->AddObserver(this, "xpcom-shutdown", false);
73 : }
74 1 : }
75 :
76 0 : nsAppShellService::~nsAppShellService()
77 : {
78 0 : }
79 :
80 :
81 : /*
82 : * Implement the nsISupports methods...
83 : */
84 69 : NS_IMPL_ISUPPORTS(nsAppShellService,
85 : nsIAppShellService,
86 : nsIObserver)
87 :
88 : NS_IMETHODIMP
89 1 : nsAppShellService::CreateHiddenWindow()
90 : {
91 1 : return CreateHiddenWindowHelper(false);
92 : }
93 :
94 : NS_IMETHODIMP
95 0 : nsAppShellService::SetScreenId(uint32_t aScreenId)
96 : {
97 0 : mScreenId = aScreenId;
98 0 : return NS_OK;
99 : }
100 :
101 : void
102 0 : nsAppShellService::EnsurePrivateHiddenWindow()
103 : {
104 0 : if (!mHiddenPrivateWindow) {
105 0 : CreateHiddenWindowHelper(true);
106 : }
107 0 : }
108 :
109 : nsresult
110 1 : nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate)
111 : {
112 : nsresult rv;
113 1 : int32_t initialHeight = 100, initialWidth = 100;
114 :
115 : #ifdef XP_MACOSX
116 : uint32_t chromeMask = 0;
117 : nsAdoptingCString prefVal =
118 : Preferences::GetCString("browser.hiddenWindowChromeURL");
119 : const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
120 : if (aIsPrivate) {
121 : hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL;
122 : } else {
123 : mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
124 : }
125 : #else
126 : static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
127 1 : uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL;
128 : #endif
129 :
130 2 : nsCOMPtr<nsIURI> url;
131 1 : rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
132 1 : NS_ENSURE_SUCCESS(rv, rv);
133 :
134 1 : if (aIsPrivate) {
135 0 : chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
136 : }
137 :
138 2 : RefPtr<nsWebShellWindow> newWindow;
139 1 : rv = JustCreateTopWindow(nullptr, url,
140 : chromeMask, initialWidth, initialHeight,
141 2 : true, nullptr, nullptr, getter_AddRefs(newWindow));
142 1 : NS_ENSURE_SUCCESS(rv, rv);
143 :
144 2 : nsCOMPtr<nsIDocShell> docShell;
145 1 : newWindow->GetDocShell(getter_AddRefs(docShell));
146 1 : if (docShell) {
147 1 : docShell->SetIsActive(false);
148 1 : if (aIsPrivate) {
149 0 : docShell->SetAffectPrivateSessionLifetime(false);
150 : }
151 : }
152 :
153 1 : if (aIsPrivate) {
154 0 : mHiddenPrivateWindow.swap(newWindow);
155 : } else {
156 1 : mHiddenWindow.swap(newWindow);
157 : }
158 :
159 1 : return NS_OK;
160 : }
161 :
162 : NS_IMETHODIMP
163 0 : nsAppShellService::DestroyHiddenWindow()
164 : {
165 0 : if (mHiddenWindow) {
166 0 : mHiddenWindow->Destroy();
167 :
168 0 : mHiddenWindow = nullptr;
169 : }
170 :
171 0 : if (mHiddenPrivateWindow) {
172 0 : mHiddenPrivateWindow->Destroy();
173 :
174 0 : mHiddenPrivateWindow = nullptr;
175 : }
176 :
177 0 : return NS_OK;
178 : }
179 :
180 : /*
181 : * Create a new top level window and display the given URL within it...
182 : */
183 : NS_IMETHODIMP
184 1 : nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent,
185 : nsIURI *aUrl,
186 : uint32_t aChromeMask,
187 : int32_t aInitialWidth,
188 : int32_t aInitialHeight,
189 : nsITabParent *aOpeningTab,
190 : mozIDOMWindowProxy *aOpenerWindow,
191 : nsIXULWindow **aResult)
192 :
193 : {
194 : nsresult rv;
195 :
196 1 : StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
197 :
198 2 : RefPtr<nsWebShellWindow> newWindow;
199 1 : rv = JustCreateTopWindow(aParent, aUrl,
200 : aChromeMask, aInitialWidth, aInitialHeight,
201 : false, aOpeningTab, aOpenerWindow,
202 2 : getter_AddRefs(newWindow));
203 1 : newWindow.forget(aResult);
204 :
205 1 : if (NS_SUCCEEDED(rv)) {
206 : // the addref resulting from this is the owning addref for this window
207 1 : RegisterTopLevelWindow(*aResult);
208 2 : nsCOMPtr<nsIXULWindow> parent;
209 1 : if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
210 0 : parent = aParent;
211 1 : (*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
212 : }
213 :
214 2 : return rv;
215 : }
216 :
217 : /*
218 : * This class provides a stub implementation of nsIWebBrowserChrome2, as needed
219 : * by nsAppShellService::CreateWindowlessBrowser
220 : */
221 : class WebBrowserChrome2Stub : public nsIWebBrowserChrome2,
222 : public nsIEmbeddingSiteWindow,
223 : public nsIInterfaceRequestor,
224 : public nsSupportsWeakReference {
225 : protected:
226 : nsCOMPtr<nsIWebBrowser> mBrowser;
227 0 : virtual ~WebBrowserChrome2Stub() {}
228 : public:
229 0 : explicit WebBrowserChrome2Stub(nsIWebBrowser *aBrowser) : mBrowser(aBrowser) {}
230 : NS_DECL_ISUPPORTS
231 : NS_DECL_NSIWEBBROWSERCHROME
232 : NS_DECL_NSIWEBBROWSERCHROME2
233 : NS_DECL_NSIINTERFACEREQUESTOR
234 : NS_DECL_NSIEMBEDDINGSITEWINDOW
235 : };
236 :
237 0 : NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
238 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
239 0 : NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
240 0 : NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
241 0 : NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
242 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
243 0 : NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
244 0 : NS_INTERFACE_MAP_END
245 :
246 0 : NS_IMPL_ADDREF(WebBrowserChrome2Stub)
247 0 : NS_IMPL_RELEASE(WebBrowserChrome2Stub)
248 :
249 : NS_IMETHODIMP
250 0 : WebBrowserChrome2Stub::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
251 : {
252 0 : return NS_OK;
253 : }
254 :
255 : NS_IMETHODIMP
256 0 : WebBrowserChrome2Stub::GetWebBrowser(nsIWebBrowser** aWebBrowser)
257 : {
258 0 : NS_NOTREACHED("WebBrowserChrome2Stub::GetWebBrowser is not supported");
259 0 : return NS_ERROR_NOT_IMPLEMENTED;
260 : }
261 :
262 : NS_IMETHODIMP
263 0 : WebBrowserChrome2Stub::SetWebBrowser(nsIWebBrowser* aWebBrowser)
264 : {
265 0 : NS_NOTREACHED("WebBrowserChrome2Stub::SetWebBrowser is not supported");
266 0 : return NS_ERROR_NOT_IMPLEMENTED;
267 : }
268 :
269 : NS_IMETHODIMP
270 0 : WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags)
271 : {
272 0 : *aChromeFlags = 0;
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags)
278 : {
279 0 : NS_NOTREACHED("WebBrowserChrome2Stub::SetChromeFlags is not supported");
280 0 : return NS_ERROR_NOT_IMPLEMENTED;
281 : }
282 :
283 : NS_IMETHODIMP
284 0 : WebBrowserChrome2Stub::DestroyBrowserWindow()
285 : {
286 0 : NS_NOTREACHED("WebBrowserChrome2Stub::DestroyBrowserWindow is not supported");
287 0 : return NS_ERROR_NOT_IMPLEMENTED;
288 : }
289 :
290 : NS_IMETHODIMP
291 0 : WebBrowserChrome2Stub::SizeBrowserTo(int32_t aCX, int32_t aCY)
292 : {
293 0 : NS_NOTREACHED("WebBrowserChrome2Stub::SizeBrowserTo is not supported");
294 0 : return NS_ERROR_NOT_IMPLEMENTED;
295 : }
296 :
297 : NS_IMETHODIMP
298 0 : WebBrowserChrome2Stub::ShowAsModal()
299 : {
300 0 : NS_NOTREACHED("WebBrowserChrome2Stub::ShowAsModal is not supported");
301 0 : return NS_ERROR_NOT_IMPLEMENTED;
302 : }
303 :
304 : NS_IMETHODIMP
305 0 : WebBrowserChrome2Stub::IsWindowModal(bool* aResult)
306 : {
307 0 : *aResult = false;
308 0 : return NS_OK;
309 : }
310 :
311 : NS_IMETHODIMP
312 0 : WebBrowserChrome2Stub::ExitModalEventLoop(nsresult aStatus)
313 : {
314 0 : NS_NOTREACHED("WebBrowserChrome2Stub::ExitModalEventLoop is not supported");
315 0 : return NS_ERROR_NOT_IMPLEMENTED;
316 : }
317 :
318 : NS_IMETHODIMP
319 0 : WebBrowserChrome2Stub::SetStatusWithContext(uint32_t aStatusType,
320 : const nsAString& aStatusText,
321 : nsISupports* aStatusContext)
322 : {
323 0 : return NS_OK;
324 : }
325 :
326 : NS_IMETHODIMP
327 0 : WebBrowserChrome2Stub::GetInterface(const nsIID& aIID, void** aSink)
328 : {
329 0 : return QueryInterface(aIID, aSink);
330 : }
331 :
332 : // nsIEmbeddingSiteWindow impl
333 : NS_IMETHODIMP
334 0 : WebBrowserChrome2Stub::GetDimensions(uint32_t flags, int32_t* x, int32_t* y, int32_t* cx, int32_t* cy)
335 : {
336 0 : if (x) {
337 0 : *x = 0;
338 : }
339 :
340 0 : if (y) {
341 0 : *y = 0;
342 : }
343 :
344 0 : if (cx) {
345 0 : *cx = 0;
346 : }
347 :
348 0 : if (cy) {
349 0 : *cy = 0;
350 : }
351 :
352 0 : return NS_OK;
353 : }
354 :
355 : NS_IMETHODIMP
356 0 : WebBrowserChrome2Stub::SetDimensions(uint32_t flags, int32_t x, int32_t y, int32_t cx, int32_t cy)
357 : {
358 0 : nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
359 0 : NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
360 0 : window->SetSize(cx, cy, true);
361 0 : return NS_OK;
362 : }
363 :
364 : NS_IMETHODIMP
365 0 : WebBrowserChrome2Stub::SetFocus()
366 : {
367 0 : return NS_ERROR_NOT_IMPLEMENTED;
368 : }
369 :
370 : NS_IMETHODIMP
371 0 : WebBrowserChrome2Stub::GetVisibility(bool* aVisibility)
372 : {
373 0 : return NS_ERROR_NOT_IMPLEMENTED;
374 : }
375 : NS_IMETHODIMP
376 0 : WebBrowserChrome2Stub::SetVisibility(bool aVisibility)
377 : {
378 0 : return NS_ERROR_NOT_IMPLEMENTED;
379 : }
380 :
381 : NS_IMETHODIMP
382 0 : WebBrowserChrome2Stub::GetTitle(char16_t** aTitle)
383 : {
384 0 : return NS_ERROR_NOT_IMPLEMENTED;
385 : }
386 : NS_IMETHODIMP
387 0 : WebBrowserChrome2Stub::SetTitle(const char16_t* aTitle)
388 : {
389 0 : return NS_ERROR_NOT_IMPLEMENTED;
390 : }
391 :
392 : NS_IMETHODIMP
393 0 : WebBrowserChrome2Stub::GetSiteWindow(void** aSiteWindow)
394 : {
395 0 : return NS_ERROR_NOT_IMPLEMENTED;
396 : }
397 :
398 : NS_IMETHODIMP
399 0 : WebBrowserChrome2Stub::Blur()
400 : {
401 0 : return NS_ERROR_NOT_IMPLEMENTED;
402 : }
403 :
404 : class BrowserDestroyer final : public Runnable
405 : {
406 : public:
407 0 : BrowserDestroyer(nsIWebBrowser* aBrowser, nsISupports* aContainer)
408 0 : : mozilla::Runnable("BrowserDestroyer")
409 : , mBrowser(aBrowser)
410 0 : , mContainer(aContainer)
411 : {
412 0 : }
413 :
414 : NS_IMETHOD
415 0 : Run() override
416 : {
417 : // Explicitly destroy the browser, in case this isn't the last reference.
418 0 : nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
419 0 : return window->Destroy();
420 : }
421 :
422 : protected:
423 0 : virtual ~BrowserDestroyer() {}
424 :
425 : private:
426 : nsCOMPtr<nsIWebBrowser> mBrowser;
427 : nsCOMPtr<nsISupports> mContainer;
428 : };
429 :
430 : // This is the "stub" we return from CreateWindowlessBrowser - it exists
431 : // to manage the lifetimes of the nsIWebBrowser and container window.
432 : // In particular, it keeps a strong reference to both, to prevent them from
433 : // being collected while this object remains alive, and ensures that they
434 : // aren't destroyed when it's not safe to run scripts.
435 : class WindowlessBrowser final : public nsIWindowlessBrowser,
436 : public nsIInterfaceRequestor
437 : {
438 : public:
439 0 : WindowlessBrowser(nsIWebBrowser *aBrowser, nsISupports *aContainer) :
440 : mBrowser(aBrowser),
441 : mContainer(aContainer),
442 0 : mClosed(false)
443 : {
444 0 : mWebNavigation = do_QueryInterface(aBrowser);
445 0 : mInterfaceRequestor = do_QueryInterface(aBrowser);
446 0 : }
447 : NS_DECL_ISUPPORTS
448 0 : NS_FORWARD_SAFE_NSIWEBNAVIGATION(mWebNavigation)
449 0 : NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor)
450 :
451 : NS_IMETHOD
452 0 : Close() override
453 : {
454 0 : NS_ENSURE_TRUE(!mClosed, NS_ERROR_UNEXPECTED);
455 0 : NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
456 : "WindowlessBrowser::Close called when not safe to run scripts");
457 :
458 0 : mClosed = true;
459 :
460 0 : mWebNavigation = nullptr;
461 0 : mInterfaceRequestor = nullptr;
462 :
463 0 : nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
464 0 : return window->Destroy();
465 : }
466 :
467 : protected:
468 0 : virtual ~WindowlessBrowser()
469 0 : {
470 0 : if (mClosed) {
471 0 : return;
472 : }
473 :
474 0 : NS_WARNING("Windowless browser was not closed prior to destruction");
475 :
476 : // The docshell destructor needs to dispatch events, and can only run
477 : // when it's safe to run scripts. If this was triggered by GC, it may
478 : // not always be safe to run scripts, in which cases we need to delay
479 : // destruction until it is.
480 0 : nsCOMPtr<nsIRunnable> runnable = new BrowserDestroyer(mBrowser, mContainer);
481 0 : nsContentUtils::AddScriptRunner(runnable);
482 0 : }
483 :
484 : private:
485 : nsCOMPtr<nsIWebBrowser> mBrowser;
486 : nsCOMPtr<nsIWebNavigation> mWebNavigation;
487 : nsCOMPtr<nsIInterfaceRequestor> mInterfaceRequestor;
488 : // we don't use the container but just hold a reference to it.
489 : nsCOMPtr<nsISupports> mContainer;
490 :
491 : bool mClosed;
492 : };
493 :
494 0 : NS_IMPL_ISUPPORTS(WindowlessBrowser, nsIWindowlessBrowser, nsIWebNavigation, nsIInterfaceRequestor)
495 :
496 :
497 : NS_IMETHODIMP
498 0 : nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWindowlessBrowser **aResult)
499 : {
500 : /* First, we create an instance of nsWebBrowser. Instances of this class have
501 : * an associated doc shell, which is what we're interested in.
502 : */
503 0 : nsCOMPtr<nsIWebBrowser> browser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
504 0 : if (!browser) {
505 0 : NS_ERROR("Couldn't create instance of nsWebBrowser!");
506 0 : return NS_ERROR_FAILURE;
507 : }
508 :
509 : /* Next, we set the container window for our instance of nsWebBrowser. Since
510 : * we don't actually have a window, we instead set the container window to be
511 : * an instance of WebBrowserChrome2Stub, which provides a stub implementation
512 : * of nsIWebBrowserChrome2.
513 : */
514 0 : RefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub(browser);
515 0 : browser->SetContainerWindow(stub);
516 :
517 0 : nsCOMPtr<nsIWebNavigation> navigation = do_QueryInterface(browser);
518 :
519 0 : nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(navigation);
520 0 : item->SetItemType(aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
521 0 : : nsIDocShellTreeItem::typeContentWrapper);
522 :
523 : /* A windowless web browser doesn't have an associated OS level window. To
524 : * accomplish this, we initialize the window associated with our instance of
525 : * nsWebBrowser with an instance of HeadlessWidget/PuppetWidget, which provide
526 : * a stub implementation of nsIWidget.
527 : */
528 0 : nsCOMPtr<nsIWidget> widget;
529 0 : if (gfxPlatform::IsHeadless()) {
530 0 : widget = nsIWidget::CreateHeadlessWidget();
531 : } else {
532 0 : widget = nsIWidget::CreatePuppetWidget(nullptr);
533 : }
534 0 : if (!widget) {
535 0 : NS_ERROR("Couldn't create instance of stub widget");
536 0 : return NS_ERROR_FAILURE;
537 : }
538 : nsresult rv =
539 0 : widget->Create(nullptr, 0, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
540 0 : NS_ENSURE_SUCCESS(rv, rv);
541 0 : nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(navigation);
542 0 : window->InitWindow(0, widget, 0, 0, 0, 0);
543 0 : window->Create();
544 :
545 0 : nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub);
546 0 : RefPtr<nsIWindowlessBrowser> result = new WindowlessBrowser(browser, isstub);
547 0 : nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
548 0 : docshell->SetInvisible(true);
549 :
550 0 : result.forget(aResult);
551 0 : return NS_OK;
552 : }
553 :
554 : uint32_t
555 1 : nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
556 : uint32_t aChromeMask)
557 : {
558 : uint32_t zLevel;
559 :
560 1 : zLevel = nsIXULWindow::normalZ;
561 1 : if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
562 0 : zLevel = nsIXULWindow::raisedZ;
563 1 : else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
564 0 : zLevel = nsIXULWindow::loweredZ;
565 :
566 : #ifdef XP_MACOSX
567 : /* Platforms on which modal windows are always application-modal, not
568 : window-modal (that's just the Mac, right?) want modal windows to
569 : be stacked on top of everyone else.
570 :
571 : On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
572 : */
573 : uint32_t modalDepMask = nsIWebBrowserChrome::CHROME_MODAL |
574 : nsIWebBrowserChrome::CHROME_DEPENDENT;
575 : if (aParent && (aChromeMask & modalDepMask)) {
576 : aParent->GetZLevel(&zLevel);
577 : }
578 : #else
579 : /* Platforms with native support for dependent windows (that's everyone
580 : but pre-Mac OS X, right?) know how to stack dependent windows. On these
581 : platforms, give the dependent window the same level as its parent,
582 : so we won't try to override the normal platform behaviour. */
583 1 : if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent)
584 0 : aParent->GetZLevel(&zLevel);
585 : #endif
586 :
587 1 : return zLevel;
588 : }
589 :
590 : #ifdef XP_WIN
591 : /*
592 : * Checks to see if any existing window is currently in fullscreen mode.
593 : */
594 : static bool
595 : CheckForFullscreenWindow()
596 : {
597 : nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
598 : if (!wm)
599 : return false;
600 :
601 : nsCOMPtr<nsISimpleEnumerator> windowList;
602 : wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList));
603 : if (!windowList)
604 : return false;
605 :
606 : for (;;) {
607 : bool more = false;
608 : windowList->HasMoreElements(&more);
609 : if (!more)
610 : return false;
611 :
612 : nsCOMPtr<nsISupports> supportsWindow;
613 : windowList->GetNext(getter_AddRefs(supportsWindow));
614 : nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
615 : if (baseWin) {
616 : nsCOMPtr<nsIWidget> widget;
617 : baseWin->GetMainWidget(getter_AddRefs(widget));
618 : if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) {
619 : return true;
620 : }
621 : }
622 : }
623 : return false;
624 : }
625 : #endif
626 :
627 : /*
628 : * Just do the window-making part of CreateTopLevelWindow
629 : */
630 : nsresult
631 2 : nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent,
632 : nsIURI *aUrl,
633 : uint32_t aChromeMask,
634 : int32_t aInitialWidth,
635 : int32_t aInitialHeight,
636 : bool aIsHiddenWindow,
637 : nsITabParent *aOpeningTab,
638 : mozIDOMWindowProxy *aOpenerWindow,
639 : nsWebShellWindow **aResult)
640 : {
641 2 : *aResult = nullptr;
642 2 : NS_ENSURE_STATE(!mXPCOMWillShutDown);
643 :
644 4 : nsCOMPtr<nsIXULWindow> parent;
645 2 : if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
646 0 : parent = aParent;
647 :
648 4 : RefPtr<nsWebShellWindow> window = new nsWebShellWindow(aChromeMask);
649 :
650 : #ifdef XP_WIN
651 : // If the parent is currently fullscreen, tell the child to ignore persisted
652 : // full screen states. This way new browser windows open on top of fullscreen
653 : // windows normally.
654 : if (window && CheckForFullscreenWindow())
655 : window->IgnoreXULSizeMode(true);
656 : #endif
657 :
658 2 : nsWidgetInitData widgetInitData;
659 :
660 2 : if (aIsHiddenWindow)
661 1 : widgetInitData.mWindowType = eWindowType_invisible;
662 : else
663 1 : widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ?
664 : eWindowType_dialog : eWindowType_toplevel;
665 :
666 2 : if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
667 0 : widgetInitData.mWindowType = eWindowType_popup;
668 :
669 2 : if (aChromeMask & nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION)
670 1 : widgetInitData.mIsAnimationSuppressed = true;
671 :
672 : #ifdef XP_MACOSX
673 : // Mac OS X sheet support
674 : // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
675 : // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
676 : // windows opened from nsPromptService::DoDialog() still are sheets. This
677 : // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
678 : // nsCocoaWindow::SetModal()).
679 : uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
680 : nsIWebBrowserChrome::CHROME_MODAL |
681 : nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
682 : if (parent &&
683 : (parent != mHiddenWindow && parent != mHiddenPrivateWindow) &&
684 : ((aChromeMask & sheetMask) == sheetMask)) {
685 : widgetInitData.mWindowType = eWindowType_sheet;
686 : }
687 : #endif
688 :
689 : #if defined(XP_WIN)
690 : if (widgetInitData.mWindowType == eWindowType_toplevel ||
691 : widgetInitData.mWindowType == eWindowType_dialog)
692 : widgetInitData.clipChildren = true;
693 : #endif
694 :
695 : // note default chrome overrides other OS chrome settings, but
696 : // not internal chrome
697 2 : if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT)
698 0 : widgetInitData.mBorderStyle = eBorderStyle_default;
699 2 : else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
700 2 : widgetInitData.mBorderStyle = eBorderStyle_all;
701 : else {
702 0 : widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00
703 0 : if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS)
704 0 : widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_border);
705 0 : if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR)
706 0 : widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_title);
707 0 : if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
708 0 : widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_close);
709 0 : if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
710 0 : widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_resizeh);
711 : // only resizable windows get the maximize button (but not dialogs)
712 0 : if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
713 0 : widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_maximize);
714 : }
715 : // all windows (except dialogs) get minimize buttons and the system menu
716 0 : if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
717 0 : widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize | eBorderStyle_menu);
718 : // but anyone can explicitly ask for a minimize button
719 0 : if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) {
720 0 : widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize);
721 : }
722 : }
723 :
724 2 : if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
725 : aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
726 1 : aInitialWidth = 1;
727 1 : aInitialHeight = 1;
728 1 : window->SetIntrinsicallySized(true);
729 : }
730 :
731 2 : bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
732 :
733 2 : widgetInitData.mRTL = LocaleService::GetInstance()->IsAppLocaleRTL();
734 :
735 : #ifdef MOZ_WIDGET_GONK
736 : // B2G multi-screen support. Screen ID is for differentiating screens of
737 : // windows, and due to the hardware limitation, it is platform-specific for
738 : // now, which align with the value of display type defined in HWC.
739 : widgetInitData.mScreenId = mScreenId;
740 : #endif
741 :
742 2 : nsresult rv = window->Initialize(parent, center ? aParent : nullptr,
743 : aUrl, aInitialWidth, aInitialHeight,
744 : aIsHiddenWindow, aOpeningTab,
745 2 : aOpenerWindow, widgetInitData);
746 :
747 2 : NS_ENSURE_SUCCESS(rv, rv);
748 :
749 : // Enforce the Private Browsing autoStart pref first.
750 : bool isPrivateBrowsingWindow =
751 2 : Preferences::GetBool("browser.privatebrowsing.autostart");
752 2 : bool isUsingRemoteTabs = mozilla::BrowserTabsRemoteAutostart();
753 :
754 2 : if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
755 : // Caller requested a private window
756 0 : isPrivateBrowsingWindow = true;
757 : }
758 2 : if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
759 1 : isUsingRemoteTabs = true;
760 : }
761 :
762 4 : nsCOMPtr<mozIDOMWindowProxy> domWin = do_GetInterface(aParent);
763 4 : nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(domWin);
764 4 : nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(webNav);
765 :
766 2 : if (!isPrivateBrowsingWindow && parentContext) {
767 : // Ensure that we propagate any existing private browsing status
768 : // from the parent, even if it will not actually be used
769 : // as a parent value.
770 0 : isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
771 : }
772 :
773 2 : if (parentContext) {
774 0 : isUsingRemoteTabs = parentContext->UseRemoteTabs();
775 : }
776 :
777 : nsCOMPtr<mozIDOMWindowProxy> newDomWin =
778 4 : do_GetInterface(NS_ISUPPORTS_CAST(nsIBaseWindow*, window));
779 4 : nsCOMPtr<nsIWebNavigation> newWebNav = do_GetInterface(newDomWin);
780 4 : nsCOMPtr<nsILoadContext> thisContext = do_GetInterface(newWebNav);
781 2 : if (thisContext) {
782 2 : thisContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
783 2 : thisContext->SetRemoteTabs(isUsingRemoteTabs);
784 : }
785 :
786 2 : window.forget(aResult);
787 2 : if (parent)
788 0 : parent->AddChildWindow(*aResult);
789 :
790 2 : if (center)
791 0 : rv = (*aResult)->Center(parent, parent ? false : true, false);
792 :
793 2 : return rv;
794 : }
795 :
796 : NS_IMETHODIMP
797 0 : nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow)
798 : {
799 0 : NS_ENSURE_ARG_POINTER(aWindow);
800 :
801 0 : *aWindow = mHiddenWindow;
802 0 : NS_IF_ADDREF(*aWindow);
803 0 : return *aWindow ? NS_OK : NS_ERROR_FAILURE;
804 : }
805 :
806 : NS_IMETHODIMP
807 1 : nsAppShellService::GetHiddenDOMWindow(mozIDOMWindowProxy **aWindow)
808 : {
809 : nsresult rv;
810 2 : nsCOMPtr<nsIDocShell> docShell;
811 1 : NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
812 :
813 1 : rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
814 1 : NS_ENSURE_SUCCESS(rv, rv);
815 1 : NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
816 :
817 2 : nsCOMPtr<nsPIDOMWindowOuter> hiddenDOMWindow(docShell->GetWindow());
818 1 : hiddenDOMWindow.forget(aWindow);
819 1 : return *aWindow ? NS_OK : NS_ERROR_FAILURE;
820 : }
821 :
822 : NS_IMETHODIMP
823 0 : nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow)
824 : {
825 0 : NS_ENSURE_ARG_POINTER(aWindow);
826 :
827 0 : EnsurePrivateHiddenWindow();
828 :
829 0 : *aWindow = mHiddenPrivateWindow;
830 0 : NS_IF_ADDREF(*aWindow);
831 0 : return *aWindow ? NS_OK : NS_ERROR_FAILURE;
832 : }
833 :
834 : NS_IMETHODIMP
835 0 : nsAppShellService::GetHiddenPrivateDOMWindow(mozIDOMWindowProxy **aWindow)
836 : {
837 0 : EnsurePrivateHiddenWindow();
838 :
839 : nsresult rv;
840 0 : nsCOMPtr<nsIDocShell> docShell;
841 0 : NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE);
842 :
843 0 : rv = mHiddenPrivateWindow->GetDocShell(getter_AddRefs(docShell));
844 0 : NS_ENSURE_SUCCESS(rv, rv);
845 0 : NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
846 :
847 0 : nsCOMPtr<nsPIDOMWindowOuter> hiddenPrivateDOMWindow(docShell->GetWindow());
848 0 : hiddenPrivateDOMWindow.forget(aWindow);
849 0 : return *aWindow ? NS_OK : NS_ERROR_FAILURE;
850 : }
851 :
852 : NS_IMETHODIMP
853 0 : nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow)
854 : {
855 0 : NS_ENSURE_ARG_POINTER(aHasPrivateWindow);
856 :
857 0 : *aHasPrivateWindow = !!mHiddenPrivateWindow;
858 0 : return NS_OK;
859 : }
860 :
861 : NS_IMETHODIMP
862 0 : nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW)
863 : {
864 0 : *aAPHW = mApplicationProvidedHiddenWindow;
865 0 : return NS_OK;
866 : }
867 :
868 : /*
869 : * Register a new top level window (created elsewhere)
870 : */
871 : NS_IMETHODIMP
872 1 : nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
873 : {
874 1 : NS_ENSURE_ARG_POINTER(aWindow);
875 :
876 2 : nsCOMPtr<nsIDocShell> docShell;
877 1 : aWindow->GetDocShell(getter_AddRefs(docShell));
878 1 : NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
879 :
880 2 : nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
881 1 : NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
882 1 : domWindow->SetInitialPrincipalToSubject();
883 :
884 : // tell the window mediator about the new window
885 : nsCOMPtr<nsIWindowMediator> mediator
886 2 : ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
887 1 : NS_ASSERTION(mediator, "Couldn't get window mediator.");
888 :
889 1 : if (mediator)
890 1 : mediator->RegisterWindow(aWindow);
891 :
892 : // tell the window watcher about the new window
893 2 : nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
894 1 : NS_ASSERTION(wwatcher, "No windowwatcher?");
895 1 : if (wwatcher && domWindow) {
896 1 : wwatcher->AddWindow(domWindow, 0);
897 : }
898 :
899 : // an ongoing attempt to quit is stopped by a newly opened window
900 2 : nsCOMPtr<nsIObserverService> obssvc = services::GetObserverService();
901 1 : NS_ASSERTION(obssvc, "Couldn't get observer service.");
902 :
903 1 : if (obssvc) {
904 1 : obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
905 1 : nsXULWindow* xulWindow = static_cast<nsXULWindow*>(aWindow);
906 1 : xulWindow->WasRegistered();
907 : }
908 :
909 1 : return NS_OK;
910 : }
911 :
912 :
913 : NS_IMETHODIMP
914 0 : nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
915 : {
916 0 : if (mXPCOMShuttingDown) {
917 : /* return an error code in order to:
918 : - avoid doing anything with other member variables while we are in
919 : the destructor
920 : - notify the caller not to release the AppShellService after
921 : unregistering the window
922 : (we don't want to be deleted twice consecutively to
923 : mHiddenWindow->Destroy() in our destructor)
924 : */
925 0 : return NS_ERROR_FAILURE;
926 : }
927 :
928 0 : NS_ENSURE_ARG_POINTER(aWindow);
929 :
930 0 : if (aWindow == mHiddenWindow) {
931 : // CreateHiddenWindow() does not register the window, so we're done.
932 0 : return NS_OK;
933 : }
934 0 : if (aWindow == mHiddenPrivateWindow) {
935 : // CreateHiddenWindow() does not register the window, so we're done.
936 0 : return NS_OK;
937 : }
938 :
939 : // tell the window mediator
940 : nsCOMPtr<nsIWindowMediator> mediator
941 0 : ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
942 0 : NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
943 :
944 0 : if (mediator)
945 0 : mediator->UnregisterWindow(aWindow);
946 :
947 : // tell the window watcher
948 0 : nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
949 0 : NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
950 0 : if (wwatcher) {
951 0 : nsCOMPtr<nsIDocShell> docShell;
952 0 : aWindow->GetDocShell(getter_AddRefs(docShell));
953 0 : if (docShell) {
954 0 : nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
955 0 : if (domWindow)
956 0 : wwatcher->RemoveWindow(domWindow);
957 : }
958 : }
959 :
960 0 : return NS_OK;
961 : }
962 :
963 :
964 : NS_IMETHODIMP
965 0 : nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic,
966 : const char16_t *aData)
967 : {
968 0 : if (!strcmp(aTopic, "xpcom-will-shutdown")) {
969 0 : mXPCOMWillShutDown = true;
970 0 : } else if (!strcmp(aTopic, "xpcom-shutdown")) {
971 0 : mXPCOMShuttingDown = true;
972 0 : if (mHiddenWindow) {
973 0 : mHiddenWindow->Destroy();
974 : }
975 0 : if (mHiddenPrivateWindow) {
976 0 : mHiddenPrivateWindow->Destroy();
977 : }
978 : } else {
979 0 : NS_ERROR("Unexpected observer topic!");
980 : }
981 :
982 0 : return NS_OK;
983 : }
984 :
985 : NS_IMETHODIMP
986 0 : nsAppShellService::StartEventLoopLagTracking(bool* aResult)
987 : {
988 : #ifdef MOZ_INSTRUMENT_EVENT_LOOP
989 0 : *aResult = mozilla::InitEventTracing(true);
990 : #endif
991 0 : return NS_OK;
992 : }
993 :
994 : NS_IMETHODIMP
995 0 : nsAppShellService::StopEventLoopLagTracking()
996 : {
997 : #ifdef MOZ_INSTRUMENT_EVENT_LOOP
998 0 : mozilla::ShutdownEventTracing();
999 : #endif
1000 0 : return NS_OK;
1001 : }
|