Bug 371273. Fire caret/selection events for movement within document when find bar is open. Also fixes MSAA caret position when user is typing/deleting text, and moves MSAA specific code out of cross platform code area. r=surkov

This commit is contained in:
aaronleventhal@moonset.net 2007-05-07 11:55:17 -07:00
parent a71973dab1
commit c2459774c9
7 changed files with 282 additions and 150 deletions

View File

@ -38,10 +38,40 @@
#include "nsISupports.idl"
#include "nsIDOMNode.idl"
[scriptable, uuid(9124c666-6133-4be6-b3ed-dd0ec35f1e64)]
[scriptable, uuid(ef372cc1-0fd4-4e71-ac32-64028e680f17)]
interface nsIAccessibleCaret : nsISupports
{
void attachNewSelectionListener(in nsIDOMNode aFocusedNode);
void removeSelectionListener();
/**
* Listen to selection events on the focused control.
* Only one control's selection events are listened to at a time, per top-level window.
* This will remove the previous control's selection listener.
* It will fail if aFocusedNode is a document node -- document selection must be listened
* to via addDocSelectionListener().
* @param aFocusedNode The node for the focused control
*/
void setControlSelectionListener(in nsIDOMNode aFocusedNode);
/**
* Stop listening to selection events for any control.
* This does not have to be called explicitly in Shutdown() procedures,
* because the implementation of nsIAccessibleCaret will guarantee that.
*/
void clearControlSelectionListener();
/**
* Start listening to selection events for a given document
* More than one document's selection events can be listened to
* at the same time, by a given nsIAccessibleCaret.
* @param aDocument Document to listen to selection events for.
*/
void addDocSelectionListener(in nsIDOMDocument aDocument);
/**
* Stop listening to selection events for a given document
* If the document goes away, this method needs to be called for
* that document by the owner of the nsIAccessibleCaret
* @param aDocument Document to listen to selection events for.
*/
void removeDocSelectionListener(in nsIDOMDocument aDocument);
};

View File

