Bug 575195 - Send size mode events to dom from web shell window, and insure new windo...
[mozilla-central.git] / xpfe / appshell / src / nsAppShellService.cpp
blob5c680b5afdb1ca531b699cd764465f44e6fc6525
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Pierre Phaneuf <pp@ludusdesign.com>
24 * Robert O'Callahan <roc+moz@cs.cmu.edu>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 #include "nsIAppShellService.h"
42 #include "nsISupportsArray.h"
43 #include "nsIComponentManager.h"
44 #include "nsIURL.h"
45 #include "nsNetUtil.h"
46 #include "nsIServiceManager.h"
47 #include "nsIObserverService.h"
48 #include "nsIObserver.h"
49 #include "nsIXPConnect.h"
50 #include "nsIJSContextStack.h"
51 #include "nsIPrefBranch.h"
52 #include "nsIPrefService.h"
54 #include "nsIWindowMediator.h"
55 #include "nsIWindowWatcher.h"
56 #include "nsPIWindowWatcher.h"
57 #include "nsIDOMWindowInternal.h"
58 #include "nsWebShellWindow.h"
60 #include "nsIEnumerator.h"
61 #include "nsCRT.h"
62 #include "nsITimelineService.h"
63 #include "prprf.h"
65 #include "nsWidgetsCID.h"
66 #include "nsIRequestObserver.h"
68 /* For implementing GetHiddenWindowAndJSContext */
69 #include "nsIScriptGlobalObject.h"
70 #include "nsIScriptContext.h"
71 #include "jsapi.h"
73 #include "nsAppShellService.h"
74 #include "nsISupportsPrimitives.h"
75 #include "nsIPlatformCharset.h"
76 #include "nsICharsetConverterManager.h"
77 #include "nsIUnicodeDecoder.h"
78 #include "nsIChromeRegistry.h"
80 // Default URL for the hidden window, can be overridden by a pref on Mac
81 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
83 class nsIAppShell;
85 nsAppShellService::nsAppShellService() :
86 mXPCOMWillShutDown(PR_FALSE),
87 mXPCOMShuttingDown(PR_FALSE),
88 mModalWindowCount(0),
89 mApplicationProvidedHiddenWindow(PR_FALSE)
91 nsCOMPtr<nsIObserverService> obs
92 (do_GetService("@mozilla.org/observer-service;1"));
94 if (obs) {
95 obs->AddObserver(this, "xpcom-will-shutdown", PR_FALSE);
96 obs->AddObserver(this, "xpcom-shutdown", PR_FALSE);
100 nsAppShellService::~nsAppShellService()
106 * Implement the nsISupports methods...
108 NS_IMPL_ISUPPORTS2(nsAppShellService,
109 nsIAppShellService,
110 nsIObserver)
112 nsresult
113 nsAppShellService::SetXPConnectSafeContext()
115 nsresult rv;
117 nsCOMPtr<nsIThreadJSContextStack> cxstack =
118 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
119 NS_ENSURE_SUCCESS(rv, rv);
121 nsCOMPtr<nsIDOMWindowInternal> junk;
122 JSContext *cx;
123 rv = GetHiddenWindowAndJSContext(getter_AddRefs(junk), &cx);
124 NS_ENSURE_SUCCESS(rv, rv);
126 return cxstack->SetSafeJSContext(cx);
129 nsresult nsAppShellService::ClearXPConnectSafeContext()
131 nsresult rv;
133 nsCOMPtr<nsIThreadJSContextStack> cxstack =
134 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
135 if (NS_FAILED(rv)) {
136 NS_ERROR("XPConnect ContextStack gone before XPCOM shutdown?");
137 return rv;
140 nsCOMPtr<nsIDOMWindowInternal> junk;
141 JSContext *cx;
142 rv = GetHiddenWindowAndJSContext(getter_AddRefs(junk), &cx);
143 NS_ENSURE_SUCCESS(rv, rv);
145 JSContext *safe_cx;
146 rv = cxstack->GetSafeJSContext(&safe_cx);
147 NS_ENSURE_SUCCESS(rv, rv);
149 if (cx == safe_cx)
150 rv = cxstack->SetSafeJSContext(nsnull);
152 return rv;
155 NS_IMETHODIMP
156 nsAppShellService::CreateHiddenWindow(nsIAppShell* aAppShell)
158 nsresult rv;
159 PRInt32 initialHeight = 100, initialWidth = 100;
161 #ifdef XP_MACOSX
162 PRUint32 chromeMask = 0;
163 nsCOMPtr<nsIPrefBranch> prefBranch;
164 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
165 prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
166 nsXPIDLCString prefVal;
167 rv = prefBranch->GetCharPref("browser.hiddenWindowChromeURL", getter_Copies(prefVal));
168 const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
169 mApplicationProvidedHiddenWindow = prefVal.get() ? PR_TRUE : PR_FALSE;
170 #else
171 static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
172 PRUint32 chromeMask = nsIWebBrowserChrome::CHROME_ALL;
173 #endif
175 nsCOMPtr<nsIURI> url;
176 rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
177 NS_ENSURE_SUCCESS(rv, rv);
179 nsRefPtr<nsWebShellWindow> newWindow;
180 rv = JustCreateTopWindow(nsnull, url,
181 chromeMask, initialWidth, initialHeight,
182 PR_TRUE, aAppShell, getter_AddRefs(newWindow));
183 NS_ENSURE_SUCCESS(rv, rv);
185 mHiddenWindow.swap(newWindow);
187 #ifdef XP_MACOSX
188 // hide the hidden window by launching it into outer space. This
189 // way, we can keep it visible and let the OS send it activates
190 // to keep menus happy. This will cause it to show up in window
191 // lists under osx, but I think that's ok.
192 mHiddenWindow->SetPosition ( -32000, -32000 );
193 mHiddenWindow->SetVisibility ( PR_TRUE );
194 #endif
196 // Set XPConnect's fallback JSContext (used for JS Components)
197 // to the DOM JSContext for this thread, so that DOM-to-XPConnect
198 // conversions get the JSContext private magic they need to
199 // succeed.
200 SetXPConnectSafeContext();
202 // RegisterTopLevelWindow(newWindow); -- Mac only
204 return NS_OK;
207 NS_IMETHODIMP
208 nsAppShellService::DestroyHiddenWindow()
210 if (mHiddenWindow) {
211 ClearXPConnectSafeContext();
212 mHiddenWindow->Destroy();
214 mHiddenWindow = nsnull;
217 return NS_OK;
221 * Create a new top level window and display the given URL within it...
223 NS_IMETHODIMP
224 nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent,
225 nsIURI *aUrl,
226 PRUint32 aChromeMask,
227 PRInt32 aInitialWidth,
228 PRInt32 aInitialHeight,
229 nsIAppShell* aAppShell,
230 nsIXULWindow **aResult)
233 nsresult rv;
235 nsWebShellWindow *newWindow = nsnull;
236 rv = JustCreateTopWindow(aParent, aUrl,
237 aChromeMask, aInitialWidth, aInitialHeight,
238 PR_FALSE, aAppShell, &newWindow); // addrefs
240 *aResult = newWindow; // transfer ref
242 if (NS_SUCCEEDED(rv)) {
243 // the addref resulting from this is the owning addref for this window
244 RegisterTopLevelWindow(*aResult);
245 nsCOMPtr<nsIXULWindow> parent;
246 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
247 parent = aParent;
248 (*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
251 return rv;
254 PRUint32
255 nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
256 PRUint32 aChromeMask)
258 PRUint32 zLevel;
260 zLevel = nsIXULWindow::normalZ;
261 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
262 zLevel = nsIXULWindow::raisedZ;
263 else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
264 zLevel = nsIXULWindow::loweredZ;
266 #ifdef XP_MACOSX
267 /* Platforms on which modal windows are always application-modal, not
268 window-modal (that's just the Mac, right?) want modal windows to
269 be stacked on top of everyone else.
271 On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
273 PRUint32 modalDepMask = nsIWebBrowserChrome::CHROME_MODAL |
274 nsIWebBrowserChrome::CHROME_DEPENDENT;
275 if (aParent && (aChromeMask & modalDepMask)) {
276 aParent->GetZLevel(&zLevel);
278 #else
279 /* Platforms with native support for dependent windows (that's everyone
280 but pre-Mac OS X, right?) know how to stack dependent windows. On these
281 platforms, give the dependent window the same level as its parent,
282 so we won't try to override the normal platform behaviour. */
283 if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent)
284 aParent->GetZLevel(&zLevel);
285 #endif
287 return zLevel;
291 * Checks to see if any existing window is currently in fullscreen mode.
293 static PRBool
294 CheckForFullscreenWindow()
296 nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
297 if (!wm)
298 return PR_FALSE;
300 nsCOMPtr<nsISimpleEnumerator> windowList;
301 wm->GetXULWindowEnumerator(nsnull, getter_AddRefs(windowList));
302 if (!windowList)
303 return PR_FALSE;
305 for (;;) {
306 PRBool more = PR_FALSE;
307 windowList->HasMoreElements(&more);
308 if (!more)
309 return PR_FALSE;
311 nsCOMPtr<nsISupports> supportsWindow;
312 windowList->GetNext(getter_AddRefs(supportsWindow));
313 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
314 if (baseWin) {
315 PRInt32 sizeMode;
316 nsCOMPtr<nsIWidget> widget;
317 baseWin->GetMainWidget(getter_AddRefs(widget));
318 if (widget && NS_SUCCEEDED(widget->GetSizeMode(&sizeMode)) &&
319 sizeMode == nsSizeMode_Fullscreen) {
320 return PR_TRUE;
324 return PR_FALSE;
328 * Just do the window-making part of CreateTopLevelWindow
330 nsresult
331 nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent,
332 nsIURI *aUrl,
333 PRUint32 aChromeMask,
334 PRInt32 aInitialWidth,
335 PRInt32 aInitialHeight,
336 PRBool aIsHiddenWindow,
337 nsIAppShell* aAppShell,
338 nsWebShellWindow **aResult)
340 *aResult = nsnull;
341 NS_ENSURE_STATE(!mXPCOMWillShutDown);
343 nsCOMPtr<nsIXULWindow> parent;
344 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
345 parent = aParent;
347 nsRefPtr<nsWebShellWindow> window = new nsWebShellWindow(aChromeMask);
348 NS_ENSURE_TRUE(window, NS_ERROR_OUT_OF_MEMORY);
350 #ifdef XP_WIN
351 // If the parent is currently fullscreen, tell the child to ignore persisted
352 // full screen states. This way new browser windows open on top of fullscreen
353 // windows normally.
354 if (window && CheckForFullscreenWindow())
355 window->IgnoreXULSizeMode(PR_TRUE);
356 #endif
358 nsWidgetInitData widgetInitData;
360 if (aIsHiddenWindow)
361 widgetInitData.mWindowType = eWindowType_invisible;
362 else
363 widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ?
364 eWindowType_dialog : eWindowType_toplevel;
366 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
367 widgetInitData.mWindowType = eWindowType_popup;
369 #ifdef XP_MACOSX
370 // Mac OS X sheet support
371 // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
372 // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
373 // windows opened from nsPromptService::DoDialog() still are sheets. This
374 // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
375 // nsCocoaWindow::SetModal()).
376 PRUint32 sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
377 nsIWebBrowserChrome::CHROME_MODAL |
378 nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
379 if (parent && ((aChromeMask & sheetMask) == sheetMask))
380 widgetInitData.mWindowType = eWindowType_sheet;
381 #endif
383 #if defined(XP_WIN)
384 if (widgetInitData.mWindowType == eWindowType_toplevel ||
385 widgetInitData.mWindowType == eWindowType_dialog)
386 widgetInitData.clipChildren = PR_TRUE;
387 #endif
389 widgetInitData.mContentType = eContentTypeUI;
391 // note default chrome overrides other OS chrome settings, but
392 // not internal chrome
393 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT)
394 widgetInitData.mBorderStyle = eBorderStyle_default;
395 else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
396 widgetInitData.mBorderStyle = eBorderStyle_all;
397 else {
398 widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00
399 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS)
400 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_border);
401 if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR)
402 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_title);
403 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
404 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_close);
405 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
406 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_resizeh);
407 // only resizable windows get the maximize button (but not dialogs)
408 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
409 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_maximize);
411 // all windows (except dialogs) get minimize buttons and the system menu
412 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
413 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize | eBorderStyle_menu);
414 // but anyone can explicitly ask for a minimize button
415 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) {
416 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize);
420 if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
421 aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
422 aInitialWidth = 1;
423 aInitialHeight = 1;
424 window->SetIntrinsicallySized(PR_TRUE);
427 PRBool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
429 nsCOMPtr<nsIXULChromeRegistry> reg =
430 mozilla::services::GetXULChromeRegistryService();
431 if (reg) {
432 nsCAutoString package;
433 package.AssignLiteral("global");
434 PRBool isRTL = PR_FALSE;
435 reg->IsLocaleRTL(package, &isRTL);
436 widgetInitData.mRTL = isRTL;
439 nsresult rv = window->Initialize(parent, center ? aParent : nsnull,
440 aAppShell, aUrl,
441 aInitialWidth, aInitialHeight,
442 aIsHiddenWindow, widgetInitData);
444 NS_ENSURE_SUCCESS(rv, rv);
446 window.swap(*aResult); // transfer reference
447 if (parent)
448 parent->AddChildWindow(*aResult);
450 if (center)
451 rv = (*aResult)->Center(parent, parent ? PR_FALSE : PR_TRUE, PR_FALSE);
453 return rv;
456 NS_IMETHODIMP
457 nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow)
459 NS_ENSURE_ARG_POINTER(aWindow);
461 *aWindow = mHiddenWindow;
462 NS_IF_ADDREF(*aWindow);
463 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
466 NS_IMETHODIMP
467 nsAppShellService::GetHiddenDOMWindow(nsIDOMWindowInternal **aWindow)
469 nsresult rv;
470 nsCOMPtr<nsIDocShell> docShell;
471 NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
473 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
474 NS_ENSURE_SUCCESS(rv, rv);
476 nsCOMPtr<nsIDOMWindowInternal> hiddenDOMWindow(do_GetInterface(docShell, &rv));
477 NS_ENSURE_SUCCESS(rv, rv);
479 *aWindow = hiddenDOMWindow;
480 NS_IF_ADDREF(*aWindow);
481 return NS_OK;
484 NS_IMETHODIMP
485 nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindowInternal **aWindow,
486 JSContext **aJSContext)
488 nsresult rv = NS_OK;
489 if ( aWindow && aJSContext ) {
490 *aWindow = nsnull;
491 *aJSContext = nsnull;
493 if ( mHiddenWindow ) {
494 // Convert hidden window to nsIDOMWindowInternal and extract its JSContext.
495 do {
496 // 1. Get doc for hidden window.
497 nsCOMPtr<nsIDocShell> docShell;
498 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
499 if (NS_FAILED(rv)) break;
501 // 2. Convert that to an nsIDOMWindowInternal.
502 nsCOMPtr<nsIDOMWindowInternal> hiddenDOMWindow(do_GetInterface(docShell));
503 if(!hiddenDOMWindow) break;
505 // 3. Get script global object for the window.
506 nsCOMPtr<nsIScriptGlobalObject> sgo;
507 sgo = do_QueryInterface( hiddenDOMWindow );
508 if (!sgo) { rv = NS_ERROR_FAILURE; break; }
510 // 4. Get script context from that.
511 nsIScriptContext *scriptContext = sgo->GetContext();
512 if (!scriptContext) { rv = NS_ERROR_FAILURE; break; }
514 // 5. Get JSContext from the script context.
515 JSContext *jsContext = (JSContext*)scriptContext->GetNativeContext();
516 if (!jsContext) { rv = NS_ERROR_FAILURE; break; }
518 // Now, give results to caller.
519 *aWindow = hiddenDOMWindow.get();
520 NS_IF_ADDREF( *aWindow );
521 *aJSContext = jsContext;
522 } while (0);
523 } else {
524 rv = NS_ERROR_FAILURE;
526 } else {
527 rv = NS_ERROR_NULL_POINTER;
529 return rv;
532 NS_IMETHODIMP
533 nsAppShellService::GetApplicationProvidedHiddenWindow(PRBool* aAPHW)
535 *aAPHW = mApplicationProvidedHiddenWindow;
536 return NS_OK;
540 * Register a new top level window (created elsewhere)
542 NS_IMETHODIMP
543 nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
545 // tell the window mediator about the new window
546 nsCOMPtr<nsIWindowMediator> mediator
547 ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
548 NS_ASSERTION(mediator, "Couldn't get window mediator.");
550 if (mediator)
551 mediator->RegisterWindow(aWindow);
553 // tell the window watcher about the new window
554 nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
555 NS_ASSERTION(wwatcher, "No windowwatcher?");
556 if (wwatcher) {
557 nsCOMPtr<nsIDocShell> docShell;
558 aWindow->GetDocShell(getter_AddRefs(docShell));
559 NS_ASSERTION(docShell, "Window has no docshell");
560 if (docShell) {
561 nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
562 NS_ASSERTION(domWindow, "Couldn't get DOM window.");
563 if (domWindow)
564 wwatcher->AddWindow(domWindow, 0);
568 // an ongoing attempt to quit is stopped by a newly opened window
569 nsCOMPtr<nsIObserverService> obssvc =
570 do_GetService("@mozilla.org/observer-service;1");
571 NS_ASSERTION(obssvc, "Couldn't get observer service.");
573 if (obssvc)
574 obssvc->NotifyObservers(aWindow, "xul-window-registered", nsnull);
576 return NS_OK;
580 NS_IMETHODIMP
581 nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
583 if (mXPCOMShuttingDown) {
584 /* return an error code in order to:
585 - avoid doing anything with other member variables while we are in
586 the destructor
587 - notify the caller not to release the AppShellService after
588 unregistering the window
589 (we don't want to be deleted twice consecutively to
590 mHiddenWindow->Destroy() in our destructor)
592 return NS_ERROR_FAILURE;
595 NS_ENSURE_ARG_POINTER(aWindow);
597 if (aWindow == mHiddenWindow) {
598 // CreateHiddenWindow() does not register the window, so we're done.
599 return NS_OK;
602 // tell the window mediator
603 nsCOMPtr<nsIWindowMediator> mediator
604 ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
605 NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
607 if (mediator)
608 mediator->UnregisterWindow(aWindow);
610 // tell the window watcher
611 nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
612 NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
613 if (wwatcher) {
614 nsCOMPtr<nsIDocShell> docShell;
615 aWindow->GetDocShell(getter_AddRefs(docShell));
616 if (docShell) {
617 nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
618 if (domWindow)
619 wwatcher->RemoveWindow(domWindow);
623 return NS_OK;
627 NS_IMETHODIMP
628 nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic,
629 const PRUnichar *aData)
631 if (!strcmp(aTopic, "xpcom-will-shutdown")) {
632 mXPCOMWillShutDown = PR_TRUE;
633 } else if (!strcmp(aTopic, "xpcom-shutdown")) {
634 mXPCOMShuttingDown = PR_TRUE;
635 if (mHiddenWindow) {
636 ClearXPConnectSafeContext();
637 mHiddenWindow->Destroy();
639 } else {
640 NS_ERROR("Unexpected observer topic!");
643 return NS_OK;