Fixing bug 334891. Prevent window.close() from closing the window if there's a modal dialog parented at the window. r=dveditz@cruzio.com, sr=bzbarsky@mit.edu

This commit is contained in:
jst%mozilla.jstenback.com 2006-07-05 22:48:04 +00:00
parent dd15a518df
commit b271739439
4 changed files with 115 additions and 36 deletions

View File

@ -400,14 +400,22 @@ public:
virtual void EnsureSizeUpToDate() = 0;
/**
* Callback for notifying a window about a modal dialog being
* opened/closed with the window as a parent.
*/
virtual void EnterModalState() = 0;
virtual void LeaveModalState() = 0;
protected:
// The nsPIDOMWindow constructor. The aOuterWindow argument should
// be null if and only if the created window itself is an outer
// window. In all other cases aOuterWindow should be the outer
// window for the inner window that is being created.
nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
: mFrameElement(nsnull), mDocShell(nsnull), mRunningTimeout(nsnull),
mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
: mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0),
mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull),
mInnerWindow(nsnull), mOuterWindow(aOuterWindow)
{
@ -423,6 +431,8 @@ protected:
nsIDOMElement *mFrameElement; // weak
nsIDocShell *mDocShell; // Weak Reference
PRUint32 mModalStateDepth;
// These variables are only used on inner windows.
nsTimeout *mRunningTimeout;

View File

@ -3387,7 +3387,8 @@ nsGlobalWindow::Confirm(const nsAString& aString, PRBool* aReturn)
nsAutoString title;
MakeScriptDialogTitle(EmptyString(), title);
return prompter->Confirm(title.get(), PromiseFlatString(aString).get(), aReturn);
return prompter->Confirm(title.get(),
PromiseFlatString(aString).get(), aReturn);
}
NS_IMETHODIMP
@ -4427,9 +4428,10 @@ nsGlobalWindow::Close()
{
FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
if (IsFrame() || !mDocShell) {
// window.close() is called on a frame in a frameset, or on a
// window that's already closed. Ignore such calls.
if (IsFrame() || !mDocShell || IsInModalState()) {
// window.close() is called on a frame in a frameset, on a window
// that's already closed, or on a window for which there's
// currently a modal dialog open. Ignore such calls.
return NS_OK;
}
@ -4605,6 +4607,57 @@ nsGlobalWindow::ReallyCloseWindow()
}
}
void
nsGlobalWindow::EnterModalState()
{
nsCOMPtr<nsIDOMWindow> top;
GetTop(getter_AddRefs(top));
if (!top) {
NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
return;
}
NS_STATIC_CAST(nsGlobalWindow *,
NS_STATIC_CAST(nsIDOMWindow *,
top.get()))->mModalStateDepth++;
}
void
nsGlobalWindow::LeaveModalState()
{
nsCOMPtr<nsIDOMWindow> top;
GetTop(getter_AddRefs(top));
if (!top) {
NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
return;
}
NS_STATIC_CAST(nsGlobalWindow *,
NS_STATIC_CAST(nsIDOMWindow *,
top.get()))->mModalStateDepth--;
}
PRBool
nsGlobalWindow::IsInModalState()
{
nsCOMPtr<nsIDOMWindow> top;
GetTop(getter_AddRefs(top));
if (!top) {
NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
return PR_FALSE;
}
return NS_STATIC_CAST(nsGlobalWindow *,
NS_STATIC_CAST(nsIDOMWindow *,
top.get()))->mModalStateDepth != 0;
}
NS_IMETHODIMP
nsGlobalWindow::GetFrameElement(nsIDOMElement** aFrameElement)
{

View File

@ -266,6 +266,9 @@ public:
PRBool aOriginalOpener);
virtual NS_HIDDEN_(void) EnsureSizeUpToDate();
virtual NS_HIDDEN_(void) EnterModalState();
virtual NS_HIDDEN_(void) LeaveModalState();
// nsIDOMViewCSS
NS_DECL_NSIDOMVIEWCSS
@ -505,6 +508,8 @@ protected:
mIsFrozen = PR_FALSE;
}
PRBool IsInModalState();
// When adding new member variables, be careful not to create cycles
// through JavaScript. If there is any chance that a member variable
// could own objects that are implemented in JavaScript, then those

