vcl/CustomTarget_qt5_moc.mk    |    1 
 vcl/CustomTarget_qt6_moc.mk    |    1 
 vcl/inc/qt5/QtClipboard.hxx    |    2 -
 vcl/inc/qt5/QtTransferable.hxx |    2 +
 vcl/qt5/QtClipboard.cxx        |   52 +++++++++++++++++++++++++++++++++--------
 vcl/qt5/QtFrame.cxx            |    4 +--
 vcl/qt5/QtTransferable.cxx     |    1 
 vcl/qt5/QtWidget.cxx           |    2 -
 8 files changed, 51 insertions(+), 14 deletions(-)

New commits:
commit b152f5c8fb7db2e2c047d56131fe1b57097b6dfc
Author:     Stephan Bergmann <stephan.bergm...@allotropia.de>
AuthorDate: Tue Jan 7 16:21:05 2025 +0100
Commit:     Stephan Bergmann <stephan.bergm...@allotropia.de>
CommitDate: Wed Jan 8 16:04:45 2025 +0100

    Rudimentary Emscripten copy -> paste support
    
    ...with two hacks, so that at least copying text from LO and pasting it back
    into LO works (instead of the copying step either hitting the
    
    >         assert(pTrans);
    
    in QtClipboard::getContents in --enable-assert-always-abort builds or doing
    nothing in --disable-assert-always-abort builds)
    
    Change-Id: I246986fa1beaf17a8390eccb404408605e121630
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179894
    Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de>
    Tested-by: Jenkins
    (cherry picked from commit 5a4ca3ce934ca3f34669bc66b8941544aef1bc89)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179899
    Tested-by: allotropia jenkins <jenk...@allotropia.de>

diff --git a/vcl/inc/qt5/QtClipboard.hxx b/vcl/inc/qt5/QtClipboard.hxx
index f07414bfbc70..81c84ed3996d 100644
--- a/vcl/inc/qt5/QtClipboard.hxx
+++ b/vcl/inc/qt5/QtClipboard.hxx
@@ -50,7 +50,7 @@ class QtClipboard final
     css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> 
m_aOwner;
     
std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>>
 m_aListeners;
 
-    static bool isOwner(const QClipboard::Mode aMode);
+    bool isOwner(const QClipboard::Mode aMode);
     static bool isSupported(const QClipboard::Mode aMode);
 
     explicit QtClipboard(OUString aModeString, const QClipboard::Mode aMode);
diff --git a/vcl/qt5/QtClipboard.cxx b/vcl/qt5/QtClipboard.cxx
index 602c154e34e4..3628d1f6a60e 100644
--- a/vcl/qt5/QtClipboard.cxx
+++ b/vcl/qt5/QtClipboard.cxx
@@ -158,14 +158,31 @@ void QtClipboard::handleChanged(QClipboard::Mode aMode)
 
     osl::ClearableMutexGuard aGuard(m_aMutex);
 
-    // QtWayland will send a second change notification (seemingly without any
-    // trigger). And any C'n'P operation in the Qt file picker emits a signal,
-    // with LO still holding the clipboard ownership, but internally having 
lost
-    // it. So ignore any signal, which still delivers the internal QtMimeData
-    // as the clipboard content and is no "advertised" change.
-    if (!m_bOwnClipboardChange && isOwner(aMode)
-        && qobject_cast<const 
QtMimeData*>(QApplication::clipboard()->mimeData(aMode)))
-        return;
+    if (!m_bOwnClipboardChange && isOwner(aMode))
+    {
+        auto const mimeData = QApplication::clipboard()->mimeData(aMode);
+
+        // QtWayland will send a second change notification (seemingly without 
any
+        // trigger). And any C'n'P operation in the Qt file picker emits a 
signal,
+        // with LO still holding the clipboard ownership, but internally 
having lost
+        // it. So ignore any signal, which still delivers the internal 
QtMimeData
+        // as the clipboard content and is no "advertised" change.
+        if (qobject_cast<const QtMimeData*>(mimeData))
+            return;
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && defined EMSCRIPTEN
+        // At least for the Qt5 Wasm backend, copying text from LO and then 
pasting it back into LO
+        // will, for whatever reason, call here with an empty text/plain 
mimeData; while that
+        // doesn't seem to be an issue at least with the current upstream Qt6 
dev branch (again, for
+        // whatever reason), for at least our Qt 5.15.2+wasm branch the below 
m_aContents.clear()
+        // would make us lose the text just copied from LO into the clipboard 
and thus make us paste
+        // an empty text into LO, so, as a hack, filter out this unhelpful 
event here:
+        if (mimeData != nullptr && mimeData->hasText() && 
mimeData->text().isEmpty())
+        {
+            return;
+        }
+#endif
+    }
 
     css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> 
xOldOwner(m_aOwner);
     css::uno::Reference<css::datatransfer::XTransferable> 
xOldContents(m_aContents);
@@ -251,7 +268,22 @@ bool QtClipboard::isOwner(const QClipboard::Mode aMode)
             return pClipboard->ownsFindBuffer();
 
         case QClipboard::Clipboard:
-            return pClipboard->ownsClipboard();
+            if (pClipboard->ownsClipboard())
+            {
+                return true;
+            }
+#if defined EMSCRIPTEN
+            // QWasmClipboard::ownsMode (in 
qtbase/src/plugins/platforms/wasm/qwasmclipboard.cpp,
+            // which is the actual implementation of the above ownsClipboard 
call) unconditionally
+            // returns false, so as a hack use "m_aContents is a LO-internal 
XTransferable type" as
+            // a poor approximation of "LO owns the clipboard":
+            if (m_aContents.is()
+                && dynamic_cast<QtClipboardTransferable*>(m_aContents.get()) 
== nullptr)
+            {
+                return true;
+            }
+#endif
+            return false;
     }
     return false;
 }
