comphelper/source/misc/accessiblecomponenthelper.cxx | 3 - comphelper/source/misc/accessibleeventnotifier.cxx | 17 ++++++- include/comphelper/accessiblecomponenthelper.hxx | 3 - sc/source/ui/Accessibility/AccessibleDocument.cxx | 2 vcl/unx/gtk3/a11y/atklistener.cxx | 42 +++++++++++++------ 5 files changed, 51 insertions(+), 16 deletions(-)
New commits: commit 2361718a34ee4ef47901846cb35eea4552bca46b Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Fri May 5 12:11:34 2023 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Fri May 5 14:39:58 2023 +0200 tdf#155149 Crash when exiting cell edit mode regression from commit 2dc240a82646fc23c673a6fd5a29ade934dd5b67 Author: Noel Grandin <noel.gran...@collabora.co.uk> Date: Tue May 2 14:47:43 2023 +0200 improve AccessibleEventNotifier::addEvent and commit 3b7db802731826b6cc3b55100470b0c61c1f2dfa Author: Noel Grandin <noel.gran...@collabora.co.uk> Date: Thu May 4 10:06:14 2023 +0200 tdf#105404 [API CHANGE] add index to accessiblity change event (*) Send better index hints (*) Error check the index hints better (*) Convert asserts to warnings and fall back to old code when index hint is wrong. Change-Id: I8e752fc26e729c9c8926beb2c7b196f5418a147e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151419 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/comphelper/source/misc/accessiblecomponenthelper.cxx b/comphelper/source/misc/accessiblecomponenthelper.cxx index 816b3b69ee0c..07d05d31a31d 100644 --- a/comphelper/source/misc/accessiblecomponenthelper.cxx +++ b/comphelper/source/misc/accessiblecomponenthelper.cxx @@ -113,7 +113,7 @@ namespace comphelper void OCommonAccessibleComponent::NotifyAccessibleEvent( const sal_Int16 _nEventId, - const Any& _rOldValue, const Any& _rNewValue ) + const Any& _rOldValue, const Any& _rNewValue, sal_Int32 nIndexHint ) { if ( !m_nClientId ) // if we don't have a client id for the notifier, then we don't have listeners, then @@ -126,6 +126,7 @@ namespace comphelper aEvent.EventId = _nEventId; aEvent.OldValue = _rOldValue; aEvent.NewValue = _rNewValue; + aEvent.IndexHint = nIndexHint; // let the notifier handle this event AccessibleEventNotifier::addEvent( m_nClientId, aEvent ); diff --git a/comphelper/source/misc/accessibleeventnotifier.cxx b/comphelper/source/misc/accessibleeventnotifier.cxx index d146d11812ba..37c9edda2625 100644 --- a/comphelper/source/misc/accessibleeventnotifier.cxx +++ b/comphelper/source/misc/accessibleeventnotifier.cxx @@ -246,8 +246,21 @@ void AccessibleEventNotifier::addEvent( const TClientId _nClient, const Accessib return; // since we're synchronous, again, we want to notify immediately - aClientPos->second.notifyEach(aGuard, &XAccessibleEventListener::notifyEvent, _rEvent); - + OInterfaceIteratorHelper4 aIt(aGuard, aClientPos->second); + // no need to hold lock here, and we don't want to hold lock while calling listeners + aGuard.unlock(); + while (aIt.hasMoreElements()) + { + try + { + aIt.next()->notifyEvent(_rEvent); + } + catch (Exception&) + { + // no assertion, because a broken access remote bridge or something like this + // can cause this exception + } + } } } // namespace comphelper diff --git a/include/comphelper/accessiblecomponenthelper.hxx b/include/comphelper/accessiblecomponenthelper.hxx index 2a840ea9e36e..328d61316b15 100644 --- a/include/comphelper/accessiblecomponenthelper.hxx +++ b/include/comphelper/accessiblecomponenthelper.hxx @@ -128,7 +128,8 @@ namespace comphelper void NotifyAccessibleEvent( const sal_Int16 _nEventId, const css::uno::Any& _rOldValue, - const css::uno::Any& _rNewValue + const css::uno::Any& _rNewValue, + sal_Int32 nIndexHint = -1 ); // life time control diff --git a/sc/source/ui/Accessibility/AccessibleDocument.cxx b/sc/source/ui/Accessibility/AccessibleDocument.cxx index 6d5dacede496..870851691a43 100644 --- a/sc/source/ui/Accessibility/AccessibleDocument.cxx +++ b/sc/source/ui/Accessibility/AccessibleDocument.cxx @@ -2136,6 +2136,7 @@ void ScAccessibleDocument::AddChild(const uno::Reference<XAccessible>& xAcc, boo aEvent.Source = uno::Reference<XAccessibleContext>(this); aEvent.EventId = AccessibleEventId::CHILD; aEvent.NewValue <<= mxTempAcc; + aEvent.IndexHint = getAccessibleChildCount() - 1; CommitChange( aEvent ); } } @@ -2154,6 +2155,7 @@ void ScAccessibleDocument::RemoveChild(const uno::Reference<XAccessible>& xAcc, aEvent.Source = uno::Reference<XAccessibleContext>(this); aEvent.EventId = AccessibleEventId::CHILD; aEvent.OldValue <<= mxTempAcc; + aEvent.IndexHint = -1; CommitChange( aEvent ); } mxTempAcc = nullptr; diff --git a/vcl/unx/gtk3/a11y/atklistener.cxx b/vcl/unx/gtk3/a11y/atklistener.cxx index b0f091142832..57f40af1db06 100644 --- a/vcl/unx/gtk3/a11y/atklistener.cxx +++ b/vcl/unx/gtk3/a11y/atklistener.cxx @@ -171,16 +171,23 @@ void AtkListener::handleChildAdded( if( !pChild ) return; + bool bNeedToFullFullChildList = true; if (nIndexHint != -1) { + bNeedToFullFullChildList = false; sal_Int64 nStateSet = rxParent->getAccessibleStateSet(); if( !(nStateSet & accessibility::AccessibleStateType::DEFUNC) || (nStateSet & accessibility::AccessibleStateType::MANAGES_DESCENDANTS) ) { m_aChildList.insert(m_aChildList.begin() + nIndexHint, rxAccessible); + if (m_aChildList[nIndexHint] != rxParent->getAccessibleChild(nIndexHint)) + { + SAL_WARN("vcl", "wrong index hint, falling back to updating full child list"); + bNeedToFullFullChildList = true; + } } } - else + if (bNeedToFullFullChildList) updateChildList(rxParent); atk_object_wrapper_add_child( mpWrapper, pChild, @@ -197,20 +204,32 @@ void AtkListener::handleChildRemoved( int nChildIndexHint) { sal_Int32 nIndex = nChildIndexHint; + if (nIndex < 0 || nIndex >= static_cast<sal_Int32>(m_aChildList.size())) + { + SAL_WARN("vcl", "index hint out of range, ignoring"); + nIndex = -1; + } + if (nIndex != -1 && rxChild != m_aChildList[nIndex]) + { + SAL_WARN("vcl", "index hint points to wrong child, somebody forgot to send accessibility update event"); + nIndex = -1; + } - // Locate the child in the children list + // if the hint did not work, search const size_t nmax = m_aChildList.size(); - for( size_t n = 0; n < nmax; ++n ) - { - // Comparing via uno::Reference::operator== is expensive - // with lots of objects, so assume we can find it the cheap way - // first, which works most of the time. - if( rxChild.get() == m_aChildList[n].get() ) + if (nIndex == -1) + // Locate the child in the children list + for( size_t n = 0; n < nmax; ++n ) { - nIndex = n; - break; + // Comparing via uno::Reference::operator== is expensive + // with lots of objects, so assume we can find it the cheap way + // first, which works most of the time. + if( rxChild.get() == m_aChildList[n].get() ) + { + nIndex = n; + break; + } } - } // The cheap way failed, find it via the more expensive path if (nIndex == -1) for( size_t n = 0; n < nmax; ++n ) @@ -248,7 +267,6 @@ void AtkListener::handleChildRemoved( if(!( (nStateSet & accessibility::AccessibleStateType::DEFUNC) || (nStateSet & accessibility::AccessibleStateType::MANAGES_DESCENDANTS) )) { - assert( m_aChildList[nIndex] == rxParent->getAccessibleChild(nIndex) ); m_aChildList.erase(m_aChildList.begin() + nIndex); }