[idd] clipboard: accept restarted client generations
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled

This commit is contained in:
Geoffrey McRae
2026-08-14 12:46:11 +10:00
parent 20c63464a7
commit 71acbe71ad
2 changed files with 25 additions and 34 deletions

View File

@@ -878,8 +878,12 @@ bool CClipboardManager::QueueUI(UIWork&& work)
queued.epoch == work.epoch; queued.epoch == work.epoch;
else if (same && (work.type == UIType::OFFER || else if (same && (work.type == UIType::OFFER ||
work.type == UIType::CLEAR)) work.type == UIType::CLEAR))
{
same = queued.record.clipboardGeneration == same = queued.record.clipboardGeneration ==
work.record.clipboardGeneration; work.record.clipboardGeneration;
if (same && work.type == UIType::OFFER)
same = queued.record.token == work.record.token;
}
else if (same && work.type == UIType::REQUEST) else if (same && work.type == UIType::REQUEST)
same = queued.record.transfer == work.record.transfer; same = queued.record.transfer == work.record.transfer;
if (!same) if (!same)
@@ -1490,7 +1494,6 @@ void CClipboardManager::HandleState(bool available, uint64_t epoch)
ClearRemoteRetry(); ClearRemoteRetry();
InvalidateLocalClipboard(ERROR_DEVICE_NOT_CONNECTED); InvalidateLocalClipboard(ERROR_DEVICE_NOT_CONNECTED);
ClearOwnedClipboard(); ClearOwnedClipboard();
m_remoteControlGeneration = 0;
return; return;
} }
@@ -1503,44 +1506,21 @@ void CClipboardManager::HandleOffer(
if (!m_available || !record.clipboardGeneration || if (!m_available || !record.clipboardGeneration ||
!record.token || (record.token & ~KVMFR_CLIPBOARD_FORMAT_MASK_ALL)) !record.token || (record.token & ~KVMFR_CLIPBOARD_FORMAT_MASK_ALL))
return; return;
if (m_remoteControlGeneration &&
record.clipboardGeneration < m_remoteControlGeneration)
return;
const bool newOffer = // Clipboard generations identify content within one publisher process;
m_pendingRemoteOffer.clipboardGeneration != record.clipboardGeneration; // they restart when the client does. Serialized channel order determines
if (newOffer) // which publication is current.
{
ClearRemoteRetry();
m_remoteControlGeneration = record.clipboardGeneration;
m_pendingRemoteOffer = record;
m_remoteRetryDeadline = GetTickCount64() + REMOTE_RETRY_TIMEOUT_MS;
InvalidateLocalClipboard(ERROR_OPERATION_ABORTED);
}
if (ApplyRemoteOffer(record.token, record.clipboardGeneration))
{
ClearRemoteRetry();
return;
}
if (GetTickCount64() < m_remoteRetryDeadline &&
SetTimer(m_hwnd, REMOTE_RETRY_TIMER, REMOTE_RETRY_MS, nullptr))
return;
DEBUG_WARN("Failed to apply remote clipboard offer");
ClearRemoteRetry(); ClearRemoteRetry();
PublishLocalClipboard(); m_pendingRemoteOffer = record;
m_remoteRetryDeadline = GetTickCount64() + REMOTE_RETRY_TIMEOUT_MS;
InvalidateLocalClipboard(ERROR_OPERATION_ABORTED);
RetryRemoteOffer();
} }
void CClipboardManager::HandleClear( void CClipboardManager::HandleClear(
const KVMFRClipboardMessage& record) const KVMFRClipboardMessage&)
{ {
if (record.clipboardGeneration && m_remoteControlGeneration &&
record.clipboardGeneration < m_remoteControlGeneration)
return;
ClearRemoteRetry(); ClearRemoteRetry();
m_remoteControlGeneration = record.clipboardGeneration;
InvalidateLocalClipboard(ERROR_OPERATION_ABORTED); InvalidateLocalClipboard(ERROR_OPERATION_ABORTED);
ClearOwnedClipboard(); ClearOwnedClipboard();
} }
@@ -1789,7 +1769,19 @@ void CClipboardManager::RetryRemoteOffer()
if (!m_pendingRemoteOffer.clipboardGeneration || !m_available) if (!m_pendingRemoteOffer.clipboardGeneration || !m_available)
return; return;
const KVMFRClipboardMessage offer = m_pendingRemoteOffer; const KVMFRClipboardMessage offer = m_pendingRemoteOffer;
HandleOffer(offer); if (ApplyRemoteOffer(offer.token, offer.clipboardGeneration))
{
ClearRemoteRetry();
return;
}
if (GetTickCount64() < m_remoteRetryDeadline &&
SetTimer(m_hwnd, REMOTE_RETRY_TIMER, REMOTE_RETRY_MS, nullptr))
return;
DEBUG_WARN("Failed to apply remote clipboard offer");
ClearRemoteRetry();
PublishLocalClipboard();
} }
bool CClipboardManager::SetOriginMarker(uint64_t generation) const bool CClipboardManager::SetOriginMarker(uint64_t generation) const

View File

@@ -152,7 +152,6 @@ private:
uint64_t m_epoch = 0; uint64_t m_epoch = 0;
uint64_t m_localGeneration = 0; uint64_t m_localGeneration = 0;
DWORD m_localSequence = 0; DWORD m_localSequence = 0;
uint64_t m_remoteControlGeneration = 0;
uint64_t m_remoteGeneration = 0; uint64_t m_remoteGeneration = 0;
uint32_t m_remoteFormats = 0; uint32_t m_remoteFormats = 0;
DWORD m_ownedSequence = 0; DWORD m_ownedSequence = 0;