include/vcl/qt/QtUtils.hxx | 6 ++++ vcl/inc/qt5/QtInstanceDrawingArea.hxx | 6 ++++ vcl/qt5/QtInstanceBuilder.cxx | 1 vcl/qt5/QtInstanceDrawingArea.cxx | 50 ++++++++++++++++++++++++++++++++++ vcl/qt5/QtInstanceLinkButton.cxx | 1 5 files changed, 64 insertions(+)
New commits: commit 226980d063858d3d21096e5ed73b5312ef0728d7 Author: Michael Weghorn <[email protected]> AuthorDate: Wed Nov 6 22:55:40 2024 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Thu Nov 7 09:54:11 2024 +0100 tdf#130857 qt weld: Take SolarMutex in QtInstanceLinkButton::linkActivated Apparently the expectation is that the SolarMutex is held when calling weld::signal_activate_link. At least, not doing so would trigger an assert when clicking a hyperlink in the "Help" -> "Show Tip of the Day" dialog when using the qt6 VCL plugin started with SAL_VCL_QT_USE_WELDED_WIDGETS=1 set: 1 __pthread_kill_implementation pthread_kill.c 44 0x7f083869de5c 2 __pthread_kill_internal pthread_kill.c 78 0x7f083869debf 3 __GI_raise raise.c 26 0x7f0838649c82 4 __GI_abort abort.c 79 0x7f08386324f0 5 __assert_fail_base assert.c 94 0x7f0838632418 6 __assert_fail assert.c 103 0x7f0838642592 7 ImplDbgTestSolarMutex dbggui.cxx 35 0x7f082fa2dd3e 8 DbgTestSolarMutex debug.cxx 54 0x7f0837b2bec0 9 vcl::WindowOutputDevice::AcquireGraphics window.cxx 822 0x7f082f306276 10 OutputDevice::IsNativeControlSupported nativecontrols.cxx 139 0x7f082f584492 11 vcl::Window::IsNativeControlSupported window3.cxx 77 0x7f082f2fd8b9 12 Dialog::ImplInitSettings dialog.cxx 524 0x7f082f167189 13 Dialog::ImplInitDialog dialog.cxx 495 0x7f082f167086 14 Dialog::Dialog dialog.cxx 586 0x7f082f167d92 15 MessageDialog::MessageDialog layout.cxx 2521 0x7f082f1df4a6 16 VclPtr<MessageDialog>::Create<vcl::Window *&, long&> vclptr.hxx 129 0x7f082f0e8fa6 17 VclBuilder::makeObject builder.cxx 1605 0x7f082f0c5326 18 VclBuilder::insertObject builder.cxx 2454 0x7f082f0d09eb 19 WidgetBuilder<vcl::Window, VclPtr<vcl::Window>>::handleObject widgetbuilder.hxx 213 0x7f082f145937 20 WidgetBuilder<vcl::Window, VclPtr<vcl::Window>>::handleChild widgetbuilder.hxx 107 0x7f082f0f13ce 21 WidgetBuilder<vcl::Window, VclPtr<vcl::Window>>::processUIFile widgetbuilder.hxx 49 0x7f082f0e1b78 22 VclBuilder::VclBuilder builder.cxx 520 0x7f082f0ba596 23 SalInstanceBuilder::SalInstanceBuilder salvtables.cxx 7088 0x7f082fa7b318 24 std::make_unique<SalInstanceBuilder, vcl::Window *&, rtl::OUString const&, rtl::OUString const&> unique_ptr.h 1077 0x7f082fa99ef9 25 SalInstance::CreateBuilder salvtables.cxx 7470 0x7f082fa7f468 26 QtInstance::CreateBuilder QtInstance.cxx 843 0x7f08254e89e5 27 non-virtual thunk to QtInstance::CreateBuilder(weld::Widget *, rtl::OUString const&, rtl::OUString const&) 0x7f08254e8a4c 28 Application::CreateBuilder builder.cxx 198 0x7f082f0b7f02 29 weld::MessageDialogController::MessageDialogController weldutils.cxx 65 0x7f082fb52635 30 (anonymous namespace)::HelpManualMessage::HelpManualMessage sfxhelp.cxx 958 0x7f0834939fb0 31 SfxHelp::Start_Impl sfxhelp.cxx 1283 0x7f08349369ec 32 SfxHelp::Start sfxhelp.cxx 642 0x7f08349389fe 33 TipOfTheDayDialog::OnLinkClick tipofthedaydlg.cxx 261 0x7f07b37ebb64 34 TipOfTheDayDialog::LinkStubOnLinkClick tipofthedaydlg.cxx 251 0x7f07b37eb99d 35 Link<weld::LinkButton&, bool>::Call link.hxx 111 0x7f082552dc26 36 weld::LinkButton::signal_activate_link weld.hxx 1688 0x7f082552d95c 37 QtInstanceLinkButton::linkActivated QtInstanceLinkButton.cxx 58 0x7f082552ba6d 38 QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul>, QtPrivate::List<QString const&>, void, void (QtInstanceLinkButton:: *)(QString const&)>::call(void (QtInstanceLinkButton:: *)(QString const&), QtInstanceLinkButton *, void * *)::{lambda()#1}::operator()() const qobjectdefs_impl.h 127 0x7f082552e074 39 QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul>, QtPrivate::List<QString const&>, void, void (QtInstanceLinkButton:: *)(QString const&)>::call(void (QtInstanceLinkButton:: *)(QString const&), QtInstanceLinkButton *, void * *)::{lambda()#1}>(void * *, QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul>, QtPrivate::List<QString const&>, void, void (QtInstanceLinkButton:: *)(QString const&)>::call(void (QtInstanceLinkButton:: *)(QString const&), QtInstanceLinkButton *, void * *)::{lambda()#1}&&) qobjectdefs_impl.h 65 0x7f082552df99 40 QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul>, QtPrivate::List<QString const&>, void, void (QtInstanceLinkButton:: *)(QString const&)>::call qobjectdefs_impl.h 126 0x7f082552ded3 41 QtPrivate::FunctionPointer<void (QtInstanceLinkButton:: *)(QString const&)>::call<QtPrivate::List<QString const&>, void> qobjectdefs_impl.h 174 0x7f082552de4d 42 QtPrivate::QCallableObject<void (QtInstanceLinkButton:: *)(QString const&), QtPrivate::List<QString const&>, void>::impl qobjectdefs_impl.h 545 0x7f082552dd76 43 QtPrivate::QSlotObjectBase::call qobjectdefs_impl.h 461 0x7f082465ab72 44 doActivate<false> qobject.cpp 4127 0x7f0824718ee4 45 QMetaObject::activate qobject.cpp 4187 0x7f082470eb83 46 QLabel::linkActivated moc_qlabel.cpp 386 0x7f08228ddb72 47 QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul>, QtPrivate::List<QString const&>, void, void (QLabel:: *)(QString const&)>::call(void (QLabel:: *)(QString const&), QLabel *, void * *)::{lambda()#1}::operator()() const qobjectdefs_impl.h 127 0x7f08228e29a8 48 QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul>, QtPrivate::List<QString const&>, void, void (QLabel:: *)(QString const&)>::call(void (QLabel:: *)(QString const&), QLabel *, void * *)::{lambda()#1}>(void * *, QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul>, QtPrivate::List<QString const&>, void, void (QLabel:: *)(QString const&)>::call(void (QLabel:: *)(QString const&), QLabel *, void * *)::{lambda()#1}&&) qobjectdefs_impl.h 65 0x7f08228e291d 49 QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul>, QtPrivate::List<QString const&>, void, void (QLabel:: *)(QString const&)>::call qobjectdefs_impl.h 126 0x7f08228e28d7 50 QtPrivate::FunctionPointer<void (QLabel:: *)(QString const&)>::call<QtPrivate::List<QString const&>, void> qobjectdefs_impl.h 174 0x7f08228e2841 51 QtPrivate::QCallableObject<void (QLabel:: *)(QString const&), QtPrivate::List<QString const&>, void>::impl qobjectdefs_impl.h 545 0x7f08228e276b 52 QtPrivate::QSlotObjectBase::call qobjectdefs_impl.h 461 0x7f082465ab72 53 doActivate<false> qobject.cpp 4127 0x7f0824718ee4 54 QMetaObject::activate qobject.cpp 4187 0x7f082470eb83 55 QWidgetTextControl::linkActivated moc_qwidgettextcontrol_p.cpp 806 0x7f0822a5a415 56 QWidgetTextControlPrivate::activateLinkUnderCursor qwidgettextcontrol.cpp 2962 0x7f0822a544c1 57 QWidgetTextControlPrivate::keyPressEvent qwidgettextcontrol.cpp 1242 0x7f0822a50454 58 QWidgetTextControl::processEvent qwidgettextcontrol.cpp 1024 0x7f0822a4f23b 59 QWidgetTextControl::processEvent qwidgettextcontrol.cpp 984 0x7f0822a4f0c1 60 QLabelPrivate::sendControlEvent qlabel.cpp 1557 0x7f08228db3c4 61 QLabel::keyPressEvent qlabel.cpp 912 0x7f08228db7fe [...] Change-Id: I20f11ff2e7c00e65098bd7fb39afefdc4a622138 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176175 Reviewed-by: Michael Weghorn <[email protected]> Tested-by: Jenkins diff --git a/vcl/qt5/QtInstanceLinkButton.cxx b/vcl/qt5/QtInstanceLinkButton.cxx index c54b6d1801e5..5d2671249979 100644 --- a/vcl/qt5/QtInstanceLinkButton.cxx +++ b/vcl/qt5/QtInstanceLinkButton.cxx @@ -55,6 +55,7 @@ OUString QtInstanceLinkButton::get_uri() const void QtInstanceLinkButton::linkActivated(const QString& rUrl) { + SolarMutexGuard g; if (signal_activate_link()) return; commit 473dccf597c551a03ae02a94a1a2f846ac0e6868 Author: Michael Weghorn <[email protected]> AuthorDate: Wed Nov 6 22:49:34 2024 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Thu Nov 7 09:54:04 2024 +0100 tdf#130857 qt weld: Declare support for "Tip of the Day" dialog Add .ui file for the dialog that can be triggered via "Help" -> "Show Tip of the Day" to the list of supported .ui files. This means that native Qt widgets are used for that dialog now when LO gets started with environment variable SAL_VCL_QT_USE_WELDED_WIDGETS=1 set. This dialog makes use of the QtInstanceDrawingArea logic implemented in previous commits. Change-Id: Id252e38e2eb9265276457ab64d582f71d628e369 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176174 Reviewed-by: Michael Weghorn <[email protected]> Tested-by: Jenkins diff --git a/vcl/qt5/QtInstanceBuilder.cxx b/vcl/qt5/QtInstanceBuilder.cxx index 82036d43e1c0..53144d4adc18 100644 --- a/vcl/qt5/QtInstanceBuilder.cxx +++ b/vcl/qt5/QtInstanceBuilder.cxx @@ -48,6 +48,7 @@ bool QtInstanceBuilder::IsUIFileSupported(const OUString& rUIFile) u"cui/ui/optnewdictionarydialog.ui"_ustr, u"cui/ui/querysetinsmodedialog.ui"_ustr, u"cui/ui/securityoptionsdialog.ui"_ustr, + u"cui/ui/tipofthedaydialog.ui"_ustr, u"modules/scalc/ui/inputstringdialog.ui"_ustr, u"modules/scalc/ui/selectsource.ui"_ustr, u"modules/schart/ui/insertaxisdlg.ui"_ustr, commit a3400e0471e99a3f3cfa750d0a5cf61a9c3ee0cc Author: Michael Weghorn <[email protected]> AuthorDate: Wed Nov 6 22:42:40 2024 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Thu Nov 7 09:53:56 2024 +0100 tdf#130857 qt weld: Implement simple drawing in QtInstanceDrawingArea Implement simple drawing in QtInstanceDrawingArea by handling the QEvent::Resize and QEvent::Paint events for the QLabel widget. While the QLabel does not emit any signals when these events occur, it's possible to handle them by setting an event filter using QObject::installEventFilter [1]. Install QtInstanceDrawingArea as an event filter for its label, and implement handling of the Resize and Paint event in QtInstanceDrawingArea::eventFilter: On the QEvent::Resize event, adjust the output size of the output device and call the `weld::Widget::m_aSizeAllocateHdl` handler. (See also GtkInstanceDrawingArea::signal_size_allocate and SalInstanceDrawingArea::ResizeHdl to see what the gtk3 and VCL implementations do.) On the QEvent::Paint event, trigger drawing on the output device via the weld::DrawingArea::m_aDrawHdl handler, and get a QPixmap for what's painted on the output device and set that QPixmap for the label if it has changed. With this in place, the GtkDrawingArea in the "Help" -> "Show Tip of the Day" dialog displays the image as expected, and gets updated when moving to the next tip, once support for that dialog has been declared, which will be done in an upcoming commit. For more complex cases, a more performant solution might become necessary and can be investigated once support for these is implemented. For the "Tip of the Day" dialog, the `aRect` passed in QtInstanceDrawingArea::handlePaintEvent is irrelevant as CuiGraphicPreviewWindow::Paint doesn't make use of the passed rectangle. (This might also have to be reconsidered/adjusted in case a dialog actually making use of the rectangle doesn't work as expected.) [1] https://doc.qt.io/qt-6/qobject.html#installEventFilter Change-Id: I651e00043fac04a4c77aae921e6397e8d97cc69c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176173 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/include/vcl/qt/QtUtils.hxx b/include/vcl/qt/QtUtils.hxx index 368424a8cbe7..87f21d96315c 100644 --- a/include/vcl/qt/QtUtils.hxx +++ b/include/vcl/qt/QtUtils.hxx @@ -21,6 +21,7 @@ #include <rtl/ustring.hxx> #include <vcl/filter/PngImageWriter.hxx> #include <vcl/image.hxx> +#include <vcl/outdev.hxx> #include <QtCore/QString> #include <QtGui/QPixmap> @@ -53,6 +54,11 @@ inline QPixmap toQPixmap(const css::uno::Reference<css::graphic::XGraphic>& rIma return toQPixmap(aImage); } +inline QPixmap toQPixmap(const OutputDevice& rDevice) +{ + return toQPixmap(Image(rDevice.GetBitmapEx(Point(), rDevice.GetOutputSizePixel()))); +} + inline QPixmap loadQPixmapIcon(const OUString& rIconName) { BitmapEx aIcon(rIconName); diff --git a/vcl/inc/qt5/QtInstanceDrawingArea.hxx b/vcl/inc/qt5/QtInstanceDrawingArea.hxx index 757174330c13..e730464ee83e 100644 --- a/vcl/inc/qt5/QtInstanceDrawingArea.hxx +++ b/vcl/inc/qt5/QtInstanceDrawingArea.hxx @@ -45,6 +45,12 @@ public: virtual a11yrelationset get_accessible_relation_set() override; virtual AbsoluteScreenPixelPoint get_accessible_location_on_screen() override; + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + +private: + void handlePaintEvent(); + void handleResizeEvent(); + private: virtual void click(const Point&) override; }; diff --git a/vcl/qt5/QtInstanceDrawingArea.cxx b/vcl/qt5/QtInstanceDrawingArea.cxx index 0ae6baa2b087..3046c890022d 100644 --- a/vcl/qt5/QtInstanceDrawingArea.cxx +++ b/vcl/qt5/QtInstanceDrawingArea.cxx @@ -10,12 +10,17 @@ #include <QtInstanceDrawingArea.hxx> #include <QtInstanceDrawingArea.moc> +#include <vcl/qt/QtUtils.hxx> + QtInstanceDrawingArea::QtInstanceDrawingArea(QLabel* pLabel) : QtInstanceWidget(pLabel) , m_pLabel(pLabel) , m_xDevice(DeviceFormat::WITHOUT_ALPHA) { assert(m_pLabel); + + // install event filter, so eventFilter() can handle widget events + m_pLabel->installEventFilter(this); } void QtInstanceDrawingArea::queue_draw() @@ -74,4 +79,49 @@ AbsoluteScreenPixelPoint QtInstanceDrawingArea::get_accessible_location_on_scree void QtInstanceDrawingArea::click(const Point&) { assert(false && "Not implemented yet"); } +bool QtInstanceDrawingArea::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pObject != m_pLabel) + return false; + + SolarMutexGuard g; + assert(GetQtInstance().IsMainThread()); + + switch (pEvent->type()) + { + case QEvent::Paint: + handlePaintEvent(); + return false; + case QEvent::Resize: + handleResizeEvent(); + return false; + default: + return false; + } +} + +void QtInstanceDrawingArea::handlePaintEvent() +{ + tools::Rectangle aRect(0, 0, m_pLabel->width(), m_pLabel->height()); + aRect = m_xDevice->PixelToLogic(aRect); + m_xDevice->Erase(aRect); + m_aDrawHdl.Call(std::pair<vcl::RenderContext&, const tools::Rectangle&>(*m_xDevice, aRect)); + QPixmap aPixmap = toQPixmap(*m_xDevice); + + // set new pixmap if it changed +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (aPixmap.toImage() != m_pLabel->pixmap().toImage()) +#else + if (aPixmap.toImage() != m_pLabel->pixmap(Qt::ReturnByValue).toImage()) +#endif + m_pLabel->setPixmap(aPixmap); +} + +void QtInstanceDrawingArea::handleResizeEvent() +{ + const Size aSize = toSize(m_pLabel->size()); + m_xDevice->SetOutputSizePixel(aSize); + m_aSizeAllocateHdl.Call(aSize); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
