mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-29 02:11:52 +00:00
[idd] clipboard: handle delayed-render sequence changes
This commit is contained in:
@@ -3404,7 +3404,8 @@ void CClipboardManager::HandleRequest(
|
|||||||
record.clipboardGeneration != m_localGeneration ||
|
record.clipboardGeneration != m_localGeneration ||
|
||||||
record.clipboardGeneration != Atomic::Load(
|
record.clipboardGeneration != Atomic::Load(
|
||||||
m_liveLocalGeneration, std::memory_order_acquire) ||
|
m_liveLocalGeneration, std::memory_order_acquire) ||
|
||||||
GetClipboardSequenceNumber() != m_localSequence)
|
GetClipboardSequenceNumber() != m_localSequence ||
|
||||||
|
GetClipboardOwner() != m_localOwner)
|
||||||
{
|
{
|
||||||
QueueCancel(record, ERROR_NOT_FOUND);
|
QueueCancel(record, ERROR_NOT_FOUND);
|
||||||
return;
|
return;
|
||||||
@@ -3418,8 +3419,11 @@ void CClipboardManager::HandleRequest(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<CClipboardSpool> spool =
|
const DWORD sequence = m_localSequence;
|
||||||
CaptureFormat(record.format, m_localSequence);
|
const HWND owner = m_localOwner;
|
||||||
|
DWORD capturedSequence = sequence;
|
||||||
|
std::shared_ptr<CClipboardSpool> spool = CaptureFormat(
|
||||||
|
record.format, sequence, owner, capturedSequence);
|
||||||
if (!spool)
|
if (!spool)
|
||||||
{
|
{
|
||||||
const DWORD error = GetLastError();
|
const DWORD error = GetLastError();
|
||||||
@@ -3428,6 +3432,38 @@ void CClipboardManager::HandleRequest(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool generationLive = false;
|
||||||
|
bool transferLive = false;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_outgoingLock);
|
||||||
|
generationLive =
|
||||||
|
record.clipboardGeneration == Atomic::Load(
|
||||||
|
m_liveLocalGeneration, std::memory_order_acquire);
|
||||||
|
transferLive = generationLive &&
|
||||||
|
record.transfer == Atomic::Load(
|
||||||
|
m_outgoingTransfer, std::memory_order_acquire);
|
||||||
|
if (generationLive && capturedSequence != sequence)
|
||||||
|
{
|
||||||
|
m_localSequence = capturedSequence;
|
||||||
|
if (capturedSequence)
|
||||||
|
{
|
||||||
|
m_materializedSequence = capturedSequence;
|
||||||
|
m_materializedGeneration = record.clipboardGeneration;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_materializedSequence = 0;
|
||||||
|
m_materializedGeneration = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!transferLive)
|
||||||
|
{
|
||||||
|
ReleaseOutgoing(record.transfer);
|
||||||
|
QueueCancel(record, ERROR_OPERATION_ABORTED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Work data;
|
Work data;
|
||||||
data.type = WorkType::SEND_DATA;
|
data.type = WorkType::SEND_DATA;
|
||||||
data.record = record;
|
data.record = record;
|
||||||
@@ -3970,6 +4006,23 @@ CClipboardManager::CaptureClipboardFiles(DWORD sequence, int rawFormatCount,
|
|||||||
|
|
||||||
void CClipboardManager::HandleClipboardUpdate()
|
void CClipboardManager::HandleClipboardUpdate()
|
||||||
{
|
{
|
||||||
|
const DWORD sequenceBefore = GetClipboardSequenceNumber();
|
||||||
|
const HWND owner = GetClipboardOwner();
|
||||||
|
const DWORD sequenceAfter = GetClipboardSequenceNumber();
|
||||||
|
// GetClipboardData can materialize delayed data and post an update without
|
||||||
|
// changing the clipboard that the current generation represents.
|
||||||
|
if (sequenceBefore &&
|
||||||
|
sequenceBefore == sequenceAfter &&
|
||||||
|
sequenceBefore == m_materializedSequence &&
|
||||||
|
owner == m_localOwner &&
|
||||||
|
m_materializedGeneration &&
|
||||||
|
m_materializedGeneration == Atomic::Load(
|
||||||
|
m_liveLocalGeneration, std::memory_order_acquire))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_materializedSequence = 0;
|
||||||
|
m_materializedGeneration = 0;
|
||||||
|
|
||||||
if (m_applyingRemote || IsOurClipboard())
|
if (m_applyingRemote || IsOurClipboard())
|
||||||
{
|
{
|
||||||
ClearLocalRetry();
|
ClearLocalRetry();
|
||||||
@@ -4025,16 +4078,21 @@ void CClipboardManager::PublishLocalClipboard()
|
|||||||
Atomic::Store(m_liveLocalGeneration, UINT64_C(0),
|
Atomic::Store(m_liveLocalGeneration, UINT64_C(0),
|
||||||
std::memory_order_release);
|
std::memory_order_release);
|
||||||
m_localSequence = GetClipboardSequenceNumber();
|
m_localSequence = GetClipboardSequenceNumber();
|
||||||
|
m_localOwner = GetClipboardOwner();
|
||||||
|
m_materializedSequence = 0;
|
||||||
|
m_materializedGeneration = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DWORD before = GetClipboardSequenceNumber();
|
const DWORD before = GetClipboardSequenceNumber();
|
||||||
|
const HWND ownerBefore = GetClipboardOwner();
|
||||||
uint32_t formats = EnumerateFormats();
|
uint32_t formats = EnumerateFormats();
|
||||||
const uint32_t recognizedFormats = formats;
|
const uint32_t recognizedFormats = formats;
|
||||||
const int rawFormatCount = CountClipboardFormatsLogged(
|
const int rawFormatCount = CountClipboardFormatsLogged(
|
||||||
"PublishLocalClipboard", before);
|
"PublishLocalClipboard", before);
|
||||||
const DWORD after = GetClipboardSequenceNumber();
|
const DWORD after = GetClipboardSequenceNumber();
|
||||||
if (before != after)
|
const HWND ownerAfter = GetClipboardOwner();
|
||||||
|
if (before != after || ownerBefore != ownerAfter)
|
||||||
{
|
{
|
||||||
ClearLocalRetry();
|
ClearLocalRetry();
|
||||||
PostMessageW(m_hwnd, WM_CLIPBOARDUPDATE, 0, 0);
|
PostMessageW(m_hwnd, WM_CLIPBOARDUPDATE, 0, 0);
|
||||||
@@ -4050,7 +4108,8 @@ void CClipboardManager::PublishLocalClipboard()
|
|||||||
after, rawFormatCount, fileViaOLE, fileRetryStage, fileError,
|
after, rawFormatCount, fileViaOLE, fileRetryStage, fileError,
|
||||||
fileOleError);
|
fileOleError);
|
||||||
const DWORD capturedSequence = GetClipboardSequenceNumber();
|
const DWORD capturedSequence = GetClipboardSequenceNumber();
|
||||||
if (capturedSequence != after)
|
const HWND capturedOwner = GetClipboardOwner();
|
||||||
|
if (capturedSequence != after || capturedOwner != ownerAfter)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR_HR(HRESULT_FROM_WIN32(ERROR_RETRY),
|
DEBUG_ERROR_HR(HRESULT_FROM_WIN32(ERROR_RETRY),
|
||||||
"Failed to publish local clipboard: "
|
"Failed to publish local clipboard: "
|
||||||
@@ -4072,6 +4131,9 @@ void CClipboardManager::PublishLocalClipboard()
|
|||||||
if (!generation)
|
if (!generation)
|
||||||
generation = ++m_localGeneration;
|
generation = ++m_localGeneration;
|
||||||
m_localSequence = after;
|
m_localSequence = after;
|
||||||
|
m_localOwner = ownerAfter;
|
||||||
|
m_materializedSequence = 0;
|
||||||
|
m_materializedGeneration = 0;
|
||||||
if (files)
|
if (files)
|
||||||
{
|
{
|
||||||
formats |= KVMFR_CLIPBOARD_FORMAT_MASK_FILES;
|
formats |= KVMFR_CLIPBOARD_FORMAT_MASK_FILES;
|
||||||
@@ -4183,6 +4245,9 @@ void CClipboardManager::InvalidateOutgoing(uint32_t reason)
|
|||||||
void CClipboardManager::InvalidateLocalClipboard(uint32_t reason)
|
void CClipboardManager::InvalidateLocalClipboard(uint32_t reason)
|
||||||
{
|
{
|
||||||
m_localSequence = 0;
|
m_localSequence = 0;
|
||||||
|
m_localOwner = nullptr;
|
||||||
|
m_materializedSequence = 0;
|
||||||
|
m_materializedGeneration = 0;
|
||||||
RetireLocalFileDataset();
|
RetireLocalFileDataset();
|
||||||
InvalidateOutgoing(reason);
|
InvalidateOutgoing(reason);
|
||||||
}
|
}
|
||||||
@@ -4237,6 +4302,9 @@ void CClipboardManager::ExpireLocalRetry(DWORD sequence)
|
|||||||
if (!generation)
|
if (!generation)
|
||||||
generation = ++m_localGeneration;
|
generation = ++m_localGeneration;
|
||||||
m_localSequence = sequence;
|
m_localSequence = sequence;
|
||||||
|
m_localOwner = GetClipboardOwner();
|
||||||
|
m_materializedSequence = 0;
|
||||||
|
m_materializedGeneration = 0;
|
||||||
PublishClear(generation);
|
PublishClear(generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4472,9 +4540,12 @@ UINT CClipboardManager::ToWindowsFormat(KVMFRClipboardFormat format) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<CClipboardSpool> CClipboardManager::CaptureFormat(
|
std::shared_ptr<CClipboardSpool> CClipboardManager::CaptureFormat(
|
||||||
KVMFRClipboardFormat format, DWORD sequence)
|
KVMFRClipboardFormat format, DWORD sequence, HWND owner,
|
||||||
|
DWORD& capturedSequence)
|
||||||
{
|
{
|
||||||
if (GetClipboardSequenceNumber() != sequence)
|
capturedSequence = sequence;
|
||||||
|
if (GetClipboardSequenceNumber() != sequence ||
|
||||||
|
GetClipboardOwner() != owner)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_RETRY);
|
SetLastError(ERROR_RETRY);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -4488,7 +4559,8 @@ std::shared_ptr<CClipboardSpool> CClipboardManager::CaptureFormat(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetClipboardSequenceNumber() != sequence)
|
if (GetClipboardSequenceNumber() != sequence ||
|
||||||
|
GetClipboardOwner() != owner)
|
||||||
{
|
{
|
||||||
CloseClipboard();
|
CloseClipboard();
|
||||||
SetLastError(ERROR_RETRY);
|
SetLastError(ERROR_RETRY);
|
||||||
@@ -4635,7 +4707,12 @@ std::shared_ptr<CClipboardSpool> CClipboardManager::CaptureFormat(
|
|||||||
if (!success && !error)
|
if (!success && !error)
|
||||||
error = ERROR_NOT_ENOUGH_MEMORY;
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
GlobalUnlock(handle);
|
GlobalUnlock(handle);
|
||||||
if (GetClipboardSequenceNumber() != sequence)
|
const DWORD renderedSequence = GetClipboardSequenceNumber();
|
||||||
|
const HWND renderedOwner = GetClipboardOwner();
|
||||||
|
const bool sequenceChanged = renderedSequence != sequence;
|
||||||
|
// With the clipboard still open, another process cannot replace it. A
|
||||||
|
// sequence advance from the same owner is delayed or synthesized rendering.
|
||||||
|
if (renderedOwner != owner || (sequenceChanged && !owner))
|
||||||
{
|
{
|
||||||
CloseClipboard();
|
CloseClipboard();
|
||||||
SetLastError(ERROR_RETRY);
|
SetLastError(ERROR_RETRY);
|
||||||
@@ -4647,6 +4724,7 @@ std::shared_ptr<CClipboardSpool> CClipboardManager::CaptureFormat(
|
|||||||
SetLastError(error);
|
SetLastError(error);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
capturedSequence = renderedSequence;
|
||||||
return spool;
|
return spool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -225,6 +225,9 @@ 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;
|
||||||
|
HWND m_localOwner = nullptr;
|
||||||
|
DWORD m_materializedSequence = 0;
|
||||||
|
uint64_t m_materializedGeneration = 0;
|
||||||
DWORD m_localRetrySequence = 0;
|
DWORD m_localRetrySequence = 0;
|
||||||
uint64_t m_localRetryDeadline = 0;
|
uint64_t m_localRetryDeadline = 0;
|
||||||
uint64_t m_remoteGeneration = 0;
|
uint64_t m_remoteGeneration = 0;
|
||||||
@@ -321,7 +324,8 @@ private:
|
|||||||
KVMFRClipboardFormat ToWireFormat(UINT format) const;
|
KVMFRClipboardFormat ToWireFormat(UINT format) const;
|
||||||
UINT ToWindowsFormat(KVMFRClipboardFormat format) const;
|
UINT ToWindowsFormat(KVMFRClipboardFormat format) const;
|
||||||
std::shared_ptr<CClipboardSpool> CaptureFormat(
|
std::shared_ptr<CClipboardSpool> CaptureFormat(
|
||||||
KVMFRClipboardFormat format, DWORD sequence);
|
KVMFRClipboardFormat format, DWORD sequence, HWND owner,
|
||||||
|
DWORD& capturedSequence);
|
||||||
bool MaterializeFormat(KVMFRClipboardFormat format,
|
bool MaterializeFormat(KVMFRClipboardFormat format,
|
||||||
UINT windowsFormat, CClipboardSpool& spool);
|
UINT windowsFormat, CClipboardSpool& spool);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user