summaryrefslogtreecommitdiff
path: root/toolkit
diff options
context:
space:
mode:
authorMichael Weghorn <m.weghorn@posteo.de>2022-09-19 14:44:46 +0200
committerMichael Weghorn <m.weghorn@posteo.de>2022-09-26 16:14:51 +0200
commitc26d6cc3c4878d356328a538b5bf11e4e6a0e7dc (patch)
treee69aca14bce5782552ee3cefef2f6a34afb54099 /toolkit
parentd8789d175af75e7768e601662619b116e9780937 (diff)
tdf#117173 a11y: Send SHOWING state change event on Window{Show,Hide}
When a `vcl::Window` becomes visible, `Window::ImplSetReallyVisible` calls the registered event listeners with a `VclEventId::WindowShow` event. Likewise, a `VclEventId::WindowHide` events is sent in `Window::ImplResetReallyVisible` when the window is no longer visible. Handle that event in `VCLXAccessibleComponent` by sending a state change event for the SHOWING state, so assistive technology gets notified about this. (Similar handling can already be found e.g. in `AccessibleTabBar::ProcessWindowEvent` or `AccessibleTabBarPageList::ProcessWindowEvent`.) While doing so in `VCLXAccessibleComponent::ProcessWindowEvent` for the object itself would generally seem like a more straightforward and conceptually nicer approach, this would have the problem that the event wouldn't get propagated to the platform-specific a11y integration layer (like winaccessibility) for the `VclEventId::WindowShow` case, since the a11y event listeners are registered and unregistered as a response to the CHILD event (at least for winaccessibility and gtk3, qt6 doesn't do that (yet?)), and if the accessible event listener is not (yet) registered, the event is simply ignored. Since the CHILD event is sent in `VCLXAccessibleComponent::ProcessChildWindowEvent` and that gets called on the parent *after* `VCLXAccessibleComponent::ProcessWindowEvent` gets called for the object that became shown/hidden (s. `Window::CallEventListeners`), also send the state change event for the SHOWING state of the child from there, so the proper order can be made sure. The reverse order (first the state change event for the SHOWING state, then the CHILD event which results in removal of the a11y event listeners) is used for the case where the window gets hidden. In combination with Change-Id Ifcf9304883e2e824ea1b7998d7767e474b87c8b6 ("tdf#119788 tdf#117173 add atk notification role") and commit 155e8b1683f10847ff18e75287e2466220242bb1 ("tdf#117173: qt a11y: Forward changes to SHOWING state"), this makes Orca announce the label with notification role in the Search and Replace dialog for the qt6 VCL plugin as well. The gtk3 case already works with just Change-Id Ifcf9304883e2e824ea1b7998d7767e474b87c8b6 ("tdf#119788 tdf#117173 add atk notification role") in place, because that one uses native gtk widgets in the Search and Replace dialog, and the Gtk library then takes care of sending the object:state-changed:showing event when the label with notification role gets shown. Side note: There are also comments that suggest to rework the a11y event handling for the show/hide changes more fundamentally, e.g. this comment in `Window::ImplSetReallyVisible`: // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge. // For this, the data member of the event must not be NULL. // Previously, we did this in Window::Show, but there some events got lost in certain situations. Now // we're doing it when the visibility really changes if( bBecameReallyVisible && ImplIsAccessibleCandidate() ) CallEventListeners( VclEventId::WindowShow, this ); // TODO. It's kind of a hack that we're re-using the VclEventId::WindowShow. Normally, we should // introduce another event which explicitly triggers the Accessibility implementations. Similar ones can be found in `Window::ImplResetReallyVisible` and `Window::Show`. Change-Id: Id62b3942dc17c3a1ed6a08d23438406e5a19c39d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139813 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Diffstat (limited to 'toolkit')
-rw-r--r--toolkit/source/awt/vclxaccessiblecomponent.cxx32
1 files changed, 32 insertions, 0 deletions
diff --git a/toolkit/source/awt/vclxaccessiblecomponent.cxx b/toolkit/source/awt/vclxaccessiblecomponent.cxx
index b7c44f53bd68..5d3b15653ba3 100644
--- a/toolkit/source/awt/vclxaccessiblecomponent.cxx
+++ b/toolkit/source/awt/vclxaccessiblecomponent.cxx
@@ -163,6 +163,20 @@ void VCLXAccessibleComponent::ProcessWindowChildEvent( const VclWindowEvent& rVc
{
aNewValue <<= xAcc;
NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue );
+
+ // CHILD event above results in a11y event listeners getting registered,
+ // so send state change event for SHOWING event after that
+ uno::Reference<XAccessibleContext> xChildContext = xAcc->getAccessibleContext();
+ if (xChildContext.is())
+ {
+ VCLXAccessibleComponent* pChildComponent = dynamic_cast<VCLXAccessibleComponent*>(xChildContext.get());
+ if (pChildComponent)
+ {
+ css::uno::Any aNewStateValue;
+ aNewStateValue <<= accessibility::AccessibleStateType::SHOWING;
+ pChildComponent->NotifyAccessibleEvent(accessibility::AccessibleEventId::STATE_CHANGED, css::uno::Any(), aNewStateValue);
+ }
+ }
}
}
break;
@@ -171,6 +185,20 @@ void VCLXAccessibleComponent::ProcessWindowChildEvent( const VclWindowEvent& rVc
xAcc = GetChildAccessible( rVclWindowEvent );
if( xAcc.is() )
{
+ // send send state change event for SHOWING before sending the CHILD event below,
+ // since that one results in a11y event listeners getting removed
+ uno::Reference<XAccessibleContext> xChildContext = xAcc->getAccessibleContext();
+ if (xChildContext.is())
+ {
+ VCLXAccessibleComponent* pChildComponent = dynamic_cast<VCLXAccessibleComponent*>(xChildContext.get());
+ if (pChildComponent)
+ {
+ css::uno::Any aOldStateValue;
+ aOldStateValue <<= accessibility::AccessibleStateType::SHOWING;
+ pChildComponent->NotifyAccessibleEvent(accessibility::AccessibleEventId::STATE_CHANGED, aOldStateValue, css::uno::Any());
+ }
+ }
+
aOldValue <<= xAcc;
NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue );
}
@@ -334,6 +362,10 @@ void VCLXAccessibleComponent::ProcessWindowEvent( const VclWindowEvent& rVclWind
NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
}
break;
+ case VclEventId::WindowHide:
+ case VclEventId::WindowShow:
+ // WindowHide and WindowShow are handled in ProcessWindowChildEvent so the right order
+ // regarding the CHILD event can be taken into account
default:
{
}