xpfe/appshell/src/nsAppShellService.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:bb1f187f9edf
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
16 #include "nsIWindowMediator.h"
17 #include "nsIWindowWatcher.h"
18 #include "nsPIWindowWatcher.h"
19 #include "nsIDOMWindow.h"
20 #include "nsPIDOMWindow.h"
21 #include "nsWebShellWindow.h"
22
23 #include "nsCRT.h"
24 #include "prprf.h"
25
26 #include "nsWidgetInitData.h"
27 #include "nsWidgetsCID.h"
28 #include "nsIWidget.h"
29 #include "nsIRequestObserver.h"
30
31 /* For implementing GetHiddenWindowAndJSContext */
32 #include "nsIScriptGlobalObject.h"
33 #include "nsIScriptContext.h"
34
35 #include "nsAppShellService.h"
36 #include "nsISupportsPrimitives.h"
37 #include "nsIChromeRegistry.h"
38 #include "nsILoadContext.h"
39 #include "nsIWebNavigation.h"
40
41 #include "mozilla/Attributes.h"
42 #include "mozilla/Preferences.h"
43 #include "mozilla/StartupTimeline.h"
44
45 #include "nsEmbedCID.h"
46 #include "nsIWebBrowser.h"
47 #include "nsIDocShell.h"
48
49 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
50 #include "EventTracer.h"
51 #endif
52
53 using namespace mozilla;
54
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"
57
58 class nsIAppShell;
59
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"));
68
69 if (obs) {
70 obs->AddObserver(this, "xpcom-will-shutdown", false);
71 obs->AddObserver(this, "xpcom-shutdown", false);
72 }
73 }
74
75 nsAppShellService::~nsAppShellService()
76 {
77 }
78
79
80 /*
81 * Implement the nsISupports methods...
82 */
83 NS_IMPL_ISUPPORTS(nsAppShellService,
84 nsIAppShellService,
85 nsIObserver)
86
87 NS_IMETHODIMP
88 nsAppShellService::CreateHiddenWindow()
89 {
90 return CreateHiddenWindowHelper(false);
91 }
92
93 void
94 nsAppShellService::EnsurePrivateHiddenWindow()
95 {
96 if (!mHiddenPrivateWindow) {
97 CreateHiddenWindowHelper(true);
98 }
99 }
100
101 nsresult
102 nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate)
103 {
104 nsresult rv;
105 int32_t initialHeight = 100, initialWidth = 100;
106
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
121
122 nsCOMPtr<nsIURI> url;
123 rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
124 NS_ENSURE_SUCCESS(rv, rv);
125
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);
132
133 mHiddenWindow.swap(newWindow);
134 } else {
135 // Create the hidden private window
136 chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
137
138 rv = JustCreateTopWindow(nullptr, url,
139 chromeMask, initialWidth, initialHeight,
140 true, getter_AddRefs(newWindow));
141 NS_ENSURE_SUCCESS(rv, rv);
142
143 nsCOMPtr<nsIDocShell> docShell;
144 newWindow->GetDocShell(getter_AddRefs(docShell));
145 if (docShell) {
146 docShell->SetAffectPrivateSessionLifetime(false);
147 }
148
149 mHiddenPrivateWindow.swap(newWindow);
150 }
151
152 // RegisterTopLevelWindow(newWindow); -- Mac only
153
154 return NS_OK;
155 }
156
157 NS_IMETHODIMP
158 nsAppShellService::DestroyHiddenWindow()
159 {
160 if (mHiddenWindow) {
161 mHiddenWindow->Destroy();
162
163 mHiddenWindow = nullptr;
164 }
165
166 if (mHiddenPrivateWindow) {
167 mHiddenPrivateWindow->Destroy();
168
169 mHiddenPrivateWindow = nullptr;
170 }
171
172 return NS_OK;
173 }
174
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)
185
186 {
187 nsresult rv;
188
189 StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
190
191 nsWebShellWindow *newWindow = nullptr;
192 rv = JustCreateTopWindow(aParent, aUrl,
193 aChromeMask, aInitialWidth, aInitialHeight,
194 false, &newWindow); // addrefs
195
196 *aResult = newWindow; // transfer ref
197
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 }
206
207 return rv;
208 }
209
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 };
224
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
232
233 NS_IMPL_ADDREF(WebBrowserChrome2Stub)
234 NS_IMPL_RELEASE(WebBrowserChrome2Stub)
235
236 NS_IMETHODIMP
237 WebBrowserChrome2Stub::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
238 {
239 return NS_OK;
240 }
241
242 NS_IMETHODIMP
243 WebBrowserChrome2Stub::GetWebBrowser(nsIWebBrowser** aWebBrowser)
244 {
245 NS_NOTREACHED("WebBrowserChrome2Stub::GetWebBrowser is not supported");
246 return NS_ERROR_NOT_IMPLEMENTED;
247 }
248
249 NS_IMETHODIMP
250 WebBrowserChrome2Stub::SetWebBrowser(nsIWebBrowser* aWebBrowser)
251 {
252 NS_NOTREACHED("WebBrowserChrome2Stub::SetWebBrowser is not supported");
253 return NS_ERROR_NOT_IMPLEMENTED;
254 }
255
256 NS_IMETHODIMP
257 WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags)
258 {
259 *aChromeFlags = 0;
260 return NS_OK;
261 }
262
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 }
269
270 NS_IMETHODIMP
271 WebBrowserChrome2Stub::DestroyBrowserWindow()
272 {
273 NS_NOTREACHED("WebBrowserChrome2Stub::DestroyBrowserWindow is not supported");
274 return NS_ERROR_NOT_IMPLEMENTED;
275 }
276
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 }
283
284 NS_IMETHODIMP
285 WebBrowserChrome2Stub::ShowAsModal()
286 {
287 NS_NOTREACHED("WebBrowserChrome2Stub::ShowAsModal is not supported");
288 return NS_ERROR_NOT_IMPLEMENTED;
289 }
290
291 NS_IMETHODIMP
292 WebBrowserChrome2Stub::IsWindowModal(bool* aResult)
293 {
294 *aResult = false;
295 return NS_OK;
296 }
297
298 NS_IMETHODIMP
299 WebBrowserChrome2Stub::ExitModalEventLoop(nsresult aStatus)
300 {
301 NS_NOTREACHED("WebBrowserChrome2Stub::ExitModalEventLoop is not supported");
302 return NS_ERROR_NOT_IMPLEMENTED;
303 }
304
305 NS_IMETHODIMP
306 WebBrowserChrome2Stub::SetStatusWithContext(uint32_t aStatusType,
307 const nsAString& aStatusText,
308 nsISupports* aStatusContext)
309 {
310 return NS_OK;
311 }
312
313 NS_IMETHODIMP
314 WebBrowserChrome2Stub::GetInterface(const nsIID & aIID, void **aSink)
315 {
316 return QueryInterface(aIID, aSink);
317 }
318
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 };
341
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
347
348 NS_IMPL_ADDREF(WindowlessBrowserStub)
349 NS_IMPL_RELEASE(WindowlessBrowserStub)
350
351
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 }
363
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);
375
376 nsCOMPtr<nsIWebNavigation> navigation = do_QueryInterface(browser);
377
378 nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(navigation);
379 item->SetItemType(aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
380 : nsIDocShellTreeItem::typeContentWrapper);
381
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();
397
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);
402
403 result.forget(aResult);
404 return NS_OK;
405 }
406
407 uint32_t
408 nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
409 uint32_t aChromeMask)
410 {
411 uint32_t zLevel;
412
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;
418
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.
423
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
439
440 return zLevel;
441 }
442
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;
453
454 nsCOMPtr<nsISimpleEnumerator> windowList;
455 wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList));
456 if (!windowList)
457 return false;
458
459 for (;;) {
460 bool more = false;
461 windowList->HasMoreElements(&more);
462 if (!more)
463 return false;
464
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
479
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);
494
495 nsCOMPtr<nsIXULWindow> parent;
496 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
497 parent = aParent;
498
499 nsRefPtr<nsWebShellWindow> window = new nsWebShellWindow(aChromeMask);
500 NS_ENSURE_TRUE(window, NS_ERROR_OUT_OF_MEMORY);
501
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
509
510 nsWidgetInitData widgetInitData;
511
512 if (aIsHiddenWindow)
513 widgetInitData.mWindowType = eWindowType_invisible;
514 else
515 widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ?
516 eWindowType_dialog : eWindowType_toplevel;
517
518 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
519 widgetInitData.mWindowType = eWindowType_popup;
520
521 if (aChromeMask & nsIWebBrowserChrome::CHROME_MAC_SUPPRESS_ANIMATION)
522 widgetInitData.mIsAnimationSuppressed = true;
523
524 if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW)
525 widgetInitData.mRequireOffMainThreadCompositing = true;
526
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
543
544 #if defined(XP_WIN)
545 if (widgetInitData.mWindowType == eWindowType_toplevel ||
546 widgetInitData.mWindowType == eWindowType_dialog)
547 widgetInitData.clipChildren = true;
548 #endif
549
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 }
578
579 if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
580 aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
581 aInitialWidth = 1;
582 aInitialHeight = 1;
583 window->SetIntrinsicallySized(true);
584 }
585
586 bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
587
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 }
597
598 nsresult rv = window->Initialize(parent, center ? aParent : nullptr,
599 aUrl, aInitialWidth, aInitialHeight,
600 aIsHiddenWindow, widgetInitData);
601
602 NS_ENSURE_SUCCESS(rv, rv);
603
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 }
629
630 window.swap(*aResult); // transfer reference
631 if (parent)
632 parent->AddChildWindow(*aResult);
633
634 if (center)
635 rv = (*aResult)->Center(parent, parent ? false : true, false);
636
637 return rv;
638 }
639
640 NS_IMETHODIMP
641 nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow)
642 {
643 NS_ENSURE_ARG_POINTER(aWindow);
644
645 *aWindow = mHiddenWindow;
646 NS_IF_ADDREF(*aWindow);
647 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
648 }
649
650 NS_IMETHODIMP
651 nsAppShellService::GetHiddenDOMWindow(nsIDOMWindow **aWindow)
652 {
653 nsresult rv;
654 nsCOMPtr<nsIDocShell> docShell;
655 NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
656
657 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
658 NS_ENSURE_SUCCESS(rv, rv);
659
660 nsCOMPtr<nsIDOMWindow> hiddenDOMWindow(do_GetInterface(docShell, &rv));
661 NS_ENSURE_SUCCESS(rv, rv);
662
663 *aWindow = hiddenDOMWindow;
664 NS_IF_ADDREF(*aWindow);
665 return NS_OK;
666 }
667
668 NS_IMETHODIMP
669 nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow)
670 {
671 NS_ENSURE_ARG_POINTER(aWindow);
672
673 EnsurePrivateHiddenWindow();
674
675 *aWindow = mHiddenPrivateWindow;
676 NS_IF_ADDREF(*aWindow);
677 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
678 }
679
680 NS_IMETHODIMP
681 nsAppShellService::GetHiddenPrivateDOMWindow(nsIDOMWindow **aWindow)
682 {
683 EnsurePrivateHiddenWindow();
684
685 nsresult rv;
686 nsCOMPtr<nsIDocShell> docShell;
687 NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE);
688
689 rv = mHiddenPrivateWindow->GetDocShell(getter_AddRefs(docShell));
690 NS_ENSURE_SUCCESS(rv, rv);
691
692 nsCOMPtr<nsIDOMWindow> hiddenPrivateDOMWindow(do_GetInterface(docShell, &rv));
693 NS_ENSURE_SUCCESS(rv, rv);
694
695 *aWindow = hiddenPrivateDOMWindow;
696 NS_IF_ADDREF(*aWindow);
697 return NS_OK;
698 }
699
700 NS_IMETHODIMP
701 nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow)
702 {
703 NS_ENSURE_ARG_POINTER(aHasPrivateWindow);
704
705 *aHasPrivateWindow = !!mHiddenPrivateWindow;
706 return NS_OK;
707 }
708
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;
717
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;
725
726 // 2. Convert that to an nsIDOMWindow.
727 nsCOMPtr<nsIDOMWindow> hiddenDOMWindow(do_GetInterface(docShell));
728 if(!hiddenDOMWindow) break;
729
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; }
734
735 // 4. Get script context from that.
736 nsIScriptContext *scriptContext = sgo->GetContext();
737 if (!scriptContext) { rv = NS_ERROR_FAILURE; break; }
738
739 // 5. Get JSContext from the script context.
740 JSContext *jsContext = scriptContext->GetNativeContext();
741 if (!jsContext) { rv = NS_ERROR_FAILURE; break; }
742
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 }
756
757 NS_IMETHODIMP
758 nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW)
759 {
760 *aAPHW = mApplicationProvidedHiddenWindow;
761 return NS_OK;
762 }
763
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);
771
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();
777
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.");
782
783 if (mediator)
784 mediator->RegisterWindow(aWindow);
785
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 }
792
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.");
797
798 if (obssvc)
799 obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
800
801 return NS_OK;
802 }
803
804
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 }
819
820 NS_ENSURE_ARG_POINTER(aWindow);
821
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 }
830
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?");
835
836 if (mediator)
837 mediator->UnregisterWindow(aWindow);
838
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 }
851
852 return NS_OK;
853 }
854
855
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 }
873
874 return NS_OK;
875 }
876
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 }
885
886 NS_IMETHODIMP
887 nsAppShellService::StopEventLoopLagTracking()
888 {
889 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
890 mozilla::ShutdownEventTracing();
891 #endif
892 return NS_OK;
893 }

mercurial