restate and simplify the application-quit and application-don't-quit-while-windows-are-open logic. bug 163710 r=brendan,pinkerton

git-svn-id: svn://10.0.0.236/trunk@128508 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
danm%netscape.com
2002-08-29 23:55:37 +00:00
parent 9ff773082c
commit f530e3f071
6 changed files with 69 additions and 63 deletions

View File

@@ -191,10 +191,14 @@ interface nsIAppShellService : nsISupports
void hideSplashScreen();
/**
* We may need to show a XUL dialog before there are any other windows.
* In this case we don't nescesarily want to quit when it is closed.
* Use with extreme caution.
* 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)
*/
attribute boolean quitOnLastWindowClosing;
void enterLastWindowClosingSurvivalArea();
void exitLastWindowClosingSurvivalArea();
};

View File

@@ -103,11 +103,11 @@ static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID);
#define gInstallRestartTopic "xpinstall-restart"
nsAppShellService::nsAppShellService() :
mDeleteCalled( PR_FALSE ),
mInProfileStartup( PR_FALSE ),
mModalWindowCount( 0 ),
mShuttingDown( PR_FALSE ),
mQuitOnLastWindowClosing( PR_TRUE )
mDeleteCalled(PR_FALSE),
mModalWindowCount(0),
mConsiderQuitStopper(0),
mShuttingDown(PR_FALSE),
mAttemptingQuit(PR_FALSE)
{
NS_INIT_REFCNT();
}
@@ -229,6 +229,29 @@ nsresult nsAppShellService::ClearXPConnectSafeContext()
return rv;
}
/* We know we're trying to quit the app, but may not be able to do so
immediately. Enter a state where we're more ready to quit.
(Does useful work only on the Mac.) */
void
nsAppShellService::AttemptingQuit(PRBool aAttempt)
{
#if defined(XP_MAC) || defined(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
}
NS_IMETHODIMP
nsAppShellService::DoProfileStartup(nsICmdLineService *aCmdLineService, PRBool canInteract)
{
@@ -237,11 +260,9 @@ nsAppShellService::DoProfileStartup(nsICmdLineService *aCmdLineService, PRBool c
nsCOMPtr<nsIProfileInternal> profileMgr(do_GetService(NS_PROFILE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv,rv);
mInProfileStartup = PR_TRUE;
PRBool saveQuitOnLastWindowClosing = mQuitOnLastWindowClosing;
mQuitOnLastWindowClosing = PR_FALSE;
// If we being launched in turbo mode, profile mgr cannot show UI
EnterLastWindowClosingSurvivalArea();
// If we are being launched in turbo mode, profile mgr cannot show UI
rv = profileMgr->StartupWithArgs(aCmdLineService, canInteract);
if (!canInteract && rv == NS_ERROR_PROFILE_REQUIRES_INTERACTION) {
NS_WARNING("nsIProfileInternal::StartupWithArgs returned NS_ERROR_PROFILE_REQUIRES_INTERACTION");
@@ -254,8 +275,7 @@ nsAppShellService::DoProfileStartup(nsICmdLineService *aCmdLineService, PRBool c
rv = NS_OK;
}
mQuitOnLastWindowClosing = saveQuitOnLastWindowClosing;
mInProfileStartup = PR_FALSE;
ExitLastWindowClosingSurvivalArea();
// if Quit() was called while we were starting up we have a failure situation...
if (mShuttingDown)
@@ -463,7 +483,6 @@ nsAppShellService::Quit(PRUint32 aFerocity)
if (mShuttingDown)
return NS_OK;
mShuttingDown = PR_TRUE;
/* eForceQuit doesn't actually work; it can cause a subtle crash if
there are windows open which have unload handlers which open
@@ -471,7 +490,9 @@ nsAppShellService::Quit(PRUint32 aFerocity)
if (aFerocity == eForceQuit)
return NS_ERROR_FAILURE;
if (aFerocity == eConsiderQuit && mQuitOnLastWindowClosing) {
mShuttingDown = PR_TRUE;
if (aFerocity == eConsiderQuit && mConsiderQuitStopper == 0) {
// attempt quit if the last window has been unregistered/closed
PRBool windowsRemain = PR_TRUE;
@@ -485,15 +506,6 @@ nsAppShellService::Quit(PRUint32 aFerocity)
if (!windowsRemain) {
aFerocity = eAttemptQuit;
#if defined(XP_MAC) || defined(XP_MACOSX)
// 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 focusing 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)
aFerocity = eConsiderQuit; // don't quit after all
#else
// Check to see if we should quit in this case.
if (mNativeAppSupport) {
PRBool serverMode = PR_FALSE;
@@ -505,7 +517,6 @@ nsAppShellService::Quit(PRUint32 aFerocity)
return NS_OK;
}
}
#endif
}
}
@@ -514,6 +525,9 @@ nsAppShellService::Quit(PRUint32 aFerocity)
this code is part of the eForceQuit case, so I'm checking against
that value anyway. Reviewers made me add this comment. */
if (aFerocity == eAttemptQuit || aFerocity == eForceQuit) {
AttemptingQuit(PR_TRUE);
/* Enumerate through each open window and close it. It's important to do
this before we forcequit because this can control whether we really quit
at all. e.g. if one of these windows has an unload handler that
@@ -636,9 +650,7 @@ nsAppShellService::HandleExitEvent(PLEvent* aEvent)
event->mService->mAppShell->Exit();
// We're done "shutting down".
// unless we are currently "starting up" in which case this event wasn't properly handled.
if (!event->mService->mInProfileStartup)
event->mService->mShuttingDown = PR_FALSE;
event->mService->mShuttingDown = PR_FALSE;
return nsnull;
}
@@ -918,6 +930,9 @@ nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
}
}
// an ongoing attempt to quit is stopped by a newly opened window
AttemptingQuit(PR_FALSE);
return NS_OK;
}
@@ -1015,18 +1030,18 @@ nsAppShellService::TopLevelWindowIsModal(nsIXULWindow *aWindow, PRBool aModal)
}
NS_IMETHODIMP
nsAppShellService::GetQuitOnLastWindowClosing(PRBool *aQuitOnLastWindowClosing)
nsAppShellService::EnterLastWindowClosingSurvivalArea(void)
{
NS_ENSURE_ARG_POINTER(aQuitOnLastWindowClosing);
*aQuitOnLastWindowClosing = mQuitOnLastWindowClosing;
return NS_OK;
PR_AtomicIncrement(&mConsiderQuitStopper);
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::SetQuitOnLastWindowClosing(PRBool aQuitOnLastWindowClosing)
nsAppShellService::ExitLastWindowClosingSurvivalArea(void)
{
mQuitOnLastWindowClosing = aQuitOnLastWindowClosing;
return NS_OK;
NS_ASSERTION(mConsiderQuitStopper > 0, "consider quit stopper out of bounds");
PR_AtomicDecrement(&mConsiderQuitStopper);
return NS_OK;
}

View File

@@ -73,6 +73,7 @@ protected:
PRBool aIsHiddenWindow, nsIXULWindow **aResult);
nsresult SetXPConnectSafeContext();
nsresult ClearXPConnectSafeContext();
void AttemptingQuit(PRBool aAttempt);
nsCOMPtr<nsIAppShell> mAppShell;
nsCOMPtr<nsICmdLineService> mCmdLineService;
@@ -82,12 +83,11 @@ protected:
PRBool mDeleteCalled;
nsCOMPtr<nsISplashScreen> mSplashScreen;
nsCOMPtr<nsINativeAppSupport> mNativeAppSupport;
PRBool mInProfileStartup;
PRUint16 mModalWindowCount;
// Set when the appshell service is going away.
PRBool mShuttingDown;
PRBool mQuitOnLastWindowClosing;
PRUint16 mModalWindowCount;
PRInt32 mConsiderQuitStopper; // if > 0, Quit(eConsiderQuit) fails
PRPackedBool mShuttingDown; // Quit method reentrancy check
PRPackedBool mAttemptingQuit; // Quit(eAttemptQuit) still trying
// A "last event" that is used to flush the appshell's event queue.
struct ExitEvent {

View File

@@ -1456,7 +1456,7 @@ static nsresult main1(int argc, char* argv[], nsISupports *nativeApp )
if (NS_FAILED(rv)) return rv;
// So we can open and close windows during startup
appShell->SetQuitOnLastWindowClosing(PR_FALSE);
appShell->EnterLastWindowClosingSurvivalArea();
// Initialize Profile Service here.
NS_TIMELINE_ENTER("InitializeProfileService");
@@ -1495,8 +1495,9 @@ static nsresult main1(int argc, char* argv[], nsISupports *nativeApp )
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to Ensure1Window");
if (NS_FAILED(rv)) return rv;
// From this point on, should be true
appShell->SetQuitOnLastWindowClosing(PR_TRUE);
#if !defined(XP_MAC) && !defined(XP_MACOSX)
appShell->ExitLastWindowClosingSurvivalArea();
#endif
#ifdef MOZ_ENABLE_XREMOTE
// if we have X remote support and we have our one window up and

View File

@@ -1824,14 +1824,7 @@ nsNativeAppSupportOS2::HandleRequest( LPBYTE request, PRBool newWindow ) {
native->SetIsServerMode( PR_FALSE );
// close app if there are no more top-level windows.
PRBool quitIfNoWindows = PR_FALSE;
appShell->GetQuitOnLastWindowClosing( &quitIfNoWindows );
if (quitIfNoWindows) {
nsCOMPtr<nsIDOMWindowInternal> win;
GetMostRecentWindow( 0, getter_AddRefs( win ) );
if (!win)
appShell->Quit(nsIAppShellService::eAttemptQuit);
}
appShell->Quit(nsIAppShellService::eConsiderQuit);
}
return;

View File

@@ -1792,14 +1792,7 @@ nsNativeAppSupportWin::HandleRequest( LPBYTE request, PRBool newWindow ) {
native->SetIsServerMode( PR_FALSE );
// close app if there are no more top-level windows.
PRBool quitIfNoWindows = PR_FALSE;
appShell->GetQuitOnLastWindowClosing( &quitIfNoWindows );
if (quitIfNoWindows) {
nsCOMPtr<nsIDOMWindowInternal> win;
GetMostRecentWindow( 0, getter_AddRefs( win ) );
if (!win)
appShell->Quit(nsIAppShellService::eAttemptQuit);
}
appShell->Quit(nsIAppShellService::eConsiderQuit);
}
return;