tell nsWindowWatcher about window creation/destruction so its enumerators will work. bug 97514 r=hyatt,pchen

This commit is contained in:
danm%netscape.com 2001-09-06 18:26:52 +00:00
parent 306e8a9552
commit 910ae825f5
2 changed files with 153 additions and 134 deletions

View File

@ -69,6 +69,7 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID);
static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID);
static char *sWindowWatcherContractID = "@mozilla.org/embedcomp/window-watcher;1";
// copied from nsEventQueue.cpp
static char *gEQActivatedNotification = "nsIEventQueueActivated";
@ -80,9 +81,9 @@ NS_NAMED_LITERAL_STRING(gInstallRestartTopic, "xpinstall-restart");
nsAppShellService::nsAppShellService() :
mAppShell( nsnull ),
mWindowList( nsnull ),
mCmdLineService( nsnull ),
mWindowMediator( nsnull ),
mWindowWatcher( nsnull ),
mHiddenWindow( nsnull ),
mDeleteCalled( PR_FALSE ),
mSplashScreen( nsnull ),
@ -133,18 +134,11 @@ nsAppShellService::Initialize( nsICmdLineService *aCmdLineService,
mCmdLineService = aCmdLineService;
// Remember where the native app support lives.
mNativeAppSupport = do_QueryInterface( aNativeAppSupportOrSplashScreen );
mNativeAppSupport = do_QueryInterface(aNativeAppSupportOrSplashScreen);
// Or, remember the splash screen (for backward compatibility).
if ( !mNativeAppSupport ) {
mSplashScreen = do_QueryInterface( aNativeAppSupportOrSplashScreen );
}
// Create the toplevel window list...
rv = NS_NewISupportsArray(getter_AddRefs(mWindowList));
if (NS_FAILED(rv)) {
goto done;
}
if (!mNativeAppSupport)
mSplashScreen = do_QueryInterface(aNativeAppSupportOrSplashScreen);
NS_TIMELINE_ENTER("nsComponentManager::CreateInstance.");
// Create widget application shell
@ -152,25 +146,21 @@ nsAppShellService::Initialize( nsICmdLineService *aCmdLineService,
NS_GET_IID(nsIAppShell),
(void**)getter_AddRefs(mAppShell));
NS_TIMELINE_LEAVE("nsComponentManager::CreateInstance");
if (NS_FAILED(rv)) {
if (NS_FAILED(rv))
goto done;
}
rv = mAppShell->Create(0, nsnull);
if (NS_FAILED(rv)) {
goto done;
}
if (NS_FAILED(rv))
goto done;
// listen to EventQueues' comings and goings. do this after the appshell
// has been created, but after the event queue has been created. that
// latter bit is unfortunate, but we deal with it.
RegisterObserver(PR_TRUE);
// enable window mediation
mWindowMediator = do_GetService(kWindowMediatorCID);
// CreateHiddenWindow(); // rjc: now require this to be explicitly called
// enable window mediation (and fail if we can't get the mediator)
mWindowMediator = do_GetService(kWindowMediatorCID, &rv);
mWindowWatcher = do_GetService(sWindowWatcherContractID);
done:
return rv;
@ -464,86 +454,86 @@ nsAppShellService::Quit()
// through any events in the queue. This guarantees a tidy cleanup.
nsresult rv = NS_OK;
if (! mShuttingDown) {
mShuttingDown = PR_TRUE;
if (mShuttingDown)
return NS_OK;
// Shutdown native app support; doing this first will prevent new
// requests to open additional windows coming in.
if ( mNativeAppSupport ) {
mNativeAppSupport->Quit();
mNativeAppSupport = 0;
}
mShuttingDown = PR_TRUE;
// Enumerate through each open window and close it
if (mWindowMediator) {
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
rv = mWindowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
// Shutdown native app support; doing this first will prevent new
// requests to open additional windows coming in.
if (mNativeAppSupport) {
mNativeAppSupport->Quit();
mNativeAppSupport = 0;
}
if (NS_SUCCEEDED(rv)) {
PRBool more;
// Enumerate through each open window and close it
if (mWindowMediator) {
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
mWindowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
while (1) {
rv = windowEnumerator->HasMoreElements(&more);
if (NS_FAILED(rv) || !more)
break;
if (windowEnumerator) {
PRBool more;
nsCOMPtr<nsISupports> isupports;
rv = windowEnumerator->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv))
break;
while (1) {
rv = windowEnumerator->HasMoreElements(&more);
if (NS_FAILED(rv) || !more)
break;
nsCOMPtr<nsIDOMWindowInternal> window = do_QueryInterface(isupports);
NS_ASSERTION(window != nsnull, "not an nsIDOMWindowInternal");
if (! window)
continue;
nsCOMPtr<nsISupports> isupports;
rv = windowEnumerator->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv))
break;
window->Close();
}
nsCOMPtr<nsIDOMWindowInternal> window = do_QueryInterface(isupports);
NS_ASSERTION(window != nsnull, "not an nsIDOMWindowInternal");
if (! window)
continue;
window->Close();
}
}
}
{
nsCOMPtr<nsIWebShellWindow> hiddenWin(do_QueryInterface(mHiddenWindow));
if (hiddenWin) {
ClearXPConnectSafeContext();
hiddenWin->Close();
}
mHiddenWindow = nsnull;
{
nsCOMPtr<nsIWebShellWindow> hiddenWin(do_QueryInterface(mHiddenWindow));
if (hiddenWin) {
ClearXPConnectSafeContext();
hiddenWin->Close();
}
// Note that we don't allow any premature returns from the above
// loop: no matter what, make sure we send the exit event. If
// worst comes to worst, we'll do a leaky shutdown but we WILL
// shut down. Well, assuming that all *this* stuff works ;-).
nsCOMPtr<nsIEventQueueService> svc = do_GetService(kEventQueueServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
mHiddenWindow = nsnull;
}
// Note that we don't allow any premature returns from the above
// loop: no matter what, make sure we send the exit event. If
// worst comes to worst, we'll do a leaky shutdown but we WILL
// shut down. Well, assuming that all *this* stuff works ;-).
nsCOMPtr<nsIEventQueueService> svc = do_GetService(kEventQueueServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIEventQueue> queue;
rv = svc->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIEventQueue> queue;
rv = svc->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
if (NS_FAILED(rv)) return rv;
ExitEvent* event = new ExitEvent;
if (! event)
return NS_ERROR_OUT_OF_MEMORY;
ExitEvent* event = new ExitEvent;
if (!event)
return NS_ERROR_OUT_OF_MEMORY;
PL_InitEvent(NS_REINTERPRET_CAST(PLEvent*, event),
nsnull,
HandleExitEvent,
DestroyExitEvent);
PL_InitEvent(NS_REINTERPRET_CAST(PLEvent*, event),
nsnull,
HandleExitEvent,
DestroyExitEvent);
event->mService = this;
NS_ADDREF(event->mService);
event->mService = this;
NS_ADDREF(event->mService);
rv = queue->EnterMonitor();
if (NS_SUCCEEDED(rv)) {
rv = queue->PostEvent(NS_REINTERPRET_CAST(PLEvent*, event));
}
(void) queue->ExitMonitor();
rv = queue->EnterMonitor();
if (NS_SUCCEEDED(rv))
rv = queue->PostEvent(NS_REINTERPRET_CAST(PLEvent*, event));
queue->ExitMonitor();
if (NS_FAILED(rv)) {
NS_RELEASE(event->mService);
delete event;
}
if (NS_FAILED(rv)) {
NS_RELEASE(event->mService);
delete event;
}
return rv;
@ -808,64 +798,93 @@ nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindowInternal **aWindow,
NS_IMETHODIMP
nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
{
mWindowList->AppendElement(aWindow);
// tell the window mediator about the new window
if (mWindowMediator)
mWindowMediator->RegisterWindow(aWindow);
if(mWindowMediator)
mWindowMediator->RegisterWindow(aWindow);
// tell the window watcher about the new window
if (mWindowWatcher) {
nsCOMPtr<nsIDocShell> docShell;
aWindow->GetDocShell(getter_AddRefs(docShell));
if (docShell) {
nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
if (domWindow)
mWindowWatcher->AddWindow(domWindow, 0);
}
}
return NS_OK;
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
{
if (mDeleteCalled) {
// return an error code in order to:
// - avoid doing anything with other member variables while we are in the destructor
// - notify the caller not to release the AppShellService after unregistering the window
// (we don't want to be deleted twice consecutively to mHiddenWindow->Close() in our destructor)
return NS_ERROR_FAILURE;
}
if(mWindowMediator)
mWindowMediator->UnregisterWindow(aWindow);
nsresult rv;
PRBool windowsRemain = PR_TRUE;
mWindowList->RemoveElement(aWindow);
PRUint32 cnt;
rv = mWindowList->Count(&cnt);
if (NS_FAILED(rv)) return rv;
if (0 == cnt)
{
if (!mQuitOnLastWindowClosing)
return NS_OK;
#if XP_MAC
// if no hidden window is available (perhaps due to initial
// Profile Manager window being cancelled), then just quit. We don't have
// to worry about focussing the hidden window, because it will get activated
// by the OS since it is visible (but waaaay offscreen).
nsCOMPtr<nsIBaseWindow> hiddenWin(do_QueryInterface(mHiddenWindow));
if (!hiddenWin)
Quit();
#else
// Check to see if we should quit in this case.
if (mNativeAppSupport) {
PRBool serverMode = PR_FALSE;
mNativeAppSupport->GetIsServerMode(&serverMode);
if (serverMode) {
mNativeAppSupport->OnLastWindowClosing(aWindow);
return NS_OK;
}
}
Quit();
#endif
if (mDeleteCalled) {
/* return an error code in order to:
- avoid doing anything with other member variables while we are in
the destructor
- notify the caller not to release the AppShellService after
unregistering the window
(we don't want to be deleted twice consecutively to
mHiddenWindow->Close() in our destructor)
*/
return NS_ERROR_FAILURE;
}
return rv;
// tell the window mediator
if (mWindowMediator) {
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
mWindowMediator->UnregisterWindow(aWindow);
mWindowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
if (windowEnumerator)
windowEnumerator->HasMoreElements(&windowsRemain);
}
// tell the window watcher
if (mWindowWatcher) {
nsCOMPtr<nsIDocShell> docShell;
aWindow->GetDocShell(getter_AddRefs(docShell));
if (docShell) {
nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
if (domWindow)
mWindowWatcher->RemoveWindow(domWindow);
}
}
// now quit if the last window has been unregistered (unless we shouldn't)
if (!mQuitOnLastWindowClosing)
return NS_OK;
if (!windowsRemain) {
#if XP_MAC
// if no hidden window is available (perhaps due to initial
// Profile Manager window being cancelled), then just quit. We don't have
// to worry about focussing the hidden window, because it will get activated
// by the OS since it is visible (but waaaay offscreen).
nsCOMPtr<nsIBaseWindow> hiddenWin(do_QueryInterface(mHiddenWindow));
if (!hiddenWin)
Quit();
#else
// Check to see if we should quit in this case.
if (mNativeAppSupport) {
PRBool serverMode = PR_FALSE;
mNativeAppSupport->GetIsServerMode(&serverMode);
if (serverMode) {
mNativeAppSupport->OnLastWindowClosing(aWindow);
return NS_OK;
}
}
Quit();
#endif
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -22,7 +22,6 @@
#ifndef __nsAppShellService_h
#define __nsAppShellService_h
#include "nsISupports.h"
#include "nsIAppShellService.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
@ -32,6 +31,7 @@
//Interfaces Needed
#include "nsIXULWindow.h"
#include "nsIWindowMediator.h"
#include "nsPIWindowWatcher.h"
#include "nsISplashScreen.h"
class nsAppShellService : public nsIAppShellService,
@ -63,9 +63,9 @@ protected:
nsresult ClearXPConnectSafeContext();
nsCOMPtr<nsIAppShell> mAppShell;
nsCOMPtr<nsISupportsArray> mWindowList;
nsCOMPtr<nsICmdLineService> mCmdLineService;
nsCOMPtr<nsIWindowMediator> mWindowMediator;
nsCOMPtr<nsPIWindowWatcher> mWindowWatcher;
nsCOMPtr<nsIXULWindow> mHiddenWindow;
PRBool mDeleteCalled;
nsCOMPtr<nsISplashScreen> mSplashScreen;