Skip to content

Commit

Permalink
Abort cloning clipboard data if changed
Browse files Browse the repository at this point in the history
  • Loading branch information
hluk committed Nov 10, 2024
1 parent f29ccbe commit 45fb9a0
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 24 deletions.
17 changes: 9 additions & 8 deletions src/common/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ class ClipboardDataGuard final {
QElapsedTimer m_elapsed;
};

explicit ClipboardDataGuard(const QMimeData &data, bool *abortCloning = nullptr)
explicit ClipboardDataGuard(const QMimeData &data, const long int *clipboardSequenceNumber = nullptr)
: m_data(&data)
, m_abort(abortCloning)
, m_clipboardSequenceNumber(clipboardSequenceNumber)
, m_clipboardSequenceNumberOriginal(clipboardSequenceNumber ? *clipboardSequenceNumber : 0)
{
// This uses simple connection to ensure pointer is not destroyed
// instead of QPointer to work around a possible Qt bug
Expand Down Expand Up @@ -188,7 +189,7 @@ class ClipboardDataGuard final {
private:
bool refresh()
{
if (m_abort && *m_abort)
if (m_clipboardSequenceNumber && *m_clipboardSequenceNumber != m_clipboardSequenceNumberOriginal)
return false;

if (!m_data)
Expand All @@ -209,7 +210,8 @@ class ClipboardDataGuard final {

const QMimeData *m_data;
QElapsedTimer m_timerExpire;
bool *m_abort = nullptr;
const long int *m_clipboardSequenceNumber;
long int m_clipboardSequenceNumberOriginal;
QMetaObject::Connection m_connection;
};

Expand Down Expand Up @@ -380,16 +382,15 @@ QVariantMap cloneData(ClipboardDataGuard &data, QStringList &formats)

} // namespace

QVariantMap cloneData(const QMimeData &rawData, QStringList formats, bool *abortCloning)
QVariantMap cloneData(const QMimeData &rawData, QStringList formats, const long int *clipboardSequenceNumber)
{
ClipboardDataGuard data(rawData, abortCloning);
ClipboardDataGuard data(rawData, clipboardSequenceNumber);
return cloneData(data, formats);
}

QVariantMap cloneData(const QMimeData &rawData)
{
bool abortCloning = false;
ClipboardDataGuard data(rawData, &abortCloning);
ClipboardDataGuard data(rawData);

static const QSet<QString> ignoredFormats({
mimeOwner,
Expand Down
2 changes: 1 addition & 1 deletion src/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ bool isMainThread();
QByteArray makeClipboardOwnerData();

/** Clone data for given formats (text or HTML will be UTF8 encoded). */
QVariantMap cloneData(const QMimeData &data, QStringList formats, bool *abortCloning = nullptr);
QVariantMap cloneData(const QMimeData &data, QStringList formats, const long int *clipboardSequenceNumber = nullptr);

/** Clone all data as is. */
QVariantMap cloneData(const QMimeData &data);
Expand Down
2 changes: 1 addition & 1 deletion src/platform/dummy/dummyclipboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ QVariantMap DummyClipboard::data(ClipboardMode mode, const QStringList &formats)
return {};

const bool isDataSecret = isHidden(*data);
QVariantMap dataMap = cloneData(*data, formats);
QVariantMap dataMap = cloneData(*data, formats, clipboardSequenceNumber(mode));
if (isDataSecret)
dataMap[mimeSecret] = QByteArrayLiteral("1");

Expand Down
1 change: 1 addition & 0 deletions src/platform/dummy/dummyclipboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class DummyClipboard : public PlatformClipboard
virtual const QMimeData *rawMimeData(ClipboardMode mode) const;
virtual void onChanged(int mode);
void onClipboardChanged(QClipboard::Mode mode);
virtual const long int *clipboardSequenceNumber(ClipboardMode) const { return nullptr; }
};

#endif // DUMMYCLIPBOARD_H
3 changes: 3 additions & 0 deletions src/platform/mac/macclipboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class MacClipboard final : public DummyClipboard {

protected:
void onChanged(int mode) override;
const long int *clipboardSequenceNumber(ClipboardMode) const override {
return &m_prevChangeCount;
}

private:
void clipboardTimeout();
Expand Down
5 changes: 4 additions & 1 deletion src/platform/win/winplatformclipboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ class WinPlatformClipboard final : public DummyClipboard

protected:
void onChanged(int) override;
const long int *clipboardSequenceNumber(ClipboardMode) const override {
return &m_lastClipboardSequenceNumber;
}

private:
DWORD m_lastClipboardSequenceNumber = -1;
long int m_lastClipboardSequenceNumber = 0;
};

#endif // WINPLATFORMCLIPBOARD_H
16 changes: 6 additions & 10 deletions src/platform/x11/x11platformclipboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ void X11PlatformClipboard::onChanged(int mode)
if (!clipboardData.enabled)
return;

++clipboardData.sequenceNumber;

// Store the current window title right after the clipboard/selection changes.
// This makes sure that the title points to the correct clipboard/selection
// owner most of the times.
Expand All @@ -207,14 +209,8 @@ void X11PlatformClipboard::onChanged(int mode)
}
}

if (m_clipboardData.cloningData || m_selectionData.cloningData) {
if (clipboardData.cloningData && !clipboardData.abortCloning) {
COPYQ_LOG( QString("Aborting getting %1, the data changed again")
.arg(mode == QClipboard::Clipboard ? "clipboard" : "selection") );
clipboardData.abortCloning = true;
}
if (m_clipboardData.cloningData || m_selectionData.cloningData)
return;
}

updateClipboardData(&clipboardData);

Expand Down Expand Up @@ -299,14 +295,14 @@ void X11PlatformClipboard::updateClipboardData(X11PlatformClipboard::ClipboardDa
}

clipboardData->timerEmitChange.stop();
clipboardData->abortCloning = false;
clipboardData->cloningData = true;
const bool isDataSecret = isHidden(*data);
clipboardData->newData = cloneData(*data, clipboardData->formats, &clipboardData->abortCloning);
const auto sequenceNumberOrig = clipboardData->sequenceNumber;
clipboardData->newData = cloneData(*data, clipboardData->formats, &clipboardData->sequenceNumber);
if (isDataSecret)
clipboardData->newData[mimeSecret] = QByteArrayLiteral("1");
clipboardData->cloningData = false;
if (clipboardData->abortCloning) {
if (sequenceNumberOrig != clipboardData->sequenceNumber) {
m_timerCheckAgain.setInterval(0);
m_timerCheckAgain.start();
return;
Expand Down
9 changes: 6 additions & 3 deletions src/platform/x11/x11platformclipboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
#include <QStringList>
#include <QTimer>

#include <memory>

class X11PlatformClipboard final : public DummyClipboard
{
public:
Expand All @@ -32,6 +30,11 @@ class X11PlatformClipboard final : public DummyClipboard
protected:
const QMimeData *rawMimeData(ClipboardMode mode) const override;
void onChanged(int mode) override;
const long int *clipboardSequenceNumber(ClipboardMode mode) const override {
return mode == ClipboardMode::Clipboard
? &m_clipboardData.sequenceNumber
: &m_selectionData.sequenceNumber;
}

private:
struct ClipboardData {
Expand All @@ -45,7 +48,7 @@ class X11PlatformClipboard final : public DummyClipboard
ClipboardMode mode;
bool enabled = true;
bool cloningData = false;
bool abortCloning = false;
long int sequenceNumber = 0;
bool ignoreNext = false;
int retry = 0;
};
Expand Down

0 comments on commit 45fb9a0

Please sign in to comment.