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();