Back to index

lightning-sunbird  0.9+nobinonly
nsAppShellService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *   Robert O'Callahan <roc+moz@cs.cmu.edu>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 
00041 #include "nsIAppShellService.h"
00042 #include "nsISupportsArray.h"
00043 #include "nsIComponentManager.h"
00044 #include "nsIURL.h"
00045 #include "nsNetUtil.h"
00046 #include "nsIServiceManager.h"
00047 #include "nsIEventQueueService.h"
00048 #include "nsIObserverService.h"
00049 #include "nsIObserver.h"
00050 #include "nsIXPConnect.h"
00051 #include "nsIJSContextStack.h"
00052 #include "nsIPrefBranch.h"
00053 #include "nsIPrefService.h"
00054 
00055 #include "nsIWidget.h"
00056 #include "nsIWindowMediator.h"
00057 #include "nsIWindowWatcher.h"
00058 #include "nsPIWindowWatcher.h"
00059 #include "nsIDOMWindowInternal.h"
00060 #include "nsWebShellWindow.h"
00061 
00062 #include "nsIEnumerator.h"
00063 #include "nsCRT.h"
00064 #include "nsITimelineService.h"
00065 #include "prprf.h"    
00066 #include "plevent.h"
00067 
00068 #include "nsWidgetsCID.h"
00069 #include "nsIRequestObserver.h"
00070 
00071 /* For implementing GetHiddenWindowAndJSContext */
00072 #include "nsIScriptGlobalObject.h"
00073 #include "nsIScriptContext.h"
00074 #include "jsapi.h"
00075 
00076 #include "nsAppShellService.h"
00077 #include "nsISupportsPrimitives.h"
00078 #include "nsIPlatformCharset.h"
00079 #include "nsICharsetConverterManager.h"
00080 #include "nsIUnicodeDecoder.h"
00081 
00082 class nsIAppShell;
00083 
00084 nsAppShellService::nsAppShellService() : 
00085   mXPCOMShuttingDown(PR_FALSE),
00086   mModalWindowCount(0)
00087 {
00088   nsCOMPtr<nsIObserverService> obs
00089     (do_GetService("@mozilla.org/observer-service;1"));
00090 
00091   if (obs)
00092     obs->AddObserver(this, "xpcom-shutdown", PR_FALSE);
00093 }
00094 
00095 nsAppShellService::~nsAppShellService()
00096 {
00097 }
00098 
00099 
00100 /*
00101  * Implement the nsISupports methods...
00102  */
00103 NS_IMPL_ISUPPORTS2(nsAppShellService,
00104                    nsIAppShellService,
00105                    nsIObserver)
00106 
00107 nsresult 
00108 nsAppShellService::SetXPConnectSafeContext()
00109 {
00110   nsresult rv;
00111 
00112   nsCOMPtr<nsIThreadJSContextStack> cxstack =
00113     do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
00114   NS_ENSURE_SUCCESS(rv, rv);
00115 
00116   nsCOMPtr<nsIDOMWindowInternal> junk;
00117   JSContext *cx;
00118   rv = GetHiddenWindowAndJSContext(getter_AddRefs(junk), &cx);
00119   NS_ENSURE_SUCCESS(rv, rv);
00120 
00121   return cxstack->SetSafeJSContext(cx);
00122 }  
00123 
00124 nsresult nsAppShellService::ClearXPConnectSafeContext()
00125 {
00126   nsresult rv;
00127 
00128   nsCOMPtr<nsIThreadJSContextStack> cxstack =
00129     do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
00130   if (NS_FAILED(rv)) {
00131     NS_ERROR("XPConnect ContextStack gone before XPCOM shutdown?");
00132     return rv;
00133   }
00134 
00135   nsCOMPtr<nsIDOMWindowInternal> junk;
00136   JSContext *cx;
00137   rv = GetHiddenWindowAndJSContext(getter_AddRefs(junk), &cx);
00138   NS_ENSURE_SUCCESS(rv, rv);
00139 
00140   JSContext *safe_cx;
00141   rv = cxstack->GetSafeJSContext(&safe_cx);
00142   NS_ENSURE_SUCCESS(rv, rv);
00143 
00144   if (cx == safe_cx)
00145     rv = cxstack->SetSafeJSContext(nsnull);
00146 
00147   return rv;
00148 }
00149 
00150 NS_IMETHODIMP
00151 nsAppShellService::CreateHiddenWindow(nsIAppShell* aAppShell)
00152 {
00153   nsresult rv;
00154   PRInt32 initialHeight = 100, initialWidth = 100;
00155     
00156 #if defined(XP_MAC) || defined(XP_MACOSX)
00157   static const char defaultHiddenWindowURL[] = "chrome://global/content/hiddenWindow.xul";
00158   PRUint32    chromeMask = 0;
00159   nsCOMPtr<nsIPrefBranch> prefBranch;
00160   nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
00161   prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
00162   nsXPIDLCString prefVal;
00163   rv = prefBranch->GetCharPref("browser.hiddenWindowChromeURL", getter_Copies(prefVal));
00164   const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : defaultHiddenWindowURL;
00165 #else
00166   static const char hiddenWindowURL[] = "resource://gre/res/hiddenWindow.html";
00167   PRUint32    chromeMask =  nsIWebBrowserChrome::CHROME_ALL;
00168 #endif
00169 
00170   nsCOMPtr<nsIURI> url;
00171   rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
00172   NS_ENSURE_SUCCESS(rv, rv);
00173 
00174   nsRefPtr<nsWebShellWindow> newWindow;
00175   rv = JustCreateTopWindow(nsnull, url,
00176                            chromeMask, initialWidth, initialHeight,
00177                            PR_TRUE, aAppShell, getter_AddRefs(newWindow));
00178   NS_ENSURE_SUCCESS(rv, rv);
00179 
00180   mHiddenWindow.swap(newWindow);
00181 
00182 #if defined(XP_MAC) || defined(XP_MACOSX)
00183   // hide the hidden window by launching it into outer space. This
00184   // way, we can keep it visible and let the OS send it activates
00185   // to keep menus happy. This will cause it to show up in window
00186   // lists under osx, but I think that's ok.
00187   mHiddenWindow->SetPosition ( -32000, -32000 );
00188   mHiddenWindow->SetVisibility ( PR_TRUE );
00189 #endif
00190 
00191   // Set XPConnect's fallback JSContext (used for JS Components)
00192   // to the DOM JSContext for this thread, so that DOM-to-XPConnect
00193   // conversions get the JSContext private magic they need to
00194   // succeed.
00195   SetXPConnectSafeContext();
00196 
00197   // RegisterTopLevelWindow(newWindow); -- Mac only
00198 
00199   return NS_OK;
00200 }
00201 
00202 NS_IMETHODIMP
00203 nsAppShellService::DestroyHiddenWindow()
00204 {
00205   if (mHiddenWindow) {
00206     ClearXPConnectSafeContext();
00207     mHiddenWindow->Destroy();
00208 
00209     mHiddenWindow = nsnull;
00210   }
00211 
00212   return NS_OK;
00213 }
00214 
00215 /*
00216  * Create a new top level window and display the given URL within it...
00217  */
00218 NS_IMETHODIMP
00219 nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent,
00220                                         nsIURI *aUrl, 
00221                                         PRUint32 aChromeMask,
00222                                         PRInt32 aInitialWidth,
00223                                         PRInt32 aInitialHeight,
00224                                         nsIAppShell* aAppShell,
00225                                         nsIXULWindow **aResult)
00226 
00227 {
00228   nsresult rv;
00229 
00230   nsWebShellWindow *newWindow = nsnull;
00231   rv = JustCreateTopWindow(aParent, aUrl,
00232                            aChromeMask, aInitialWidth, aInitialHeight,
00233                            PR_FALSE, aAppShell, &newWindow);  // addrefs
00234 
00235   *aResult = newWindow; // transfer ref
00236 
00237   if (NS_SUCCEEDED(rv)) {
00238     // the addref resulting from this is the owning addref for this window
00239     RegisterTopLevelWindow(*aResult);
00240     (*aResult)->SetZLevel(CalculateWindowZLevel(aParent, aChromeMask));
00241   }
00242 
00243   return rv;
00244 }
00245 
00246 PRUint32
00247 nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
00248                                          PRUint32      aChromeMask)
00249 {
00250   PRUint32 zLevel;
00251 
00252   zLevel = nsIXULWindow::normalZ;
00253   if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
00254     zLevel = nsIXULWindow::raisedZ;
00255   else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
00256     zLevel = nsIXULWindow::loweredZ;
00257 
00258 #if defined(XP_MAC) || defined(XP_MACOSX)
00259   /* Platforms on which modal windows are always application-modal, not
00260      window-modal (that's just the Mac, right?) want modal windows to
00261      be stacked on top of everyone else.
00262 
00263      On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
00264   */
00265   PRUint32 modalDepMask = nsIWebBrowserChrome::CHROME_MODAL |
00266                           nsIWebBrowserChrome::CHROME_DEPENDENT;
00267   if (aParent && (aChromeMask & modalDepMask)) {
00268     aParent->GetZLevel(&zLevel);
00269   }
00270 #else
00271   /* Platforms with native support for dependent windows (that's everyone
00272       but pre-Mac OS X, right?) know how to stack dependent windows. On these
00273       platforms, give the dependent window the same level as its parent,
00274       so we won't try to override the normal platform behaviour. */
00275   if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent)
00276     aParent->GetZLevel(&zLevel);
00277 #endif
00278 
00279   return zLevel;
00280 }
00281 
00282 /*
00283  * Just do the window-making part of CreateTopLevelWindow
00284  */
00285 nsresult
00286 nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent,
00287                                        nsIURI *aUrl, 
00288                                        PRUint32 aChromeMask,
00289                                        PRInt32 aInitialWidth,
00290                                        PRInt32 aInitialHeight,
00291                                        PRBool aIsHiddenWindow,
00292                                        nsIAppShell* aAppShell,
00293                                        nsWebShellWindow **aResult)
00294 {
00295   *aResult = nsnull;
00296 
00297   nsRefPtr<nsWebShellWindow> window = new nsWebShellWindow();
00298   NS_ENSURE_TRUE(window, NS_ERROR_OUT_OF_MEMORY);
00299 
00300   nsWidgetInitData widgetInitData;
00301 
00302   if (aIsHiddenWindow)
00303     widgetInitData.mWindowType = eWindowType_invisible;
00304   else
00305     widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ?
00306       eWindowType_dialog : eWindowType_toplevel;
00307 
00308   if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
00309     widgetInitData.mWindowType = eWindowType_popup;
00310 
00311 #ifdef XP_MACOSX
00312   // Mac OS X sheet support
00313   PRUint32 sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
00314     nsIWebBrowserChrome::CHROME_MODAL;
00315   if (aParent && ((aChromeMask & sheetMask) == sheetMask))
00316     widgetInitData.mWindowType = eWindowType_sheet;
00317 #endif
00318 
00319   widgetInitData.mContentType = eContentTypeUI;                
00320 
00321   // note default chrome overrides other OS chrome settings, but
00322   // not internal chrome
00323   if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT)
00324     widgetInitData.mBorderStyle = eBorderStyle_default;
00325   else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
00326     widgetInitData.mBorderStyle = eBorderStyle_all;
00327   else {
00328     widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00
00329     if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS)
00330       widgetInitData.mBorderStyle = NS_STATIC_CAST(enum nsBorderStyle, widgetInitData.mBorderStyle | eBorderStyle_border);
00331     if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR)
00332       widgetInitData.mBorderStyle = NS_STATIC_CAST(enum nsBorderStyle, widgetInitData.mBorderStyle | eBorderStyle_title);
00333     if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
00334       widgetInitData.mBorderStyle = NS_STATIC_CAST(enum nsBorderStyle, widgetInitData.mBorderStyle | eBorderStyle_close);
00335     if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
00336       widgetInitData.mBorderStyle = NS_STATIC_CAST(enum nsBorderStyle, widgetInitData.mBorderStyle | eBorderStyle_resizeh);
00337       // only resizable windows get the maximize button (but not dialogs)
00338       if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
00339         widgetInitData.mBorderStyle = NS_STATIC_CAST(enum nsBorderStyle, widgetInitData.mBorderStyle | eBorderStyle_maximize);
00340     }
00341     // all windows (except dialogs) get minimize buttons and the system menu
00342     if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
00343       widgetInitData.mBorderStyle = NS_STATIC_CAST(enum nsBorderStyle, widgetInitData.mBorderStyle | eBorderStyle_minimize | eBorderStyle_menu);
00344     // but anyone can explicitly ask for a minimize button
00345     if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) {
00346       widgetInitData.mBorderStyle = NS_STATIC_CAST(enum nsBorderStyle, widgetInitData.mBorderStyle | eBorderStyle_minimize );
00347     }  
00348   }
00349 
00350   if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
00351       aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
00352     aInitialWidth = 1;
00353     aInitialHeight = 1;
00354     window->SetIntrinsicallySized(PR_TRUE);
00355   }
00356 
00357   nsresult rv = window->Initialize(aParent, aAppShell, aUrl,
00358                                    aInitialWidth, aInitialHeight,
00359                                    aIsHiddenWindow, widgetInitData);
00360       
00361   NS_ENSURE_SUCCESS(rv, rv);
00362 
00363   window.swap(*aResult); // transfer reference
00364   if (aParent)
00365     aParent->AddChildWindow(*aResult);
00366 
00367   if (aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN)
00368     rv = (*aResult)->Center(aParent, aParent ? PR_FALSE : PR_TRUE, PR_FALSE);
00369 
00370   return rv;
00371 }
00372 
00373 NS_IMETHODIMP
00374 nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow)
00375 {
00376   NS_ENSURE_ARG_POINTER(aWindow);
00377 
00378   *aWindow = mHiddenWindow;
00379   NS_IF_ADDREF(*aWindow);
00380   return *aWindow ? NS_OK : NS_ERROR_FAILURE;
00381 }
00382 
00383 NS_IMETHODIMP
00384 nsAppShellService::GetHiddenDOMWindow(nsIDOMWindowInternal **aWindow)
00385 {
00386   nsresult rv;
00387   nsCOMPtr<nsIDocShell> docShell;
00388   NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
00389 
00390   rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
00391   NS_ENSURE_SUCCESS(rv, rv);
00392   
00393   nsCOMPtr<nsIDOMWindowInternal> hiddenDOMWindow(do_GetInterface(docShell, &rv));
00394   NS_ENSURE_SUCCESS(rv, rv);
00395 
00396   *aWindow = hiddenDOMWindow;
00397   NS_IF_ADDREF(*aWindow);
00398   return NS_OK;
00399 }
00400 
00401 NS_IMETHODIMP
00402 nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindowInternal **aWindow,
00403                                                JSContext    **aJSContext)
00404 {
00405     nsresult rv = NS_OK;
00406     if ( aWindow && aJSContext ) {
00407         *aWindow    = nsnull;
00408         *aJSContext = nsnull;
00409 
00410         if ( mHiddenWindow ) {
00411             // Convert hidden window to nsIDOMWindowInternal and extract its JSContext.
00412             do {
00413                 // 1. Get doc for hidden window.
00414                 nsCOMPtr<nsIDocShell> docShell;
00415                 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
00416                 if (NS_FAILED(rv)) break;
00417 
00418                 // 2. Convert that to an nsIDOMWindowInternal.
00419                 nsCOMPtr<nsIDOMWindowInternal> hiddenDOMWindow(do_GetInterface(docShell));
00420                 if(!hiddenDOMWindow) break;
00421 
00422                 // 3. Get script global object for the window.
00423                 nsCOMPtr<nsIScriptGlobalObject> sgo;
00424                 sgo = do_QueryInterface( hiddenDOMWindow );
00425                 if (!sgo) { rv = NS_ERROR_FAILURE; break; }
00426 
00427                 // 4. Get script context from that.
00428                 nsIScriptContext *scriptContext = sgo->GetContext();
00429                 if (!scriptContext) { rv = NS_ERROR_FAILURE; break; }
00430 
00431                 // 5. Get JSContext from the script context.
00432                 JSContext *jsContext = (JSContext*)scriptContext->GetNativeContext();
00433                 if (!jsContext) { rv = NS_ERROR_FAILURE; break; }
00434 
00435                 // Now, give results to caller.
00436                 *aWindow    = hiddenDOMWindow.get();
00437                 NS_IF_ADDREF( *aWindow );
00438                 *aJSContext = jsContext;
00439             } while (0);
00440         } else {
00441             rv = NS_ERROR_FAILURE;
00442         }
00443     } else {
00444         rv = NS_ERROR_NULL_POINTER;
00445     }
00446     return rv;
00447 }
00448 
00449 /*
00450  * Register a new top level window (created elsewhere)
00451  */
00452 NS_IMETHODIMP
00453 nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
00454 {
00455   // tell the window mediator about the new window
00456   nsCOMPtr<nsIWindowMediator> mediator
00457     ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
00458   NS_ASSERTION(mediator, "Couldn't get window mediator.");
00459 
00460   if (mediator)
00461     mediator->RegisterWindow(aWindow);
00462 
00463   // tell the window watcher about the new window
00464   nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
00465   NS_ASSERTION(wwatcher, "No windowwatcher?");
00466   if (wwatcher) {
00467     nsCOMPtr<nsIDocShell> docShell;
00468     aWindow->GetDocShell(getter_AddRefs(docShell));
00469     NS_ASSERTION(docShell, "Window has no docshell");
00470     if (docShell) {
00471       nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
00472       NS_ASSERTION(domWindow, "Couldn't get DOM window.");
00473       if (domWindow)
00474         wwatcher->AddWindow(domWindow, 0);
00475     }
00476   }
00477 
00478   // an ongoing attempt to quit is stopped by a newly opened window
00479   nsCOMPtr<nsIObserverService> obssvc =
00480     do_GetService("@mozilla.org/observer-service;1");
00481   NS_ASSERTION(obssvc, "Couldn't get observer service.");
00482 
00483   if (obssvc)
00484     obssvc->NotifyObservers(aWindow, "xul-window-registered", nsnull);
00485 
00486   return NS_OK;
00487 }
00488 
00489 
00490 NS_IMETHODIMP
00491 nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
00492 {
00493   if (mXPCOMShuttingDown) {
00494     /* return an error code in order to:
00495        - avoid doing anything with other member variables while we are in
00496          the destructor
00497        - notify the caller not to release the AppShellService after
00498          unregistering the window
00499          (we don't want to be deleted twice consecutively to
00500          mHiddenWindow->Destroy() in our destructor)
00501     */
00502     return NS_ERROR_FAILURE;
00503   }
00504   
00505   NS_ENSURE_ARG_POINTER(aWindow);
00506 
00507   // tell the window mediator
00508   nsCOMPtr<nsIWindowMediator> mediator
00509     ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
00510   NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
00511 
00512   if (mediator)
00513     mediator->UnregisterWindow(aWindow);
00514        
00515   // tell the window watcher
00516   nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
00517   NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
00518   if (wwatcher) {
00519     nsCOMPtr<nsIDocShell> docShell;
00520     aWindow->GetDocShell(getter_AddRefs(docShell));
00521     if (docShell) {
00522       nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
00523       if (domWindow)
00524         wwatcher->RemoveWindow(domWindow);
00525     }
00526   }
00527 
00528   return NS_OK;
00529 }
00530 
00531 /* Old function, needs to be removed... it was only used on Mac OS9 */
00532 NS_IMETHODIMP
00533 nsAppShellService::TopLevelWindowIsModal(nsIXULWindow *aWindow, PRBool aModal)
00534 {
00535   return NS_OK;
00536 }
00537 
00538 NS_IMETHODIMP
00539 nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic,
00540                            const PRUnichar *aData)
00541 {
00542   NS_ASSERTION(!strcmp(aTopic, "xpcom-shutdown"), "Unexpected observer topic!");
00543 
00544   mXPCOMShuttingDown = PR_TRUE;
00545   if (mHiddenWindow) {
00546     ClearXPConnectSafeContext();
00547     mHiddenWindow->Destroy();
00548   }
00549 
00550   return NS_OK;
00551 }