include/vcl/toolkit/treelistentry.hxx | 3 ++ include/vcl/weld.hxx | 1 svx/source/tbxctrls/fontworkgallery.cxx | 1 vcl/inc/qt5/QtInstanceIconView.hxx | 1 vcl/inc/salvtables.hxx | 2 + vcl/qt5/QtInstanceIconView.cxx | 10 ++++++ vcl/source/accessibility/accessiblelistboxentry.cxx | 7 ++++ vcl/source/app/salvtables.cxx | 7 ++++ vcl/unx/gtk3/a11y/atkcomponent.cxx | 3 +- vcl/unx/gtk3/gtkinst.cxx | 29 ++++++++++++++++++++ 10 files changed, 63 insertions(+), 1 deletion(-)
New commits: commit 3c063aecde00fa9746a2822b44f0d9d962bbeefe Author: Michael Weghorn <[email protected]> AuthorDate: Thu Feb 13 14:21:24 2025 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Thu Feb 13 19:44:35 2025 +0100 gtk3 a11y: Don't pass null ref to atk_object_wrapper_ref XAccessibleComponent::getAccessibleAtPoint can return an empty ref if there is no child at the given position (e.g. also for any a11y object that doesn't have any children.) Fixes the following critical warning seen with the gtk3 VCL plugin when using Accerciser's "Inspect object under mouse" feature when the mouse pointer is over one of the items in the "Insert" -> "Fontwork" dialog. Backtrace received with G_DEBUG=fatal-criticals: ** (soffice:2129541): CRITICAL **: 14:07:18.230: AtkObject *atk_object_wrapper_ref(const uno::Reference<accessibility::XAccessible> &, bool): assertion 'bool(rxAccessible)' failed Fatal exception: Signal 5 Stack: #0 sal::backtrace_get(unsigned int) at /home/michi/development/git/libreoffice/sal/osl/unx/backtraceapi.cxx:42 #1 (anonymous namespace)::printStack(int) at /home/michi/development/git/libreoffice/sal/osl/unx/signal.cxx:289 #2 (anonymous namespace)::callSystemHandler(int, siginfo_t*, void*) at /home/michi/development/git/libreoffice/sal/osl/unx/signal.cxx:330 #3 (anonymous namespace)::signalHandlerFunction(int, siginfo_t*, void*) at /home/michi/development/git/libreoffice/sal/osl/unx/signal.cxx:427 #4 /lib/x86_64-linux-gnu/libc.so.6(+0x3fda0) [0x7f57da649da0] #5 g_logv in /lib/x86_64-linux-gnu/libglib-2.0.so.0 #6 g_log in /lib/x86_64-linux-gnu/libglib-2.0.so.0 #7 atk_object_wrapper_ref at /home/michi/development/git/libreoffice/vcl/unx/gtk3/a11y/atkwrapper.cxx:936 #8 component_wrapper_ref_accessible_at_point(_AtkComponent*, int, int, AtkCoordType) at /home/michi/development/git/libreoffice/vcl/unx/gtk3/a11y/atkcomponent.cxx:174 #9 /lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0(+0x1b57d) [0x7f57c736c57d] #10 /lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0(+0x2348d) [0x7f57c737448d] #11 /lib/x86_64-linux-gnu/libdbus-1.so.3(+0x29024) [0x7f57da4f6024] #12 dbus_connection_dispatch in /lib/x86_64-linux-gnu/libdbus-1.so.3 #13 /lib/x86_64-linux-gnu/libatspi.so.0(+0x1bb79) [0x7f57c62adb79] #14 /lib/x86_64-linux-gnu/libglib-2.0.so.0(+0x5ad5f) [0x7f57ccf03d5f] #15 /lib/x86_64-linux-gnu/libglib-2.0.so.0(+0x5cfd7) [0x7f57ccf05fd7] #16 g_main_context_iteration in /lib/x86_64-linux-gnu/libglib-2.0.so.0 #17 GtkSalData::Yield(bool, bool) at /home/michi/development/git/libreoffice/vcl/unx/gtk3/gtkdata.cxx:405 #18 GtkInstance::DoYield(bool, bool) at /home/michi/development/git/libreoffice/vcl/unx/gtk3/gtkinst.cxx:439 #19 ImplYield(bool, bool) at /home/michi/development/git/libreoffice/vcl/source/app/svapp.cxx:385 #20 Application::Yield() at /home/michi/development/git/libreoffice/vcl/source/app/svapp.cxx:489 #21 Application::Execute() at /home/michi/development/git/libreoffice/vcl/source/app/svapp.cxx:360 #22 desktop::Desktop::Main() at /home/michi/development/git/libreoffice/desktop/source/app/app.cxx:1679 #23 ImplSVMain() at /home/michi/development/git/libreoffice/vcl/source/app/svmain.cxx:230 #24 SVMain() at /home/michi/development/git/libreoffice/vcl/source/app/svmain.cxx:248 #25 soffice_main at /home/michi/development/git/libreoffice/desktop/source/app/sofficemain.cxx:122 #26 sal_main at /home/michi/development/git/libreoffice/desktop/source/app/main.c:51 #27 main at /home/michi/development/git/libreoffice/desktop/source/app/main.c:49 #28 __libc_start_call_main at ./csu/../sysdeps/nptl/libc_start_call_main.h:74 #29 call_init at ./csu/../csu/libc-start.c:128 #30 _start in ./instdir/program/soffice.bin Change-Id: I07b3f8a8a1b817fcc666c8477f90b54b5f97fe5f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181622 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/vcl/unx/gtk3/a11y/atkcomponent.cxx b/vcl/unx/gtk3/a11y/atkcomponent.cxx index 9b5bb2f6edfb..1211cecdf5e3 100644 --- a/vcl/unx/gtk3/a11y/atkcomponent.cxx +++ b/vcl/unx/gtk3/a11y/atkcomponent.cxx @@ -171,7 +171,8 @@ component_wrapper_ref_accessible_at_point (AtkComponent *component, { uno::Reference< accessibility::XAccessible > xAccessible = pComponent->getAccessibleAtPoint( translatePoint(component, pComponent, x, y, coord_type)); - return atk_object_wrapper_ref( xAccessible ); + if (xAccessible.is()) + return atk_object_wrapper_ref(xAccessible); } } catch( const uno::Exception & ) commit 73941c857946b4831968886a3e1b048968d78832 Author: Michael Weghorn <[email protected]> AuthorDate: Thu Feb 13 13:48:35 2025 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Thu Feb 13 19:44:28 2025 +0100 svx a11y: Set accessible name for Fontwork Gallery items Use weld API newly introduced in Change-Id: I8fcbdddd74d75283469f046ff5b60f111051b021 Author: Michael Weghorn <[email protected]> Date: Thu Feb 13 13:42:05 2025 +0100 a11y: Introduce weld::IconView::set_item_accessible_name to set the accessible name for items in the "Fontwork Gallery" dialog ("Insert" -> "Fontwork" in Writer). With this in place, Accerciser now shows accessible names for them for all 3 weld::IconView variants: * GtkInstanceIconView (SAL_USE_VCLPLUGIN=gtk3) * SalInstanceIconView (SAL_USE_VCLPLUGIN=qt6, SAL_VCL_QT_USE_WELDED_WIDGETS *not* set) * QtInstanceIconView (SAL_USE_VCLPLUGIN=qt6 and SAL_VCL_QT_USE_WELDED_WIDGETS=1 set) Change-Id: I59275d8020d0ebd46256bdc1531849cf5be5a353 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181621 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/svx/source/tbxctrls/fontworkgallery.cxx b/svx/source/tbxctrls/fontworkgallery.cxx index 41190e689abe..7c8f2b789525 100644 --- a/svx/source/tbxctrls/fontworkgallery.cxx +++ b/svx/source/tbxctrls/fontworkgallery.cxx @@ -143,6 +143,7 @@ void FontWorkGalleryDialog::fillFavorites(sal_uInt16 nThemeId) OUString sId = OUString::number(static_cast<sal_uInt16>(nFavorite)); maIdToTitleMap.emplace(sId, aTitles.at(nFavorite - 1)); maCtlFavorites->insert(-1, nullptr, &sId, maFavoritesHorizontal[nFavorite - 1], nullptr); + maCtlFavorites->set_item_accessible_name(maCtlFavorites->n_children() - 1, aTitles.at(nFavorite -1)); } if (maCtlFavorites->n_children()) commit 01241a6b3a5b9fed3d9b28d0b8fb8a9a5c0b5f1e Author: Michael Weghorn <[email protected]> AuthorDate: Thu Feb 13 13:42:05 2025 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Thu Feb 13 19:44:21 2025 +0100 a11y: Introduce weld::IconView::set_item_accessible_name Introduce a new weld::IconView::set_item_accessible_name method that allows to set the accessible name for an item in the IconView. So far, IconView icons don't have any accessible name if no text is set in addition to the icon. There is some logic to use (or fall back to) the tooltip text for the accessible *description* in both, SalInstanceIconView (introduced in commit 2a28ebeef5ea3e2b01d836a7233d2316b765bf38 Author: Mike Kaganski <[email protected]> Date: Wed Jun 1 11:18:26 2022 +0300 Accessibility for IconView ) and GtkInstanceIconView (introduced in commit ba0e36e607d1c380fd09b6725a4ebcb69ff399de Author: Michael Weghorn <[email protected]> Date: Thu Mar 9 11:38:36 2023 +0100 tdf#153657 tdf#140659 gtk3 a11y: Use IconView item tooltip as a11y desc ), but having a way to directly set the a11y name has the following advantages: * Focusable objects should have an accessible name, not just an accessible description (that is meant to provide additional information only, and whether or not accessible descriptions are announced is usually configurable in screen readers). * The tooltip text may or may not be appropriate as the accessible name. * a11y name/description and tooltip are generally conceptually different things in UI toolkits, so reflect that in the weld API as well and set them explicitly rather than making assumptions in the implementations that need to implement the weld API using specific toolkits (VCL or third-party). Therefore, introduce this method to allow explicitly setting the accessible name and implement it for all 3 implementations (SalInstanceIconView, GtkInstanceIconView, QtInstanceIconView). It will be used to set a11y names in upcoming commits. (The fallback to use the tooltip for the a11y description can be dropped once an accessible name is set everywhere.) For the VCL implementation (SalInstanceIconView), introduce a new SvTreeListEntry::m_sAccesibleName member and prefer that in AccessibleListBoxEntry::getAccessibleName if set. For GtkInstanceIconView, the logic is similar to the one in the existing GtkInstanceIconView::set_item_accessible_description_from_tooltip (which is gtk3-only, i.e. doesn't work for gtk4). For QtInstanceIconView, set the Qt::AccessibleTextRole [1] for the item. [1] https://doc.qt.io/qt-6/qt.html#ItemDataRole-enum Change-Id: I8fcbdddd74d75283469f046ff5b60f111051b021 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181616 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/include/vcl/toolkit/treelistentry.hxx b/include/vcl/toolkit/treelistentry.hxx index 58228711c377..d9fa804e3713 100644 --- a/include/vcl/toolkit/treelistentry.hxx +++ b/include/vcl/toolkit/treelistentry.hxx @@ -70,6 +70,7 @@ class UNLESS_MERGELIBS_MORE(VCL_DLLPUBLIC) SvTreeListEntry void* pUserData; SvTLEntryFlags nEntryFlags; std::optional<Color> mxTextColor; + OUString m_sAccessibleName; private: void ClearChildren(); @@ -115,6 +116,8 @@ public: void SetFlags( SvTLEntryFlags nFlags ); void SetTextColor( std::optional<Color> xColor ) { mxTextColor = xColor; } + OUString GetAccessibleName() { return m_sAccessibleName; } + void SetAccessibleName(const OUString& rName) { m_sAccessibleName = rName; }; std::optional<Color> const & GetTextColor() const { return mxTextColor; } void SetExtraIndent(sal_uInt32 nExtraIndent) { mnExtraIndent = nExtraIndent; } diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index a65a911d385e..b1310db5b33d 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -1518,6 +1518,7 @@ public: virtual void set_image(int pos, VirtualDevice& rDevice) = 0; virtual void set_text(int pos, const OUString& rText) = 0; virtual void set_id(int pos, const OUString& rId) = 0; + virtual void set_item_accessible_name(int pos, const OUString& rName) = 0; virtual void remove(int pos) = 0; virtual tools::Rectangle get_rect(int pos) const = 0; diff --git a/vcl/inc/qt5/QtInstanceIconView.hxx b/vcl/inc/qt5/QtInstanceIconView.hxx index e2cd83355115..72338d09ecf8 100644 --- a/vcl/inc/qt5/QtInstanceIconView.hxx +++ b/vcl/inc/qt5/QtInstanceIconView.hxx @@ -50,6 +50,7 @@ public: virtual void set_image(int nPos, VirtualDevice& rDevice) override; virtual void set_text(int nPos, const OUString& rText) override; virtual void set_id(int nPos, const OUString& rId) override; + virtual void set_item_accessible_name(int nPos, const OUString& rName) override; virtual void remove(int pos) override; virtual tools::Rectangle get_rect(int pos) const override; diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx index 82f3b0b334f5..63a2748fcd79 100644 --- a/vcl/inc/salvtables.hxx +++ b/vcl/inc/salvtables.hxx @@ -1995,6 +1995,8 @@ public: virtual void set_id(int pos, const OUString& rId) override; + virtual void set_item_accessible_name(int pos, const OUString& rName) override; + virtual OUString get_text(const weld::TreeIter& rIter) const override; virtual tools::Rectangle get_rect(int pos) const override; diff --git a/vcl/qt5/QtInstanceIconView.cxx b/vcl/qt5/QtInstanceIconView.cxx index 9a5f970b5e45..59fa0cd076e6 100644 --- a/vcl/qt5/QtInstanceIconView.cxx +++ b/vcl/qt5/QtInstanceIconView.cxx @@ -174,6 +174,16 @@ void QtInstanceIconView::set_id(int nPos, const OUString& rId) }); } +void QtInstanceIconView::set_item_accessible_name(int nPos, const OUString& rName) +{ + SolarMutexGuard g; + + GetQtInstance().RunInMainThread([&] { + QModelIndex aIndex = modelIndex(nPos); + m_pModel->setData(aIndex, toQString(rName), Qt::AccessibleTextRole); + }); +} + void QtInstanceIconView::remove(int) { assert(false && "Not implemented yet"); } tools::Rectangle QtInstanceIconView::get_rect(int) const diff --git a/vcl/source/accessibility/accessiblelistboxentry.cxx b/vcl/source/accessibility/accessiblelistboxentry.cxx index 16db22110cbb..072bfc547463 100644 --- a/vcl/source/accessibility/accessiblelistboxentry.cxx +++ b/vcl/source/accessibility/accessiblelistboxentry.cxx @@ -388,6 +388,13 @@ OUString SAL_CALL AccessibleListBoxEntry::getAccessibleName( ) EnsureIsAlive(); + if (SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath(m_aEntryPath)) + { + OUString sName = pEntry->GetAccessibleName(); + if (!sName.isEmpty()) + return sName; + } + return implGetText(); } diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 4fc566044d86..373b263aea43 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -5796,6 +5796,13 @@ void SalInstanceIconView::set_id(int pos, const OUString& rId) pEntry->SetUserData(m_aUserData.back().get()); } +void SalInstanceIconView::set_item_accessible_name(int pos, const OUString& rName) +{ + SvTreeListEntry* pEntry = m_xIconView->GetEntry(pos); + assert(pEntry); + pEntry->SetAccessibleName(rName); +} + tools::Rectangle SalInstanceIconView::get_rect(int pos) const { SvTreeListEntry* aEntry = m_xIconView->GetEntry(nullptr, pos); diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index 84fed6c5c00e..40c6378deefb 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -17252,6 +17252,35 @@ private: } } + virtual void set_item_accessible_name(int pos, const OUString& rName) override + { +#if GTK_CHECK_VERSION(4, 0, 0) + (void)pos; + (void)rName; +#else + AtkObject* pAtkObject = gtk_widget_get_accessible(GTK_WIDGET(m_pIconView)); + if (!pAtkObject) + return; + + GtkTreeModel* pModel = GTK_TREE_MODEL(m_pTreeStore); + GtkTreeIter iter; + if (gtk_tree_model_iter_nth_child(pModel, &iter, nullptr, pos)) + { + GtkTreePath* pPath = gtk_tree_model_get_path(GTK_TREE_MODEL(m_pTreeStore), &iter); + assert(gtk_tree_path_get_depth(pPath) == 1); + int* indices = gtk_tree_path_get_indices(pPath); + const int nIndex = indices[0]; + assert(nIndex < atk_object_get_n_accessible_children(pAtkObject) + && "item index too high for ItemView's accessible child count"); + + AtkObject* pChild = atk_object_ref_accessible_child(pAtkObject, nIndex); + atk_object_set_name(pChild, rName.toUtf8().getStr()); + g_object_unref(pChild); + gtk_tree_path_free(pPath); + } +#endif + } + virtual void remove(int pos) override { disable_notify_events();
