vcl/Library_vclplug_gtk4.mk | 1 vcl/unx/gtk4/a11y.cxx | 12 +++++ vcl/unx/gtk4/gtkaccessibleeventlistener.cxx | 63 ++++++++++++++++++++++++++++ vcl/unx/gtk4/gtkaccessibleeventlistener.hxx | 35 +++++++++++++++ 4 files changed, 111 insertions(+)
New commits: commit c24ed12d1098bb0a3faf1774fd8bd5f686fb49ab Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Mon Dec 18 13:50:39 2023 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Tue Dec 19 09:29:09 2023 +0100 gtk4 a11y: Add initial event handling Add a `GtkAccessibleEventListener` that is in charge of handling a11y events for the gtk4 VCL plugin. This is inspired by how the Qt-based VCL plugins do it (see `QtAccessibleEventListener`). Initially, only handle the `css::accessibility::AccessibleEventId::STATE_CHANGED` for the `AccessibleStateType::CHECKED` state by updating the value for the corresponding Gtk state. With this in place, toggling e.g. the "Bold" toggle button in Writer's formatting toolbar now properly updates the "checked" state of the corresponding a11y object in Accerciser's tree view of LO's a11y hierarchy. Gtk takes care of sending a corresponding "state-changed" event on the AT-SPI layer: 10.8 object:state-changed:checked(1, 0, 0) source: [toggle button | Bold] application: [application | soffice] Handling state changes to other states that map to a `GtkAccessibleState` should be possible in a similar way. However, other states - like the FOCUSED state - map to a `GtkAccessiblePlatformState` in Gtk 4, and the function `gtk_accessible_platform_changed` to update these that is used by Gtk's own widgets is private API for now, so cannot be used by LibreOffice, so I currently don't see a way to handle these without changes on Gtk side (see [1]). [1] https://gitlab.gnome.org/GNOME/gtk/-/issues/6272 Change-Id: I2a5ca4448ad14a61dc96aef7b22af36baeeed5c4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160929 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/Library_vclplug_gtk4.mk b/vcl/Library_vclplug_gtk4.mk index bb9d82ad570f..a288e5151aa6 100644 --- a/vcl/Library_vclplug_gtk4.mk +++ b/vcl/Library_vclplug_gtk4.mk @@ -88,6 +88,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gtk4,\ vcl/unx/gtk4/a11y \ vcl/unx/gtk4/convert3to4 \ vcl/unx/gtk4/customcellrenderer \ + vcl/unx/gtk4/gtkaccessibleeventlistener \ vcl/unx/gtk4/gtkdata \ vcl/unx/gtk4/gtkinst \ vcl/unx/gtk4/gtksys \ diff --git a/vcl/unx/gtk4/a11y.cxx b/vcl/unx/gtk4/a11y.cxx index c8103471b085..37b54bae0475 100644 --- a/vcl/unx/gtk4/a11y.cxx +++ b/vcl/unx/gtk4/a11y.cxx @@ -10,6 +10,7 @@ #include <com/sun/star/accessibility/AccessibleRole.hpp> #include <com/sun/star/accessibility/AccessibleStateType.hpp> #include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> #include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp> #include <com/sun/star/accessibility/XAccessibleText.hpp> #include <com/sun/star/accessibility/XAccessibleValue.hpp> @@ -20,6 +21,7 @@ #if GTK_CHECK_VERSION(4, 9, 0) #include "a11y.hxx" +#include "gtkaccessibleeventlistener.hxx" #define OOO_TYPE_FIXED (ooo_fixed_get_type()) #define OOO_FIXED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OOO_TYPE_FIXED, OOoFixed)) @@ -617,6 +619,16 @@ lo_accessible_new(GdkDisplay* pDisplay, GtkAccessible* pParent, GTK_ACCESSIBLE_PROPERTY_VALUE_MAX, fMaxValue, -1); } + // register event listener + css::uno::Reference<css::accessibility::XAccessibleEventBroadcaster> xBroadcaster( + xContext, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + { + css::uno::Reference<css::accessibility::XAccessibleEventListener> xListener( + new GtkAccessibleEventListener(ret)); + xBroadcaster->addAccessibleEventListener(xListener); + } + return ret; } diff --git a/vcl/unx/gtk4/gtkaccessibleeventlistener.cxx b/vcl/unx/gtk4/gtkaccessibleeventlistener.cxx new file mode 100644 index 000000000000..1bfa69530be3 --- /dev/null +++ b/vcl/unx/gtk4/gtkaccessibleeventlistener.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <sal/log.hxx> + +#include "gtkaccessibleeventlistener.hxx" + +GtkAccessibleEventListener::GtkAccessibleEventListener(LoAccessible* pLoAccessible) + : m_pLoAccessible(pLoAccessible) +{ + assert(m_pLoAccessible); + g_object_ref(m_pLoAccessible); +} + +GtkAccessibleEventListener::~GtkAccessibleEventListener() +{ + assert(m_pLoAccessible); + g_object_unref(m_pLoAccessible); +} + +void GtkAccessibleEventListener::disposing(const com::sun::star::lang::EventObject&) {} + +void GtkAccessibleEventListener::notifyEvent( + const com::sun::star::accessibility::AccessibleEventObject& rEvent) +{ + switch (rEvent.EventId) + { + case css::accessibility::AccessibleEventId::STATE_CHANGED: + { + sal_Int64 nState; + bool bNewValueSet = false; + if (rEvent.NewValue >>= nState) + { + bNewValueSet = true; + } + else if (!(rEvent.OldValue >>= nState)) + { + assert(false && "neither old nor new value set"); + } + + if (nState == css::accessibility::AccessibleStateType::CHECKED) + { + GtkAccessibleTristate eState + = bNewValueSet ? GTK_ACCESSIBLE_TRISTATE_TRUE : GTK_ACCESSIBLE_TRISTATE_FALSE; + gtk_accessible_update_state(GTK_ACCESSIBLE(m_pLoAccessible), + GTK_ACCESSIBLE_STATE_CHECKED, eState, -1); + } + break; + } + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/gtk4/gtkaccessibleeventlistener.hxx b/vcl/unx/gtk4/gtkaccessibleeventlistener.hxx new file mode 100644 index 000000000000..584cacff85fa --- /dev/null +++ b/vcl/unx/gtk4/gtkaccessibleeventlistener.hxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <gtk/gtk.h> + +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <cppuhelper/implbase.hxx> + +struct LoAccessible; + +class GtkAccessibleEventListener final + : public cppu::WeakImplHelper<css::accessibility::XAccessibleEventListener> +{ +public: + explicit GtkAccessibleEventListener(LoAccessible* pLoAccessible); + ~GtkAccessibleEventListener(); + + virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; + virtual void SAL_CALL + notifyEvent(const css::accessibility::AccessibleEventObject& rEvent) override; + +private: + LoAccessible* m_pLoAccessible; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */