Skip to content

Commit

Permalink
X11/Wayland: Fix clipboard/selection format synchronization
Browse files Browse the repository at this point in the history
Synchronize all text formats as-is to avoid any encoding conversions.
  • Loading branch information
hluk committed Nov 29, 2022
1 parent 45f0bef commit b5437e1
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 23 deletions.
5 changes: 3 additions & 2 deletions src/app/clipboardmonitor.cpp
Expand Up @@ -112,8 +112,9 @@ void ClipboardMonitor::onClipboardChanged(ClipboardMode mode)
? ClipboardMode::Selection
: ClipboardMode::Clipboard;
const QVariantMap targetData = m_clipboard->data(targetMode, {mimeText});
const uint targetTextHash = qHash( getTextData(targetData, mimeText) );
emit synchronizeSelection(mode, text, targetTextHash);
const uint targetTextHash = qHash( targetData.value(mimeText).toByteArray() );
const uint sourceTextHash = qHash( data.value(mimeText).toByteArray() );
emit synchronizeSelection(mode, sourceTextHash, targetTextHash);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/clipboardmonitor.h
Expand Up @@ -25,7 +25,7 @@ class ClipboardMonitor final : public QObject
signals:
void clipboardChanged(const QVariantMap &data, ClipboardOwnership ownership);
void clipboardUnchanged(const QVariantMap &data);
void synchronizeSelection(ClipboardMode sourceMode, const QString &text, uint targetTextHash);
void synchronizeSelection(ClipboardMode sourceMode, uint sourceTextHash, uint targetTextHash);

private:
void onClipboardChanged(ClipboardMode mode);
Expand Down
38 changes: 19 additions & 19 deletions src/scriptable/scriptable.cpp
Expand Up @@ -2863,18 +2863,20 @@ void Scriptable::onMonitorClipboardUnchanged(const QVariantMap &data)
m_proxy->runInternalAction(data, "copyq onClipboardUnchanged");
}

void Scriptable::onSynchronizeSelection(ClipboardMode sourceMode, const QString &text, uint targetTextHash)
void Scriptable::onSynchronizeSelection(ClipboardMode sourceMode, uint sourceTextHash, uint targetTextHash)
{
#ifdef HAS_MOUSE_SELECTIONS
auto data = createDataMap(mimeText, text);
QVariantMap data;
data[COPYQ_MIME_PREFIX "source-text-hash"] = QByteArray::number(sourceTextHash);
data[COPYQ_MIME_PREFIX "target-text-hash"] = QByteArray::number(targetTextHash);
const auto command = sourceMode == ClipboardMode::Clipboard
? "copyq --clipboard-access synchronizeToSelection"
: "copyq --clipboard-access synchronizeFromSelection";
m_proxy->runInternalAction(data, command);
#else
Q_UNUSED(text)
Q_UNUSED(sourceMode)
Q_UNUSED(sourceTextHash)
Q_UNUSED(targetTextHash)
#endif
}

Expand Down Expand Up @@ -3599,16 +3601,16 @@ bool Scriptable::canSynchronizeSelection(ClipboardMode targetMode)
// Stop if the clipboard/selection text already changed again.
const QVariantMap sourceData = clipboardInstance()->data(
sourceMode, {mimeTextUtf8, mimeText, mimeUriList});
QString sourceText;
QByteArray source;
if (!sourceData.isEmpty()) {
sourceText = getTextData(sourceData);
const QString newText = getTextData(m_data);
if (sourceText != newText) {
COPYQ_LOG(QStringLiteral("Sync: Cancelled - source text changed"));
COPYQ_LOG_VERBOSE(
QStringLiteral(" Expected: %1\nActual: %2")
.arg(newText, sourceText) );
return false;
source = sourceData.value(mimeText).toByteArray();
const QString owner = sourceData.value(mimeOwner).toString();
if ( owner.isEmpty() && !source.isEmpty() ) {
const auto sourceTextHash = m_data.value(COPYQ_MIME_PREFIX "source-text-hash").toByteArray().toUInt();
if (sourceTextHash != qHash(source)) {
COPYQ_LOG(QStringLiteral("Sync: Cancelled - source text changed"));
return false;
}
}
} else {
COPYQ_LOG("Sync: Failed to fetch source data");
Expand All @@ -3617,22 +3619,19 @@ bool Scriptable::canSynchronizeSelection(ClipboardMode targetMode)
const QVariantMap targetData = clipboardInstance()->data(
targetMode, {mimeText});
if (!targetData.isEmpty()) {
const QString targetText = getTextData(targetData, mimeText);
const QByteArray target = targetData.value(mimeText).toByteArray();
const QString owner = targetData.value(mimeOwner).toString();
if ( owner.isEmpty() && !targetText.isEmpty() ) {
if ( owner.isEmpty() && !target.isEmpty() ) {
const auto targetTextHash = m_data.value(COPYQ_MIME_PREFIX "target-text-hash").toByteArray().toUInt();
if (targetTextHash != qHash(targetText)) {
if (targetTextHash != qHash(target)) {
COPYQ_LOG(QStringLiteral("Sync: Cancelled - target text changed"));
COPYQ_LOG_VERBOSE(
QStringLiteral(" Actual: %1\nSource text: %2")
.arg(targetText, sourceText) );
return false;
}
}

// Stop if the clipboard and selection text is already synchronized
// or user selected text and copied it to clipboard.
if (!sourceData.isEmpty() && sourceText == targetText) {
if (!sourceData.isEmpty() && source == target) {
COPYQ_LOG(QStringLiteral("Sync: Cancelled - target text is already same as source"));
return false;
}
Expand All @@ -3645,6 +3644,7 @@ bool Scriptable::canSynchronizeSelection(ClipboardMode targetMode)
return false;
}

m_data = sourceData;
return true;
#else
Q_UNUSED(targetMode)
Expand Down
2 changes: 1 addition & 1 deletion src/scriptable/scriptable.h
Expand Up @@ -383,7 +383,7 @@ public slots:
void onExecuteOutput(const QByteArray &output);
void onMonitorClipboardChanged(const QVariantMap &data, ClipboardOwnership ownership);
void onMonitorClipboardUnchanged(const QVariantMap &data);
void onSynchronizeSelection(ClipboardMode sourceMode, const QString &text, uint targetTextHash);
void onSynchronizeSelection(ClipboardMode sourceMode, uint sourceTextHash, uint targetTextHash);

bool sourceScriptCommands();
void callDisplayFunctions(QJSValueList displayFunctions);
Expand Down

0 comments on commit b5437e1

Please sign in to comment.