commit 23a339fc0de31927f0b1a0bc76a0e4d3c26738ba
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Thu Sep 19 11:02:48 2024 +0200
Commit:     Stephan Bergmann <stephan.bergm...@allotropia.de>
CommitDate: Wed Jan 8 16:04:37 2025 +0100

    qt: Use qobject_cast to cast to QtMimeData
    
    Use `qobject_cast` instead of `dynamic_cast` to
    cast to QtMimeData.
    
    Add the `Q_OBJECT` macro to the class, as the
    the qobject_cast doc [1] says:
    
    > Warning: If T isn't declared with the Q_OBJECT macro, this function's
    > return value is undefined.
    
    Change-Id: I5de2d8dbf62ed1293f3660acae44e3b13ab5df71
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173660
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    (cherry picked from commit be113bcfef5a411af43bcbcc7e51fc959eb4bcae)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179901
    Tested-by: allotropia jenkins <jenk...@allotropia.de>
    Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de>

diff --git a/vcl/CustomTarget_qt5_moc.mk b/vcl/CustomTarget_qt5_moc.mk
index f8a6de3aa512..b746e0ae4db1 100644
--- a/vcl/CustomTarget_qt5_moc.mk
+++ b/vcl/CustomTarget_qt5_moc.mk
@@ -16,6 +16,7 @@ $(call gb_CustomTarget_get_target,vcl/qt5) : \
        $(gb_CustomTarget_workdir)/vcl/qt5/QtInstance.moc \
        $(gb_CustomTarget_workdir)/vcl/qt5/QtMainWindow.moc \
        $(gb_CustomTarget_workdir)/vcl/qt5/QtMenu.moc \
+       $(gb_CustomTarget_workdir)/vcl/qt5/QtTransferable.moc \
        $(gb_CustomTarget_workdir)/vcl/qt5/QtObject.moc \
        $(gb_CustomTarget_workdir)/vcl/qt5/QtTimer.moc \
        $(gb_CustomTarget_workdir)/vcl/qt5/QtWidget.moc \
diff --git a/vcl/CustomTarget_qt6_moc.mk b/vcl/CustomTarget_qt6_moc.mk
index 1446b626ebd0..c486fb7d0416 100644
--- a/vcl/CustomTarget_qt6_moc.mk
+++ b/vcl/CustomTarget_qt6_moc.mk
@@ -16,6 +16,7 @@ $(call gb_CustomTarget_get_target,vcl/qt6) : \
        $(gb_CustomTarget_workdir)/vcl/qt6/QtInstance.moc \
        $(gb_CustomTarget_workdir)/vcl/qt6/QtMainWindow.moc \
        $(gb_CustomTarget_workdir)/vcl/qt6/QtMenu.moc \
+       $(gb_CustomTarget_workdir)/vcl/qt6/QtTransferable.moc \
        $(gb_CustomTarget_workdir)/vcl/qt6/QtObject.moc \
        $(gb_CustomTarget_workdir)/vcl/qt6/QtTimer.moc \
        $(gb_CustomTarget_workdir)/vcl/qt6/QtWidget.moc \