@ -56,35 +56,37 @@
NS_IMPL_ISUPPORTS_INHERITED2(nsCaretAccessible, nsLeafAccessible, nsIAccessibleCaret, nsISelectionListener)
nsCaretAccessible::nsCaretAccessible(nsIDOMNode* aDocumentNode, nsIWeakReference* aShell, nsRootAccessible *aRootAccessible):
nsLeafAccessible(aDocumentNode, aShell), mVisible(PR_TRUE), mLastCaretOffset(-1), mLastNodeWithCaret(nsnull),
mSelectionControllerNode(nsnull), mRootAccessible(aRootAccessible)
nsLeafAccessible(aDocumentNode, aShell), mLastCaretOffset(-1), mLastNodeWithCaret(nsnull),
mCurrentControl(nsnull), mRootAccessible(aRootAccessible)
{
}
NS_IMETHODIMP nsCaretAccessible::Shutdown()
{
mDomSelectionWeak = nsnull;
// The caret accessible isn't shut down until the nsRootAccessible owning it is shut down
// Each nsDocAccessible, including the nsRootAccessible, is responsible for clearing the
// doc selection listeners they registeed in this nsCaretAccessible
ClearControlSelectionListener(); // Clear the selection listener for the currently focused control
mLastNodeWithCaret = nsnull;
mSelectionControllerNode = nsnull;
RemoveSelectionListener();
mLastUsedSelection = nsnull;
return nsLeafAccessible::Shutdown();
}
NS_IMETHODIMP nsCaretAccessible::RemoveSelectionListener()
NS_IMETHODIMP nsCaretAccessible::ClearControlSelectionListener()
{
nsCOMPtr<nsISelection> prevDomSel(do_QueryReferent(mDomSelectionWeak));
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(prevDomSel));
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryReferent(mCurrentControlSelection));
if (selPrivate) {
mDomSelectionWeak = nsnull;
mCurrentControlSelection = nsnull;
mCurrentControl = nsnull;
return selPrivate->RemoveSelectionListener(this);
}
return NS_OK;
}
NS_IMETHODIMP nsCaretAccessible::AttachNewSelectionListener(nsIDOMNode *aCurrentNode)
NS_IMETHODIMP nsCaretAccessible::SetControlSelectionListener(nsIDOMNode *aCurrentNode)
{
mSelectionControllerNode = aCurrentNode;
mCurrentControl = aCurrentNode;
mLastNodeWithCaret = nsnull;
// When focus moves such that the caret is part of a new frame selection
@ -95,87 +97,74 @@ NS_IMETHODIMP nsCaretAccessible::AttachNewSelectionListener(nsIDOMNode *aCurrent
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
if (!doc) // we also should try to QI to document instead (necessary to do when node is a document)
doc = do_QueryInterface(aCurrentNode);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
nsCOMPtr<nsIContent> content(do_QueryInterface(aCurrentNode));
if (!content)
content = doc->GetRootContent(); // If node is not content, use root content
// The control selection listener is only for form controls, not for the document
// When there is no document, the content will be null
if (!content) {
return NS_OK;
}
nsIFrame *frame = presShell->GetPrimaryFrameFor(content);
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
nsPresContext *presContext = presShell->GetPresContext();
if (!frame || !presContext)
return NS_ERROR_FAILURE;
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
nsCOMPtr<nsISelectionController> selCon;
frame->GetSelectionController(presContext, getter_AddRefs(selCon));
if (!selCon)
return NS_ERROR_FAILURE;
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
nsCOMPtr<nsISelection> domSel, prevDomSel(do_QueryReferent(mDomSelectionWeak));
nsCOMPtr<nsISelection> domSel;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
if (domSel == prevDomSel)
return NS_OK; // This is already the selection we're listening to
RemoveSelectionListener();
ClearControlSelectionListener();
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(domSel));
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
if (!selPrivate)
return NS_ERROR_FAILURE;
mDomSelectionWeak = do_GetWeakReference(domSel);
mCurrentControlSelection = do_GetWeakReference(domSel);
return selPrivate->AddSelectionListener(this);
}
NS_IMETHODIMP nsCaretAccessible::AddDocSelectionListener(nsIDOMDocument *aDoc)
{
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(doc->GetPrimaryShell());
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
nsCOMPtr<nsISelection> domSel;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(domSel);
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
return selPrivate->AddSelectionListener(this);
}
NS_IMETHODIMP nsCaretAccessible::RemoveDocSelectionListener(nsIDOMDocument *aDoc)
{
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(doc->GetPrimaryShell());
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
nsCOMPtr<nsISelection> domSel;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(domSel);
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
return selPrivate->RemoveSelectionListener(this);
}
NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel, PRInt16 aReason)
{
nsCOMPtr<nsIPresShell> presShell = GetPresShellFor(mSelectionControllerNode);
nsCOMPtr<nsISelection> domSel(do_QueryReferent(mDomSelectionWeak));
if (!presShell || domSel != aSel)
return NS_OK; // Only listening to selection changes in currently focused frame
mLastUsedSelection = do_GetWeakReference(aSel);
nsCOMPtr<nsICaret> caret;
presShell->GetCaret(getter_AddRefs(caret));
if (!caret)
return NS_OK;
nsRect caretRect;
PRBool isCollapsed;
caret->GetCaretCoordinates(nsICaret::eTopLevelWindowCoordinates, domSel,
&caretRect, &isCollapsed, nsnull);
PRBool visible = !caretRect.IsEmpty();
if (visible) // Make sure it's visible both by looking at coordinates and visible flag
caret->GetCaretVisible(&visible);
if (visible != mVisible) {
mVisible = visible;
#ifdef XP_WIN
mRootAccessible->FireToolkitEvent(mVisible? nsIAccessibleEvent::EVENT_SHOW:
nsIAccessibleEvent::EVENT_HIDE, this, nsnull);
#endif
}
#ifdef XP_WIN
// Support old style MSAA caret move events, which utilize screen coodinates
// rather than position within the text
nsPresContext *presContext = presShell->GetPresContext();
nsIViewManager* viewManager = presShell->GetViewManager();
if (!presContext || !viewManager)
return NS_OK;
nsIView *view = nsnull;
viewManager->GetRootView(view);
if (!view)
return NS_OK;
nsIWidget* widget = view->GetWidget();
if (!widget)
return NS_OK;
caretRect.x = presContext->AppUnitsToDevPixels(caretRect.x);
caretRect.y = presContext->AppUnitsToDevPixels(caretRect.y);
caretRect.width = presContext->AppUnitsToDevPixels(caretRect.width);
caretRect.height = presContext->AppUnitsToDevPixels(caretRect.height);
widget->WidgetToScreen(caretRect, mCaretRect);
mRootAccessible->FireToolkitEvent(nsIAccessibleEvent::EVENT_LOCATION_CHANGE, this, nsnull);
#endif
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
nsIPresShell *presShell = doc->GetPrimaryShell();
NS_ENSURE_TRUE(presShell, NS_OK);
// Get first nnsIAccessibleText in parent chain and fire caret-move, selection-change event for it
nsCOMPtr<nsIAccessible> accessible;
@ -183,7 +172,7 @@ NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, ns
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
// Get accessible from selection's focus node or its parent
nsCOMPtr<nsIDOMNode> focusNode;
domSel->GetFocusNode(getter_AddRefs(focusNode));
aSel->GetFocusNode(getter_AddRefs(focusNode));
if (!focusNode) {
mLastNodeWithCaret = nsnull;
return NS_OK; // No selection
@ -230,16 +219,72 @@ NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, ns
focusNode, nsnull, PR_FALSE);
}
/** Return the caret's bounds */
NS_IMETHODIMP nsCaretAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
already_AddRefed<nsICaret>
nsCaretAccessible::GetLastCaret(nsRect *aRect, PRBool *aIsVisible)
{
if (mCaretRect.IsEmpty()) {
*aIsVisible = PR_FALSE;
if (!mLastNodeWithCaret) {
return nsnull;
}
nsCOMPtr<nsIPresShell> presShell = GetPresShellFor(mLastNodeWithCaret);
NS_ENSURE_TRUE(presShell, nsnull);
nsICaret *caret;
presShell->GetCaret(&caret);
NS_ENSURE_TRUE(caret, nsnull);
nsRect caretRect;
PRBool isCollapsed;
nsCOMPtr<nsISelection> caretSelection(do_QueryReferent(mLastUsedSelection));
caret->GetCaretCoordinates(nsICaret::eTopLevelWindowCoordinates, caretSelection,
aRect, &isCollapsed, nsnull);
if (!aRect->IsEmpty()) {
caret->GetCaretVisible(aIsVisible);
}
return caret;
}
/** Return the caret's bounds */
NS_IMETHODIMP nsCaretAccessible::GetBounds(PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
{
*aX = *aY = *aWidth = *aHeight = 0;
nsRect caretRect;
PRBool isVisible;
nsCOMPtr<nsICaret> caret = GetLastCaret(&caretRect, &isVisible);
if (!caret || caretRect.IsEmpty()) {
return NS_ERROR_FAILURE;
}
*x = mCaretRect.x;
*y = mCaretRect.y;
*width = mCaretRect.width;
*height = mCaretRect.height;
nsCOMPtr<nsIPresShell> presShell = GetPresShellFor(mLastNodeWithCaret);
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
nsPresContext *presContext = presShell->GetPresContext();
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
nsIViewManager* viewManager = presShell->GetViewManager();
NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
nsIView *view = nsnull;
viewManager->GetRootView(view);
NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
nsIWidget* widget = view->GetWidget();
NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
caretRect.x = presContext->AppUnitsToDevPixels(caretRect.x);
caretRect.y = presContext->AppUnitsToDevPixels(caretRect.y);
caretRect.width = presContext->AppUnitsToDevPixels(caretRect.width);
caretRect.height = presContext->AppUnitsToDevPixels(caretRect.height);
nsRect caretScreenRect;
widget->WidgetToScreen(caretRect, caretScreenRect);
*aX = caretScreenRect.x;
*aY = caretScreenRect.y;
*aWidth = caretScreenRect.width;
*aHeight = caretScreenRect.height;
return NS_OK;
}
@ -252,10 +297,21 @@ NS_IMETHODIMP nsCaretAccessible::GetRole(PRUint32 *_retval)
NS_IMETHODIMP
nsCaretAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
{
*aState = 0;
if (aExtraState)
*aExtraState = 0;
*aState = mVisible? 0: nsIAccessibleStates::STATE_INVISIBLE;
NS_ENSURE_TRUE(mLastNodeWithCaret, NS_ERROR_FAILURE);
nsCOMPtr<nsIPresShell> presShell = GetPresShellFor(mLastNodeWithCaret);
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
nsRect caretRect;
PRBool isVisible;
GetLastCaret(&caretRect, &isVisible);
if (!isVisible) {
*aState = nsIAccessibleStates::STATE_INVISIBLE;
}
return NS_OK;
}

View File

@ -49,11 +49,23 @@ class nsRootAccessible;
/*
* This special accessibility class is for the caret, which is really the currently focused selection.
* There is only 1 visible caret per top level window (nsRootAccessible)
* There is only 1 visible caret per top level window (nsRootAccessible),
* However, there may be several visible selections.
*
* The important selections are the one owned by each document, and the one in the currently focused control.
*
* The caret accesible does not exist within the normal accessible tree; it lives in a different world.
* In MSAA, it is retrieved with via the WM_GETOBJECT message with lParam = OBJID_CARET,
* (as opposed to the root accessible tree for a window which is retrieved with OBJID_CLIENT)
* In ATK, the caret accessible is never exposed as an accessible object, but is used to fire
* caret move and selection change events.
*
* The caret accessible is owned by the nsRootAccessible for the top level window that it's in.
* The nsRootAccessible needs to tell the nsCaretAccessible about focus changes via
* setControlSelectionListener().
* Each nsDocAccessible needs to tell the nsCaretAccessible owned by the root to
* listen for selection events via addDocSelectionListener() and then needs to remove the
* selection listener when the doc goes away via removeDocSelectionListener().
*/
class nsCaretAccessible : public nsLeafAccessible, public nsIAccessibleCaret, public nsISelectionListener
@ -72,9 +84,8 @@ public:
NS_IMETHOD GetPreviousSibling(nsIAccessible **_retval);
/* ----- nsIAccessibleCaret ------ */
NS_IMETHOD AttachNewSelectionListener(nsIDOMNode *aFocusedNode);
NS_IMETHOD RemoveSelectionListener();
NS_DECL_NSIACCESSIBLECARET
/* ----- nsISelectionListener ---- */
NS_DECL_NSISELECTIONLISTENER
@ -89,15 +100,22 @@ public:
NS_IMETHOD Shutdown();
private:
nsRect mCaretRect;
PRBool mVisible;
PRInt32 mLastCaretOffset;
// The currently focused control -- never a document.
// We listen to selection for one control at a time (the focused one)
// Document selection is handled separately via additional listeners on all active documents
// The current control is set via SetControlSelectionListener()
nsCOMPtr<nsIDOMNode> mCurrentControl; // Selection controller for the currently focused control
nsCOMPtr<nsIWeakReference> mCurrentControlSelection;
// Info for the the last selection event
// If it was on a control, then mLastUsedSelection == mCurrentControlSelection
// Otherwise, it's for a document where the selection changed
nsCOMPtr<nsIWeakReference> mLastUsedSelection; // Weak ref to nsISelection
nsCOMPtr<nsIDOMNode> mLastNodeWithCaret;
nsCOMPtr<nsIDOMNode> mSelectionControllerNode;
// mListener is not a com pointer. It's a copy of the listener in the nsRootAccessible owner.
//See nsRootAccessible.h for details of the lifetime if this listener
PRInt32 mLastCaretOffset;
already_AddRefed<nsICaret> GetLastCaret(nsRect *aRect, PRBool *aIsVisible);
nsRootAccessible *mRootAccessible;
nsCOMPtr<nsIWeakReference> mDomSelectionWeak;
};
#endif

View File

@ -663,6 +663,19 @@ nsresult nsDocAccessible::AddEventListeners()
}
}
nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
docShellTreeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
if (rootTreeItem) {
nsCOMPtr<nsIAccessibleDocument> rootAccDoc = GetDocAccessibleFor(rootTreeItem, PR_TRUE);
nsCOMPtr<nsIAccessible> caretAccessible;
rootAccDoc->GetCaretAccessible(getter_AddRefs(caretAccessible));
nsCOMPtr<nsIAccessibleCaret> caretAccessibleIface(do_QueryInterface(caretAccessible));
if (caretAccessibleIface) {
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
caretAccessibleIface->AddDocSelectionListener(domDoc);
}
}
// add document observer
mDocument->AddObserver(this);
return NS_OK;
@ -682,6 +695,17 @@ nsresult nsDocAccessible::RemoveEventListeners()
mScrollWatchTimer = nsnull;
}
nsRefPtr<nsRootAccessible> rootAccessible(GetRootAccessible());
if (rootAccessible) {
nsCOMPtr<nsIAccessible> caretAccessible;
rootAccessible->GetCaretAccessible(getter_AddRefs(caretAccessible));
nsCOMPtr<nsIAccessibleCaret> caretAccessibleIface(do_QueryInterface(caretAccessible));
if (caretAccessibleIface) {
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
caretAccessibleIface->RemoveDocSelectionListener(domDoc);
}
}
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(container));
NS_ENSURE_TRUE(docShellTreeItem, NS_ERROR_FAILURE);
@ -1254,10 +1278,10 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
PRInt32 selectionCount;
accessibleText->GetSelectionCount(&selectionCount);
if (selectionCount) { // There's a selection so fire selection change as well
FireToolkitEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
accessible, nsnull);
FireToolkitEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
accessible, nsnull);
}
}
}
}
else {
FireAccessibleEvent(accessibleEvent);

View File

@ -43,7 +43,6 @@
#include "nsIAccessibleDocument.h"
#include "nsPIAccessibleDocument.h"
#include "nsIAccessibleEvent.h"
#include "nsIArray.h"
#include "nsIDocument.h"
#include "nsIDocumentObserver.h"
#include "nsIEditor.h"

View File

@ -345,8 +345,9 @@ nsresult nsRootAccessible::RemoveEventListeners()
target->RemoveEventListener(NS_LITERAL_STRING("pagehide"), this, PR_TRUE);
}
if (mCaretAccessible) {
mCaretAccessible->RemoveSelectionListener();
nsCOMPtr<nsPIAccessNode> caretAccessNode(do_QueryInterface(mCaretAccessible));
if (caretAccessNode) {
caretAccessNode->Shutdown();
mCaretAccessible = nsnull;
}
@ -440,7 +441,7 @@ PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
nsCOMPtr<nsIDOMNode> realFocusedNode(do_QueryInterface(domEventTarget));
if (realFocusedNode) {
mCaretAccessible->AttachNewSelectionListener(realFocusedNode);
mCaretAccessible->SetControlSelectionListener(realFocusedNode);
}
}
}
@ -896,7 +897,6 @@ NS_IMETHODIMP nsRootAccessible::Shutdown()
if (!mWeakShell) {
return NS_OK; // Already shutdown
}
mCaretAccessible = nsnull;
if (mFireFocusTimer) {
mFireFocusTimer->Cancel();
mFireFocusTimer = nsnull;

View File

@ -55,6 +55,7 @@
#include "nsINameSpaceManager.h"
#include "nsINodeInfo.h"
#include "nsIPrefService.h"
#include "nsRootAccessible.h"
#include "nsIServiceManager.h"
#include "nsTextFormatter.h"
#include "nsIView.h"
@ -1493,55 +1494,59 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
if (!accessible)
return NS_OK;
PRInt32 childID, worldID = OBJID_CLIENT;
PRUint32 role = ROLE_SYSTEM_TEXT; // Default value
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(accessible));
NS_ENSURE_STATE(accessNode);
HWND hWnd = 0;
if (NS_SUCCEEDED(accessible->GetRole(&role)) && role == ROLE_SYSTEM_CARET) {
childID = CHILDID_SELF;
worldID = OBJID_CARET;
} else {
childID = GetChildIDFor(accessible); // get the id for the accessible
if (!childID)
return NS_OK; // Can't fire an event without a child ID
// See if we're in a scrollable area with its own window
nsCOMPtr<nsIAccessible> newAccessible;
if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
// Don't use frame from current accessible when we're hiding that
// accessible.
accessible->GetParent(getter_AddRefs(newAccessible));
} else {
newAccessible = accessible;
if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
// Fire additional old-style MSAA caret events as well as the IA2 event
nsRefPtr<nsRootAccessible> rootAccessible = GetRootAccessible();
if (rootAccessible) {
nsCOMPtr<nsIAccessible> caretAccessible;
void* handle = nsnull;
rootAccessible->GetWindowHandle(&handle);
NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, (HWND)handle, OBJID_CARET, CHILDID_SELF);
}
}
nsCOMPtr<nsPIAccessNode> privateAccessNode =
do_QueryInterface(newAccessible);
if (privateAccessNode) {
nsIFrame *frame = privateAccessNode->GetFrame();
if (frame) {
nsIWidget *window = frame->GetWindow();
PRBool isVisible;
window->IsVisible(isVisible);
if (isVisible) {
// Short explanation:
// If HWND for frame is inside a hidden window, fire the event on the
// containing document's visible window.
//
// Long explanation:
// This is really just to fix combo boxes with JAWS. Window-Eyes already worked with
// combo boxes because they use the value change event in the closed combo box
// case. JAWS will only pay attention to the focus events on the list items.
// The JAWS developers haven't fixed that, so we'll use the focus events to make JAWS work.
// However, JAWS is ignoring events on a hidden window. So, in order to fix the bug where
// JAWS doesn't echo the current option as it changes in a closed combo box, we need to use an
// ensure that we never fire an event with an HWND for a hidden window.
hWnd = (HWND)frame->GetWindow()->GetNativeData(NS_NATIVE_WINDOW);
}
+ PRInt32 childID = GetChildIDFor(accessible); // get the id for the accessible
+ if (!childID)
+ return NS_OK; // Can't fire an event without a child ID
+
+ // See if we're in a scrollable area with its own window
+ nsCOMPtr<nsIAccessible> newAccessible;
+ if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
+ // Don't use frame from current accessible when we're hiding that
+ // accessible.
+ accessible->GetParent(getter_AddRefs(newAccessible));
+ } else {
+ newAccessible = accessible;
+ }
HWND hWnd = 0;
nsCOMPtr<nsPIAccessNode> privateAccessNode =
do_QueryInterface(newAccessible);
if (privateAccessNode) {
nsIFrame *frame = privateAccessNode->GetFrame();
if (frame) {
nsIWidget *window = frame->GetWindow();
PRBool isVisible;
window->IsVisible(isVisible);
if (isVisible) {
// Short explanation:
// If HWND for frame is inside a hidden window, fire the event on the
// containing document's visible window.
//
// Long explanation:
// This is really just to fix combo boxes with JAWS. Window-Eyes already worked with
// combo boxes because they use the value change event in the closed combo box
// case. JAWS will only pay attention to the focus events on the list items.
// The JAWS developers haven't fixed that, so we'll use the focus events to make JAWS work.
// However, JAWS is ignoring events on a hidden window. So, in order to fix the bug where
// JAWS doesn't echo the current option as it changes in a closed combo box, we need to use an
// ensure that we never fire an event with an HWND for a hidden window.
hWnd = (HWND)frame->GetWindow()->GetNativeData(NS_NATIVE_WINDOW);
}
}
}
@ -1562,7 +1567,7 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
// * Client area window: text drawing window & MSAA event window
// Fire MSAA event for client area window.
NotifyWinEvent(winEvent, hWnd, worldID, childID);
NotifyWinEvent(winEvent, hWnd, OBJID_CLIENT, childID);
return NS_OK;
}