Bug 212316 - Mozilla must handle WM_ENDSESSION message to cleanly unload in case of exiting or restarting windows, r=neil, sr=bsmedberg

This commit is contained in:
Ere Maijala 2008-08-30 11:57:48 +03:00
Родитель 295f2daae2
Коммит 2d78d7a03d
4 изменённых файлов: 67 добавлений и 56 удалений

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

@ -115,6 +115,7 @@ nsAppStartup::Init()
(do_GetService("@mozilla.org/observer-service;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
os->AddObserver(this, "quit-application-forced", PR_TRUE);
os->AddObserver(this, "profile-change-teardown", PR_TRUE);
os->AddObserver(this, "xul-window-registered", PR_TRUE);
os->AddObserver(this, "xul-window-destroyed", PR_TRUE);
@ -201,14 +202,6 @@ nsAppStartup::Quit(PRUint32 aMode)
if (mShuttingDown)
return NS_OK;
/* eForceQuit doesn't actually work; it can cause a subtle crash if
there are windows open which have unload handlers which open
new windows. Use eAttemptQuit for now. */
if (ferocity == eForceQuit) {
NS_WARNING("attempted to force quit");
// it will be treated the same as eAttemptQuit, below
}
// If we're considering quitting, we will only do so if:
if (ferocity == eConsiderQuit) {
if (mConsiderQuitStopper == 0) {
@ -243,10 +236,6 @@ nsAppStartup::Quit(PRUint32 aMode)
mRestart = (aMode & eRestart) != 0;
nsCOMPtr<nsIObserverService> obsService;
/* Currently ferocity can never have the value of eForceQuit here.
That's temporary (in an unscheduled kind of way) and logically
this code is part of the eForceQuit case, so I'm checking against
that value anyway. Reviewers made me add this comment. */
if (ferocity == eAttemptQuit || ferocity == eForceQuit) {
obsService = do_GetService("@mozilla.org/observer-service;1");
@ -488,10 +477,15 @@ nsAppStartup::Observe(nsISupports *aSubject,
const char *aTopic, const PRUnichar *aData)
{
NS_ASSERTION(mAppShell, "appshell service notified before appshell built");
if (!strcmp(aTopic, "profile-change-teardown")) {
EnterLastWindowClosingSurvivalArea();
CloseAllWindows();
ExitLastWindowClosingSurvivalArea();
if (!strcmp(aTopic, "quit-application-forced")) {
mShuttingDown = PR_TRUE;
}
else if (!strcmp(aTopic, "profile-change-teardown")) {
if (!mShuttingDown) {
EnterLastWindowClosingSurvivalArea();
CloseAllWindows();
ExitLastWindowClosingSurvivalArea();
}
} else if (!strcmp(aTopic, "xul-window-registered")) {
EnterLastWindowClosingSurvivalArea();
AttemptingQuit(PR_FALSE);

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

@ -625,34 +625,6 @@ struct MessageWindow {
nsCOMPtr<nsIDOMWindowInternal> win;
GetMostRecentWindow( 0, getter_AddRefs( win ) );
return win ? (long)hwndForDOMWindow( win ) : 0;
} else if ( msg == WM_QUERYENDSESSION ) {
if (!nsNativeAppSupportWin::mCanHandleRequests)
return FALSE;
nsCOMPtr<nsIObserverService> obsServ =
do_GetService("@mozilla.org/observer-service;1");
nsCOMPtr<nsISupportsPRBool> cancelQuit =
do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
cancelQuit->SetData(PR_FALSE);
obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
PRBool abortQuit;
cancelQuit->GetData(&abortQuit);
return !abortQuit;
} else if ( msg == WM_ENDSESSION ) {
if (!nsNativeAppSupportWin::mCanHandleRequests)
return FALSE;
if (wp == FALSE)
return TRUE;
nsCOMPtr<nsIAppStartup> appService =
do_GetService("@mozilla.org/toolkit/app-startup;1");
if (appService)
appService->Quit(nsIAppStartup::eForceQuit);
return TRUE;
}
return DefWindowProc( msgWindow, msg, wp, lp );
}

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

@ -80,6 +80,7 @@
#include <process.h>
#include "nsUnicharUtils.h"
#include "prlog.h"
#include "nsISupportsPrimitives.h"
#ifdef WINCE
#include "aygshell.h"
@ -297,7 +298,7 @@ long nsWindow::sIMECursorPosition = 0;
RECT* nsWindow::sIMECompCharPos = nsnull;
PRBool nsWindow::sIsInEndSession = PR_FALSE;
TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
BOOL nsWindow::sIsRegistered = FALSE;
BOOL nsWindow::sIsPopupClassRegistered = FALSE;
@ -1181,9 +1182,6 @@ LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
//
LRESULT CALLBACK nsWindow::DefaultWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_ENDSESSION && wParam == TRUE)
nsWindow::sIsInEndSession = PR_TRUE;
//XXX nsWindow::DefaultWindowProc still ever required?
return ::DefWindowProcW(hWnd, msg, wParam, lParam);
}
@ -1459,11 +1457,7 @@ NS_METHOD nsWindow::Destroy()
}
#endif
// bug 333907: During WM_*ENDSESSION, closing all windows
// will cause immediate termination of the process. This
// avoids closing windows during WM_ENDSESSION for a cleaner exit.
if (!sIsInEndSession)
VERIFY(::DestroyWindow(mWnd));
VERIFY(::DestroyWindow(mWnd));
mWnd = NULL;
//our windows can be subclassed by
@ -1661,8 +1655,7 @@ NS_METHOD nsWindow::Show(PRBool bState)
}
} else {
if (mWindowType != eWindowType_dialog) {
if (!sIsInEndSession)
::ShowWindow(mWnd, SW_HIDE);
::ShowWindow(mWnd, SW_HIDE);
} else {
::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
SWP_NOZORDER | SWP_NOACTIVATE);
@ -4144,6 +4137,51 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT
}
break;
// WM_QUERYENDSESSION must be handled by all windows.
// Otherwise Windows thinks the window can just be killed at will.
case WM_QUERYENDSESSION:
if (sCanQuit == TRI_UNKNOWN)
{
// Ask if it's ok to quit, and store the answer until we
// get WM_ENDSESSION signaling the round is complete.
nsCOMPtr<nsIObserverService> obsServ =
do_GetService("@mozilla.org/observer-service;1");
nsCOMPtr<nsISupportsPRBool> cancelQuit =
do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
cancelQuit->SetData(PR_FALSE);
obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nsnull);
PRBool abortQuit;
cancelQuit->GetData(&abortQuit);
sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE;
}
*aRetValue = sCanQuit ? TRUE : FALSE;
result = PR_TRUE;
break;
case WM_ENDSESSION:
if (wParam == TRUE && sCanQuit == TRI_TRUE)
{
// Let's fake a shutdown sequence without actually closing windows etc.
// to avoid Windows killing us in the middle. A proper shutdown would
// require having a chance to pump some messages. Unfortunately
// Windows won't let us do that. Bug 212316.
nsCOMPtr<nsIObserverService> obsServ =
do_GetService("@mozilla.org/observer-service;1");
NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
obsServ->NotifyObservers(nsnull, "quit-application-granted", nsnull);
obsServ->NotifyObservers(nsnull, "quit-application-forced", nsnull);
obsServ->NotifyObservers(nsnull, "quit-application", nsnull);
obsServ->NotifyObservers(nsnull, "profile-change-net-teardown", context.get());
obsServ->NotifyObservers(nsnull, "profile-change-teardown", context.get());
obsServ->NotifyObservers(nsnull, "profile-before-change", context.get());
// Then a controlled but very quick exit.
_exit(0);
}
sCanQuit = TRI_UNKNOWN;
result = PR_TRUE;
break;
#ifndef WINCE
case WM_DISPLAYCHANGE:
DispatchStandardEvent(NS_DISPLAYCHANGED);

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

@ -107,6 +107,13 @@ const LPCSTR kClassNameContentFrame = "MozillaContentFrameWindowClass";
const LPCSTR kClassNameGeneral = "MozillaWindowClass";
const LPCSTR kClassNameDialog = "MozillaDialogClass";
typedef enum
{
TRI_UNKNOWN = -1,
TRI_FALSE = 0,
TRI_TRUE = 1
} TriStateBool;
/**
* Native WIN32 window wrapper.
*/
@ -415,7 +422,7 @@ protected:
// For describing composing frame
static RECT* sIMECompCharPos;
static PRBool sIsInEndSession;
static TriStateBool sCanQuit;
nsSize mLastSize;
static nsWindow* gCurrentWindow;