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

Reply via email to