From d04c652303c7ef4e9b00a8f51ec9db63b2100f29 Mon Sep 17 00:00:00 2001 From: "bryner%netscape.com" Date: Tue, 1 Jul 2003 22:46:55 +0000 Subject: [PATCH] Fix some issues related to focus changes in onfocus and onblur handlers: - Abort firing blur events on the document and/or window if one of the blur handlers focuses something else. This ensures that the caret doesn't get confused about whether it should be active. - Release any mouse or key grab when the view manager sees a deactivate event; this fixes event targeting when a mousedown handler opens a modal dialog. - Make sure the editor element is actually focused before activating the caret. Just receiving a focus event isn't good enough, since a focus change does not cancel propagation of the original event. Bug 53579, r=jkeiser, sr=roc. git-svn-id: svn://10.0.0.236/trunk@144362 18797224-902f-48f8-a5cc-f745e15eee43 --- .../events/src/nsEventStateManager.cpp | 27 +++++++++- .../libeditor/text/nsEditorEventListeners.cpp | 54 +++++++++++++++++++ mozilla/view/src/nsViewManager.cpp | 3 ++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/mozilla/content/events/src/nsEventStateManager.cpp b/mozilla/content/events/src/nsEventStateManager.cpp index 2496521ba52..391756fd2ee 100644 --- a/mozilla/content/events/src/nsEventStateManager.cpp +++ b/mozilla/content/events/src/nsEventStateManager.cpp @@ -4145,9 +4145,13 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo { nsCOMPtr presShell; aPresContext->GetShell(getter_AddRefs(presShell)); - + + nsCOMPtr previousFocus = mCurrentFocus; + if (nsnull != gLastFocusedPresContext) { - + + nsCOMPtr focusAfterBlur; + if (gLastFocusedContent && gLastFocusedContent != mFirstBlurEvent) { //Store the first blur event we fire and don't refire blur @@ -4215,6 +4219,7 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo temp->HandleDOMEvent(oldPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); pusher.Pop(); + focusAfterBlur = mCurrentFocus; esm->SetFocusedContent(nsnull); } } @@ -4222,6 +4227,12 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo if (clearFirstBlurEvent) { mFirstBlurEvent = nsnull; } + + if (previousFocus != focusAfterBlur) { + // The content node's blur handler focused something else. + // In this case, abort firing any more blur or focus events. + return NS_OK; + } } // Go ahead and fire a blur on the window. @@ -4269,8 +4280,20 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo temp->HandleDOMEvent(gLastFocusedPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); pusher.Pop(); + if (mCurrentFocus != previousFocus) { + // The document's blur handler focused something else. + // Abort firing any additional blur or focus events. + return NS_OK; + } + pusher.Push(globalObject); globalObject->HandleDOMEvent(gLastFocusedPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); + + if (mCurrentFocus != previousFocus) { + // The window's blur handler focused something else. + // Abort firing any additional blur or focus events. + return NS_OK; + } } } diff --git a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp index 612ae674b9f..bda9dc912c6 100644 --- a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp +++ b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp @@ -87,6 +87,8 @@ #include "nsLayoutCID.h" #include "nsIDOMNSRange.h" #include "nsEditorUtils.h" +#include "nsIDOMEventTarget.h" +#include "nsIEventStateManager.h" // Drag & Drop, Clipboard Support static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID); @@ -989,9 +991,61 @@ nsTextEditorFocusListener::HandleEvent(nsIDOMEvent* aEvent) return NS_OK; } +static PRBool +IsTargetFocused(nsIDOMEventTarget* aTarget) +{ + // The event target could be either a content node or a document. + nsCOMPtr doc; + nsCOMPtr content = do_QueryInterface(aTarget); + if (content) + content->GetDocument(getter_AddRefs(doc)); + else + doc = do_QueryInterface(aTarget); + + if (!doc) + return PR_FALSE; + + nsCOMPtr shell; + doc->GetShellAt(0, getter_AddRefs(shell)); + if (!shell) + return PR_FALSE; + + nsCOMPtr presContext; + shell->GetPresContext(getter_AddRefs(presContext)); + if (!presContext) + return PR_FALSE; + + nsCOMPtr esm; + presContext->GetEventStateManager(getter_AddRefs(esm)); + if (!esm) + return PR_FALSE; + + nsCOMPtr focusedContent; + esm->GetFocusedContent(getter_AddRefs(focusedContent)); + + // focusedContent will be null in the case where the document has focus, + // and so will content. + + return (focusedContent == content); +} + nsresult nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent) { + // It's possible for us to receive a focus when we're really not focused. + // This happens, for example, when an onfocus handler that's hooked up + // before this listener focuses something else. In that case, all of the + // onblur handlers will be fired synchronously, then the remaining focus + // handlers will be fired from the original event. So, check to see that + // we're really focused. (Note that the analogous situation does not + // happen for blurs, due to the ordering in + // nsEventStateManager::SendFocuBlur(). + + nsCOMPtr target; + aEvent->GetTarget(getter_AddRefs(target)); + if (!IsTargetFocused(target)) + return NS_OK; + // turn on selection and caret if (mEditor) { diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index 55d5ed3a71a..0e100f8e3e5 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -2003,6 +2003,9 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS //Find the view whose coordinates system we're in. baseView = nsView::GetViewFor(aEvent->widget); + if (aEvent->message == NS_DEACTIVATE) + mMouseGrabber = mKeyGrabber = nsnull; + //Find the view to which we're initially going to send the event //for hittesting. if (nsnull != mMouseGrabber && (NS_IS_MOUSE_EVENT(aEvent) || (NS_IS_DRAG_EVENT(aEvent)))) {