vcl/inc/qt5/QtInstanceTreeView.hxx | 4 ++++ vcl/qt5/QtInstanceTreeView.cxx | 29 +++++++++++++++++++++++++++++ vcl/unx/gtk3/gtkinst.cxx | 2 ++ 3 files changed, 35 insertions(+)
New commits: commit b6cded6e887aa8e15496afb68bd3a4add4af7c12 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Aug 28 10:53:58 2025 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Thu Aug 28 12:18:09 2025 +0200 tdf#168041 gtk: Hold SolarMutex when querying tree view tooltip This fixes the below assert seen with gtk4 when hovering over paragraph styles in the "Styles" sidebar deck in Writer with. soffice.bin: /home/michi/development/git/libreoffice/vcl/source/app/dbggui.cxx:36: void ImplDbgTestSolarMutex(bool): Assertion `ImplGetSVData()->mpDefInst->GetYieldMutex()->IsCurrentThread() && "SolarMutex not owned!"' failed. Thread 1 received signal SIGABRT, Aborted. __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44 warning: 44 ./nptl/pthread_kill.c: No such file or directory (rr) bt #0 __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44 #1 0x00007fe0abe9e9ff in __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:89 #2 0x00007fe0abe49cc2 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26 #3 0x00007fe0abe324ac in __GI_abort () at ./stdlib/abort.c:73 #4 0x00007fe0abe32420 in __assert_fail_base (fmt=<optimized out>, assertion=<optimized out>, file=<optimized out>, line=36, function=<optimized out>) at ./assert/assert.c:118 #5 0x00007fe0a31b5ccc in ImplDbgTestSolarMutex (owned=true) at /home/michi/development/git/libreoffice/vcl/source/app/dbggui.cxx:36 #6 0x00007fe0aa32b044 in DbgTestSolarMutex (owned=true) at /home/michi/development/git/libreoffice/tools/source/debug/debug.cxx:54 #7 0x00007fe0549fc572 in SwModify::CallSwClientNotify (this=0x559770009880, rHint=...) at /home/michi/development/git/libreoffice/sw/source/core/attr/calbck.cxx:273 #8 0x00007fe0549fc9b1 in sw::BroadcastingModify::CallSwClientNotify (this=0x559770009880, rHint=...) at /home/michi/development/git/libreoffice/sw/source/core/attr/calbck.cxx:297 #9 0x00007fe054f0cd67 in SwDoc::IsUsed (this=0x55976fdd1cf0, rModify=...) at /home/michi/development/git/libreoffice/sw/source/core/doc/poolfmt.cxx:109 #10 0x00007fe055e8fe47 in SwDocStyleSheet::IsUsed (this=0x55976fe02e80) at /home/michi/development/git/libreoffice/sw/source/uibase/app/docstyle.cxx:2481 #11 0x00007fe0a83f603d in StyleList::QueryTooltipHdl (this=0x559771b48dd0, rEntry=...) at /home/michi/development/git/libreoffice/sfx2/source/dialog/StyleList.cxx:1753 #12 0x00007fe0a83edd68 in StyleList::LinkStubQueryTooltipHdl (instance=0x559771b48dd0, data=...) at /home/michi/development/git/libreoffice/sfx2/source/dialog/StyleList.cxx:1743 #13 0x00007fe09a7907bd in Link<weld::TreeIter const&, rtl::OUString>::Call (this=0x559771b27bb8, data=...) at include/tools/link.hxx:105 #14 0x00007fe09a79075f in weld::TreeView::signal_query_tooltip (this=0x559771b27a08, rIter=...) at include/vcl/weld.hxx:1025 #15 0x00007fe09a6e8d09 in (anonymous namespace)::GtkInstanceTreeView::signalQueryTooltip (x=382, y=153, keyboard_tip=0, tooltip=0x559769fbaa90, widget=0x559771b27400) at vcl/unx/gtk4/../gtk3/gtkinst.cxx:14531 #16 0x00007fe0994dedfc in _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECT (closure=0x559771b24580, return_value=0x7ffef76e15b0, n_param_values=5, param_values=0x7ffef76e1640, invocation_hint=0x7ffef76e1590, marshal_data=0x0) at gtk/gtkmarshalers.c:1109 #17 0x00007fe0a967d950 in g_closure_invoke () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #18 0x00007fe0a9691d43 in ??? () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #19 0x00007fe0a9693032 in ??? () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #20 0x00007fe0a96995a6 in g_signal_emit_valist () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #21 0x00007fe0a9699663 in g_signal_emit () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #22 0x00007fe0997c6ada in gtk_widget_query_tooltip (widget=0x55976892b2b0, x=382, y=153, keyboard_mode=0, tooltip=0x559769fbaa90) at ../gtk/gtkwidget.c:5114 #23 0x00007fe0997af430 in gtk_tooltip_run_requery (widget=0x7ffef76e1a58, tooltip=0x559769fbaa90, x=0x7ffef76e1a90, y=0x7ffef76e1a8c) at ../gtk/gtktooltip.c:559 #24 0x00007fe0997b01bb in gtk_tooltip_handle_event_internal (event_type=GDK_MOTION_NOTIFY, surface=0x559764aa88a0, target_widget=0x55976892b2b0, dx=382.953125, dy=153.796875) at ../gtk/gtktooltip.c:1009 #25 0x00007fe0997b0065 in _gtk_tooltip_handle_event (target=0x55976892b2b0, event=0x559772515280) at ../gtk/gtktooltip.c:957 #26 0x00007fe099686120 in gtk_main_do_event (event=0x559772515280) at ../gtk/gtkmain.c:1751 #27 0x00007fe0997e6720 in surface_event (surface=0x559764aa88a0, event=0x559772515280, widget=0x55976a125f10) at ../gtk/gtkwindow.c:4951 #28 0x00007fe099a684cb in _gdk_marshal_BOOLEAN__POINTERv (closure=0x55976bc7ddf0, return_value=0x7ffef76e1eb0, instance=0x559764aa88a0, args=0x7ffef76e1fb0, marshal_data=0x0, n_params=1, param_types=0x559764ac5730) at gdk/gdkmarshalers.c:302 #29 0x00007fe099b50e3c in gdk_surface_event_marshallerv (closure=0x55976bc7ddf0, return_value=0x7ffef76e1eb0, instance=0x559764aa88a0, args=0x7ffef76e1fb0, marshal_data=0x0, n_params=1, param_types=0x559764ac5730) at ../gdk/gdksurface.c:465 #30 0x00007fe0a967db81 in ??? () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #31 0x00007fe0a9692b33 in ??? () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #32 0x00007fe0a96995a6 in g_signal_emit_valist () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #33 0x00007fe0a9699663 in g_signal_emit () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #34 0x00007fe099b55ee7 in gdk_surface_handle_event (event=0x559772515280) at ../gdk/gdksurface.c:3001 #35 0x00007fe099b0ae91 in _gdk_event_emit (event=0x559772515280) at ../gdk/gdkevents.c:491 #36 0x00007fe099b0b946 in _gdk_event_queue_flush (display=0x5597649c1140) at ../gdk/gdkevents.c:856 #37 0x00007fe099b54d84 in gdk_surface_flush_events (clock=0x559764a437b0, data=0x559764aa88a0) at ../gdk/gdksurface.c:2419 #38 0x00007fe0a967db81 in ??? () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #39 0x00007fe0a96938b8 in ??? () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #40 0x00007fe0a96995a6 in g_signal_emit_valist () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #41 0x00007fe0a9699663 in g_signal_emit () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 #42 0x00007fe099b13cae in _gdk_frame_clock_emit_flush_events (frame_clock=0x559764a437b0) at ../gdk/gdkframeclock.c:701 #43 0x00007fe099b1492d in gdk_frame_clock_flush_idle (data=0x559764a437b0) at ../gdk/gdkframeclockidle.c:391 #44 0x00007fe09e50744e in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 #45 0x00007fe09e5043c5 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 #46 0x00007fe09e5065f7 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 #47 0x00007fe09e506d60 in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 #48 0x00007fe09a683dac in GtkSalData::Yield (this=0x5597637370a0, bWait=true, bHandleAllCurrentEvents=false) at vcl/unx/gtk4/../gtk3/gtkdata.cxx:403 #49 0x00007fe09a689403 in GtkInstance::DoYield (this=0x559763736f50, bWait=true, bHandleAllCurrentEvents=false) at vcl/unx/gtk4/../gtk3/gtkinst.cxx:440 #50 0x00007fe0a328c606 in ImplYield (i_bWait=true, i_bAllEvents=false) at /home/michi/development/git/libreoffice/vcl/source/app/svapp.cxx:385 #51 0x00007fe0a328bf1f in Application::Yield () at /home/michi/development/git/libreoffice/vcl/source/app/svapp.cxx:488 #52 0x00007fe0a328bd00 in Application::Execute () at /home/michi/development/git/libreoffice/vcl/source/app/svapp.cxx:360 #53 0x00007fe0ac129915 in desktop::Desktop::Main (this=0x7ffef76e4160) at /home/michi/development/git/libreoffice/desktop/source/app/app.cxx:1678 #54 0x00007fe0a32b8526 in ImplSVMain () at /home/michi/development/git/libreoffice/vcl/source/app/svmain.cxx:230 #55 0x00007fe0a32ba019 in SVMain () at /home/michi/development/git/libreoffice/vcl/source/app/svmain.cxx:248 #56 0x00007fe0ac1a35ca in soffice_main () at /home/michi/development/git/libreoffice/desktop/source/app/sofficemain.cxx:122 #57 0x0000559759c3b9fd in sal_main () at /home/michi/development/git/libreoffice/desktop/source/app/main.c:51 #58 0x0000559759c3b9d7 in main (argc=2, argv=0x7ffef76e4368) at /home/michi/development/git/libreoffice/desktop/source/app/main.c:49 Change-Id: If520816e8f748a7f082226d216b10aa5a2c27717 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190318 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index b51c24893707..81fac405b837 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -14528,6 +14528,8 @@ private: if (!gtk_tree_view_get_tooltip_context(pTreeView, &x, &y, keyboard_tip, &pModel, &pPath, &iter)) return false; #endif + + SolarMutexGuard g; OUString aTooltip = pThis->signal_query_tooltip(GtkInstanceTreeIter(iter)); if (!aTooltip.isEmpty()) { commit 39075c7db1d10542dec318f410ae9b03ac615355 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Aug 28 10:41:11 2025 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Thu Aug 28 12:18:02 2025 +0200 tdf#130857 qt weld: Implement TreeView tooltip handling Handle the QEvent::ToolTip event for the QTreeView's viewport. Retrieve the tooltip for the item using weld::TreeView::signal_query_tooltip and display it if it's non-empty. This makes the file path of the corresponding template show up when hovering over an item in the "File" -> "Templates" -> "Manage Templates" dialog with the list view mode enabled with SAL_VCL_QT_USE_WELDED_WIDGETS=1, in a WIP branch where support for that dialog using native Qt widgets is declared. Change-Id: Ia849a9fa6506ffbd2d74be00600e0a694f1b9efd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190317 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/inc/qt5/QtInstanceTreeView.hxx b/vcl/inc/qt5/QtInstanceTreeView.hxx index aa78075d38aa..cc36e5bbbea6 100644 --- a/vcl/inc/qt5/QtInstanceTreeView.hxx +++ b/vcl/inc/qt5/QtInstanceTreeView.hxx @@ -209,6 +209,8 @@ public: static void setColumnRoles(QTreeView& rTreeView, const QList<QList<Qt::ItemDataRole>>& rDataRoles); + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + private: QModelIndex modelIndex(int nRow, int nCol = 0, const QModelIndex& rParentIndex = QModelIndex()) const; @@ -221,6 +223,8 @@ private: void setImage(const weld::TreeIter& rIter, const QPixmap& rPixmap, int nCol); + bool handleToolTipEvent(const QHelpEvent* pEvent); + private Q_SLOTS: void handleActivated(); void handleDataChanged(const QModelIndex& rTopLeft, const QModelIndex& rBottomRight, diff --git a/vcl/qt5/QtInstanceTreeView.cxx b/vcl/qt5/QtInstanceTreeView.cxx index 3a767595546e..fa5126f42f78 100644 --- a/vcl/qt5/QtInstanceTreeView.cxx +++ b/vcl/qt5/QtInstanceTreeView.cxx @@ -13,6 +13,7 @@ #include <vcl/qt/QtUtils.hxx> #include <QtWidgets/QHeaderView> +#include <QtWidgets/QToolTip> // role used for the ID in the QStandardItem constexpr int ROLE_ID = Qt::UserRole + 1000; @@ -43,6 +44,9 @@ QtInstanceTreeView::QtInstanceTreeView(QTreeView* pTreeView) &QtInstanceTreeView::handleSelectionChanged); connect(m_pModel, &QSortFilterProxyModel::dataChanged, this, &QtInstanceTreeView::handleDataChanged); + + assert(m_pTreeView->viewport()); + m_pTreeView->viewport()->installEventFilter(this); } void QtInstanceTreeView::insert(const weld::TreeIter* pParent, int nPos, const OUString* pStr, @@ -1097,6 +1101,14 @@ void QtInstanceTreeView::setColumnRoles(QTreeView& rTreeView, rTreeView.setProperty(PROPERTY_COLUMN_ROLES, QVariant::fromValue(rDataRoles)); } +bool QtInstanceTreeView::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::ToolTip && pObject == m_pTreeView->viewport()) + return handleToolTipEvent(static_cast<QHelpEvent*>(pEvent)); + + return QtInstanceWidget::eventFilter(pObject, pEvent); +} + QModelIndex QtInstanceTreeView::modelIndex(int nRow, int nCol, const QModelIndex& rParentIndex) const { @@ -1158,6 +1170,23 @@ void QtInstanceTreeView::setImage(const weld::TreeIter& rIter, const QPixmap& rP }); } +bool QtInstanceTreeView::handleToolTipEvent(const QHelpEvent* pHelpEvent) +{ + QModelIndex aIndex = m_pTreeView->indexAt(pHelpEvent->pos()); + if (!aIndex.isValid()) + return false; + + SolarMutexGuard g; + const QtInstanceTreeIter aIter(aIndex); + const QString sToolTip = toQString(signal_query_tooltip(aIter)); + if (sToolTip.isEmpty()) + return false; + + QToolTip::showText(pHelpEvent->globalPos(), sToolTip, m_pTreeView, + m_pTreeView->visualRect(aIndex)); + return true; +} + void QtInstanceTreeView::handleActivated() { SolarMutexGuard g;