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: */

Reply via email to