rdp: Add clipboard redirection support

Allow clipboard pasting in and out of an RDP session.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
dev
Hideyuki Nagase 3 years ago committed by Derek Foreman
parent 252771d9aa
commit 297ad403d6
  1. 1
      libweston/backend-rdp/meson.build
  2. 44
      libweston/backend-rdp/rdp.c
  3. 30
      libweston/backend-rdp/rdp.h
  4. 1744
      libweston/backend-rdp/rdpclip.c
  5. 36
      libweston/backend-rdp/rdputil.c

@ -31,6 +31,7 @@ deps_rdp = [
] ]
srcs_rdp = [ srcs_rdp = [
'rdp.c', 'rdp.c',
'rdpclip.c',
'rdputil.c', 'rdputil.c',
] ]

@ -555,6 +555,16 @@ rdp_destroy(struct weston_compositor *ec)
if (b->listener_events[i]) if (b->listener_events[i])
wl_event_source_remove(b->listener_events[i]); wl_event_source_remove(b->listener_events[i]);
if (b->clipboard_debug) {
weston_log_scope_destroy(b->clipboard_debug);
b->clipboard_debug = NULL;
}
if (b->clipboard_verbose) {
weston_log_scope_destroy(b->clipboard_verbose);
b->clipboard_verbose = NULL;
}
if (b->debug) { if (b->debug) {
weston_log_scope_destroy(b->debug); weston_log_scope_destroy(b->debug);
b->debug = NULL; b->debug = NULL;
@ -669,6 +679,8 @@ rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
wl_event_source_remove(context->events[i]); wl_event_source_remove(context->events[i]);
} }
rdp_clipboard_destroy(context);
if (context->vcm) if (context->vcm)
WTSCloseServer(context->vcm); WTSCloseServer(context->vcm);
@ -924,6 +936,13 @@ xf_peer_activate(freerdp_peer* client)
settings->CompressionEnabled = FALSE; settings->CompressionEnabled = FALSE;
} }
if (settings->RedirectClipboard) {
if (!peerCtx->vcm) {
weston_log("Virtual channel is required for clipboard\n");
goto error_exit;
}
}
if (output->base.width != (int)settings->DesktopWidth || if (output->base.width != (int)settings->DesktopWidth ||
output->base.height != (int)settings->DesktopHeight) output->base.height != (int)settings->DesktopHeight)
{ {
@ -995,6 +1014,11 @@ xf_peer_activate(freerdp_peer* client)
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
weston_seat_init_pointer(peersItem->seat); weston_seat_init_pointer(peersItem->seat);
/* Initialize RDP clipboard after seat is initialized */
if (settings->RedirectClipboard)
if (rdp_clipboard_init(client) != 0)
goto error_exit;
peersItem->flags |= RDP_PEER_ACTIVATED; peersItem->flags |= RDP_PEER_ACTIVATED;
/* disable pointer on the client side */ /* disable pointer on the client side */
@ -1014,6 +1038,12 @@ xf_peer_activate(freerdp_peer* client)
pixman_region32_fini(&damage); pixman_region32_fini(&damage);
return TRUE; return TRUE;
error_exit:
rdp_clipboard_destroy(peerCtx);
return FALSE;
} }
static BOOL static BOOL
@ -1450,6 +1480,7 @@ rdp_peer_init(freerdp_peer *client, struct rdp_backend *b)
settings->NSCodec = TRUE; settings->NSCodec = TRUE;
settings->FrameMarkerCommandEnabled = TRUE; settings->FrameMarkerCommandEnabled = TRUE;
settings->SurfaceFrameMarkerEnabled = TRUE; settings->SurfaceFrameMarkerEnabled = TRUE;
settings->RedirectClipboard = TRUE;
settings->HasExtendedMouseEvent = TRUE; settings->HasExtendedMouseEvent = TRUE;
settings->HasHorizontalWheel = TRUE; settings->HasHorizontalWheel = TRUE;
@ -1569,6 +1600,15 @@ rdp_backend_create(struct weston_compositor *compositor,
b->rdp_monitor_refresh_rate = config->refresh_rate * 1000; b->rdp_monitor_refresh_rate = config->refresh_rate * 1000;
rdp_debug(b, "RDP backend: WESTON_RDP_MONITOR_REFRESH_RATE: %d\n", b->rdp_monitor_refresh_rate); rdp_debug(b, "RDP backend: WESTON_RDP_MONITOR_REFRESH_RATE: %d\n", b->rdp_monitor_refresh_rate);
b->clipboard_debug = weston_log_ctx_add_log_scope(b->compositor->weston_log_ctx,
"rdp-backend-clipboard",
"Debug messages from RDP backend clipboard\n",
NULL, NULL, NULL);
b->clipboard_verbose = weston_log_ctx_add_log_scope(b->compositor->weston_log_ctx,
"rdp-backend-clipboard-verbose",
"Debug messages from RDP backend clipboard\n",
NULL, NULL, NULL);
compositor->backend = &b->base; compositor->backend = &b->base;
if (config->server_cert && config->server_key) { if (config->server_cert && config->server_key) {
@ -1660,6 +1700,10 @@ err_compositor:
weston_compositor_shutdown(compositor); weston_compositor_shutdown(compositor);
err_free_strings: err_free_strings:
if (b->clipboard_debug)
weston_log_scope_destroy(b->clipboard_debug);
if (b->clipboard_verbose)
weston_log_scope_destroy(b->clipboard_verbose);
if (b->debug) if (b->debug)
weston_log_scope_destroy(b->debug); weston_log_scope_destroy(b->debug);
if (b->verbose) if (b->verbose)

@ -38,6 +38,7 @@
#include <freerdp/codec/nsc.h> #include <freerdp/codec/nsc.h>
#include <freerdp/locale/keyboard.h> #include <freerdp/locale/keyboard.h>
#include <freerdp/channels/wtsvc.h> #include <freerdp/channels/wtsvc.h>
#include <freerdp/server/cliprdr.h>
#include <libweston/libweston.h> #include <libweston/libweston.h>
#include <libweston/backend-rdp.h> #include <libweston/backend-rdp.h>
@ -78,6 +79,9 @@ struct rdp_backend {
struct weston_log_scope *debug; struct weston_log_scope *debug;
struct weston_log_scope *verbose; struct weston_log_scope *verbose;
struct weston_log_scope *clipboard_debug;
struct weston_log_scope *clipboard_verbose;
char *server_cert; char *server_cert;
char *server_key; char *server_key;
char *rdp_key; char *rdp_key;
@ -142,6 +146,13 @@ struct rdp_peer_context {
pthread_mutex_t loop_task_list_mutex; pthread_mutex_t loop_task_list_mutex;
struct wl_list loop_task_list; /* struct rdp_loop_task::link */ struct wl_list loop_task_list; /* struct rdp_loop_task::link */
/* Clipboard support */
CliprdrServerContext *clipboard_server_context;
struct rdp_clipboard_data_source *clipboard_client_data_source;
struct rdp_clipboard_data_source *clipboard_inflight_client_data_source;
struct wl_listener clipboard_selection_listener;
}; };
typedef struct rdp_peer_context RdpPeerContext; typedef struct rdp_peer_context RdpPeerContext;
@ -171,10 +182,22 @@ struct rdp_loop_task {
#define rdp_debug_continue(b, ...) \ #define rdp_debug_continue(b, ...) \
rdp_debug_print(b->debug, true, __VA_ARGS__) rdp_debug_print(b->debug, true, __VA_ARGS__)
#define rdp_debug_clipboard_verbose(b, ...) \
rdp_debug_print(b->clipboard_verbose, false, __VA_ARGS__)
#define rdp_debug_clipboard_verbose_continue(b, ...) \
rdp_debug_print(b->clipboard_verbose, true, __VA_ARGS__)
#define rdp_debug_clipboard(b, ...) \
rdp_debug_print(b->clipboard_debug, false, __VA_ARGS__)
#define rdp_debug_clipboard_continue(b, ...) \
rdp_debug_print(b->clipboard_debug, true, __VA_ARGS__)
/* rdputil.c */ /* rdputil.c */
void void
rdp_debug_print(struct weston_log_scope *log_scope, bool cont, char *fmt, ...); rdp_debug_print(struct weston_log_scope *log_scope, bool cont, char *fmt, ...);
int
rdp_wl_array_read_fd(struct wl_array *array, int fd);
void void
convert_rdp_keyboard_to_xkb_rule_names(UINT32 KeyboardType, UINT32 KeyboardSubType, UINT32 KeyboardLayout, struct xkb_rule_names *xkbRuleNames); convert_rdp_keyboard_to_xkb_rule_names(UINT32 KeyboardType, UINT32 KeyboardSubType, UINT32 KeyboardLayout, struct xkb_rule_names *xkbRuleNames);
@ -204,6 +227,13 @@ rdp_initialize_dispatch_task_event_source(RdpPeerContext *peerCtx);
void void
rdp_destroy_dispatch_task_event_source(RdpPeerContext *peerCtx); rdp_destroy_dispatch_task_event_source(RdpPeerContext *peerCtx);
/* rdpclip.c */
int
rdp_clipboard_init(freerdp_peer *client);
void
rdp_clipboard_destroy(RdpPeerContext *peerCtx);
static inline struct rdp_head * static inline struct rdp_head *
to_rdp_head(struct weston_head *base) to_rdp_head(struct weston_head *base)
{ {

File diff suppressed because it is too large Load Diff

@ -226,3 +226,39 @@ rdp_destroy_dispatch_task_event_source(RdpPeerContext *peerCtx)
pthread_mutex_destroy(&peerCtx->loop_task_list_mutex); pthread_mutex_destroy(&peerCtx->loop_task_list_mutex);
} }
/* This is a little tricky - it makes sure there's always at least
* one spare byte in the array in case the caller needs to add a
* null terminator to it. We can't just null terminate the array
* here, because some callers won't want that - and some won't
* like having an odd number of bytes.
*/
int
rdp_wl_array_read_fd(struct wl_array *array, int fd)
{
int len, size;
char *data;
/* Make sure we have at least 1024 bytes of space left */
if (array->alloc - array->size < 1024) {
if (!wl_array_add(array, 1024)) {
errno = ENOMEM;
return -1;
}
array->size -= 1024;
}
data = (char *)array->data + array->size;
/* Leave one char in case the caller needs space for a
* null terminator */
size = array->alloc - array->size - 1;
do {
len = read(fd, data, size);
} while (len == -1 && errno == EINTR);
if (len == -1)
return -1;
array->size += len;
return len;
}

Loading…
Cancel
Save