[client] clipboard: add direct LGMP synchronization

This commit is contained in:
Geoffrey McRae
2026-08-14 06:27:12 +10:00
parent b786167f72
commit be2f79a412
21 changed files with 5228 additions and 350 deletions

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.10)
project(transport_LGMP LANGUAGES C)
add_library(transport_LGMP STATIC
clipboard.c
input.c
lgmp.c
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
/**
* 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
*/
#ifndef _H_LG_CLIENT_TRANSPORT_LGMP_CLIPBOARD_
#define _H_LG_CLIENT_TRANSPORT_LGMP_CLIPBOARD_
#include "interface/clipboard.h"
#include <lgmp/client.h>
#include <stdbool.h>
#include <stdint.h>
typedef struct LGMPClipboard LGMPClipboard;
bool lgmpClipboard_create(PLGMPClient client, LGMPClipboard ** result);
void lgmpClipboard_destroy(LGMPClipboard ** clipboard);
bool lgmpClipboard_connect(LGMPClipboard * clipboard, uint32_t clientID);
void lgmpClipboard_disconnect(LGMPClipboard * clipboard);
const LG_ClipboardOps * lgmpClipboard_getOps(void);
#endif

View File

@@ -20,6 +20,7 @@
#include "interface/transport.h"
#include "clipboard.h"
#include "input.h"
#include "common/KVMFR.h"
@@ -109,6 +110,7 @@ struct LG_Transport
PLGMPClientQueue ownerFrameQueue[LGMP_Q_FRAME_LEN];
PLGMPClientQueue pointerQueue;
LGMPInput * input;
LGMPClipboard * clipboard;
LG_Lock frameLock;
LG_Lock pointerLock;
LG_RWLock videoStatusLock;
@@ -133,6 +135,7 @@ struct LG_Transport
bool frameStopRequested;
bool frameScheduleSupported;
atomic_bool inputSupported;
atomic_bool clipboardSupported;
uint64_t frameLeaseHandle;
uint32_t frameGeneration;
uint32_t clientID;
@@ -628,6 +631,13 @@ static LGMP_STATUS lgmp_initializeClient(struct LG_Transport * this)
return LGMP_ERR_NO_MEM;
}
if (!lgmpClipboard_create(this->client, &this->clipboard))
{
lgmpInput_destroy(&this->input);
lgmpClientFree(&this->client);
return LGMP_ERR_NO_MEM;
}
return LGMP_OK;
}
@@ -650,6 +660,7 @@ static bool lgmp_create(LG_Transport ** result)
this->cursorPollInterval = cursorPoll;
atomic_init(&this->connected, false);
atomic_init(&this->inputSupported, false);
atomic_init(&this->clipboardSupported, false);
atomic_init(&this->destroyPending, false);
this->frameWake = lgCreateEvent(true, 0);
@@ -860,6 +871,7 @@ static void lgmp_destroyNow(LG_Transport * this)
{
if (this->client)
{
lgmpClipboard_destroy(&this->clipboard);
lgmpInput_destroy(&this->input);
lgmp_closeQueues(this);
lgmpClientFree(&this->client);
@@ -958,6 +970,8 @@ static bool lgmp_parseSession(struct LG_Transport * this,
session->features |= LG_TRANSPORT_FEATURE_FRAME_SCHEDULE;
if (header->features & KVMFR_FEATURE_INPUT)
session->features |= LG_TRANSPORT_FEATURE_INPUT;
if (header->features & KVMFR_FEATURE_CLIPBOARD)
session->features |= LG_TRANSPORT_FEATURE_CLIPBOARD;
data += sizeof(*header);
size -= sizeof(*header);
@@ -1076,6 +1090,9 @@ static LG_TransportStatus lgmp_connectInternal(LG_Transport * this,
atomic_store_explicit(&this->inputSupported,
session->features & LG_TRANSPORT_FEATURE_INPUT,
memory_order_release);
atomic_store_explicit(&this->clipboardSupported,
session->features & LG_TRANSPORT_FEATURE_CLIPBOARD,
memory_order_release);
this->frameSerial = 0;
this->frameSerialValid = false;
this->formatValid = false;
@@ -1136,6 +1153,7 @@ static void lgmp_disconnect(LG_Transport * this)
lgmp_retainVideoStatusLifetime(this);
lgmpInput_disconnect(this->input);
lgmpClipboard_disconnect(this->clipboard);
LG_LOCK(this->frameLock);
if (++this->frameGeneration == 0)
@@ -1145,6 +1163,8 @@ static void lgmp_disconnect(LG_Transport * this)
this->frameScheduleSupported = false;
atomic_store_explicit(
&this->inputSupported, false, memory_order_release);
atomic_store_explicit(
&this->clipboardSupported, false, memory_order_release);
this->clientID = 0;
LG_UNLOCK(this->frameLock);
@@ -2474,6 +2494,20 @@ static const LG_InputOps * lgmp_getInputOps(LG_Transport * this,
return lgmpInput_getOps();
}
static const LG_ClipboardOps * lgmp_getClipboardOps(
LG_Transport * this, void ** opaque)
{
*opaque = NULL;
if (!atomic_load_explicit(&this->connected, memory_order_acquire) ||
!atomic_load_explicit(
&this->clipboardSupported, memory_order_acquire) ||
!lgmpClipboard_connect(this->clipboard, this->clientID))
return NULL;
*opaque = this->clipboard;
return lgmpClipboard_getOps();
}
static void lgmp_probeVideoStatus(LG_Transport * this)
{
bool frameAvailable = false;
@@ -2617,6 +2651,7 @@ const LG_TransportOps LGT_LGMP =
.sessionValid = lgmp_sessionValid,
.getVideoOps = lgmp_getVideoOps,
.getInputOps = lgmp_getInputOps,
.getClipboardOps = lgmp_getClipboardOps,
.getRecoveryInfo = lgmp_getRecoveryInfo,
.requestRecovery = lgmp_requestRecovery,
.sendControl = lgmp_sendControl,