Bug 310076 (scary version) - Use the considerquitstopper to control when to run the event loop, not window enumerators r=darin

This commit is contained in:
bsmedberg%covad.net 2005-10-04 14:41:18 +00:00
Родитель 301c4d790a
Коммит 77cf9f7768
4 изменённых файлов: 83 добавлений и 113 удалений

Просмотреть файл

@ -51,7 +51,9 @@ interface nsIAppStartup : nsISupports
/**
* Runs an application event loop: normally the main event pump which
* defines the lifetime of the application.
* defines the lifetime of the application. If there are no windows open
* and no outstanding calls to enterLastWindowClosingSurvivalArea this
* method will exit immediately.
*
* @returnCode NS_SUCCESS_RESTART_APP
* This return code indicates that the application should be
@ -60,12 +62,10 @@ interface nsIAppStartup : nsISupports
void run();
/**
* During application startup (and at other times!) we may temporarily
* encounter a situation where all application windows will be closed
* but we don't want to take this as a signal to quit the app. Bracket
* the code where the last window could close with these.
* (And at application startup, on platforms that don't normally quit
* when the last window has closed, call Enter once, but not Exit)
* There are situations where all application windows will be
* closed but we don't want to take this as a signal to quit the
* app. Bracket the code where the last window could close with
* these.
*/
void enterLastWindowClosingSurvivalArea();
void exitLastWindowClosingSurvivalArea();

Просмотреть файл

