Patch for bug 112294: calling an alert box from window.onblur triggers the event multiple times

r=smaug
sr=roc
This commit is contained in:
Ere Maijala 2008-08-01 10:32:32 -07:00
Родитель 0aca100286
Коммит 781fb84f74
6 изменённых файлов: 89 добавлений и 50 удалений

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

@ -160,7 +160,7 @@ static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
nsIContent * gLastFocusedContent = 0; // Strong reference
nsIDocument * gLastFocusedDocument = 0; // Strong reference
nsPresContext* gLastFocusedPresContext = 0; // Weak reference
nsPresContext* gLastFocusedPresContextWeak = 0; // Weak reference
enum nsTextfieldSelectModel {
eTextfieldSelect_unset = -1,
@ -693,6 +693,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEventStateManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastFocus);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastContentFocus);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstBlurEvent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstDocumentBlurEvent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstFocusEvent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstMouseOverEventElement);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstMouseOutEventElement);
@ -716,6 +717,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEventStateManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastFocus);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastContentFocus);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstBlurEvent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstDocumentBlurEvent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstFocusEvent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstMouseOverEventElement);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstMouseOutEventElement);
@ -874,7 +876,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
break;
if (mDocument) {
if (gLastFocusedDocument && gLastFocusedPresContext) {
if (gLastFocusedDocument && gLastFocusedPresContextWeak) {
nsCOMPtr<nsPIDOMWindow> ourWindow =
gLastFocusedDocument->GetWindow();
@ -907,7 +909,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
blurevent.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
nsEventDispatcher::Dispatch(gLastFocusedDocument,
gLastFocusedPresContext,
gLastFocusedPresContextWeak,
&blurevent, nsnull, &blurstatus);
if (!mCurrentFocus && gLastFocusedContent) {
@ -918,7 +920,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
nsCOMPtr<nsIContent> blurContent = gLastFocusedContent;
blurevent.target = nsnull;
nsEventDispatcher::Dispatch(gLastFocusedContent,
gLastFocusedPresContext,
gLastFocusedPresContextWeak,
&blurevent, nsnull, &blurstatus);
// XXX bryner this isn't quite right -- it can result in
@ -1011,7 +1013,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
NS_IF_RELEASE(gLastFocusedDocument);
gLastFocusedDocument = mDocument;
gLastFocusedPresContext = aPresContext;
gLastFocusedPresContextWeak = aPresContext;
NS_IF_ADDREF(gLastFocusedDocument);
}
@ -1068,7 +1070,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
nsEvent event(PR_TRUE, NS_BLUR_CONTENT);
event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
if (gLastFocusedDocument && gLastFocusedPresContext) {
if (gLastFocusedDocument && gLastFocusedPresContextWeak) {
if (gLastFocusedContent) {
// Retrieve this content node's pres context. it can be out of sync
// in the Ender widget case.
@ -1090,29 +1092,32 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
}
}
// Clear our global variables before firing the event to prevent
// duplicate blur events (bug 112294).
nsCOMPtr<nsIDocument> lastFocusedDocument;
lastFocusedDocument.swap(gLastFocusedDocument);
nsCOMPtr<nsPresContext> lastFocusedPresContext = gLastFocusedPresContextWeak;
gLastFocusedPresContextWeak = nsnull;
mCurrentTarget = nsnull;
// fire blur on document and window
if (gLastFocusedDocument) {
if (lastFocusedDocument) {
// get the window here, in case the event causes
// gLastFocusedDocument to change.
nsCOMPtr<nsPIDOMWindow> window(gLastFocusedDocument->GetWindow());
nsCOMPtr<nsPIDOMWindow> window(lastFocusedDocument->GetWindow());
event.target = nsnull;
nsEventDispatcher::Dispatch(gLastFocusedDocument,
gLastFocusedPresContext,
nsEventDispatcher::Dispatch(lastFocusedDocument,
lastFocusedPresContext,
&event, nsnull, &status);
if (window) {
event.target = nsnull;
nsEventDispatcher::Dispatch(window, gLastFocusedPresContext,
nsEventDispatcher::Dispatch(window, lastFocusedPresContext,
&event, nsnull, &status);
}
}
// Now clear our our global variables
mCurrentTarget = nsnull;
NS_IF_RELEASE(gLastFocusedDocument);
gLastFocusedPresContext = nsnull;
}
}
#endif
@ -1233,8 +1238,15 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
// Now fire blurs. Blur the content, then the document, then the window.
if (gLastFocusedDocument && gLastFocusedDocument == mDocument) {
if (gLastFocusedDocument && gLastFocusedDocument == mDocument &&
gLastFocusedDocument != mFirstDocumentBlurEvent) {
PRBool clearFirstDocumentBlurEvent = PR_FALSE;
if (!mFirstDocumentBlurEvent) {
mFirstDocumentBlurEvent = gLastFocusedDocument;
clearFirstDocumentBlurEvent = PR_TRUE;
}
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event(PR_TRUE, NS_BLUR_CONTENT);
event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
@ -1264,6 +1276,12 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
}
}
// Clear our global variables before firing the event to prevent
// duplicate blur events (bug 112294).
mCurrentTarget = nsnull;
NS_IF_RELEASE(gLastFocusedDocument);
gLastFocusedPresContextWeak = nsnull;
// fire blur on document and window
event.target = nsnull;
nsEventDispatcher::Dispatch(mDocument, aPresContext, &event, nsnull,
@ -1274,11 +1292,9 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
nsEventDispatcher::Dispatch(ourWindow, aPresContext, &event, nsnull,
&status);
}
// Now clear our our global variables
mCurrentTarget = nsnull;
NS_IF_RELEASE(gLastFocusedDocument);
gLastFocusedPresContext = nsnull;
if (clearFirstDocumentBlurEvent) {
mFirstDocumentBlurEvent = nsnull;
}
}
if (focusController) {
@ -2664,8 +2680,8 @@ nsEventStateManager::SetPresContext(nsPresContext* aPresContext)
if (aPresContext == nsnull) {
// XXX should we move this block to |NotifyDestroyPresContext|?
// A pres context is going away. Make sure we do cleanup.
if (mPresContext == gLastFocusedPresContext) {
gLastFocusedPresContext = nsnull;
if (mPresContext == gLastFocusedPresContextWeak) {
gLastFocusedPresContextWeak = nsnull;
NS_IF_RELEASE(gLastFocusedDocument);
NS_IF_RELEASE(gLastFocusedContent);
}
@ -4465,7 +4481,7 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
// Track the old focus controller if any focus suppressions is used on it.
nsFocusSuppressor oldFocusSuppressor;
if (nsnull != gLastFocusedPresContext) {
if (nsnull != gLastFocusedPresContextWeak) {
nsCOMPtr<nsIContent> focusAfterBlur;
@ -4584,14 +4600,14 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
}
}
gLastFocusedPresContext->EventStateManager()->SetFocusedContent(nsnull);
gLastFocusedPresContextWeak->EventStateManager()->SetFocusedContent(nsnull);
nsCOMPtr<nsIDocument> temp = gLastFocusedDocument;
NS_RELEASE(gLastFocusedDocument);
gLastFocusedDocument = nsnull;
nsCxPusher pusher;
if (pusher.Push(temp)) {
nsEventDispatcher::Dispatch(temp, gLastFocusedPresContext, &event,
nsEventDispatcher::Dispatch(temp, gLastFocusedPresContextWeak, &event,
nsnull, &status);
pusher.Pop();
}
@ -4606,7 +4622,7 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
}
if (pusher.Push(window)) {
nsEventDispatcher::Dispatch(window, gLastFocusedPresContext, &event,
nsEventDispatcher::Dispatch(window, gLastFocusedPresContextWeak, &event,
nsnull, &status);
if (previousFocus && mCurrentFocus != previousFocus) {

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

@ -379,6 +379,7 @@ protected:
//Anti-recursive stack controls
nsCOMPtr<nsIContent> mFirstBlurEvent;
nsCOMPtr<nsIDocument> mFirstDocumentBlurEvent;
nsCOMPtr<nsIContent> mFirstFocusEvent;
// The last element on which we fired a mouseover event, or null if

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

@ -522,7 +522,8 @@ nsFocusController::SetSuppressFocus(PRBool aSuppressFocus, const char* aReason)
//#endif
}
else
NS_ASSERTION(PR_FALSE, "Attempt to decrement focus controller's suppression when no suppression active!\n");
// It's ok to unsuppress even if no suppression is active (bug 112294)
return NS_OK;
// we are unsuppressing after activating, so update focus-related commands
// we need this to update command, including the case where there is no element

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

@ -675,8 +675,18 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
if (popupConditions)
contextFlags |= nsIWindowCreator2::PARENT_IS_LOADING_OR_RUNNING_TIMEOUT;
PRBool parentVisible = PR_TRUE;
if (parentChrome)
{
nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner));
nsCOMPtr<nsIWidget> parentWidget;
if (parentWindow)
parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
if (parentWidget)
parentWidget->IsVisible(parentVisible);
}
PRBool cancel = PR_FALSE;
rv = windowCreator2->CreateChromeWindow2(parentChrome, chromeFlags,
rv = windowCreator2->CreateChromeWindow2(parentVisible ? parentChrome : nsnull, chromeFlags,
contextFlags, uriToLoad,
&cancel,
getter_AddRefs(newChrome));

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

@ -1608,9 +1608,14 @@ PRBool nsWindow::CanTakeFocus()
NS_METHOD nsWindow::Show(PRBool bState)
{
PRBool wasVisible = mIsVisible;
// Set the status now so that anyone asking during ShowWindow or
// SetWindowPos would get the correct answer.
mIsVisible = bState;
if (mWnd) {
if (bState) {
if (!mIsVisible && mWindowType == eWindowType_toplevel) {
if (!wasVisible && mWindowType == eWindowType_toplevel) {
switch (mSizeMode) {
case nsSizeMode_Maximized :
::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
@ -1638,7 +1643,7 @@ NS_METHOD nsWindow::Show(PRBool bState)
}
} else {
DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
if (mIsVisible)
if (wasVisible)
flags |= SWP_NOZORDER;
if (mWindowType == eWindowType_popup) {
@ -1668,12 +1673,10 @@ NS_METHOD nsWindow::Show(PRBool bState)
}
#ifdef MOZ_XUL
if (!mIsVisible && bState)
if (!wasVisible && bState)
Invalidate(PR_FALSE);
#endif
mIsVisible = bState;
return NS_OK;
}

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

@ -478,23 +478,31 @@ NS_IMETHODIMP nsXULWindow::Destroy()
mWindow->Show(PR_FALSE);
#if defined(XP_WIN) || defined(XP_OS2)
// We need to explicitly set the focus on Windows
// We need to explicitly set the focus on Windows, but
// only if the parent is visible.
nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
if (parent) {
nsCOMPtr<nsIBaseWindow> baseHiddenWindow;
if (appShell) {
nsCOMPtr<nsIXULWindow> hiddenWindow;
appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
if (hiddenWindow)
baseHiddenWindow = do_GetInterface(hiddenWindow);
}
// somebody screwed up somewhere. hiddenwindow shouldn't be anybody's
// parent. still, when it happens, skip activating it.
if (baseHiddenWindow != parent) {
nsCOMPtr<nsIWidget> parentWidget;
parent->GetMainWidget(getter_AddRefs(parentWidget));
if (parentWidget)
parentWidget->PlaceBehind(eZPlacementTop, 0, PR_TRUE);
PRBool parentVisible = PR_TRUE;
nsCOMPtr<nsIWidget> parentWidget;
parent->GetMainWidget(getter_AddRefs(parentWidget));
if (parentWidget)
parentWidget->IsVisible(parentVisible);
if (parentVisible) {
nsCOMPtr<nsIBaseWindow> baseHiddenWindow;
if (appShell) {
nsCOMPtr<nsIXULWindow> hiddenWindow;
appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
if (hiddenWindow)
baseHiddenWindow = do_GetInterface(hiddenWindow);
}
// somebody screwed up somewhere. hiddenwindow shouldn't be anybody's
// parent. still, when it happens, skip activating it.
if (baseHiddenWindow != parent) {
nsCOMPtr<nsIWidget> parentWidget;
parent->GetMainWidget(getter_AddRefs(parentWidget));
if (parentWidget)
parentWidget->PlaceBehind(eZPlacementTop, 0, PR_TRUE);
}
}
}
#endif