From bd77bde56c61bfeed9049b39365a58756967d0ca Mon Sep 17 00:00:00 2001 From: "hyatt%netscape.com" Date: Fri, 11 Feb 2000 23:41:13 +0000 Subject: [PATCH] Landing focus memory. If you pull before saari completes this checkin (we still have to land nsWebShellWindow and nsGlobalWindow), you will not like the result. r=saari --- content/events/src/nsEventStateManager.cpp | 193 ++++++++++++++------- layout/events/src/nsEventStateManager.cpp | 193 ++++++++++++++------- 2 files changed, 258 insertions(+), 128 deletions(-) diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 05cc2152219..272b8b7cb1d 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -50,6 +50,7 @@ #include "nsISelfScrollingFrame.h" #include "nsIPrivateDOMEvent.h" #include "nsIGfxTextControlFrame.h" +#include "nsIDOMWindow.h" #include "nsPIDOMWindow.h" #include "nsIServiceManager.h" @@ -58,6 +59,8 @@ #include "nsISessionHistory.h" #include "nsXULAtoms.h" +#include "nsIDOMXULDocument.h" +#include "nsIDOMXULCommandDispatcher.h" #undef DEBUG_scroll // define to see ugly mousewheel messages #undef GFXSCROLL_IS_PRIMARY // define this when the code is enabled to make @@ -425,6 +428,8 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, break; case NS_GOTFOCUS: { + printf("Got focus.\n"); + nsCOMPtr presShell; aPresContext->GetShell(getter_AddRefs(presShell)); @@ -466,6 +471,8 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, case NS_LOSTFOCUS: { + printf("Lost focus.\n"); + // Hold the blur, wait for the focus so we can query the style of the focus // target as to what to do with the event. If appropriate we fire the blur // at that time. @@ -474,25 +481,9 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, case NS_ACTIVATE: { - nsIContent* newFocus; - mCurrentTarget->GetContentForEvent(aPresContext, aEvent, &newFocus); - if (newFocus) { - nsIFocusableContent *focusChange; - if (NS_SUCCEEDED(newFocus->QueryInterface(NS_GET_IID(nsIFocusableContent), - (void **)&focusChange))) { - NS_RELEASE(focusChange); - NS_RELEASE(newFocus); - break; - } - NS_RELEASE(newFocus); - } - - //fire focus - nsEventStatus status = nsEventStatus_eIgnore; - nsEvent focusevent; - focusevent.eventStructType = NS_EVENT; - focusevent.message = NS_FOCUS_CONTENT; - + // If we have a command dispatcher, and if it has a focused window and a + // focused element in its focus memory, then restore the focus to those + // objects. if (!mDocument) { nsCOMPtr presShell; aPresContext->GetShell(getter_AddRefs(presShell)); @@ -501,65 +492,139 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, } } - if (mDocument) { - // NS_IF_RELEASE(gLastFocusedContent); - // mCurrentTarget->GetContent(&gLastFocusedContent); - - mCurrentTarget = nsnull; + nsCOMPtr commandDispatcher; + nsCOMPtr focusedElement; + nsCOMPtr focusedWindow; + nsCOMPtr xulDoc = do_QueryInterface(mDocument); + if (xulDoc) { + // See if we have a command dispatcher attached. + xulDoc->GetCommandDispatcher(getter_AddRefs(commandDispatcher)); + if (commandDispatcher) { + // Obtain focus info from the command dispatcher. + commandDispatcher->GetFocusedWindow(getter_AddRefs(focusedWindow)); + commandDispatcher->GetFocusedElement(getter_AddRefs(focusedElement)); + } + } - // fire focus on window, not document + if (!focusedWindow) { nsCOMPtr globalObject; mDocument->GetScriptGlobalObject(getter_AddRefs(globalObject)); - mDocument->HandleDOMEvent(aPresContext, &focusevent, nsnull, NS_EVENT_FLAG_INIT, &status); - if(!globalObject) break; - - globalObject->HandleDOMEvent(aPresContext, &focusevent, nsnull, NS_EVENT_FLAG_INIT, &status); + focusedWindow = do_QueryInterface(globalObject); } + + // Focus the DOM window. + focusedWindow->Focus(); + + if (focusedElement) { + // Focus the content node. + nsCOMPtr focusContent = do_QueryInterface(focusedElement); + nsCOMPtr domDoc; + nsCOMPtr document; + focusedWindow->GetDocument(getter_AddRefs(domDoc)); + document = do_QueryInterface(domDoc); + nsCOMPtr shell; + nsCOMPtr context; + shell = getter_AddRefs(document->GetShellAt(0)); + shell->GetPresContext(getter_AddRefs(context)); + focusContent->SetFocus(context); + } + + if (commandDispatcher) + commandDispatcher->SetSuppressFocus(PR_FALSE); // Unsuppress and let the command dispatcher listen again. } break; case NS_DEACTIVATE: { - nsIContent* newFocus; - mCurrentTarget->GetContentForEvent(aPresContext, aEvent, &newFocus); - if (newFocus) { - nsIFocusableContent *focusChange; - if (NS_SUCCEEDED(newFocus->QueryInterface(NS_GET_IID(nsIFocusableContent), - (void **)&focusChange))) { - NS_RELEASE(focusChange); - NS_RELEASE(newFocus); - break; + if (!mDocument) { + nsCOMPtr presShell; + aPresContext->GetShell(getter_AddRefs(presShell)); + if (presShell) { + presShell->GetDocument(&mDocument); } - NS_RELEASE(newFocus); } - - //fire blur - nsEventStatus status = nsEventStatus_eIgnore; - nsEvent event; - event.eventStructType = NS_EVENT; - event.message = NS_BLUR_CONTENT; - if (!mDocument) { - nsCOMPtr presShell; - aPresContext->GetShell(getter_AddRefs(presShell)); - if (presShell) { - presShell->GetDocument(&mDocument); - } - } - - if (mDocument) { - mCurrentTarget = nsnull; + // We can get a deactivate on an Ender widget. In this + // case, we would like to obtain the DOM Window to start + // with by looking at gLastFocusedContent. + nsCOMPtr ourGlobal; + if (gLastFocusedContent) { + nsCOMPtr doc; + gLastFocusedContent->GetDocument(*getter_AddRefs(doc)); + doc->GetScriptGlobalObject(getter_AddRefs(ourGlobal)); + } + else mDocument->GetScriptGlobalObject(getter_AddRefs(ourGlobal)); + + // Suppress the command dispatcher for the duration of the + // de-activation. This will cause it to remember the last + // focused sub-window and sub-element for this top-level + // window. + nsCOMPtr rootWindow; + nsCOMPtr ourWindow = do_QueryInterface(ourGlobal); + ourWindow->GetPrivateRoot(getter_AddRefs(rootWindow)); + nsCOMPtr rootDocument; + rootWindow->GetDocument(getter_AddRefs(rootDocument)); - // fire focus on window, not document - nsCOMPtr globalObject; - mDocument->GetScriptGlobalObject(getter_AddRefs(globalObject)); - mDocument->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); - if(!globalObject) break; - - globalObject->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); - } - + nsCOMPtr commandDispatcher; + nsCOMPtr xulDoc = do_QueryInterface(rootDocument); + if (xulDoc) { + // See if we have a command dispatcher attached. + xulDoc->GetCommandDispatcher(getter_AddRefs(commandDispatcher)); + if (commandDispatcher) { + // Suppress the command dispatcher. + commandDispatcher->SetSuppressFocus(PR_TRUE); + } + } + + // Now fire blurs. We have to fire a blur on the focused window + // and on the focused element if there is one. + if (gLastFocusedDocument && gLastFocusedPresContext) { + // Blur the element. + if (gLastFocusedContent) { + // Retrieve this content node's pres context. it can be out of sync in + // the Ender widget case. + nsCOMPtr doc; + gLastFocusedContent->GetDocument(*getter_AddRefs(doc)); + if (doc) { + nsCOMPtr shell = getter_AddRefs(doc->GetShellAt(0)); + nsCOMPtr oldPresContext; + shell->GetPresContext(getter_AddRefs(oldPresContext)); + + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + event.message = NS_BLUR_CONTENT; + nsCOMPtr esm; + oldPresContext->GetEventStateManager(getter_AddRefs(esm)); + esm->SetFocusedContent(gLastFocusedContent); + gLastFocusedContent->HandleDOMEvent(oldPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); + esm->SetFocusedContent(nsnull); + NS_RELEASE(gLastFocusedContent); + } + } + + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + event.message = NS_BLUR_CONTENT; + + // fire blur on document and window + nsCOMPtr globalObject; + gLastFocusedDocument->GetScriptGlobalObject(getter_AddRefs(globalObject)); + gLastFocusedDocument->HandleDOMEvent(gLastFocusedPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); + if(!globalObject) break; + + globalObject->HandleDOMEvent(gLastFocusedPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); + mCurrentTarget = nsnull; + + // Now clear our our global variables + NS_RELEASE(gLastFocusedDocument); + gLastFocusedPresContext = nsnull; + } + + if (commandDispatcher) + commandDispatcher->SetSuppressFocus(PR_FALSE); } break; diff --git a/layout/events/src/nsEventStateManager.cpp b/layout/events/src/nsEventStateManager.cpp index 05cc2152219..272b8b7cb1d 100644 --- a/layout/events/src/nsEventStateManager.cpp +++ b/layout/events/src/nsEventStateManager.cpp @@ -50,6 +50,7 @@ #include "nsISelfScrollingFrame.h" #include "nsIPrivateDOMEvent.h" #include "nsIGfxTextControlFrame.h" +#include "nsIDOMWindow.h" #include "nsPIDOMWindow.h" #include "nsIServiceManager.h" @@ -58,6 +59,8 @@ #include "nsISessionHistory.h" #include "nsXULAtoms.h" +#include "nsIDOMXULDocument.h" +#include "nsIDOMXULCommandDispatcher.h" #undef DEBUG_scroll // define to see ugly mousewheel messages #undef GFXSCROLL_IS_PRIMARY // define this when the code is enabled to make @@ -425,6 +428,8 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, break; case NS_GOTFOCUS: { + printf("Got focus.\n"); + nsCOMPtr presShell; aPresContext->GetShell(getter_AddRefs(presShell)); @@ -466,6 +471,8 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, case NS_LOSTFOCUS: { + printf("Lost focus.\n"); + // Hold the blur, wait for the focus so we can query the style of the focus // target as to what to do with the event. If appropriate we fire the blur // at that time. @@ -474,25 +481,9 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, case NS_ACTIVATE: { - nsIContent* newFocus; - mCurrentTarget->GetContentForEvent(aPresContext, aEvent, &newFocus); - if (newFocus) { - nsIFocusableContent *focusChange; - if (NS_SUCCEEDED(newFocus->QueryInterface(NS_GET_IID(nsIFocusableContent), - (void **)&focusChange))) { - NS_RELEASE(focusChange); - NS_RELEASE(newFocus); - break; - } - NS_RELEASE(newFocus); - } - - //fire focus - nsEventStatus status = nsEventStatus_eIgnore; - nsEvent focusevent; - focusevent.eventStructType = NS_EVENT; - focusevent.message = NS_FOCUS_CONTENT; - + // If we have a command dispatcher, and if it has a focused window and a + // focused element in its focus memory, then restore the focus to those + // objects. if (!mDocument) { nsCOMPtr presShell; aPresContext->GetShell(getter_AddRefs(presShell)); @@ -501,65 +492,139 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, } } - if (mDocument) { - // NS_IF_RELEASE(gLastFocusedContent); - // mCurrentTarget->GetContent(&gLastFocusedContent); - - mCurrentTarget = nsnull; + nsCOMPtr commandDispatcher; + nsCOMPtr focusedElement; + nsCOMPtr focusedWindow; + nsCOMPtr xulDoc = do_QueryInterface(mDocument); + if (xulDoc) { + // See if we have a command dispatcher attached. + xulDoc->GetCommandDispatcher(getter_AddRefs(commandDispatcher)); + if (commandDispatcher) { + // Obtain focus info from the command dispatcher. + commandDispatcher->GetFocusedWindow(getter_AddRefs(focusedWindow)); + commandDispatcher->GetFocusedElement(getter_AddRefs(focusedElement)); + } + } - // fire focus on window, not document + if (!focusedWindow) { nsCOMPtr globalObject; mDocument->GetScriptGlobalObject(getter_AddRefs(globalObject)); - mDocument->HandleDOMEvent(aPresContext, &focusevent, nsnull, NS_EVENT_FLAG_INIT, &status); - if(!globalObject) break; - - globalObject->HandleDOMEvent(aPresContext, &focusevent, nsnull, NS_EVENT_FLAG_INIT, &status); + focusedWindow = do_QueryInterface(globalObject); } + + // Focus the DOM window. + focusedWindow->Focus(); + + if (focusedElement) { + // Focus the content node. + nsCOMPtr focusContent = do_QueryInterface(focusedElement); + nsCOMPtr domDoc; + nsCOMPtr document; + focusedWindow->GetDocument(getter_AddRefs(domDoc)); + document = do_QueryInterface(domDoc); + nsCOMPtr shell; + nsCOMPtr context; + shell = getter_AddRefs(document->GetShellAt(0)); + shell->GetPresContext(getter_AddRefs(context)); + focusContent->SetFocus(context); + } + + if (commandDispatcher) + commandDispatcher->SetSuppressFocus(PR_FALSE); // Unsuppress and let the command dispatcher listen again. } break; case NS_DEACTIVATE: { - nsIContent* newFocus; - mCurrentTarget->GetContentForEvent(aPresContext, aEvent, &newFocus); - if (newFocus) { - nsIFocusableContent *focusChange; - if (NS_SUCCEEDED(newFocus->QueryInterface(NS_GET_IID(nsIFocusableContent), - (void **)&focusChange))) { - NS_RELEASE(focusChange); - NS_RELEASE(newFocus); - break; + if (!mDocument) { + nsCOMPtr presShell; + aPresContext->GetShell(getter_AddRefs(presShell)); + if (presShell) { + presShell->GetDocument(&mDocument); } - NS_RELEASE(newFocus); } - - //fire blur - nsEventStatus status = nsEventStatus_eIgnore; - nsEvent event; - event.eventStructType = NS_EVENT; - event.message = NS_BLUR_CONTENT; - if (!mDocument) { - nsCOMPtr presShell; - aPresContext->GetShell(getter_AddRefs(presShell)); - if (presShell) { - presShell->GetDocument(&mDocument); - } - } - - if (mDocument) { - mCurrentTarget = nsnull; + // We can get a deactivate on an Ender widget. In this + // case, we would like to obtain the DOM Window to start + // with by looking at gLastFocusedContent. + nsCOMPtr ourGlobal; + if (gLastFocusedContent) { + nsCOMPtr doc; + gLastFocusedContent->GetDocument(*getter_AddRefs(doc)); + doc->GetScriptGlobalObject(getter_AddRefs(ourGlobal)); + } + else mDocument->GetScriptGlobalObject(getter_AddRefs(ourGlobal)); + + // Suppress the command dispatcher for the duration of the + // de-activation. This will cause it to remember the last + // focused sub-window and sub-element for this top-level + // window. + nsCOMPtr rootWindow; + nsCOMPtr ourWindow = do_QueryInterface(ourGlobal); + ourWindow->GetPrivateRoot(getter_AddRefs(rootWindow)); + nsCOMPtr rootDocument; + rootWindow->GetDocument(getter_AddRefs(rootDocument)); - // fire focus on window, not document - nsCOMPtr globalObject; - mDocument->GetScriptGlobalObject(getter_AddRefs(globalObject)); - mDocument->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); - if(!globalObject) break; - - globalObject->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); - } - + nsCOMPtr commandDispatcher; + nsCOMPtr xulDoc = do_QueryInterface(rootDocument); + if (xulDoc) { + // See if we have a command dispatcher attached. + xulDoc->GetCommandDispatcher(getter_AddRefs(commandDispatcher)); + if (commandDispatcher) { + // Suppress the command dispatcher. + commandDispatcher->SetSuppressFocus(PR_TRUE); + } + } + + // Now fire blurs. We have to fire a blur on the focused window + // and on the focused element if there is one. + if (gLastFocusedDocument && gLastFocusedPresContext) { + // Blur the element. + if (gLastFocusedContent) { + // Retrieve this content node's pres context. it can be out of sync in + // the Ender widget case. + nsCOMPtr doc; + gLastFocusedContent->GetDocument(*getter_AddRefs(doc)); + if (doc) { + nsCOMPtr shell = getter_AddRefs(doc->GetShellAt(0)); + nsCOMPtr oldPresContext; + shell->GetPresContext(getter_AddRefs(oldPresContext)); + + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + event.message = NS_BLUR_CONTENT; + nsCOMPtr esm; + oldPresContext->GetEventStateManager(getter_AddRefs(esm)); + esm->SetFocusedContent(gLastFocusedContent); + gLastFocusedContent->HandleDOMEvent(oldPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); + esm->SetFocusedContent(nsnull); + NS_RELEASE(gLastFocusedContent); + } + } + + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + event.message = NS_BLUR_CONTENT; + + // fire blur on document and window + nsCOMPtr globalObject; + gLastFocusedDocument->GetScriptGlobalObject(getter_AddRefs(globalObject)); + gLastFocusedDocument->HandleDOMEvent(gLastFocusedPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); + if(!globalObject) break; + + globalObject->HandleDOMEvent(gLastFocusedPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); + mCurrentTarget = nsnull; + + // Now clear our our global variables + NS_RELEASE(gLastFocusedDocument); + gLastFocusedPresContext = nsnull; + } + + if (commandDispatcher) + commandDispatcher->SetSuppressFocus(PR_FALSE); } break;