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);

Reply via email to