diff --git a/src/platform/dummy/dummyclipboard.cpp b/src/platform/dummy/dummyclipboard.cpp index 18819ef1e..3212ebcab 100644 --- a/src/platform/dummy/dummyclipboard.cpp +++ b/src/platform/dummy/dummyclipboard.cpp @@ -48,6 +48,11 @@ void DummyClipboard::setData(ClipboardMode mode, const QVariantMap &dataMap) QGuiApplication::clipboard()->setMimeData( createMimeData(dataMap), modeToQClipboardMode(mode) ); } +void DummyClipboard::setRawData(ClipboardMode mode, QMimeData *mimeData) +{ + QGuiApplication::clipboard()->setMimeData( mimeData, modeToQClipboardMode(mode) ); +} + const QMimeData *DummyClipboard::rawMimeData(ClipboardMode mode) const { return QGuiApplication::clipboard()->mimeData( modeToQClipboardMode(mode) ); diff --git a/src/platform/dummy/dummyclipboard.h b/src/platform/dummy/dummyclipboard.h index bda2f0850..d964ce47d 100644 --- a/src/platform/dummy/dummyclipboard.h +++ b/src/platform/dummy/dummyclipboard.h @@ -20,6 +20,7 @@ class DummyClipboard : public PlatformClipboard QVariantMap data(ClipboardMode mode, const QStringList &formats) const override; void setData(ClipboardMode mode, const QVariantMap &dataMap) override; + void setRawData(ClipboardMode mode, QMimeData *mimeData) override; const QMimeData *mimeData(ClipboardMode mode) const override; diff --git a/src/platform/platformclipboard.h b/src/platform/platformclipboard.h index 33427296e..744ff5086 100644 --- a/src/platform/platformclipboard.h +++ b/src/platform/platformclipboard.h @@ -33,6 +33,7 @@ class PlatformClipboard : public QObject * Set data to clipboard. */ virtual void setData(ClipboardMode mode, const QVariantMap &dataMap) = 0; + virtual void setRawData(ClipboardMode mode, QMimeData *mimeData) = 0; virtual const QMimeData *mimeData(ClipboardMode mode) const = 0; diff --git a/src/platform/x11/x11platformclipboard.cpp b/src/platform/x11/x11platformclipboard.cpp index ecae271c3..18cce79d4 100644 --- a/src/platform/x11/x11platformclipboard.cpp +++ b/src/platform/x11/x11platformclipboard.cpp @@ -160,6 +160,16 @@ void X11PlatformClipboard::setData(ClipboardMode mode, const QVariantMap &dataMa } } +void X11PlatformClipboard::setRawData(ClipboardMode mode, QMimeData *mimeData) +{ + if ( X11Info::isPlatformX11() ) { + DummyClipboard::setRawData(mode, mimeData); + } else { + const auto qmode = modeToQClipboardMode(mode); + WaylandClipboard::instance()->setMimeData(mimeData, qmode); + } +} + const QMimeData *X11PlatformClipboard::rawMimeData(ClipboardMode mode) const { if ( X11Info::isPlatformX11() ) diff --git a/src/platform/x11/x11platformclipboard.h b/src/platform/x11/x11platformclipboard.h index ffa2f3014..aa452831a 100644 --- a/src/platform/x11/x11platformclipboard.h +++ b/src/platform/x11/x11platformclipboard.h @@ -23,6 +23,7 @@ class X11PlatformClipboard final : public DummyClipboard QVariantMap data(ClipboardMode mode, const QStringList &formats) const override; void setData(ClipboardMode mode, const QVariantMap &dataMap) override; + void setRawData(ClipboardMode mode, QMimeData *mimeData) override; bool isSelectionSupported() const override { return m_selectionSupported; } diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index abe6f69d7..3c37d62a0 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -22,6 +22,7 @@ #include "platform/platformclipboard.h" #include "platform/platformnativeinterface.h" +#include #include #include #include @@ -270,6 +271,7 @@ class TestInterfaceImpl final : public TestInterface { m_env.insert("COPYQ_LOG_LEVEL", "DEBUG"); m_env.insert("COPYQ_SESSION_COLOR", defaultSessionColor); m_env.insert("COPYQ_SESSION_NAME", "TEST"); + m_env.insert("COPYQ_CLIPBOARD_COPY_TIMEOUT_MS", "2000"); } ~TestInterfaceImpl() @@ -835,6 +837,41 @@ QVariantMap secretData(const QByteArray &text) }; } +class SlowMimeData final : public QMimeData { +public: + explicit SlowMimeData(const QByteArray &data, int delayMs) + : m_data(data) + , m_delayMs(delayMs) + {} + + bool hasFormat(const QString &mimeType) const override + { + return formats().contains(mimeType); + } + + QStringList formats() const override + { + return {"a/a", "b/b", "c/c"}; + } + +protected: +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + QVariant retrieveData(const QString &mimeType, QMetaType) const override +#else + QVariant retrieveData(const QString &mimeType, QVariant::Type) const override +#endif + { + if (formats().contains(mimeType)) { + waitFor(m_delayMs); + return m_data; + } + return {}; + } +private: + QByteArray m_data; + int m_delayMs; +}; + } // namespace Tests::Tests(const TestInterfacePtr &test, QObject *parent) @@ -4999,6 +5036,62 @@ void Tests::saveLargeItem() RUN(args << "getItem(0)['application/x-copyq-test-data'].length", "260000\n"); } +void Tests::slowClipboard() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: 'global.clipboardFormatsToSave = function() { return ["a/a", "b/b", "c/c"] }' + }, + ]) + )"; + RUN(script, ""); + WAIT_ON_OUTPUT("clipboardFormatsToSave", "a/a\nb/b\nc/c\n"); + + TEST( m_test->setClipboard("A", "a/a") ); + WAIT_ON_OUTPUT("clipboard" << "a/a", "A"); + + auto clipboard = platformNativeInterface()->clipboard(); + for (int i = 0; i < 3; ++i) { + QMimeData *data = new SlowMimeData(QByteArray::number(i), 501); + clipboard->setRawData(ClipboardMode::Clipboard, data); + waitFor(100); + } + WAIT_ON_OUTPUT("read('a/a', 0)", "2"); + RUN("read('b/b', 0)", "2"); + RUN("read('c/c', 0)", "2"); + RUN("read('?', 0)", "a/a\nb/b\nc/c\n"); + + QMimeData *data = new SlowMimeData("X", 2001); + clipboard->setRawData(ClipboardMode::Clipboard, data); + waitFor(2000); + const auto expectedLog = R"(^.*: Clipboard data expired, refusing to access old data$)"; + QTRY_COMPARE( count(splitLines(readLogFile(maxReadLogSize)), expectedLog), 1 ); + WAIT_ON_OUTPUT("read('a/a', 0)", "X"); + RUN("read('b/b', 0)", ""); + RUN("read('?', 0)", "a/a\n"); +} + +void Tests::clipboardUriList() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: 'global.clipboardFormatsToSave = function() { return [mimeUriList] }' + }, + ]) + )"; + + RUN(script, ""); + WAIT_ON_OUTPUT("commands().length", "1\n"); + + const QByteArray uris = "https://test1.example.com\nhttps://test1.example.com"; + TEST( m_test->setClipboard(uris, mimeUriList) ); + WAIT_ON_OUTPUT("clipboard(mimeUriList)", uris); +} + int Tests::run( const QStringList &arguments, QByteArray *stdoutData, QByteArray *stderrData, const QByteArray &in, const QStringList &environment) diff --git a/src/tests/tests.h b/src/tests/tests.h index 096fbd96c..9b7eb5eb3 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -315,6 +315,9 @@ private slots: void saveLargeItem(); + void slowClipboard(); + void clipboardUriList(); + private: void clearServerErrors(); int run(const QStringList &arguments, QByteArray *stdoutData = nullptr,