Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 77999733 authored by Colin Redman's avatar Colin Redman Committed by Albert Vaca Cintora

Clipboard sync on new connection

Summary: Added a timestamp to track clipboard changes, so when a new device connects it will sync the most recently updated clipboard to both devices.

Reviewers: #kde_connect, albertvaka

Reviewed By: #kde_connect, albertvaka

Subscribers: albertvaka, sredman, kdeconnect

Tags: #kde_connect

Differential Revision: https://phabricator.kde.org/D22584
parent 88e0ffa0
......@@ -20,7 +20,7 @@
#include "clipboardlistener.h"
ClipboardListener::ClipboardListener()
ClipboardListener::ClipboardListener()
: clipboard(QGuiApplication::clipboard())
{
#ifdef Q_OS_MAC
......@@ -30,7 +30,7 @@ ClipboardListener::ClipboardListener()
connect(clipboard, &QClipboard::changed, this, &ClipboardListener::updateClipboard);
}
void ClipboardListener::updateClipboard(QClipboard::Mode mode)
void ClipboardListener::updateClipboard(QClipboard::Mode mode)
{
if (mode != QClipboard::Clipboard) {
return;
......@@ -38,16 +38,28 @@ void ClipboardListener::updateClipboard(QClipboard::Mode mode)
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);
}
......@@ -21,6 +21,7 @@
#ifndef CLIPBOARDLISTENER_H
#define CLIPBOARDLISTENER_H
#include <QDateTime>
#include <QTimer>
#include <QObject>
#include <QClipboard>
......@@ -29,13 +30,14 @@
/**
* 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;
......@@ -43,7 +45,7 @@ private:
public:
static ClipboardListener* instance()
static ClipboardListener* instance()
{
static ClipboardListener* me = nullptr;
if (!me) {
......@@ -56,6 +58,9 @@ public:
void setText(const QString& content);
QString currentContent();
qint64 updateTimestamp();
Q_SIGNALS:
void clipboardChanged(const QString& content);
};
......
......@@ -35,17 +35,44 @@ ClipboardPlugin::ClipboardPlugin(QObject* parent, const QVariantList& args)
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<QString>(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<qint64>(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"
......@@ -27,8 +27,32 @@
#include <core/kdeconnectplugin.h>
Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_CLIPBOARD)
/**
* Packet containing just clipboard contents, sent when a device updates its clipboard.
* <p>
* 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
* <p>
* The timestamp is milliseconds since epoch. It can be 0, which indicates that the clipboard
* update time is currently unknown.
* <p>
* 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 @@ public:
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();
};
......
......@@ -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"
]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment