Sync local clipboard to a tab when it becomes visible

Only the visible tab syncs the clipboard, but a tab in the background
missed local clipboard changes and kept a stale remote clipboard when
switched to, so with two RDP/VNC sessions only the one last copied in
worked. A tab now pushes the current local clipboard to its remote on
show.

Bump version to v2026.9.26.2.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ksmithandClaude Sonnet 5 committed 2026-09-26 15:38:58 -06:00
1 parent 0f821feeed
commit 67ea7ea6b3
4 files changed
+40 -13

No files matched your search

+27 -12
View File
@@ -28,6 +28,7 @@
#include <QComboBox>
#include <QProcessEnvironment>
#include <QPushButton>
#include <QShowEvent>
#include <QScrollArea>
#include <QThread>
#include <QTimer>
@@ -799,6 +800,26 @@ void SessionTab::onBackendRemoteClipboardTextChanged(const QString& text)
}
void SessionTab::onSystemClipboardChanged()
{
const QClipboard* clipboard = QApplication::clipboard();
const QString text = clipboard->mimeData()->hasText() ? clipboard->text() : QString();
// Suppress only the change we caused ourselves, and only briefly. The
// old "same as last synced text" check had no expiry: once a send was
// lost (channel not ready, remote clipboard changed to something we
// never saw) copying that same text again did nothing, indefinitely.
constexpr qint64 kEchoWindowMs = 1000;
const bool isEcho = !m_pendingClipboardEcho.isEmpty() && text == m_pendingClipboardEcho
&& QDateTime::currentMSecsSinceEpoch() - m_pendingClipboardEchoMs < kEchoWindowMs;
m_pendingClipboardEcho.clear();
if (isEcho) {
return;
}
pushLocalClipboardToRemote();
}
void SessionTab::pushLocalClipboardToRemote()
{
if (!m_clipboardSyncSupported || m_state != SessionState::Connected || !isVisible()) {
return;
@@ -814,22 +835,16 @@ void SessionTab::onSystemClipboardChanged()
return;
}
// Suppress only the change we caused ourselves, and only briefly. The
// old "same as last synced text" check had no expiry: once a send was
// lost (channel not ready, remote clipboard changed to something we
// never saw) copying that same text again did nothing, indefinitely.
constexpr qint64 kEchoWindowMs = 1000;
const bool isEcho = !m_pendingClipboardEcho.isEmpty() && text == m_pendingClipboardEcho
&& QDateTime::currentMSecsSinceEpoch() - m_pendingClipboardEchoMs < kEchoWindowMs;
m_pendingClipboardEcho.clear();
if (isEcho) {
return;
}
emit requestSetClipboardText(text);
appendEvent(QStringLiteral("Clipboard: sending %1 characters to remote.").arg(text.size()));
}
void SessionTab::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
pushLocalClipboardToRemote();
}
void SessionTab::setupUi()
{
auto* rootLayout = new QVBoxLayout(this);
+7
View File
@@ -24,6 +24,7 @@ class QComboBox;
class QLabel;
class QPushButton;
class QScrollArea;
class QShowEvent;
class KodoTerm;
struct SessionUiPreferences
@@ -99,6 +100,11 @@ signals:
void requestSetClipboardText(const QString& text);
void requestProvideUsername(const QString& username);
protected:
// A tab that wasn't in front while the local clipboard changed missed
// that change (only the visible tab syncs), so catch it up on show.
void showEvent(QShowEvent* event) override;
private slots:
void onBackendStateChanged(SessionState state, const QString& message);
void onBackendEventLogged(const QString& message);
@@ -166,6 +172,7 @@ private:
std::function<void(std::optional<QString>)> callback,
bool maskInput = true);
void hidePasswordPrompt();
void pushLocalClipboardToRemote();
bool validateProfileForConnect();
void appendEvent(const QString& message);
void setState(SessionState state, const QString& message);