diff --git a/vcl/inc/qt5/QtTransferable.hxx b/vcl/inc/qt5/QtTransferable.hxx
index 5687fa06df52..6b37d65e7e87 100644
--- a/vcl/inc/qt5/QtTransferable.hxx
+++ b/vcl/inc/qt5/QtTransferable.hxx
@@ -114,6 +114,8 @@ typedef QtTransferable QtDnDTransferable;
  **/
 class QtMimeData final : public QMimeData
 {
+    Q_OBJECT
+
     friend class QtClipboardTransferable;
 
     const css::uno::Reference<css::datatransfer::XTransferable> m_aContents;
diff --git a/vcl/qt5/QtClipboard.cxx b/vcl/qt5/QtClipboard.cxx
index ea05784bbfb2..602c154e34e4 100644
--- a/vcl/qt5/QtClipboard.cxx
+++ b/vcl/qt5/QtClipboard.cxx
@@ -67,7 +67,7 @@ void QtClipboard::flushClipboard()
 
         QClipboard* pClipboard = QApplication::clipboard();
         const QtMimeData* pQtMimeData
-            = dynamic_cast<const 
QtMimeData*>(pClipboard->mimeData(m_aClipboardMode));
+            = qobject_cast<const 
QtMimeData*>(pClipboard->mimeData(m_aClipboardMode));
         assert(pQtMimeData);
 
         QMimeData* pMimeCopy = nullptr;
@@ -164,7 +164,7 @@ void QtClipboard::handleChanged(QClipboard::Mode aMode)
     // it. So ignore any signal, which still delivers the internal QtMimeData
     // as the clipboard content and is no "advertised" change.
     if (!m_bOwnClipboardChange && isOwner(aMode)
-        && dynamic_cast<const 
QtMimeData*>(QApplication::clipboard()->mimeData(aMode)))
+        && qobject_cast<const 
QtMimeData*>(QApplication::clipboard()->mimeData(aMode)))
         return;
 
     css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> 
xOldOwner(m_aOwner);
diff --git a/vcl/qt5/QtFrame.cxx b/vcl/qt5/QtFrame.cxx
index 82a30554ff57..0f0f9599ed35 100644
--- a/vcl/qt5/QtFrame.cxx
+++ b/vcl/qt5/QtFrame.cxx
@@ -1391,7 +1391,7 @@ static 
css::uno::Reference<css::datatransfer::XTransferable>
 lcl_getXTransferable(const QMimeData* pMimeData)
 {
     css::uno::Reference<css::datatransfer::XTransferable> xTransferable;
-    const QtMimeData* pQtMimeData = dynamic_cast<const QtMimeData*>(pMimeData);
+    const QtMimeData* pQtMimeData = qobject_cast<const QtMimeData*>(pMimeData);
     if (!pQtMimeData)
         xTransferable = new QtDnDTransferable(pMimeData);
     else
@@ -1423,7 +1423,7 @@ static sal_Int8 lcl_getUserDropAction(const QDropEvent* 
pEvent, const sal_Int8 n
     if (0 == nUserDropAction)
     {
         // default LO internal action is move, but default external action is 
copy
-        nUserDropAction = dynamic_cast<const QtMimeData*>(pMimeData)
+        nUserDropAction = qobject_cast<const QtMimeData*>(pMimeData)
                               ? 
css::datatransfer::dnd::DNDConstants::ACTION_MOVE
                               : 
css::datatransfer::dnd::DNDConstants::ACTION_COPY;
         nUserDropAction &= nSourceActions;
diff --git a/vcl/qt5/QtTransferable.cxx b/vcl/qt5/QtTransferable.cxx
index 440731b8dcde..7fba6d14c40a 100644
--- a/vcl/qt5/QtTransferable.cxx
+++ b/vcl/qt5/QtTransferable.cxx
@@ -9,6 +9,7 @@
  */
 
 #include <QtTransferable.hxx>
+#include <QtTransferable.moc>
 
 #include <comphelper/sequence.hxx>
 #include <sal/log.hxx>
diff --git a/vcl/qt5/QtWidget.cxx b/vcl/qt5/QtWidget.cxx
index 996a0a7cc9ce..741c105aa97c 100644
--- a/vcl/qt5/QtWidget.cxx
+++ b/vcl/qt5/QtWidget.cxx
@@ -275,7 +275,7 @@ void QtWidget::wheelEvent(QWheelEvent* pEvent)
 
 void QtWidget::dragEnterEvent(QDragEnterEvent* event)
 {
-    if (dynamic_cast<const QtMimeData*>(event->mimeData()))
+    if (qobject_cast<const QtMimeData*>(event->mimeData()))
         event->accept();
     else
         event->acceptProposedAction();

Reply via email to