diff --git a/plugins/clipboard/clipboardlistener.h b/plugins/clipboard/clipboardlistener.h --- a/plugins/clipboard/clipboardlistener.h +++ b/plugins/clipboard/clipboardlistener.h @@ -21,29 +21,31 @@ #ifndef CLIPBOARDLISTENER_H #define CLIPBOARDLISTENER_H +#include #include #include #include #include /** * Wrapper around QClipboard, which emits clipboardChanged only when it really changed */ -class ClipboardListener : public QObject +class ClipboardListener : public QObject { Q_OBJECT private: ClipboardListener(); - QString currentContent; + QString m_currentContent; + qint64 m_updateTimestamp = 0; QClipboard* clipboard; #ifdef Q_OS_MAC QTimer m_clipboardMonitorTimer; #endif public: - static ClipboardListener* instance() + static ClipboardListener* instance() { static ClipboardListener* me = nullptr; if (!me) { @@ -56,6 +58,9 @@ void setText(const QString& content); + QString currentContent(); + qint64 updateTimestamp(); + Q_SIGNALS: void clipboardChanged(const QString& content); }; diff --git a/plugins/clipboard/clipboardlistener.cpp b/plugins/clipboard/clipboardlistener.cpp --- a/plugins/clipboard/clipboardlistener.cpp +++ b/plugins/clipboard/clipboardlistener.cpp @@ -20,7 +20,7 @@ #include "clipboardlistener.h" -ClipboardListener::ClipboardListener() +ClipboardListener::ClipboardListener() : clipboard(QGuiApplication::clipboard()) { #ifdef Q_OS_MAC @@ -30,24 +30,36 @@ connect(clipboard, &QClipboard::changed, this, &ClipboardListener::updateClipboard); } -void ClipboardListener::updateClipboard(QClipboard::Mode mode) +void ClipboardListener::updateClipboard(QClipboard::Mode mode) { if (mode != QClipboard::Clipboard) { return; } QString content = clipboard->text(); - if (content == currentContent) { + if (content == m_currentContent) { return; } - currentContent = content; + m_updateTimestamp = QDateTime::currentDateTime().toMSecsSinceEpoch(); + m_currentContent = content; Q_EMIT clipboardChanged(content); } +QString ClipboardListener::currentContent() +{ + return m_currentContent; +} + +qint64 ClipboardListener::updateTimestamp(){ + + return m_updateTimestamp; +} + void ClipboardListener::setText(const QString& content) { - currentContent = content; + m_updateTimestamp = QDateTime::currentDateTime().toMSecsSinceEpoch(); + m_currentContent = content; clipboard->setText(content); } diff --git a/plugins/clipboard/clipboardplugin.h b/plugins/clipboard/clipboardplugin.h --- a/plugins/clipboard/clipboardplugin.h +++ b/plugins/clipboard/clipboardplugin.h @@ -27,8 +27,32 @@ #include Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_CLIPBOARD) + +/** + * Packet containing just clipboard contents, sent when a device updates its clipboard. + *

+ * The body should look like so: + * { + * "content": "password" + * } + */ #define PACKET_TYPE_CLIPBOARD QStringLiteral("kdeconnect.clipboard") +/** + * Packet containing clipboard contents and a timestamp that the contents were last updated, sent + * on first connection + *

+ * The timestamp is milliseconds since epoch. It can be 0, which indicates that the clipboard + * update time is currently unknown. + *

+ * The body should look like so: + * { + * "timestamp": 542904563213, + * "content": "password" + * } + */ +#define PACKET_TYPE_CLIPBOARD_CONNECT QStringLiteral("kdeconnect.clipboard.connect") + class ClipboardPlugin : public KdeConnectPlugin { @@ -38,10 +62,10 @@ explicit ClipboardPlugin(QObject* parent, const QVariantList& args); bool receivePacket(const NetworkPacket& np) override; - void connected() override { } - + void connected() override; private Q_SLOTS: void propagateClipboard(const QString& content); + void sendConnectPacket(); }; diff --git a/plugins/clipboard/clipboardplugin.cpp b/plugins/clipboard/clipboardplugin.cpp --- a/plugins/clipboard/clipboardplugin.cpp +++ b/plugins/clipboard/clipboardplugin.cpp @@ -35,17 +35,44 @@ this, &ClipboardPlugin::propagateClipboard); } +void ClipboardPlugin::connected() +{ + sendConnectPacket(); +} + void ClipboardPlugin::propagateClipboard(const QString& content) { NetworkPacket np(PACKET_TYPE_CLIPBOARD, {{QStringLiteral("content"), content}}); sendPacket(np); } +void ClipboardPlugin::sendConnectPacket() +{ + NetworkPacket np(PACKET_TYPE_CLIPBOARD_CONNECT, { + {QStringLiteral("content"), ClipboardListener::instance()->currentContent()}, + {QStringLiteral("timestamp"), ClipboardListener::instance()->updateTimestamp()} + }); + sendPacket(np); +} + + bool ClipboardPlugin::receivePacket(const NetworkPacket& np) { QString content = np.get(QStringLiteral("content")); - ClipboardListener::instance()->setText(content); - return true; + if (np.type() == PACKET_TYPE_CLIPBOARD) { + ClipboardListener::instance()->setText(content); + return true; + } else if (np.type() == PACKET_TYPE_CLIPBOARD_CONNECT) { + qint64 packetTime = np.get(QStringLiteral("timestamp")); + // If the packetTime is 0, it means the timestamp is unknown (so do nothing). + if (packetTime == 0 || packetTime < ClipboardListener::instance()->updateTimestamp()) { + return false; + } + + ClipboardListener::instance()->setText(content); + return true; + } + return false; } #include "clipboardplugin.moc" diff --git a/plugins/clipboard/kdeconnect_clipboard.json b/plugins/clipboard/kdeconnect_clipboard.json --- a/plugins/clipboard/kdeconnect_clipboard.json +++ b/plugins/clipboard/kdeconnect_clipboard.json @@ -129,9 +129,9 @@ "Website": "https://albertvaka.wordpress.com" }, "X-KdeConnect-OutgoingPacketType": [ - "kdeconnect.clipboard" + "kdeconnect.clipboard", "kdeconnect.clipboard.connect" ], "X-KdeConnect-SupportedPacketType": [ - "kdeconnect.clipboard" + "kdeconnect.clipboard", "kdeconnect.clipboard.connect" ] }