mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-10-08 22:03:51 +00:00
Some checks are pending
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / module (push) Waiting to run
build / host-linux (push) Waiting to run
build / host-windows-cross (push) Waiting to run
build / host-windows-native (push) Waiting to run
build / idd (push) Waiting to run
build / obs (clang) (push) Waiting to run
build / obs (gcc) (push) Waiting to run
build / docs (push) Waiting to run
Release LGMP stream slots before dispatching clipboard data so an X11 INCR consumer cannot prevent control queue acknowledgements. Retain one bounded record in client memory while the sink is blocked. Cancel abandoned X11 transfers after requestor destruction or a finite progress timeout.
268 lines
11 KiB
C
268 lines
11 KiB
C
/**
|
|
* 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_INTERFACE_
|
|
#define _H_LG_CLIENT_CLIPBOARD_INTERFACE_
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
typedef enum LG_ClipboardData
|
|
{
|
|
LG_CLIPBOARD_DATA_TEXT = 0,
|
|
LG_CLIPBOARD_DATA_PNG,
|
|
LG_CLIPBOARD_DATA_BMP,
|
|
LG_CLIPBOARD_DATA_TIFF,
|
|
LG_CLIPBOARD_DATA_JPEG,
|
|
LG_CLIPBOARD_DATA_FILES,
|
|
|
|
LG_CLIPBOARD_DATA_NONE
|
|
}
|
|
LG_ClipboardData;
|
|
|
|
typedef void (*LG_ClipboardReplyFn)(void * opaque,
|
|
LG_ClipboardData type, const uint8_t * data, uint32_t size);
|
|
|
|
typedef uint64_t LG_ClipboardRequest;
|
|
|
|
#define LG_CLIPBOARD_REQUEST_INVALID UINT64_C(0)
|
|
#define LG_CLIPBOARD_SIZE_UNKNOWN UINT64_MAX
|
|
|
|
typedef enum LG_ClipboardResult
|
|
{
|
|
/* The operation is terminal and consumed no data. */
|
|
LG_CLIPBOARD_RESULT_FAILED = 0,
|
|
/* The operation, including the complete chunk, was accepted. */
|
|
LG_CLIPBOARD_RESULT_ACCEPTED = 1,
|
|
/* Nothing was consumed. Retry only after the matching ready callback. */
|
|
LG_CLIPBOARD_RESULT_BLOCKED = 2,
|
|
}
|
|
LG_ClipboardResult;
|
|
|
|
typedef enum LG_ClipboardCancelReason
|
|
{
|
|
LG_CLIPBOARD_CANCEL_ABORTED = 0,
|
|
LG_CLIPBOARD_CANCEL_REPLACED = 1,
|
|
LG_CLIPBOARD_CANCEL_UNAVAILABLE = 2,
|
|
LG_CLIPBOARD_CANCEL_INVALID = 3,
|
|
}
|
|
LG_ClipboardCancelReason;
|
|
|
|
typedef enum LG_ClipboardFileOperation
|
|
{
|
|
LG_CLIPBOARD_FILE_LIST = 1,
|
|
LG_CLIPBOARD_FILE_READ = 2,
|
|
}
|
|
LG_ClipboardFileOperation;
|
|
|
|
typedef enum LG_ClipboardFileError
|
|
{
|
|
LG_CLIPBOARD_FILE_ERROR_NONE = 0,
|
|
LG_CLIPBOARD_FILE_ERROR_NOT_FOUND,
|
|
LG_CLIPBOARD_FILE_ERROR_ACCESS,
|
|
LG_CLIPBOARD_FILE_ERROR_NOT_DIRECTORY,
|
|
LG_CLIPBOARD_FILE_ERROR_IS_DIRECTORY,
|
|
LG_CLIPBOARD_FILE_ERROR_IO,
|
|
LG_CLIPBOARD_FILE_ERROR_INVALID,
|
|
LG_CLIPBOARD_FILE_ERROR_NO_MEMORY,
|
|
LG_CLIPBOARD_FILE_ERROR_NO_SPACE,
|
|
LG_CLIPBOARD_FILE_ERROR_DISCONNECTED,
|
|
LG_CLIPBOARD_FILE_ERROR_CANCELLED,
|
|
LG_CLIPBOARD_FILE_ERROR_NOT_SUPPORTED,
|
|
LG_CLIPBOARD_FILE_ERROR_STALE,
|
|
}
|
|
LG_ClipboardFileError;
|
|
|
|
typedef struct LG_ClipboardFileRequest
|
|
{
|
|
uint64_t dataset;
|
|
uint64_t request;
|
|
uint64_t node;
|
|
uint64_t offset;
|
|
uint32_t length;
|
|
LG_ClipboardFileOperation operation;
|
|
}
|
|
LG_ClipboardFileRequest;
|
|
|
|
/* A consumer of a provider-to-client stream. Callbacks are serialized and
|
|
* buffers are borrowed only for the duration of chunk(). A callback which
|
|
* returns BLOCKED consumes nothing; the consumer must subsequently call
|
|
* its request-ready entry point before the same operation can be retried. */
|
|
typedef struct LG_ClipboardStreamOps
|
|
{
|
|
LG_ClipboardResult (*begin)(void * opaque, LG_ClipboardData type,
|
|
uint64_t sizeHint);
|
|
LG_ClipboardResult (*chunk)(void * opaque, uint64_t offset,
|
|
const void * data, size_t size);
|
|
LG_ClipboardResult (*end)(void * opaque, uint64_t finalSize);
|
|
void (*cancel)(void * opaque, LG_ClipboardCancelReason reason);
|
|
}
|
|
LG_ClipboardStreamOps;
|
|
|
|
typedef struct LG_ClipboardStatus
|
|
{
|
|
bool available;
|
|
uint32_t generation;
|
|
}
|
|
LG_ClipboardStatus;
|
|
|
|
typedef void (*LG_ClipboardStatusFn)(void * opaque,
|
|
const LG_ClipboardStatus * status);
|
|
|
|
typedef struct LG_ClipboardEventOps
|
|
{
|
|
/* The type list and data are borrowed for the duration of the callback.
|
|
* Event callbacks are always invoked after releasing backend locks. */
|
|
void (*notice)(void * opaque, const LG_ClipboardData types[], size_t count);
|
|
void (*data)(void * opaque, LG_ClipboardRequest request,
|
|
LG_ClipboardData type, const void * data, size_t size);
|
|
LG_ClipboardResult (*dataBegin)(void * opaque,
|
|
LG_ClipboardRequest request, LG_ClipboardData type,
|
|
uint64_t sizeHint);
|
|
LG_ClipboardResult (*dataChunk)(void * opaque,
|
|
LG_ClipboardRequest request, uint64_t offset,
|
|
const void * data, size_t size);
|
|
LG_ClipboardResult (*dataEnd)(void * opaque,
|
|
LG_ClipboardRequest request, uint64_t finalSize);
|
|
void (*dataCancel)(void * opaque, LG_ClipboardRequest request,
|
|
LG_ClipboardCancelReason reason);
|
|
/* Signals that the provider can accept a retry of the operation which most
|
|
* recently returned BLOCKED for its request. */
|
|
void (*dataReady)(void * opaque, LG_ClipboardRequest request);
|
|
/* Cancels a request previously delivered through request(). */
|
|
void (*requestCancel)(void * opaque, LG_ClipboardRequest request,
|
|
LG_ClipboardCancelReason reason);
|
|
void (*release)(void * opaque);
|
|
bool (*request)(void * opaque, LG_ClipboardRequest request,
|
|
LG_ClipboardData type);
|
|
|
|
/* File datasets use independent, multiplexed request streams. Dataset and
|
|
* node identifiers are opaque outside the publisher. */
|
|
void (*fileOffer)(void * opaque, uint64_t dataset);
|
|
void (*fileAcquire)(void * opaque, uint64_t dataset,
|
|
uint64_t acquisition);
|
|
void (*fileAcquired)(void * opaque, uint64_t dataset,
|
|
uint64_t acquisition, LG_ClipboardFileError error);
|
|
void (*fileRelease)(void * opaque, uint64_t dataset,
|
|
uint64_t acquisition);
|
|
void (*fileRequest)(void * opaque,
|
|
const LG_ClipboardFileRequest * request);
|
|
LG_ClipboardResult (*fileDataBegin)(void * opaque,
|
|
const LG_ClipboardFileRequest * request, uint64_t sizeHint);
|
|
LG_ClipboardResult (*fileDataChunk)(void * opaque,
|
|
const LG_ClipboardFileRequest * request, uint64_t responseOffset,
|
|
const void * data, size_t size);
|
|
LG_ClipboardResult (*fileDataEnd)(void * opaque,
|
|
const LG_ClipboardFileRequest * request, uint64_t finalSize);
|
|
void (*fileDataReady)(void * opaque, uint64_t request);
|
|
void (*fileCancel)(void * opaque, uint64_t dataset,
|
|
uint64_t request, LG_ClipboardFileError reason);
|
|
}
|
|
LG_ClipboardEventOps;
|
|
|
|
typedef struct LG_ClipboardOps
|
|
{
|
|
const char * name;
|
|
|
|
/* Operations must fail safely if the remote endpoint disappears. */
|
|
|
|
/* Registration must synchronously report the current status after releasing
|
|
* any backend locks. Status callbacks must be serialized and generations
|
|
* must advance whenever availability changes. Passing NULL unregisters the
|
|
* listener and synchronously quiesces its callbacks. Status callbacks must
|
|
* not be delivered from another operation or event callback. */
|
|
void (*setStatusListener)(void * opaque, LG_ClipboardStatusFn callback,
|
|
void * callbackOpaque);
|
|
|
|
/* Attach begins serialized event delivery and may synchronously replay the
|
|
* current remote notice. Detach synchronously quiesces event callbacks.
|
|
* Other operations must not deliver event callbacks synchronously. */
|
|
bool (*attach)(void * opaque, const LG_ClipboardEventOps * events,
|
|
void * eventOpaque);
|
|
void (*detach)(void * opaque);
|
|
|
|
bool (*release)(void * opaque);
|
|
/* All outbound arrays and data are borrowed only until the call returns. */
|
|
bool (*notifyTypes)(void * opaque, const LG_ClipboardData types[],
|
|
size_t count);
|
|
/* Publishes an immutable local file dataset. The nonzero dataset ID is
|
|
* process-unique and is used as the wire clipboard generation. */
|
|
bool (*offerFiles)(void * opaque, uint64_t dataset);
|
|
/* Data is a complete response to a remote request. NONE with no payload
|
|
* reports that the request could not be completed. This operation is the
|
|
* legacy whole-buffer alternative to the stream operation group below. */
|
|
bool (*data)(void * opaque, LG_ClipboardRequest request,
|
|
LG_ClipboardData type, const void * data, size_t size);
|
|
/* Streaming providers implement this complete group instead of data().
|
|
* BEGIN may use LG_CLIPBOARD_SIZE_UNKNOWN. CHUNK is all-or-nothing and its
|
|
* offset must be the next byte in the stream. END's size is authoritative.
|
|
* A BLOCKED operation consumes nothing and is retried only after dataReady
|
|
* is delivered through the attached event operations. Ready callbacks must
|
|
* be serialized with other events, delivered without backend locks held,
|
|
* and never delivered synchronously from one of these operations. */
|
|
LG_ClipboardResult (*dataBegin)(void * opaque,
|
|
LG_ClipboardRequest request, LG_ClipboardData type,
|
|
uint64_t sizeHint);
|
|
LG_ClipboardResult (*dataChunk)(void * opaque,
|
|
LG_ClipboardRequest request, uint64_t offset,
|
|
const void * data, size_t size);
|
|
LG_ClipboardResult (*dataEnd)(void * opaque,
|
|
LG_ClipboardRequest request, uint64_t finalSize);
|
|
bool (*dataCancel)(void * opaque, LG_ClipboardRequest request,
|
|
LG_ClipboardCancelReason reason);
|
|
/* Signals that the client can accept a retry of a provider-to-client stream
|
|
* operation which returned BLOCKED. */
|
|
bool (*dataReady)(void * opaque, LG_ClipboardRequest request);
|
|
/* A successful request produces exactly one matching data event unless the
|
|
* provider is detached, becomes unavailable, or publishes a newer notice
|
|
* or release first. */
|
|
bool (*request)(void * opaque, LG_ClipboardRequest request,
|
|
LG_ClipboardData type);
|
|
/* Best-effort cancellation of a request previously submitted through
|
|
* request(). The consumer has already made its stream state inactive. */
|
|
bool (*requestCancel)(void * opaque, LG_ClipboardRequest request,
|
|
LG_ClipboardCancelReason reason);
|
|
|
|
bool (*fileAcquire)(void * opaque, uint64_t dataset,
|
|
uint64_t acquisition);
|
|
bool (*fileAcquired)(void * opaque, uint64_t dataset,
|
|
uint64_t acquisition, LG_ClipboardFileError error);
|
|
bool (*fileRelease)(void * opaque, uint64_t dataset,
|
|
uint64_t acquisition);
|
|
bool (*fileRequest)(void * opaque,
|
|
const LG_ClipboardFileRequest * request);
|
|
LG_ClipboardResult (*fileDataBegin)(void * opaque,
|
|
const LG_ClipboardFileRequest * request, uint64_t sizeHint);
|
|
/* end marks a final non-empty chunk. fileDataEnd must still be called to
|
|
* complete the producer-side stream; it emits a terminal record only when
|
|
* the final chunk was not marked, including for an empty response. */
|
|
LG_ClipboardResult (*fileDataChunk)(void * opaque,
|
|
const LG_ClipboardFileRequest * request, uint64_t responseOffset,
|
|
const void * data, size_t size, bool end);
|
|
LG_ClipboardResult (*fileDataEnd)(void * opaque,
|
|
const LG_ClipboardFileRequest * request, uint64_t finalSize);
|
|
bool (*fileCancel)(void * opaque, uint64_t dataset,
|
|
uint64_t request, LG_ClipboardFileError reason);
|
|
}
|
|
LG_ClipboardOps;
|
|
|
|
#endif
|