vcl/unx/gtk4/a11y.cxx | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
New commits: commit 3aca2d9776a871f15009a1aa70628ba3a03ee147 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Nov 9 15:31:57 2023 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Thu Nov 9 21:00:05 2023 +0100 gtk4 a11y: Handle the "level" object attribute Add initial handling/mapping for object attributes. In LibreOffice and Gtk 3/ATK/AT-SPI, object attributes are currently key-value pairs, so arbitrary attribute names and values can be set. For Gtk 4, there's currently a discussion on how AT-SPI object attributes should be handled, s. [1]. One potential option is for them to be handled as `GtkAccessibleProperty`s. In any case, there's already a `GTK_ACCESSIBLE_PROPERTY_LEVEL` property that matches the "level" object attribute that Writer sets for headings to specify what heading level this is (s. `SwAccessibleParagraph::getExtendedAttributes`) and that the gtk3 VCL plugin reports as an ATK/AT-SPI object attribute with the same name and semantics for AT-SPI, which is in line with the specification in the Core Accessibility API Mappings 1.2 [2]. Map that LO object attribute to the above-mentioned `GTK_ACCESSIBLE_PROPERTY_LEVEL`. The property is currently not yet mapped to an AT-SPI attribute in Gtk 4, but together with a corresponding merge request [3], the object attribute can be seen in Accerciser as expected. While object properties in LO are currently generally only generated/updated when they're queried (via `XAccessibleExtendedAttributes::getExtendedAttributes`), the `GtkAccessibleProperty` handling in Gtk 4 would require to explicitly call `gtk_accessible_update_property` with the new value. This may require further adjustments on LO side to keep the properties up-to-date (e.g. adding something like a new `AccessibleEventId::OBJECT_PROPERTY_CHANGED` event and then implementing corresponding handling in all places that provide object properties). But that's something to look into later, also depending on the outcome of the discussion in [1]. (As of now, the gtk4 VCL plugin doesn't handle any a11y events, not even the existing ones.) [1] https://gitlab.gnome.org/GNOME/gtk/-/issues/6196 [2] https://www.w3.org/TR/core-aam-1.2/#ariaLevelHeading [3] https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6549 Change-Id: I024afd7b527a20922e69156e1562dda783be2b49 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159216 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/unx/gtk4/a11y.cxx b/vcl/unx/gtk4/a11y.cxx index 8bd1b97f0aa9..42a0fd59e4b9 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/XAccessibleExtendedAttributes.hpp> #include <com/sun/star/accessibility/XAccessibleText.hpp> #include <com/sun/star/accessibility/XAccessibleValue.hpp> #include <unx/gtk/gtkframe.hxx> @@ -307,6 +308,50 @@ static void applyStates(GtkAccessible* pGtkAccessible, } } +static void applyObjectAttribute(GtkAccessible* pGtkAccessible, const OUString& rName, + const OUString& rValue) +{ + assert(pGtkAccessible); + + if (rName == u"level") + { + const int nLevel = static_cast<int>(rValue.toInt32()); + gtk_accessible_update_property(pGtkAccessible, GTK_ACCESSIBLE_PROPERTY_LEVEL, nLevel, -1); + } +} + +/** + * Based on the object attributes set for xContext, set the corresponding Gtk equivalents + * in pGtkAccessible, where applicable. + */ +static void +applyObjectAttributes(GtkAccessible* pGtkAccessible, + css::uno::Reference<css::accessibility::XAccessibleContext> xContext) +{ + assert(pGtkAccessible); + + css::uno::Reference<css::accessibility::XAccessibleExtendedAttributes> xAttributes( + xContext, css::uno::UNO_QUERY); + if (!xAttributes.is()) + return; + + OUString sAttrs; + xAttributes->getExtendedAttributes() >>= sAttrs; + + sal_Int32 nIndex = 0; + do + { + const OUString sAttribute = sAttrs.getToken(0, ';', nIndex); + sal_Int32 nColonPos = 0; + const OUString sName = sAttribute.getToken(0, ':', nColonPos); + const OUString sValue = sAttribute.getToken(0, ':', nColonPos); + assert(nColonPos == -1 + && "Too many colons in attribute that should have \"name:value\" syntax"); + + applyObjectAttribute(pGtkAccessible, sName, sValue); + } while (nIndex >= 0); +} + #define LO_TYPE_ACCESSIBLE (lo_accessible_get_type()) #define LO_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), LO_TYPE_ACCESSIBLE, LoAccessible)) // #define LO_IS_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LO_TYPE_ACCESSIBLE)) @@ -545,6 +590,8 @@ lo_accessible_new(GdkDisplay* pDisplay, GtkAccessible* pParent, applyStates(pGtkAccessible, xContext); + applyObjectAttributes(GTK_ACCESSIBLE(ret), xContext); + // set values from XAccessibleValue interface if that's implemented css::uno::Reference<css::accessibility::XAccessibleValue> xAccessibleValue(xContext, css::uno::UNO_QUERY);