View File

@ -130,11 +130,11 @@ nsPrompt::Init()
// nsPrompt::nsIPrompt
//*****************************************************************************
class nsAutoDOMEventDispatcher
class nsAutoWindowStateHelper
{
public:
nsAutoDOMEventDispatcher(nsIDOMWindow *aWindow);
~nsAutoDOMEventDispatcher();
nsAutoWindowStateHelper(nsIDOMWindow *aWindow);
~nsAutoWindowStateHelper();
PRBool DefaultEnabled()
{
@ -148,21 +148,32 @@ protected:
PRBool mDefaultEnabled;
};
nsAutoDOMEventDispatcher::nsAutoDOMEventDispatcher(nsIDOMWindow *aWindow)
nsAutoWindowStateHelper::nsAutoWindowStateHelper(nsIDOMWindow *aWindow)
: mWindow(aWindow),
mDefaultEnabled(DispatchCustomEvent("DOMWillOpenModalDialog"))
{
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
if (window) {
window->EnterModalState();
}
}
nsAutoDOMEventDispatcher::~nsAutoDOMEventDispatcher()
nsAutoWindowStateHelper::~nsAutoWindowStateHelper()
{
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mWindow));
if (window) {
window->LeaveModalState();
}
if (mDefaultEnabled) {
DispatchCustomEvent("DOMModalDialogClosed");
}
}
PRBool
nsAutoDOMEventDispatcher::DispatchCustomEvent(const char *aEventName)
nsAutoWindowStateHelper::DispatchCustomEvent(const char *aEventName)
{
if (!mWindow) {
return PR_TRUE;
@ -208,9 +219,9 @@ NS_IMETHODIMP
nsPrompt::Alert(const PRUnichar* dialogTitle,
const PRUnichar* text)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -223,9 +234,9 @@ nsPrompt::AlertCheck(const PRUnichar* dialogTitle,
const PRUnichar* checkMsg,
PRBool *checkValue)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -238,9 +249,9 @@ nsPrompt::Confirm(const PRUnichar* dialogTitle,
const PRUnichar* text,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -254,9 +265,9 @@ nsPrompt::ConfirmCheck(const PRUnichar* dialogTitle,
PRBool *checkValue,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -275,9 +286,9 @@ nsPrompt::ConfirmEx(const PRUnichar *dialogTitle,
PRBool *checkValue,
PRInt32 *buttonPressed)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -294,9 +305,9 @@ nsPrompt::Prompt(const PRUnichar *dialogTitle,
PRBool *checkValue,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -313,9 +324,9 @@ nsPrompt::PromptUsernameAndPassword(const PRUnichar *dialogTitle,
PRBool *checkValue,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -333,9 +344,9 @@ nsPrompt::PromptPassword(const PRUnichar *dialogTitle,
PRBool *checkValue,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -351,9 +362,9 @@ nsPrompt::Select(const PRUnichar *dialogTitle,
PRInt32 *outSelection,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -376,9 +387,9 @@ nsPrompt::Prompt(const PRUnichar* dialogTitle,
PRUnichar* *result,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -404,9 +415,9 @@ nsPrompt::PromptUsernameAndPassword(const PRUnichar* dialogTitle,
PRUnichar* *pwd,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}
@ -424,9 +435,9 @@ nsPrompt::PromptPassword(const PRUnichar* dialogTitle,
PRUnichar* *pwd,
PRBool *_retval)
{
nsAutoDOMEventDispatcher autoDOMEventDispatcher(mParent);
nsAutoWindowStateHelper windowStateHelper(mParent);
if (!autoDOMEventDispatcher.DefaultEnabled()) {
if (!windowStateHelper.DefaultEnabled()) {
return NS_OK;
}