mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 15:11:31 +00:00
[idd] clipboard: add direct synchronization
This commit is contained in:
2294
idd/LGIddHelper/CClipboardManager.cpp
Normal file
2294
idd/LGIddHelper/CClipboardManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
231
idd/LGIddHelper/CClipboardManager.h
Normal file
231
idd/LGIddHelper/CClipboardManager.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CClipboardChannel.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
class CClipboardSpool;
|
||||
|
||||
class CClipboardManager final : private IClipboardChannelHandler
|
||||
{
|
||||
private:
|
||||
enum class WorkType
|
||||
{
|
||||
STATE,
|
||||
RESET,
|
||||
RECORD,
|
||||
SEND,
|
||||
SEND_DATA,
|
||||
};
|
||||
|
||||
enum class UIType
|
||||
{
|
||||
STATE,
|
||||
OFFER,
|
||||
CLEAR,
|
||||
REQUEST,
|
||||
};
|
||||
|
||||
struct Work
|
||||
{
|
||||
WorkType type = WorkType::STATE;
|
||||
bool available = false;
|
||||
uint64_t epoch = 0;
|
||||
uint32_t reason = 0;
|
||||
KVMFRClipboardMessage record = {};
|
||||
std::vector<uint8_t> data;
|
||||
std::shared_ptr<CClipboardSpool> spool;
|
||||
uint64_t deadline = 0;
|
||||
};
|
||||
|
||||
struct UIWork
|
||||
{
|
||||
UIType type = UIType::STATE;
|
||||
bool available = false;
|
||||
uint64_t epoch = 0;
|
||||
KVMFRClipboardMessage record = {};
|
||||
};
|
||||
|
||||
struct PendingCancel
|
||||
{
|
||||
bool valid = false;
|
||||
KVMFRClipboardMessage record = {};
|
||||
uint64_t deadline = 0;
|
||||
};
|
||||
|
||||
struct PendingControl
|
||||
{
|
||||
WorkType type = WorkType::STATE;
|
||||
bool available = false;
|
||||
uint64_t epoch = 0;
|
||||
uint32_t reason = 0;
|
||||
};
|
||||
|
||||
static_assert(std::is_nothrow_move_constructible_v<Work>);
|
||||
static_assert(std::is_nothrow_move_assignable_v<Work>);
|
||||
|
||||
struct IncomingTransfer
|
||||
{
|
||||
uint64_t transfer = 0;
|
||||
uint64_t generation = 0;
|
||||
KVMFRClipboardFormat format = KVMFR_CLIPBOARD_FORMAT_NONE;
|
||||
uint64_t nextOffset = 0;
|
||||
uint32_t nextSequence = 0;
|
||||
uint64_t sizeHint = KVMFR_CLIPBOARD_SIZE_UNKNOWN;
|
||||
bool began = false;
|
||||
bool complete = false;
|
||||
uint32_t error = ERROR_SUCCESS;
|
||||
HANDLE event = nullptr;
|
||||
std::shared_ptr<CClipboardSpool> spool;
|
||||
|
||||
~IncomingTransfer();
|
||||
};
|
||||
|
||||
static constexpr UINT WM_CLIPBOARD_WORK = WM_APP + 0x4c;
|
||||
static constexpr size_t MAX_WORK = 16;
|
||||
static constexpr size_t MAX_UI_WORK = 16;
|
||||
static constexpr size_t MAX_PENDING_CANCEL = 8;
|
||||
static constexpr size_t MAX_PENDING_CONTROL = 16;
|
||||
static constexpr DWORD RENDER_TIMEOUT_MS = 15000;
|
||||
static constexpr DWORD SEND_TIMEOUT_MS = RENDER_TIMEOUT_MS;
|
||||
|
||||
HWND m_hwnd;
|
||||
CClipboardChannel& m_channel;
|
||||
HANDLE m_stop = nullptr;
|
||||
HANDLE m_wake = nullptr;
|
||||
HANDLE m_thread = nullptr;
|
||||
|
||||
std::mutex m_workLock;
|
||||
std::array<std::optional<Work>, MAX_WORK> m_recordWork;
|
||||
size_t m_recordWorkCount = 0;
|
||||
std::array<std::optional<Work>, MAX_WORK> m_sendWork;
|
||||
size_t m_sendWorkCount = 0;
|
||||
std::array<PendingCancel, MAX_PENDING_CANCEL> m_pendingCancel;
|
||||
size_t m_pendingCancelCursor = 0;
|
||||
std::array<PendingControl, MAX_PENDING_CONTROL> m_pendingControl;
|
||||
size_t m_pendingControlCount = 0;
|
||||
|
||||
std::recursive_mutex m_uiLock;
|
||||
std::array<UIWork, MAX_UI_WORK> m_uiWork;
|
||||
size_t m_uiWorkCount = 0;
|
||||
|
||||
std::mutex m_transferLock;
|
||||
std::shared_ptr<IncomingTransfer> m_incoming;
|
||||
std::mutex m_outgoingLock;
|
||||
|
||||
UINT m_formatPNG = 0;
|
||||
UINT m_formatJPEG = 0;
|
||||
UINT m_formatOrigin = 0;
|
||||
bool m_listener = false;
|
||||
std::atomic<bool> m_shutdown { false };
|
||||
bool m_applyingRemote = false;
|
||||
bool m_available = false;
|
||||
uint64_t m_epoch = 0;
|
||||
uint64_t m_localGeneration = 0;
|
||||
DWORD m_localSequence = 0;
|
||||
uint64_t m_remoteControlGeneration = 0;
|
||||
uint64_t m_remoteGeneration = 0;
|
||||
uint32_t m_remoteFormats = 0;
|
||||
DWORD m_ownedSequence = 0;
|
||||
std::atomic<uint64_t> m_liveLocalGeneration { 0 };
|
||||
std::atomic<uint64_t> m_nextTransfer {
|
||||
KVMFR_CLIPBOARD_TRANSFER_HELPER | UINT64_C(1) };
|
||||
std::atomic<uint64_t> m_outgoingTransfer { 0 };
|
||||
KVMFRClipboardMessage m_pendingRemoteOffer = {};
|
||||
uint64_t m_remoteRetryDeadline = 0;
|
||||
|
||||
static DWORD WINAPI ThreadProc(void * context);
|
||||
void Thread();
|
||||
|
||||
bool QueueWork(Work&& work);
|
||||
bool QueueCancel(const KVMFRClipboardMessage& record, uint32_t reason,
|
||||
uint64_t deadline = 0);
|
||||
void QueueControl(WorkType type, bool available,
|
||||
uint64_t epoch, uint32_t reason);
|
||||
bool QueueUI(UIWork&& work);
|
||||
void DrainUI();
|
||||
void ProcessWork(Work&& work);
|
||||
void ProcessRecord(const KVMFRClipboardMessage& record,
|
||||
const uint8_t * data);
|
||||
void ProcessData(const KVMFRClipboardMessage& record,
|
||||
const uint8_t * data);
|
||||
void ProcessSend(Work&& work);
|
||||
void ProcessSendData(Work&& work);
|
||||
void CancelIncoming(uint32_t reason, uint64_t transfer = 0);
|
||||
void ReleaseOutgoing(uint64_t transfer);
|
||||
|
||||
void HandleState(bool available, uint64_t epoch);
|
||||
void HandleOffer(const KVMFRClipboardMessage& record);
|
||||
void HandleClear(const KVMFRClipboardMessage& record);
|
||||
void HandleRequest(const KVMFRClipboardMessage& record);
|
||||
void HandleClipboardUpdate();
|
||||
void HandleDestroyClipboard();
|
||||
void RenderFormat(UINT format, uint64_t deadline = 0);
|
||||
void RenderAllFormats();
|
||||
void RetryRemoteOffer();
|
||||
|
||||
bool OpenClipboardRetry() const;
|
||||
bool IsOurClipboard();
|
||||
uint32_t EnumerateFormats() const;
|
||||
void PublishLocalClipboard();
|
||||
void PublishClear(uint64_t generation);
|
||||
bool ApplyRemoteOffer(uint32_t formats, uint64_t generation);
|
||||
void ClearOwnedClipboard();
|
||||
void InvalidateOutgoing(uint32_t reason);
|
||||
void InvalidateLocalClipboard(uint32_t reason);
|
||||
void ClearRemoteRetry();
|
||||
bool SetOriginMarker(uint64_t generation) const;
|
||||
|
||||
KVMFRClipboardFormat ToWireFormat(UINT format) const;
|
||||
UINT ToWindowsFormat(KVMFRClipboardFormat format) const;
|
||||
std::shared_ptr<CClipboardSpool> CaptureFormat(
|
||||
KVMFRClipboardFormat format, DWORD sequence);
|
||||
bool MaterializeFormat(KVMFRClipboardFormat format,
|
||||
CClipboardSpool& spool);
|
||||
|
||||
void ClipboardState(bool available, uint64_t epoch) override;
|
||||
ClipboardChannelResult ClipboardRecord(const KVMFRClipboardMessage& record,
|
||||
const uint8_t * data) override;
|
||||
void ClipboardReset(uint64_t epoch, uint32_t reason) override;
|
||||
|
||||
public:
|
||||
CClipboardManager(HWND hwnd, CClipboardChannel& channel);
|
||||
~CClipboardManager();
|
||||
|
||||
CClipboardManager(const CClipboardManager&) = delete;
|
||||
CClipboardManager& operator=(const CClipboardManager&) = delete;
|
||||
|
||||
bool Initialize();
|
||||
void Shutdown();
|
||||
bool HandleMessage(UINT message, WPARAM wParam, LPARAM lParam,
|
||||
LRESULT& result);
|
||||
};
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "CNotifyWindow.h"
|
||||
#include "CClipboardManager.h"
|
||||
#include "CConfigWindow.h"
|
||||
#include "Resources.h"
|
||||
#include <CDebug.h>
|
||||
@@ -86,6 +87,11 @@ CNotifyWindow::~CNotifyWindow()
|
||||
|
||||
LRESULT CNotifyWindow::handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT clipboardResult;
|
||||
if (m_clipboard && m_clipboard->HandleMessage(
|
||||
uMsg, wParam, lParam, clipboardResult))
|
||||
return clipboardResult;
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_NOTIFY_ICON:
|
||||
@@ -168,6 +174,8 @@ LRESULT CNotifyWindow::onClose()
|
||||
|
||||
LRESULT CNotifyWindow::onDestroy()
|
||||
{
|
||||
if (m_clipboard)
|
||||
m_clipboard->Shutdown();
|
||||
KillTimer(m_hwnd, ID_DISPLAY_CHECK_TIMER);
|
||||
Shell_NotifyIcon(NIM_DELETE, &m_iconData);
|
||||
return 0;
|
||||
@@ -310,6 +318,20 @@ void CNotifyWindow::setRecoveryMode(bool active)
|
||||
DEBUG_ERROR_HR(GetLastError(), "Failed to update recovery state");
|
||||
}
|
||||
|
||||
bool CNotifyWindow::initClipboard(CClipboardChannel& channel)
|
||||
{
|
||||
if (m_clipboard)
|
||||
return true;
|
||||
std::unique_ptr<CClipboardManager> clipboard(
|
||||
new (std::nothrow) CClipboardManager(m_hwnd, channel));
|
||||
if (!clipboard)
|
||||
return false;
|
||||
if (!clipboard->Initialize())
|
||||
return false;
|
||||
m_clipboard = std::move(clipboard);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CNotifyWindow::handleResolutionRejected(uint32_t width, uint32_t height,
|
||||
uint32_t requiredSizeMiB)
|
||||
{
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <optional>
|
||||
|
||||
class CConfigWindow;
|
||||
class CClipboardChannel;
|
||||
class CClipboardManager;
|
||||
|
||||
class CNotifyWindow : public CWindow
|
||||
{
|
||||
@@ -40,6 +42,7 @@ class CNotifyWindow : public CWindow
|
||||
std::atomic_bool closeRequested;
|
||||
bool m_recoveryActive;
|
||||
std::unique_ptr<CConfigWindow> m_config;
|
||||
std::unique_ptr<CClipboardManager> m_clipboard;
|
||||
|
||||
std::function<void()> m_onSettingChange;
|
||||
std::function<bool()> m_onEnsureOnlyDisplay;
|
||||
@@ -80,6 +83,8 @@ public:
|
||||
uint32_t requiredSizeMiB);
|
||||
void setRecoveryMode(bool active);
|
||||
|
||||
bool initClipboard(CClipboardChannel& channel);
|
||||
|
||||
HWND hwndDialog();
|
||||
void close();
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "CPipeClient.h"
|
||||
#include "CClipboardRing.h"
|
||||
#include "CDebug.h"
|
||||
#include "CSRWLock.h"
|
||||
#include "CNotifyWindow.h"
|
||||
@@ -399,7 +400,11 @@ bool CPipeClient::Init()
|
||||
|
||||
void CPipeClient::DeInit()
|
||||
{
|
||||
// Stop first so no endpoint callback can race mapping teardown.
|
||||
m_endpoint.Stop();
|
||||
|
||||
CSRWExclusiveLock lock(m_clipboardSetupLock);
|
||||
ResetClipboardSetupLocked();
|
||||
}
|
||||
|
||||
bool CPipeClient::IsLGIddDeviceAttached()
|
||||
@@ -484,6 +489,88 @@ void CPipeClient::OnPipeConnected()
|
||||
|
||||
if (hasStatus)
|
||||
WriteMsg(status);
|
||||
|
||||
if (!m_clipboardEnabled)
|
||||
return;
|
||||
|
||||
CSRWExclusiveLock setupLock(m_clipboardSetupLock);
|
||||
ResetClipboardSetupLocked();
|
||||
|
||||
LARGE_INTEGER size = {};
|
||||
size.QuadPart = sizeof(ClipboardMapping);
|
||||
m_clipboardMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr,
|
||||
PAGE_READWRITE, size.HighPart, size.LowPart, nullptr);
|
||||
if (!m_clipboardMapping)
|
||||
{
|
||||
DEBUG_ERROR_HR(GetLastError(),
|
||||
"Failed to create the clipboard mapping");
|
||||
return;
|
||||
}
|
||||
|
||||
ClipboardMapping * view = static_cast<ClipboardMapping *>(MapViewOfFile(
|
||||
m_clipboardMapping, FILE_MAP_ALL_ACCESS, 0, 0,
|
||||
sizeof(ClipboardMapping)));
|
||||
if (!view)
|
||||
{
|
||||
DEBUG_ERROR_HR(GetLastError(),
|
||||
"Failed to initialize the clipboard mapping");
|
||||
ResetClipboardSetupLocked();
|
||||
return;
|
||||
}
|
||||
|
||||
++m_clipboardEpochCounter;
|
||||
if (!m_clipboardEpochCounter)
|
||||
++m_clipboardEpochCounter;
|
||||
m_clipboardEpoch = m_clipboardEpochCounter;
|
||||
CClipboardRing::Initialize(*view, m_clipboardEpoch);
|
||||
UnmapViewOfFile(view);
|
||||
|
||||
DWORD serverPid = 0;
|
||||
if (!GetNamedPipeServerProcessId(m_endpoint.NativeHandle(), &serverPid))
|
||||
{
|
||||
DEBUG_ERROR_HR(GetLastError(),
|
||||
"Failed to identify the clipboard mapping target");
|
||||
ResetClipboardSetupLocked();
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE target = OpenProcess(PROCESS_DUP_HANDLE, FALSE, serverPid);
|
||||
HANDLE remote = nullptr;
|
||||
if (!target || !DuplicateHandle(GetCurrentProcess(),
|
||||
m_clipboardMapping, target, &remote, 0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
DEBUG_ERROR_HR(GetLastError(),
|
||||
"Failed to share the clipboard mapping with the IDD");
|
||||
if (target)
|
||||
CloseHandle(target);
|
||||
ResetClipboardSetupLocked();
|
||||
return;
|
||||
}
|
||||
|
||||
LGPipeMsg setup = {};
|
||||
setup.size = sizeof(setup);
|
||||
setup.type = LGPipeMsg::CLIPBOARD_SETUP;
|
||||
setup.clipboardSetup.handle =
|
||||
static_cast<uint64_t>(reinterpret_cast<uintptr_t>(remote));
|
||||
setup.clipboardSetup.bytes = sizeof(ClipboardMapping);
|
||||
const bool sent = m_endpoint.Send(&setup, sizeof(setup));
|
||||
if (!sent)
|
||||
{
|
||||
DEBUG_WARN("Failed to send clipboard mapping setup");
|
||||
HANDLE reclaimed = nullptr;
|
||||
if (DuplicateHandle(target, remote, GetCurrentProcess(), &reclaimed,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
|
||||
CloseHandle(reclaimed);
|
||||
ResetClipboardSetupLocked();
|
||||
}
|
||||
CloseHandle(target);
|
||||
}
|
||||
|
||||
void CPipeClient::OnPipeDisconnected()
|
||||
{
|
||||
CSRWExclusiveLock lock(m_clipboardSetupLock);
|
||||
ResetClipboardSetupLocked();
|
||||
}
|
||||
|
||||
void CPipeClient::ReloadSettings()
|
||||
@@ -740,12 +827,85 @@ bool CPipeClient::OnPipeMessage(const void * message, size_t size)
|
||||
HandleSetRecovery(msg);
|
||||
return true;
|
||||
|
||||
case LGPipeMsg::CLIPBOARD_READY:
|
||||
{
|
||||
CSRWExclusiveLock setupLock(m_clipboardSetupLock);
|
||||
|
||||
if (msg.clipboardReady.status != ERROR_SUCCESS ||
|
||||
msg.clipboardReady.epoch != m_clipboardEpoch)
|
||||
{
|
||||
DEBUG_WARN("IDD rejected the clipboard mapping (%u)",
|
||||
msg.clipboardReady.status);
|
||||
ResetClipboardSetupLocked();
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE mapping = nullptr;
|
||||
if (!m_clipboardMapping ||
|
||||
!DuplicateHandle(GetCurrentProcess(), m_clipboardMapping,
|
||||
GetCurrentProcess(), &mapping, 0, FALSE, DUPLICATE_SAME_ACCESS) ||
|
||||
!m_clipboard.Attach(mapping, m_clipboardEpoch, true, *this))
|
||||
{
|
||||
DEBUG_ERROR("Failed to activate the clipboard mapping");
|
||||
const uint64_t epoch = m_clipboardEpoch;
|
||||
ResetClipboardSetupLocked();
|
||||
setupLock.Unlock();
|
||||
|
||||
// Tell the IDD that its successful mapping is unusable here, so it
|
||||
// does not leave a one-sided channel advertised as available.
|
||||
LGPipeMsg failure = {};
|
||||
failure.size = sizeof(failure);
|
||||
failure.type = LGPipeMsg::CLIPBOARD_READY;
|
||||
failure.clipboardReady.epoch = epoch;
|
||||
failure.clipboardReady.status = ERROR_NOT_READY;
|
||||
m_endpoint.Send(&failure, sizeof(failure));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case LGPipeMsg::CLIPBOARD_KICK:
|
||||
m_clipboard.Kick(msg.clipboardKick.epoch);
|
||||
return true;
|
||||
|
||||
case LGPipeMsg::CLIPBOARD_RESET:
|
||||
m_clipboard.Reset(
|
||||
msg.clipboardReset.epoch, msg.clipboardReset.reason);
|
||||
return true;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unknown message type %d", msg.type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CPipeClient::ClipboardKick(uint64_t epoch)
|
||||
{
|
||||
LGPipeMsg msg = {};
|
||||
msg.size = sizeof(msg);
|
||||
msg.type = LGPipeMsg::CLIPBOARD_KICK;
|
||||
msg.clipboardKick.epoch = epoch;
|
||||
return m_endpoint.Send(&msg, sizeof(msg));
|
||||
}
|
||||
|
||||
void CPipeClient::ClipboardResetPeer(uint64_t epoch, uint32_t reason)
|
||||
{
|
||||
LGPipeMsg msg = {};
|
||||
msg.size = sizeof(msg);
|
||||
msg.type = LGPipeMsg::CLIPBOARD_RESET;
|
||||
msg.clipboardReset.epoch = epoch;
|
||||
msg.clipboardReset.reason = reason;
|
||||
m_endpoint.Send(&msg, sizeof(msg));
|
||||
}
|
||||
|
||||
void CPipeClient::ResetClipboardSetupLocked()
|
||||
{
|
||||
m_clipboard.Detach();
|
||||
if (m_clipboardMapping)
|
||||
CloseHandle(m_clipboardMapping);
|
||||
m_clipboardMapping = nullptr;
|
||||
m_clipboardEpoch = 0;
|
||||
}
|
||||
|
||||
void CPipeClient::HandleSetCursorPos(const LGPipeMsg& msg)
|
||||
{
|
||||
SetActiveDesktop();
|
||||
|
||||
@@ -24,14 +24,22 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "CPipeEndpoint.h"
|
||||
#include "CClipboardChannel.h"
|
||||
#include "CSRWLock.h"
|
||||
#include "PipeMsg.h"
|
||||
|
||||
class CPipeClient : private IPipeEndpointHandler
|
||||
class CPipeClient : private IPipeEndpointHandler,
|
||||
public IClipboardChannelDoorbell
|
||||
{
|
||||
private:
|
||||
CPipeEndpoint m_endpoint;
|
||||
CSRWLock m_displayLock;
|
||||
CPipeEndpoint m_endpoint;
|
||||
CClipboardChannel m_clipboard;
|
||||
CSRWLock m_clipboardSetupLock;
|
||||
HANDLE m_clipboardMapping = nullptr;
|
||||
uint64_t m_clipboardEpoch = 0;
|
||||
uint64_t m_clipboardEpochCounter = 0;
|
||||
bool m_clipboardEnabled = false;
|
||||
CSRWLock m_displayLock;
|
||||
|
||||
bool m_recoveryActive = false;
|
||||
bool m_hasRecoveryStatus = false;
|
||||
@@ -50,8 +58,10 @@ private:
|
||||
void HandleGPUStatus(const LGPipeMsg& msg);
|
||||
void HandleResolutionRejected(const LGPipeMsg& msg);
|
||||
void HandleSetRecovery(const LGPipeMsg& msg);
|
||||
void ResetClipboardSetupLocked();
|
||||
|
||||
void OnPipeConnected() override;
|
||||
void OnPipeDisconnected() override;
|
||||
bool ShouldReconnect() override;
|
||||
bool OnPipeMessage(const void * message, size_t size) override;
|
||||
|
||||
@@ -64,6 +74,11 @@ public:
|
||||
void DeInit();
|
||||
bool IsRunning() { return m_endpoint.IsRunning(); }
|
||||
|
||||
CClipboardChannel& Clipboard() { return m_clipboard; }
|
||||
void EnableClipboard() { m_clipboardEnabled = true; }
|
||||
bool ClipboardKick(uint64_t epoch) override;
|
||||
void ClipboardResetPeer(uint64_t epoch, uint32_t reason) override;
|
||||
|
||||
void ReloadSettings();
|
||||
bool EnsureOnlyDisplay();
|
||||
};
|
||||
|
||||
@@ -191,6 +191,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CButton.cpp" />
|
||||
<ClCompile Include="CCheckbox.cpp" />
|
||||
<ClCompile Include="CClipboardManager.cpp" />
|
||||
<ClCompile Include="CConfigWindow.cpp" />
|
||||
<ClCompile Include="CEditWidget.cpp" />
|
||||
<ClCompile Include="CGroupBox.cpp" />
|
||||
@@ -207,6 +208,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CButton.h" />
|
||||
<ClInclude Include="CCheckbox.h" />
|
||||
<ClInclude Include="CClipboardManager.h" />
|
||||
<ClInclude Include="CConfigWindow.h" />
|
||||
<ClInclude Include="CEditWidget.h" />
|
||||
<ClInclude Include="CGroupBox.h" />
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
<ClCompile Include="CCheckbox.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CClipboardManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CPipeClient.h">
|
||||
@@ -98,6 +101,9 @@
|
||||
<ClInclude Include="CCheckbox.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CClipboardManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Resources.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -136,6 +136,11 @@ int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _
|
||||
|
||||
CNotifyWindow& window = CNotifyWindow::instance();
|
||||
|
||||
if (!window.initClipboard(g_pipe.Clipboard()))
|
||||
DEBUG_ERROR("Failed to initialize clipboard synchronization");
|
||||
else
|
||||
g_pipe.EnableClipboard();
|
||||
|
||||
// the pipe must be initialized after the CNotifyWindow
|
||||
// has been created to avoid a potential race
|
||||
if (!g_pipe.Init())
|
||||
|
||||
Reference in New Issue
Block a user