@ -144,7 +144,18 @@ nsAppStartup::CreateHiddenWindow()
NS_IMETHODIMP
nsAppStartup::Run(void)
{
if (!mShuttingDown) {
NS_ASSERTION(!mRunning, "Reentrant appstartup->Run()");
// If we have no windows open and no explicit calls to
// enterLastWindowClosingSurvivalArea, or somebody has explicitly called
// quit, don't bother running the event loop which would probably leave us
// with a zombie process.
if (!mShuttingDown && mConsiderQuitStopper != 0) {
#ifdef XP_MACOSX
EnterLastWindowClosingSurvivalArea();
#endif
mRunning = PR_TRUE;
nsresult rv = mAppShell->Run();
@ -187,18 +198,7 @@ nsAppStartup::Quit(PRUint32 aMode)
if (ferocity == eConsiderQuit && mConsiderQuitStopper == 0) {
// attempt quit if the last window has been unregistered/closed
PRBool windowsRemain = PR_TRUE;
if (mediator) {
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
mediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
if (windowEnumerator)
windowEnumerator->HasMoreElements(&windowsRemain);
}
if (!windowsRemain) {
ferocity = eAttemptQuit;
}
ferocity = eAttemptQuit;
}
/* Currently ferocity can never have the value of eForceQuit here.
@ -296,33 +296,28 @@ nsAppStartup::Quit(PRUint32 aMode)
// 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(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
nsCOMPtr<nsIEventQueue> queue;
rv = NS_GetMainEventQ(getter_AddRefs(queue));
if (NS_SUCCEEDED(rv)) {
PLEvent* event = new PLEvent;
if (event) {
NS_ADDREF_THIS();
PL_InitEvent(event,
this,
HandleExitEvent,
DestroyExitEvent);
nsCOMPtr<nsIEventQueue> queue;
rv = NS_GetMainEventQ(getter_AddRefs(queue));
if (NS_SUCCEEDED(rv)) {
PLEvent* event = new PLEvent;
if (event) {
NS_ADDREF_THIS();
PL_InitEvent(event,
this,
HandleExitEvent,
DestroyExitEvent);
rv = queue->PostEvent(event);
if (NS_SUCCEEDED(rv)) {
postedExitEvent = PR_TRUE;
}
else {
PL_DestroyEvent(event);
}
rv = queue->PostEvent(event);
if (NS_SUCCEEDED(rv)) {
postedExitEvent = PR_TRUE;
}
else {
rv = NS_ERROR_OUT_OF_MEMORY;
PL_DestroyEvent(event);
}
}
else {
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
}
}
@ -341,21 +336,19 @@ nsAppStartup::Quit(PRUint32 aMode)
void
nsAppStartup::AttemptingQuit(PRBool aAttempt)
{
#if defined(XP_MAC) || defined(XP_MACOSX)
#ifdef XP_MACOSX
if (aAttempt) {
// now even the Mac wants to quit when the last window is closed
if (!mAttemptingQuit)
ExitLastWindowClosingSurvivalArea();
mAttemptingQuit = PR_TRUE;
} else {
// changed our mind. back to normal.
if (mAttemptingQuit)
EnterLastWindowClosingSurvivalArea();
mAttemptingQuit = PR_FALSE;
}
#else
mAttemptingQuit = aAttempt;
#endif
mAttemptingQuit = aAttempt;
}
NS_IMETHODIMP
@ -371,6 +364,10 @@ nsAppStartup::ExitLastWindowClosingSurvivalArea(void)
{
NS_ASSERTION(mConsiderQuitStopper > 0, "consider quit stopper out of bounds");
--mConsiderQuitStopper;
if (mRunning && mConsiderQuitStopper == 0)
Quit(eAttemptQuit);
return NS_OK;
}
@ -517,9 +514,10 @@ nsAppStartup::Observe(nsISupports *aSubject,
}
ExitLastWindowClosingSurvivalArea();
} else if (!strcmp(aTopic, "xul-window-registered")) {
EnterLastWindowClosingSurvivalArea();
AttemptingQuit(PR_FALSE);
} else if (!strcmp(aTopic, "xul-window-destroyed")) {
Quit(eConsiderQuit);
ExitLastWindowClosingSurvivalArea();
} else {
NS_ERROR("Unexpected observer topic.");
}

Просмотреть файл

@ -1332,8 +1332,6 @@ ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
(do_GetService(NS_APPSTARTUP_CONTRACTID));
NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
appStartup->EnterLastWindowClosingSurvivalArea();
nsCOMPtr<nsIDOMWindow> newWindow;
rv = windowWatcher->OpenWindow(nsnull,
kProfileManagerURL,
@ -1342,8 +1340,6 @@ ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
ioParamBlock,
getter_AddRefs(newWindow));
appStartup->ExitLastWindowClosingSurvivalArea();
NS_ENSURE_SUCCESS_LOG(rv, rv);
aProfileSvc->Flush();
@ -2165,9 +2161,6 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
(do_GetService(NS_APPSTARTUP_CONTRACTID));
NS_ENSURE_TRUE(appStartup, 1);
// So we can open and close windows during startup
appStartup->EnterLastWindowClosingSurvivalArea();
// Profile Migration
if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
gDoMigration = PR_FALSE;
@ -2271,62 +2264,39 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
rv = cmdLine->Run();
NS_ENSURE_SUCCESS_LOG(rv, 1);
nsCOMPtr<nsIWindowMediator> windowMediator
(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, 1);
#ifdef MOZ_ENABLE_XREMOTE
// if we have X remote support, start listening for requests on the
// proxy window.
nsCOMPtr<nsIRemoteService> remoteService;
remoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
if (remoteService)
remoteService->Startup(gAppData->name, nsnull);
#endif /* MOZ_ENABLE_XREMOTE */
// Make sure there exists at least 1 window.
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
rv = windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
NS_ENSURE_SUCCESS(rv, 1);
// enable win32 DDE responses and Mac appleevents responses
nativeApp->Enable();
PRBool more;
windowEnumerator->HasMoreElements(&more);
if (!more) {
// We didn't open any windows. This is normally not a good thing,
// so we force console logging to file.
NS_TIMELINE_ENTER("appStartup->Run");
rv = appStartup->Run();
NS_TIMELINE_LEAVE("appStartup->Run");
if (NS_FAILED(rv)) {
NS_ERROR("failed to run appstartup");
gLogConsoleErrors = PR_TRUE;
}
else {
#ifndef XP_MACOSX
appStartup->ExitLastWindowClosingSurvivalArea();
#endif
#ifdef MOZ_ENABLE_XREMOTE
// if we have X remote support and we have our one window up and
// running start listening for requests on the proxy window.
nsCOMPtr<nsIRemoteService> remoteService;
remoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
if (remoteService)
remoteService->Startup(gAppData->name, nsnull);
#endif /* MOZ_ENABLE_XREMOTE */
// enable win32 DDE responses and Mac appleevents responses
nativeApp->Enable();
// Start main event loop
NS_TIMELINE_ENTER("appStartup->Run");
rv = appStartup->Run();
NS_TIMELINE_LEAVE("appStartup->Run");
if (NS_FAILED(rv)) {
NS_ERROR("failed to run appstartup");
gLogConsoleErrors = PR_TRUE;
}
// Check for an application initiated restart. This is one that
// corresponds to nsIAppStartup.quit(eRestart)
if (rv == NS_SUCCESS_RESTART_APP) {
needsRestart = PR_TRUE;
appInitiatedRestart = PR_TRUE;
}
#ifdef MOZ_ENABLE_XREMOTE
// shut down the x remote proxy window
if (remoteService)
remoteService->Shutdown();
#endif /* MOZ_ENABLE_XREMOTE */
// Check for an application initiated restart. This is one that
// corresponds to nsIAppStartup.quit(eRestart)
if (rv == NS_SUCCESS_RESTART_APP) {
needsRestart = PR_TRUE;
appInitiatedRestart = PR_TRUE;
}
#ifdef MOZ_ENABLE_XREMOTE
// shut down the x remote proxy window
if (remoteService)
remoteService->Shutdown();
#endif /* MOZ_ENABLE_XREMOTE */
#ifdef MOZ_TIMELINE
// Make sure we print this out even if timeline is runtime disabled
if (NS_FAILED(NS_TIMELINE_LEAVE("main1")))

Просмотреть файл

@ -538,17 +538,19 @@ NS_IMETHODIMP nsXULWindow::Destroy()
mWindow = nsnull;
}
/* Inform appstartup we've destroyed this window and it could
quit now if it wanted. This must happen at least after mDocShell
is destroyed, because onunload handlers fire then, and those being
script, anything could happen. A new window could open, even.
See bug 130719. */
nsCOMPtr<nsIObserverService> obssvc =
do_GetService("@mozilla.org/observer-service;1");
NS_ASSERTION(obssvc, "Couldn't get observer service?");
if (!mIsHiddenWindow) {
/* Inform appstartup we've destroyed this window and it could
quit now if it wanted. This must happen at least after mDocShell
is destroyed, because onunload handlers fire then, and those being
script, anything could happen. A new window could open, even.
See bug 130719. */
nsCOMPtr<nsIObserverService> obssvc =
do_GetService("@mozilla.org/observer-service;1");
NS_ASSERTION(obssvc, "Couldn't get observer service?");
if (obssvc)
obssvc->NotifyObservers(nsnull, "xul-window-destroyed", nsnull);
if (obssvc)
obssvc->NotifyObservers(nsnull, "xul-window-destroyed", nsnull);
}
return NS_OK;
}