|
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 } |