mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
[client] clipboard: add seamless file backends
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "clipboard.h"
|
||||
#include "clipboard_files.h"
|
||||
#include "main.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
@@ -83,6 +84,7 @@ static struct
|
||||
LG_Lock requestLock;
|
||||
LG_Lock writeLock;
|
||||
LG_Lock callbackLock;
|
||||
LG_Lock fileLock;
|
||||
|
||||
ClipboardBinding fallback;
|
||||
ClipboardBinding transport;
|
||||
@@ -91,10 +93,12 @@ static struct
|
||||
bool localAvailable;
|
||||
LG_ClipboardData localTypes[LG_CLIPBOARD_DATA_NONE];
|
||||
size_t localTypeCount;
|
||||
uint64_t localFileDataset;
|
||||
|
||||
bool remoteNotice;
|
||||
LG_ClipboardData remoteType;
|
||||
uint32_t remoteGeneration;
|
||||
uint64_t remoteFileDataset;
|
||||
|
||||
bool remoteRequest;
|
||||
ClipboardBinding remoteRequestBinding;
|
||||
@@ -371,18 +375,22 @@ static void resetRemote(void)
|
||||
bool release;
|
||||
LG_ClipboardRequest transfer;
|
||||
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
LG_LOCK(clipboard.requestLock);
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
release = clipboard.remoteNotice && clipboard.localAvailable &&
|
||||
g_params.clipboardToLocal;
|
||||
clipboard.remoteNotice = false;
|
||||
clipboard.remoteType = LG_CLIPBOARD_DATA_NONE;
|
||||
clipboard.remoteGeneration = nextGeneration(
|
||||
clipboard.remoteNotice = false;
|
||||
clipboard.remoteType = LG_CLIPBOARD_DATA_NONE;
|
||||
clipboard.remoteFileDataset = 0;
|
||||
clipboard.remoteGeneration = nextGeneration(
|
||||
clipboard.remoteGeneration);
|
||||
transfer = clearRemoteRequestNL();
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
LG_UNLOCK(clipboard.requestLock);
|
||||
|
||||
lgClipboardFiles_providerUnavailable();
|
||||
|
||||
LG_LOCK(clipboard.callbackLock);
|
||||
cancelRequestsNL(NULL, 0, true, LG_CLIPBOARD_CANCEL_UNAVAILABLE);
|
||||
if (transfer != LG_CLIPBOARD_REQUEST_INVALID &&
|
||||
@@ -396,6 +404,7 @@ static void resetRemote(void)
|
||||
if (release)
|
||||
g_state.ds->cbRelease();
|
||||
LG_UNLOCK(clipboard.callbackLock);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
}
|
||||
|
||||
static bool validOps(const LG_ClipboardOps * ops)
|
||||
@@ -435,11 +444,18 @@ static void publishLocal(const ClipboardBinding * binding)
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
count = g_params.clipboardToVM ? clipboard.localTypeCount : 0;
|
||||
memcpy(types, clipboard.localTypes, count * sizeof(*types));
|
||||
const uint64_t fileDataset = clipboard.localFileDataset;
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
|
||||
const bool result = count ?
|
||||
binding->ops->notifyTypes(binding->opaque, types, count) :
|
||||
binding->ops->release(binding->opaque);
|
||||
bool result;
|
||||
if (count == 1 && types[0] == LG_CLIPBOARD_DATA_FILES)
|
||||
result = fileDataset && binding->ops->offerFiles ?
|
||||
binding->ops->offerFiles(binding->opaque, fileDataset) :
|
||||
binding->ops->release(binding->opaque);
|
||||
else
|
||||
result = count ? binding->ops->notifyTypes(
|
||||
binding->opaque, types, count) :
|
||||
binding->ops->release(binding->opaque);
|
||||
if (!result)
|
||||
DEBUG_WARN("Failed to publish the local clipboard to %s",
|
||||
binding->ops->name);
|
||||
@@ -454,39 +470,60 @@ static void eventNotice(void * opaque,
|
||||
return;
|
||||
|
||||
LG_ClipboardData type = LG_CLIPBOARD_DATA_NONE;
|
||||
bool hasFiles = false;
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
if (validType(types[i]))
|
||||
{
|
||||
type = types[i];
|
||||
break;
|
||||
if (types[i] == LG_CLIPBOARD_DATA_FILES)
|
||||
{
|
||||
type = LG_CLIPBOARD_DATA_FILES;
|
||||
hasFiles = true;
|
||||
}
|
||||
else if (type == LG_CLIPBOARD_DATA_NONE)
|
||||
type = types[i];
|
||||
}
|
||||
if (type == LG_CLIPBOARD_DATA_NONE)
|
||||
return;
|
||||
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (!bindingActiveNL(binding))
|
||||
{
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return;
|
||||
}
|
||||
|
||||
const ClipboardBinding current = *binding;
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
bool notice;
|
||||
bool release;
|
||||
uint32_t generation;
|
||||
uint64_t fileDataset;
|
||||
LG_ClipboardRequest transfer;
|
||||
|
||||
LG_LOCK(clipboard.requestLock);
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
clipboard.remoteNotice = true;
|
||||
clipboard.remoteType = type;
|
||||
const bool previousNotice = clipboard.remoteNotice;
|
||||
const bool usable = !hasFiles || clipboard.remoteFileDataset;
|
||||
clipboard.remoteNotice = usable;
|
||||
clipboard.remoteType = usable ? type : LG_CLIPBOARD_DATA_NONE;
|
||||
clipboard.remoteGeneration = nextGeneration(
|
||||
clipboard.remoteGeneration);
|
||||
generation = clipboard.remoteGeneration;
|
||||
if (!hasFiles || !usable)
|
||||
clipboard.remoteFileDataset = 0;
|
||||
fileDataset = clipboard.remoteFileDataset;
|
||||
transfer = clearRemoteRequestNL();
|
||||
notice = clipboard.localAvailable && g_params.clipboardToLocal;
|
||||
notice = usable && clipboard.localAvailable &&
|
||||
g_params.clipboardToLocal;
|
||||
release = !usable && previousNotice && clipboard.localAvailable &&
|
||||
g_params.clipboardToLocal;
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
LG_UNLOCK(clipboard.requestLock);
|
||||
if (!hasFiles)
|
||||
lgClipboardFiles_remoteClear();
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
|
||||
LG_LOCK(clipboard.callbackLock);
|
||||
cancelRequestsNL(¤t, generation, false,
|
||||
@@ -498,12 +535,21 @@ static void eventNotice(void * opaque,
|
||||
notice = notice && clipboard.localAvailable &&
|
||||
clipboard.remoteNotice &&
|
||||
clipboard.remoteGeneration == generation;
|
||||
release = release && clipboard.localAvailable &&
|
||||
!clipboard.remoteNotice &&
|
||||
clipboard.remoteGeneration == generation;
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
const bool active = bindingActiveNL(¤t);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
if (notice && active)
|
||||
g_state.ds->cbNotice(type);
|
||||
{
|
||||
if (type != LG_CLIPBOARD_DATA_FILES ||
|
||||
lgClipboardFiles_remoteReady(fileDataset))
|
||||
g_state.ds->cbNotice(type);
|
||||
}
|
||||
else if (release && active && g_state.ds->cbRelease)
|
||||
g_state.ds->cbRelease();
|
||||
LG_UNLOCK(clipboard.callbackLock);
|
||||
}
|
||||
|
||||
@@ -892,14 +938,19 @@ static void eventRelease(void * opaque)
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
release = clipboard.remoteNotice && clipboard.localAvailable &&
|
||||
g_params.clipboardToLocal;
|
||||
clipboard.remoteNotice = false;
|
||||
clipboard.remoteType = LG_CLIPBOARD_DATA_NONE;
|
||||
clipboard.remoteGeneration = nextGeneration(
|
||||
clipboard.remoteNotice = false;
|
||||
clipboard.remoteType = LG_CLIPBOARD_DATA_NONE;
|
||||
clipboard.remoteFileDataset = 0;
|
||||
clipboard.remoteGeneration = nextGeneration(
|
||||
clipboard.remoteGeneration);
|
||||
transfer = clearRemoteRequestNL();
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
LG_UNLOCK(clipboard.requestLock);
|
||||
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
lgClipboardFiles_remoteClear();
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
|
||||
LG_LOCK(clipboard.callbackLock);
|
||||
cancelRequestsNL(NULL, 0, true, LG_CLIPBOARD_CANCEL_REPLACED);
|
||||
if (transfer != LG_CLIPBOARD_REQUEST_INVALID &&
|
||||
@@ -1024,6 +1075,163 @@ static void eventRequestCancel(void * opaque, LG_ClipboardRequest id,
|
||||
LG_UNLOCK(clipboard.callbackLock);
|
||||
}
|
||||
|
||||
static bool fileEventBindingActive(void * opaque)
|
||||
{
|
||||
ClipboardBinding * binding = opaque;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
const bool active = bindingActiveNL(binding);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return active;
|
||||
}
|
||||
|
||||
static void eventFileOffer(void * opaque, uint64_t dataset)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
const bool active = fileEventBindingActive(opaque);
|
||||
if (!active || !dataset)
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return;
|
||||
}
|
||||
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
clipboard.remoteFileDataset = dataset;
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
if (!lgClipboardFiles_remoteOffer(dataset))
|
||||
{
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
if (clipboard.remoteFileDataset == dataset)
|
||||
clipboard.remoteFileDataset = 0;
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
lgClipboardFiles_remoteClear();
|
||||
}
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
}
|
||||
|
||||
static void eventFileAcquire(void * opaque, uint64_t dataset,
|
||||
uint64_t acquisition)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return;
|
||||
}
|
||||
lgClipboardFiles_localAcquire(dataset, acquisition);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
}
|
||||
|
||||
static void eventFileAcquired(void * opaque, uint64_t dataset,
|
||||
uint64_t acquisition, LG_ClipboardFileError error)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return;
|
||||
}
|
||||
lgClipboardFiles_remoteAcquired(dataset, acquisition, error);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
}
|
||||
|
||||
static void eventFileRelease(void * opaque, uint64_t dataset,
|
||||
uint64_t acquisition)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return;
|
||||
}
|
||||
lgClipboardFiles_localRelease(dataset, acquisition);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
}
|
||||
|
||||
static void eventFileRequest(void * opaque,
|
||||
const LG_ClipboardFileRequest * request)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return;
|
||||
}
|
||||
lgClipboardFiles_localRequest(request);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
}
|
||||
|
||||
static LG_ClipboardResult eventFileDataBegin(void * opaque,
|
||||
const LG_ClipboardFileRequest * request, uint64_t sizeHint)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return LG_CLIPBOARD_RESULT_FAILED;
|
||||
}
|
||||
const LG_ClipboardResult result =
|
||||
lgClipboardFiles_remoteDataBegin(request, sizeHint);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static LG_ClipboardResult eventFileDataChunk(void * opaque,
|
||||
const LG_ClipboardFileRequest * request, uint64_t responseOffset,
|
||||
const void * data, size_t size)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return LG_CLIPBOARD_RESULT_FAILED;
|
||||
}
|
||||
const LG_ClipboardResult result = lgClipboardFiles_remoteDataChunk(
|
||||
request, responseOffset, data, size);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static LG_ClipboardResult eventFileDataEnd(void * opaque,
|
||||
const LG_ClipboardFileRequest * request, uint64_t finalSize)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return LG_CLIPBOARD_RESULT_FAILED;
|
||||
}
|
||||
const LG_ClipboardResult result =
|
||||
lgClipboardFiles_remoteDataEnd(request, finalSize);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void eventFileDataReady(void * opaque, uint64_t request)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return;
|
||||
}
|
||||
lgClipboardFiles_localReady(request);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
}
|
||||
|
||||
static void eventFileCancel(void * opaque, uint64_t dataset,
|
||||
uint64_t request, LG_ClipboardFileError reason)
|
||||
{
|
||||
LG_LOCK(clipboard.fileLock);
|
||||
if (!fileEventBindingActive(opaque))
|
||||
{
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
return;
|
||||
}
|
||||
lgClipboardFiles_remoteCancel(dataset, request, reason);
|
||||
lgClipboardFiles_localCancel(dataset, request, reason);
|
||||
LG_UNLOCK(clipboard.fileLock);
|
||||
}
|
||||
|
||||
static const LG_ClipboardEventOps eventOps =
|
||||
{
|
||||
.notice = eventNotice,
|
||||
@@ -1036,6 +1244,16 @@ static const LG_ClipboardEventOps eventOps =
|
||||
.requestCancel = eventRequestCancel,
|
||||
.release = eventRelease,
|
||||
.request = eventRequest,
|
||||
.fileOffer = eventFileOffer,
|
||||
.fileAcquire = eventFileAcquire,
|
||||
.fileAcquired = eventFileAcquired,
|
||||
.fileRelease = eventFileRelease,
|
||||
.fileRequest = eventFileRequest,
|
||||
.fileDataBegin = eventFileDataBegin,
|
||||
.fileDataChunk = eventFileDataChunk,
|
||||
.fileDataEnd = eventFileDataEnd,
|
||||
.fileDataReady = eventFileDataReady,
|
||||
.fileCancel = eventFileCancel,
|
||||
};
|
||||
|
||||
/* providerLock must be held. dropActive suppresses all calls into an endpoint
|
||||
@@ -1168,7 +1386,7 @@ static void setBinding(ClipboardBinding * target,
|
||||
LG_UNLOCK(clipboard.registrationLock);
|
||||
}
|
||||
|
||||
void lgClipboard_init(void)
|
||||
bool lgClipboard_init(void)
|
||||
{
|
||||
memset(&clipboard, 0, sizeof(clipboard));
|
||||
LG_LOCK_INIT(clipboard.registrationLock);
|
||||
@@ -1178,9 +1396,16 @@ void lgClipboard_init(void)
|
||||
LG_LOCK_INIT(clipboard.requestLock);
|
||||
LG_LOCK_INIT(clipboard.writeLock);
|
||||
LG_LOCK_INIT(clipboard.callbackLock);
|
||||
LG_LOCK_INIT(clipboard.fileLock);
|
||||
clipboard.remoteType = LG_CLIPBOARD_DATA_NONE;
|
||||
clipboard.remoteRequestType = LG_CLIPBOARD_DATA_NONE;
|
||||
clipboard.requests = ll_new();
|
||||
if (!lgClipboardFiles_init())
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize clipboard file transfer");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void lgClipboard_free(void)
|
||||
@@ -1188,6 +1413,7 @@ void lgClipboard_free(void)
|
||||
lgClipboard_setLocalAvailable(false);
|
||||
lgClipboard_setTransport(NULL, NULL);
|
||||
lgClipboard_setFallback(NULL, NULL);
|
||||
lgClipboardFiles_free();
|
||||
LG_LOCK(clipboard.callbackLock);
|
||||
cancelRequestsNL(NULL, 0, true, LG_CLIPBOARD_CANCEL_UNAVAILABLE);
|
||||
LG_UNLOCK(clipboard.callbackLock);
|
||||
@@ -1201,6 +1427,7 @@ void lgClipboard_free(void)
|
||||
LG_LOCK_FREE(clipboard.requestLock);
|
||||
LG_LOCK_FREE(clipboard.stateLock);
|
||||
LG_LOCK_FREE(clipboard.callbackLock);
|
||||
LG_LOCK_FREE(clipboard.fileLock);
|
||||
LG_RWLOCK_FREE(clipboard.activeLock);
|
||||
LG_LOCK_FREE(clipboard.providerLock);
|
||||
LG_LOCK_FREE(clipboard.registrationLock);
|
||||
@@ -1211,6 +1438,7 @@ void lgClipboard_setLocalAvailable(bool available)
|
||||
bool notice;
|
||||
bool release;
|
||||
LG_ClipboardData type;
|
||||
uint64_t fileDataset;
|
||||
LG_ClipboardRequest transfer = LG_CLIPBOARD_REQUEST_INVALID;
|
||||
|
||||
LG_LOCK(clipboard.callbackLock);
|
||||
@@ -1222,13 +1450,18 @@ void lgClipboard_setLocalAvailable(bool available)
|
||||
notice = available && clipboard.remoteNotice &&
|
||||
g_params.clipboardToLocal;
|
||||
type = clipboard.remoteType;
|
||||
fileDataset = clipboard.remoteFileDataset;
|
||||
if (!available)
|
||||
transfer = clearRemoteRequestNL();
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
LG_UNLOCK(clipboard.requestLock);
|
||||
|
||||
if (notice)
|
||||
g_state.ds->cbNotice(type);
|
||||
{
|
||||
if (type != LG_CLIPBOARD_DATA_FILES ||
|
||||
lgClipboardFiles_remoteReady(fileDataset))
|
||||
g_state.ds->cbNotice(type);
|
||||
}
|
||||
if (!available)
|
||||
{
|
||||
cancelRequestsNL(NULL, 0, true, LG_CLIPBOARD_CANCEL_UNAVAILABLE);
|
||||
@@ -1285,6 +1518,7 @@ void lgClipboard_release(void)
|
||||
LG_LOCK(clipboard.writeLock);
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
clipboard.localTypeCount = 0;
|
||||
clipboard.localFileDataset = 0;
|
||||
clearRemoteRequestNL();
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
|
||||
@@ -1310,13 +1544,14 @@ void lgClipboard_notifyTypes(
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
if (!validType(types[i]))
|
||||
if (!validType(types[i]) || types[i] == LG_CLIPBOARD_DATA_FILES)
|
||||
return;
|
||||
|
||||
LG_LOCK(clipboard.writeLock);
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
memcpy(clipboard.localTypes, types, count * sizeof(*types));
|
||||
clipboard.localTypeCount = count;
|
||||
clipboard.localFileDataset = 0;
|
||||
clearRemoteRequestNL();
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
|
||||
@@ -1329,6 +1564,30 @@ void lgClipboard_notifyTypes(
|
||||
LG_UNLOCK(clipboard.writeLock);
|
||||
}
|
||||
|
||||
void lgClipboard_notifyFiles(uint64_t dataset)
|
||||
{
|
||||
if (!g_params.clipboardToVM || !dataset)
|
||||
return;
|
||||
|
||||
LG_LOCK(clipboard.writeLock);
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
clipboard.localTypes[0] = LG_CLIPBOARD_DATA_FILES;
|
||||
clipboard.localTypeCount = 1;
|
||||
clipboard.localFileDataset = dataset;
|
||||
clearRemoteRequestNL();
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
const bool result = !clipboard.active.ops ||
|
||||
(clipboard.active.ops->offerFiles ?
|
||||
clipboard.active.ops->offerFiles(clipboard.active.opaque, dataset) :
|
||||
clipboard.active.ops->release(clipboard.active.opaque));
|
||||
if (!result)
|
||||
DEBUG_WARN("Failed to publish the local clipboard file dataset");
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
LG_UNLOCK(clipboard.writeLock);
|
||||
}
|
||||
|
||||
/* writeLock and activeLock must be held. */
|
||||
static bool cancelRemoteNL(LG_ClipboardCancelReason reason)
|
||||
{
|
||||
@@ -1864,3 +2123,139 @@ bool lgClipboard_request(LG_ClipboardData type,
|
||||
return false;
|
||||
return requestClipboard(type, replyFn, NULL, opaque, NULL);
|
||||
}
|
||||
|
||||
bool lgClipboard_fileAcquire(uint64_t dataset, uint64_t acquisition)
|
||||
{
|
||||
bool result = false;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (clipboard.active.ops && clipboard.active.ops->fileAcquire)
|
||||
result = clipboard.active.ops->fileAcquire(
|
||||
clipboard.active.opaque, dataset, acquisition);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lgClipboard_fileAcquired(uint64_t dataset, uint64_t acquisition,
|
||||
LG_ClipboardFileError error)
|
||||
{
|
||||
bool result = false;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (clipboard.active.ops && clipboard.active.ops->fileAcquired)
|
||||
result = clipboard.active.ops->fileAcquired(
|
||||
clipboard.active.opaque, dataset, acquisition, error);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lgClipboard_fileRelease(uint64_t dataset, uint64_t acquisition)
|
||||
{
|
||||
bool result = false;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (clipboard.active.ops && clipboard.active.ops->fileRelease)
|
||||
result = clipboard.active.ops->fileRelease(
|
||||
clipboard.active.opaque, dataset, acquisition);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lgClipboard_fileRequest(const LG_ClipboardFileRequest * request)
|
||||
{
|
||||
bool result = false;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (clipboard.active.ops && clipboard.active.ops->fileRequest)
|
||||
result = clipboard.active.ops->fileRequest(
|
||||
clipboard.active.opaque, request);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
LG_ClipboardResult lgClipboard_fileDataBegin(
|
||||
const LG_ClipboardFileRequest * request, uint64_t sizeHint)
|
||||
{
|
||||
LG_ClipboardResult result = LG_CLIPBOARD_RESULT_FAILED;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (clipboard.active.ops && clipboard.active.ops->fileDataBegin)
|
||||
result = clipboard.active.ops->fileDataBegin(
|
||||
clipboard.active.opaque, request, sizeHint);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
LG_ClipboardResult lgClipboard_fileDataChunk(
|
||||
const LG_ClipboardFileRequest * request, uint64_t responseOffset,
|
||||
const void * data, size_t size)
|
||||
{
|
||||
LG_ClipboardResult result = LG_CLIPBOARD_RESULT_FAILED;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (clipboard.active.ops && clipboard.active.ops->fileDataChunk)
|
||||
result = clipboard.active.ops->fileDataChunk(
|
||||
clipboard.active.opaque, request, responseOffset, data, size);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
LG_ClipboardResult lgClipboard_fileDataEnd(
|
||||
const LG_ClipboardFileRequest * request, uint64_t finalSize)
|
||||
{
|
||||
LG_ClipboardResult result = LG_CLIPBOARD_RESULT_FAILED;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (clipboard.active.ops && clipboard.active.ops->fileDataEnd)
|
||||
result = clipboard.active.ops->fileDataEnd(
|
||||
clipboard.active.opaque, request, finalSize);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lgClipboard_fileCancel(uint64_t dataset, uint64_t request,
|
||||
LG_ClipboardFileError reason)
|
||||
{
|
||||
bool result = false;
|
||||
LG_LOCK_SHARED(clipboard.activeLock);
|
||||
if (clipboard.active.ops && clipboard.active.ops->fileCancel)
|
||||
result = clipboard.active.ops->fileCancel(
|
||||
clipboard.active.opaque, dataset, request, reason);
|
||||
LG_UNLOCK_SHARED(clipboard.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
void lgClipboard_fileRemoteReady(uint64_t dataset)
|
||||
{
|
||||
LG_LOCK(clipboard.callbackLock);
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
const bool notice = clipboard.localAvailable &&
|
||||
g_params.clipboardToLocal && clipboard.remoteNotice &&
|
||||
clipboard.remoteType == LG_CLIPBOARD_DATA_FILES &&
|
||||
clipboard.remoteFileDataset == dataset;
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
if (notice && g_state.ds->cbNotice)
|
||||
g_state.ds->cbNotice(LG_CLIPBOARD_DATA_FILES);
|
||||
LG_UNLOCK(clipboard.callbackLock);
|
||||
}
|
||||
|
||||
void lgClipboard_fileRemoteFailed(uint64_t dataset)
|
||||
{
|
||||
if (!dataset)
|
||||
return;
|
||||
|
||||
LG_LOCK(clipboard.callbackLock);
|
||||
LG_LOCK(clipboard.stateLock);
|
||||
const bool matchingDataset =
|
||||
clipboard.remoteFileDataset == dataset;
|
||||
const bool matchingNotice = matchingDataset && clipboard.remoteNotice &&
|
||||
clipboard.remoteType == LG_CLIPBOARD_DATA_FILES;
|
||||
const bool release = matchingNotice && clipboard.localAvailable &&
|
||||
g_params.clipboardToLocal;
|
||||
if (matchingDataset)
|
||||
clipboard.remoteFileDataset = 0;
|
||||
if (matchingNotice)
|
||||
{
|
||||
clipboard.remoteNotice = false;
|
||||
clipboard.remoteType = LG_CLIPBOARD_DATA_NONE;
|
||||
clipboard.remoteGeneration = nextGeneration(
|
||||
clipboard.remoteGeneration);
|
||||
}
|
||||
LG_UNLOCK(clipboard.stateLock);
|
||||
if (release && g_state.ds->cbRelease)
|
||||
g_state.ds->cbRelease();
|
||||
LG_UNLOCK(clipboard.callbackLock);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "interface/clipboard.h"
|
||||
|
||||
void lgClipboard_init(void);
|
||||
bool lgClipboard_init(void);
|
||||
void lgClipboard_free(void);
|
||||
void lgClipboard_setLocalAvailable(bool available);
|
||||
|
||||
@@ -36,6 +36,7 @@ void lgClipboard_dropTransport(void);
|
||||
void lgClipboard_release(void);
|
||||
void lgClipboard_notifyTypes(
|
||||
const LG_ClipboardData types[], size_t count);
|
||||
void lgClipboard_notifyFiles(uint64_t dataset);
|
||||
LG_ClipboardResult lgClipboard_dataBegin(LG_ClipboardRequest request,
|
||||
LG_ClipboardData type, uint64_t sizeHint);
|
||||
LG_ClipboardResult lgClipboard_dataChunk(LG_ClipboardRequest request,
|
||||
@@ -55,4 +56,22 @@ bool lgClipboard_requestReady(LG_ClipboardRequest request);
|
||||
bool lgClipboard_request(LG_ClipboardData type,
|
||||
LG_ClipboardReplyFn replyFn, void * opaque);
|
||||
|
||||
/* File-dataset transport entry points used by clipboard_files.c. */
|
||||
bool lgClipboard_fileAcquire(uint64_t dataset, uint64_t acquisition);
|
||||
bool lgClipboard_fileAcquired(uint64_t dataset, uint64_t acquisition,
|
||||
LG_ClipboardFileError error);
|
||||
bool lgClipboard_fileRelease(uint64_t dataset, uint64_t acquisition);
|
||||
bool lgClipboard_fileRequest(const LG_ClipboardFileRequest * request);
|
||||
LG_ClipboardResult lgClipboard_fileDataBegin(
|
||||
const LG_ClipboardFileRequest * request, uint64_t sizeHint);
|
||||
LG_ClipboardResult lgClipboard_fileDataChunk(
|
||||
const LG_ClipboardFileRequest * request, uint64_t responseOffset,
|
||||
const void * data, size_t size);
|
||||
LG_ClipboardResult lgClipboard_fileDataEnd(
|
||||
const LG_ClipboardFileRequest * request, uint64_t finalSize);
|
||||
bool lgClipboard_fileCancel(uint64_t dataset, uint64_t request,
|
||||
LG_ClipboardFileError reason);
|
||||
void lgClipboard_fileRemoteReady(uint64_t dataset);
|
||||
void lgClipboard_fileRemoteFailed(uint64_t dataset);
|
||||
|
||||
#endif
|
||||
|
||||
3703
client/src/clipboard_files.c
Normal file
3703
client/src/clipboard_files.c
Normal file
File diff suppressed because it is too large
Load Diff
86
client/src/clipboard_files.h
Normal file
86
client/src/clipboard_files.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 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_CLIPBOARD_FILES_
|
||||
#define _H_LG_CLIENT_CLIPBOARD_FILES_
|
||||
|
||||
#include "interface/clipboard.h"
|
||||
|
||||
bool lgClipboardFiles_init(void);
|
||||
void lgClipboardFiles_free(void);
|
||||
|
||||
/* Desktop backends install a local file selection after reading one of the
|
||||
* standard URI clipboard representations. The payload is copied. */
|
||||
bool lgClipboardFiles_setLocal(const char * mime,
|
||||
const void * data, size_t size);
|
||||
void lgClipboardFiles_clearLocal(void);
|
||||
|
||||
/* Returns an allocated desktop representation for the current guest offer. */
|
||||
bool lgClipboardFiles_getRemote(const char * mime,
|
||||
char ** data, size_t * size);
|
||||
uint64_t lgClipboardFiles_remotePresentationAcquire(void);
|
||||
bool lgClipboardFiles_getRemotePresentation(uint64_t presentation,
|
||||
const char * mime, char ** data, size_t * size);
|
||||
void lgClipboardFiles_remotePresentationDelivered(uint64_t presentation);
|
||||
void lgClipboardFiles_remotePresentationRelease(uint64_t presentation);
|
||||
bool lgClipboardFiles_remoteReady(uint64_t dataset);
|
||||
|
||||
/* Events delivered by the active clipboard transport. */
|
||||
bool lgClipboardFiles_remoteOffer(uint64_t dataset);
|
||||
void lgClipboardFiles_remoteClear(void);
|
||||
void lgClipboardFiles_providerUnavailable(void);
|
||||
void lgClipboardFiles_remoteAcquired(uint64_t dataset,
|
||||
uint64_t acquisition, LG_ClipboardFileError error);
|
||||
LG_ClipboardResult lgClipboardFiles_remoteDataBegin(
|
||||
const LG_ClipboardFileRequest * request, uint64_t sizeHint);
|
||||
LG_ClipboardResult lgClipboardFiles_remoteDataChunk(
|
||||
const LG_ClipboardFileRequest * request, uint64_t responseOffset,
|
||||
const void * data, size_t size);
|
||||
LG_ClipboardResult lgClipboardFiles_remoteDataEnd(
|
||||
const LG_ClipboardFileRequest * request, uint64_t finalSize);
|
||||
void lgClipboardFiles_remoteCancel(uint64_t dataset,
|
||||
uint64_t request, LG_ClipboardFileError reason);
|
||||
|
||||
void lgClipboardFiles_localAcquire(uint64_t dataset,
|
||||
uint64_t acquisition);
|
||||
void lgClipboardFiles_localRelease(uint64_t dataset,
|
||||
uint64_t acquisition);
|
||||
void lgClipboardFiles_localRequest(
|
||||
const LG_ClipboardFileRequest * request);
|
||||
void lgClipboardFiles_localCancel(uint64_t dataset,
|
||||
uint64_t request, LG_ClipboardFileError reason);
|
||||
void lgClipboardFiles_localReady(uint64_t request);
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
bool lgClipboardFiles_testInit(uint64_t nonce);
|
||||
bool lgClipboardFiles_testFuseStopWake(void);
|
||||
bool lgClipboardFiles_testUnsentRemoteOwnership(void);
|
||||
size_t lgClipboardFiles_testRemoteDatasetCount(void);
|
||||
void lgClipboardFiles_testExpireRemoteDeliveries(void);
|
||||
bool lgClipboardFiles_testBeginRemoteLookup(uint64_t presentation);
|
||||
void lgClipboardFiles_testEndRemoteLookup(uint64_t presentation);
|
||||
bool lgClipboardFiles_testRemoteRead(uint64_t presentation,
|
||||
uint64_t node, uint64_t offset, uint32_t length);
|
||||
void lgClipboardFiles_testForceLocalEof(void);
|
||||
bool lgClipboardFiles_testLocalRequest(
|
||||
const LG_ClipboardFileRequest * request);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -3322,7 +3322,8 @@ static int lg_run(void)
|
||||
frameTimingInit();
|
||||
lgInput_init();
|
||||
lgAudio_init();
|
||||
lgClipboard_init();
|
||||
if (!lgClipboard_init())
|
||||
return -1;
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
memset(&l_testCapture, 0, sizeof(l_testCapture));
|
||||
@@ -4018,8 +4019,6 @@ static void lg_shutdown(void)
|
||||
e_startup = NULL;
|
||||
}
|
||||
|
||||
lgClipboard_free();
|
||||
|
||||
app_releaseAllKeybinds();
|
||||
ll_free(g_state.bindings);
|
||||
|
||||
@@ -4029,6 +4028,10 @@ static void lg_shutdown(void)
|
||||
g_state.ds->free();
|
||||
}
|
||||
|
||||
/* Clipboard sources own FUSE dataset references and are released by the
|
||||
* display server before the filesystem is unmounted. */
|
||||
lgClipboard_free();
|
||||
|
||||
// Input callbacks have stopped; the evdev state and overlays can go
|
||||
evdev_free();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user