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 * 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 * @returnCode NS_SUCCESS_RESTART_APP
* This return code indicates that the application should be * This return code indicates that the application should be
@ -60,12 +62,10 @@ interface nsIAppStartup : nsISupports
void run(); void run();
/** /**
* During application startup (and at other times!) we may temporarily * There are situations where all application windows will be
* encounter a situation where all application windows will be closed * closed but we don't want to take this as a signal to quit the
* but we don't want to take this as a signal to quit the app. Bracket * app. Bracket the code where the last window could close with
* the code where the last window could close with these. * these.
* (And at application startup, on platforms that don't normally quit
* when the last window has closed, call Enter once, but not Exit)
*/ */
void enterLastWindowClosingSurvivalArea(); void enterLastWindowClosingSurvivalArea();
void exitLastWindowClosingSurvivalArea(); void exitLastWindowClosingSurvivalArea();

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

@ -144,7 +144,18 @@ nsAppStartup::CreateHiddenWindow()
NS_IMETHODIMP NS_IMETHODIMP
nsAppStartup::Run(void) 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; mRunning = PR_TRUE;
nsresult rv = mAppShell->Run(); nsresult rv = mAppShell->Run();
@ -187,18 +198,7 @@ nsAppStartup::Quit(PRUint32 aMode)
if (ferocity == eConsiderQuit && mConsiderQuitStopper == 0) { if (ferocity == eConsiderQuit && mConsiderQuitStopper == 0) {
// attempt quit if the last window has been unregistered/closed // attempt quit if the last window has been unregistered/closed
ferocity = eAttemptQuit;
PRBool windowsRemain = PR_TRUE;
if (mediator) {
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
mediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
if (windowEnumerator)
windowEnumerator->HasMoreElements(&windowsRemain);
}
if (!windowsRemain) {
ferocity = eAttemptQuit;
}
} }
/* Currently ferocity can never have the value of eForceQuit here. /* 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 // no matter what, make sure we send the exit event. If
// worst comes to worst, we'll do a leaky shutdown but we WILL // worst comes to worst, we'll do a leaky shutdown but we WILL
// shut down. Well, assuming that all *this* stuff works ;-). // 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)) { if (NS_SUCCEEDED(rv)) {
PLEvent* event = new PLEvent;
if (event) {
NS_ADDREF_THIS();
PL_InitEvent(event,
this,
HandleExitEvent,
DestroyExitEvent);
nsCOMPtr<nsIEventQueue> queue; rv = queue->PostEvent(event);
rv = NS_GetMainEventQ(getter_AddRefs(queue)); if (NS_SUCCEEDED(rv)) {
if (NS_SUCCEEDED(rv)) { postedExitEvent = PR_TRUE;
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);
}
} }
else { 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 void
nsAppStartup::AttemptingQuit(PRBool aAttempt) nsAppStartup::AttemptingQuit(PRBool aAttempt)
{ {
#if defined(XP_MAC) || defined(XP_MACOSX) #ifdef XP_MACOSX
if (aAttempt) { if (aAttempt) {
// now even the Mac wants to quit when the last window is closed // now even the Mac wants to quit when the last window is closed
if (!mAttemptingQuit) if (!mAttemptingQuit)
ExitLastWindowClosingSurvivalArea(); ExitLastWindowClosingSurvivalArea();
mAttemptingQuit = PR_TRUE;
} else { } else {
// changed our mind. back to normal. // changed our mind. back to normal.
if (mAttemptingQuit) if (mAttemptingQuit)
EnterLastWindowClosingSurvivalArea(); EnterLastWindowClosingSurvivalArea();
mAttemptingQuit = PR_FALSE;
} }
#else
mAttemptingQuit = aAttempt;
#endif #endif
mAttemptingQuit = aAttempt;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -371,6 +364,10 @@ nsAppStartup::ExitLastWindowClosingSurvivalArea(void)
{ {
NS_ASSERTION(mConsiderQuitStopper > 0, "consider quit stopper out of bounds"); NS_ASSERTION(mConsiderQuitStopper > 0, "consider quit stopper out of bounds");
--mConsiderQuitStopper; --mConsiderQuitStopper;
if (mRunning && mConsiderQuitStopper == 0)
Quit(eAttemptQuit);
return NS_OK; return NS_OK;
} }
@ -517,9 +514,10 @@ nsAppStartup::Observe(nsISupports *aSubject,
} }
ExitLastWindowClosingSurvivalArea(); ExitLastWindowClosingSurvivalArea();
} else if (!strcmp(aTopic, "xul-window-registered")) { } else if (!strcmp(aTopic, "xul-window-registered")) {
EnterLastWindowClosingSurvivalArea();
AttemptingQuit(PR_FALSE); AttemptingQuit(PR_FALSE);
} else if (!strcmp(aTopic, "xul-window-destroyed")) { } else if (!strcmp(aTopic, "xul-window-destroyed")) {
Quit(eConsiderQuit); ExitLastWindowClosingSurvivalArea();
} else { } else {
NS_ERROR("Unexpected observer topic."); NS_ERROR("Unexpected observer topic.");
} }

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

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

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

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