tdf#155149 Crash when exiting cell edit mode
regression from
commit 2dc240a82646fc23c673a6fd5a29ade934dd5b67
Author: Noel Grandin <noel.grandin@collabora.co.uk>
Date: Tue May 2 14:47:43 2023 +0200
improve AccessibleEventNotifier::addEvent
and
commit 3b7db802731826b6cc3b55100470b0c61c1f2dfa
Author: Noel Grandin <noel.grandin@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.grandin@collabora.co.uk>
diff --git a/comphelper/source/misc/accessiblecomponenthelper.cxx b/comphelper/source/misc/accessiblecomponenthelper.cxx
index 816b3b6..07d05d3 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 d146d11..37c9edd 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 2a840ea..328d613 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 6d5dace..87085169 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 b0f09114..57f40af 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;
// Locate the child in the children list
const size_t nmax = m_aChildList.size();
for( size_t n = 0; n < nmax; ++n )
if (nIndex < 0 || nIndex >= static_cast<sal_Int32>(m_aChildList.size()))
{
// 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;
}
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;
}
// if the hint did not work, search
const size_t nmax = m_aChildList.size();
if (nIndex == -1)
// Locate the child in the children list
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() )
{
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);
}