vcl/unx/gtk3/a11y/atkwrapper.cxx |    8 ++++++++
 1 file changed, 8 insertions(+)

New commits:
commit 4465cd882891caae22cf059e5b44f9642dc6d76f
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Sat Mar 15 23:43:44 2025 -0700
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Mon Mar 17 02:13:45 2025 +0100

    tdf#163989 gtk3 a11y: Set a11y parent for native GTK vcl::Window child
    
    When mixing vcl::Window and native GtkWidget, the native
    GtkWidget's AtkObject is correctly reported as the
    InterimWindow child e.g. for the text edit of the combobox
    in the Find toolbar since
    
        commit 39e0bdb686baf76a4c54d12cfa66aa9f08db8c3f
        Author: Michael Weghorn <m.wegh...@posteo.de>
        Date:   Mon Mar 3 17:42:03 2025 +0100
    
            tdf#163989 vcl a11y: Rework toolbar item window a11y
    
    . However, the GtkWidget's AtkObject was not reporting the accessible
    object of the parent vcl::Window as its parent (but presumably the
    next GtkWidget in the hierarchy), which resulted in an inconsistent
    a11y hierarchy: The "a11y object path" top-down is different from the
    bottom-up one.
    This inconsistency e.g. caused Accerciser's "Jump to object" feature
    to not select the correct object in its treeview of the LO a11y hierarchy
    when clicking on the event source of the "object:text-caret-moved"
    AT-SPI2 event triggered by typing in the search bar.
    
    Event displayed in Accerciser's Event Monitor:
    
        65.7 object:text-caret-moved(2, 0, 0)
            source: [text | ]
            application: [application | soffice]
    
    When clicking on the event source, the correct area on screen
    was highlighted and details about the object were displayed in
    Accerciser's Interface Viewer, but the object wasn't selected
    in the treeview.
    
    Bottom-up a11y object path printed via Accerciser's IPython console:
    
        In [2]: obj = acc
        In [3]: while obj:
        In [3]:     print(f'object: {obj}, index in parent: 
{obj.get_index_in_parent()}')
        In [3]:     obj = obj.parent
        In [3]:
        object: [text | ], index in parent: 0
        object: [combo box | ], index in parent: 0
        object: [filler | ], index in parent: 0
        object: [panel | ], index in parent: 0
        object: [viewport | ], index in parent: 0
        object: [scroll pane | ], index in parent: 3
        object: [root pane | Untitled 1 — LibreOfficeDev Writer 25.8 
[f3288f031a2667a8acc7b3c79744fed1db590845]], index in parent: 0
        object: [panel | ], index in parent: 1
        object: [panel | ], index in parent: 0
        object: [frame | Untitled 1 — LibreOfficeDev Writer 25.8 
[f3288f031a2667a8acc7b3c79744fed1db590845]], index in parent: 0
        object: [application | soffice], index in parent: -1
        object: [desktop frame | main], index in parent: -1
    
    This is missing various objects as compared to the top-down path
    seen when navigating from the top-level application object down
    to the combobox's text edit in Accerciser's treeview.
    
    Fix this by explicitly setting the parent of the GtkWidget's
    AtkObject to the AtkObject that wraps the XAccessible of the
    vcl::Window. This makes sure the parent <-> child relationship
    is now consistent both ways.
    
    Bottom-up a11y object path with this commit in place:
    
        In [1]: obj = acc
        In [2]: while obj:
        In [2]:     print(f'object: {obj}, index in parent: 
{obj.get_index_in_parent()}')
        In [2]:     obj = obj.parent
        In [2]:
        object: [text | ], index in parent: 0
        object: [combo box | ], index in parent: 0
        object: [filler | ], index in parent: 0
        object: [panel | ], index in parent: 0
        object: [panel | ], index in parent: 0
        object: [filler | ], index in parent: 0
        object: [panel | ], index in parent: 0
        object: [panel | Find Values], index in parent: 1
        object: [tool bar | Find], index in parent: 0
        object: [panel | ], index in parent: 5
        object: [root pane | Untitled 1 — LibreOfficeDev Writer 25.8 
[1d0572a62fcbba1a96438f49b737e2b177e6cb8e]], index in parent: 0
        object: [panel | ], index in parent: 1
        object: [panel | ], index in parent: 0
        object: [frame | Untitled 1 — LibreOfficeDev Writer 25.8 
[1d0572a62fcbba1a96438f49b737e2b177e6cb8e]], index in parent: 0
        object: [application | soffice], index in parent: -1
        object: [desktop frame | main], index in parent: -1
    
    This matches the (reversed) top-down object path, and makes Accerciser's
    "Jump to object" feature work for the scenario described above
    when using the gtk3 VCL plugin.
    
    Change-Id: Ibd18aef3c784d63c75ab29287910c31273939538
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182992
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins

diff --git a/vcl/unx/gtk3/a11y/atkwrapper.cxx b/vcl/unx/gtk3/a11y/atkwrapper.cxx
index 317c8290f461..20c978cfcd3c 100644
--- a/vcl/unx/gtk3/a11y/atkwrapper.cxx
+++ b/vcl/unx/gtk3/a11y/atkwrapper.cxx
@@ -1030,7 +1030,15 @@ atk_object_wrapper_new( const css::uno::Reference< 
css::accessibility::XAccessib
             {
                 const SystemEnvData* pEnvData = 
static_cast<SystemChildWindow*>(xWindow.get())->GetSystemData();
                 if (GtkWidget *pSysObj = pEnvData ? 
static_cast<GtkWidget*>(pEnvData->pWidget) : nullptr)
+                {
                     pWrap->mpSysObjChild = gtk_widget_get_accessible(pSysObj);
+                    AtkObject* pParent = 
atk_object_wrapper_ref(xWindow->GetAccessible());
+                    if (pParent)
+                    {
+                        atk_object_set_parent(pWrap->mpSysObjChild, pParent);
+                        g_object_unref(pParent);
+                    }
+                }
             }
         }
 

Reply via email to