xfreerdp: fix clipboard sync

This commit is contained in:
Marc-André Moreau
2014-10-15 22:48:18 -04:00
parent 38bac22204
commit 2e82e6d22d
4 changed files with 136 additions and 89 deletions

View File

@@ -214,6 +214,8 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList");
if (context->custom)
{
UINT32 index;
@@ -376,6 +378,8 @@ void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UI
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse");
/* http://msdn.microsoft.com/en-us/library/hh872154.aspx */
if (context->custom)
@@ -406,6 +410,8 @@ void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest");
if (context->custom)
{
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
@@ -465,6 +471,8 @@ void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataResponse");
if (context->custom)
{
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;

View File

@@ -36,7 +36,6 @@
#include "cliprdr_main.h"
#include "cliprdr_format.h"
#ifdef WITH_DEBUG_CLIPRDR
static const char* const CB_MSG_TYPE_STRINGS[] =
{
"",
@@ -52,7 +51,6 @@ static const char* const CB_MSG_TYPE_STRINGS[] =
"CB_LOCK_CLIPDATA"
"CB_UNLOCK_CLIPDATA"
};
#endif
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr)
{
@@ -171,7 +169,8 @@ static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16
UINT16 capabilitySetType;
Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
DEBUG_CLIPRDR("cCapabilitiesSets %d", cCapabilitiesSets);
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerCapabilities");
for (i = 0; i < cCapabilitiesSets; i++)
{
@@ -215,6 +214,8 @@ static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
WLog_Print(cliprdr->log, WLOG_DEBUG, "MonitorReady");
if (context->custom)
{
CLIPRDR_MONITOR_READY monitorReady;
@@ -240,8 +241,12 @@ static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI
static void cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
{
RDP_CB_FILECONTENTS_REQUEST_EVENT* cb_event;
WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsRequest");
cb_event = (RDP_CB_FILECONTENTS_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class,
CliprdrChannel_FilecontentsRequest, NULL, NULL);
Stream_Read_UINT32(s, cb_event->streamId);
Stream_Read_UINT32(s, cb_event->lindex);
Stream_Read_UINT32(s, cb_event->dwFlags);
@@ -255,8 +260,12 @@ static void cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream
static void cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
{
RDP_CB_FILECONTENTS_RESPONSE_EVENT* cb_event;
WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsResponse");
cb_event = (RDP_CB_FILECONTENTS_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class,
CliprdrChannel_FilecontentsResponse, NULL, NULL);
Stream_Read_UINT32(s, cb_event->streamId);
if (length > 0)
@@ -272,18 +281,28 @@ static void cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStrea
static void cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
{
RDP_CB_LOCK_CLIPDATA_EVENT* cb_event;
WLog_Print(cliprdr->log, WLOG_DEBUG, "LockClipData");
cb_event = (RDP_CB_LOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class,
CliprdrChannel_LockClipdata, NULL, NULL);
Stream_Read_UINT32(s, cb_event->clipDataId);
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
}
static void cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
{
RDP_CB_UNLOCK_CLIPDATA_EVENT* cb_event;
WLog_Print(cliprdr->log, WLOG_DEBUG, "UnlockClipData");
cb_event = (RDP_CB_UNLOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class,
CliprdrChannel_UnLockClipdata, NULL, NULL);
Stream_Read_UINT32(s, cb_event->clipDataId);
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
}
@@ -296,6 +315,7 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s)
Stream_Read_UINT16(s, msgType);
Stream_Read_UINT16(s, msgFlags);
Stream_Read_UINT32(s, dataLen);
DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d",
CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen);
#ifdef WITH_DEBUG_CLIPRDR
@@ -452,15 +472,21 @@ int cliprdr_client_capabilities(CliprdrClientContext* context, CLIPRDR_CAPABILIT
wStream* s;
CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */
Stream_Write_UINT16(s, 0); /* pad1 */
generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilities->capabilitySets;
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType); /* capabilitySetType */
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength); /* lengthCapability */
Stream_Write_UINT32(s, generalCapabilitySet->version); /* version */
Stream_Write_UINT32(s, generalCapabilitySet->generalFlags); /* generalFlags */
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientCapabilities");
cliprdr_packet_send(cliprdr, s);
return 0;
}
@@ -499,7 +525,7 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS
lpWideCharStr = (LPWSTR) Stream_Pointer(s);
cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2;
formatNameSize = MultiByteToWideChar(CP_UTF8, 0,
format->formatName, -1, lpWideCharStr, cchWideChar) * 2;
format->formatName, -1, lpWideCharStr, cchWideChar) * 2;
Stream_Seek(s, formatNameSize);
}
else
@@ -508,7 +534,10 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS
}
}
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatList: numFormats: %d",
formatList->cFormats);
cliprdr_packet_send(cliprdr, s);
return 0;
}
@@ -516,10 +545,15 @@ int cliprdr_client_format_list_response(CliprdrClientContext* context, CLIPRDR_F
{
wStream* s;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
formatListResponse->msgType = CB_FORMAT_LIST_RESPONSE;
formatListResponse->dataLen = 0;
s = cliprdr_packet_new(formatListResponse->msgType, formatListResponse->msgFlags, formatListResponse->dataLen);
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatListResponse");
cliprdr_packet_send(cliprdr, s);
return 0;
}
@@ -527,12 +561,17 @@ int cliprdr_client_format_data_request(CliprdrClientContext* context, CLIPRDR_FO
{
wStream* s;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
formatDataRequest->msgType = CB_FORMAT_DATA_REQUEST;
formatDataRequest->msgFlags = 0;
formatDataRequest->dataLen = 4;
s = cliprdr_packet_new(formatDataRequest->msgType, formatDataRequest->msgFlags, formatDataRequest->dataLen);
Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataRequest");
cliprdr_packet_send(cliprdr, s);
return 0;
}
@@ -540,10 +579,16 @@ int cliprdr_client_format_data_response(CliprdrClientContext* context, CLIPRDR_F
{
wStream* s;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
formatDataResponse->msgType = CB_FORMAT_DATA_RESPONSE;
s = cliprdr_packet_new(formatDataResponse->msgType, formatDataResponse->msgFlags, formatDataResponse->dataLen);
Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->dataLen);
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataResponse");
cliprdr_packet_send(cliprdr, s);
return 0;
}
@@ -566,6 +611,8 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
strcpy(cliprdr->plugin.channel_def.name, "cliprdr");
cliprdr->log = WLog_Get("com.freerdp.channels.cliprdr.client");
cliprdr->plugin.connect_callback = cliprdr_process_connect;
cliprdr->plugin.receive_callback = cliprdr_process_receive;
cliprdr->plugin.event_callback = cliprdr_process_event;

View File

@@ -31,6 +31,8 @@
struct cliprdr_plugin
{
rdpSvcPlugin plugin;
wLog* log;
BOOL received_caps;
BOOL use_long_format_names;
BOOL stream_fileclip_enabled;

View File

@@ -39,17 +39,6 @@
#include "xf_cliprdr.h"
#define TAG CLIENT_TAG("x11")
#ifdef WITH_DEBUG_X11
#define DEBUG_X11(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__)
#else
#define DEBUG_X11(fmt, ...) do { } while (0)
#endif
#ifdef WITH_DEBUG_X11_CLIPRDR
#define DEBUG_X11_CLIPRDR(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__)
#else
#define DEBUG_X11_CLIPRDR(fmt, ...) do { } while (0)
#endif
struct xf_cliprdr_format
{
@@ -102,6 +91,8 @@ struct xf_clipboard
BOOL xfixes_supported;
};
int xf_cliprdr_send_client_format_list(xfClipboard* clipboard);
static BYTE* lf2crlf(BYTE* data, int* size)
{
BYTE c;
@@ -272,43 +263,8 @@ static void xf_cliprdr_send_supported_format_list(xfClipboard* clipboard)
}
clipboard->context->ClientFormatList(clipboard->context, &formatList);
}
static void xf_cliprdr_send_format_list(xfClipboard* clipboard)
{
CLIPRDR_FORMAT_LIST formatList;
xfContext* xfc = clipboard->xfc;
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
if (xf_cliprdr_is_self_owned(clipboard))
{
/**
* TODO: handle (raw?) format data
* The original code appears to be sending back the original,
* unmodified server format list here.
*/
formatList.msgFlags = CB_RESPONSE_OK;
formatList.cFormats = clipboard->numServerFormats;
formatList.formats = clipboard->serverFormats;
clipboard->context->ClientFormatList(clipboard->context, &formatList);
}
else if (clipboard->owner == None)
{
formatList.msgFlags = CB_RESPONSE_OK;
formatList.cFormats = 0;
formatList.formats = NULL;
clipboard->context->ClientFormatList(clipboard->context, &formatList);
}
else if (clipboard->owner != xfc->drawable)
{
/* Request the owner for TARGETS, and wait for SelectionNotify event */
XConvertSelection(xfc->display, clipboard->clipboard_atom,
clipboard->targets[1], clipboard->property_atom, xfc->drawable, CurrentTime);
}
free(formats);
}
static void xf_cliprdr_send_data_request(xfClipboard* clipboard, UINT32 formatId)
@@ -419,10 +375,7 @@ static BYTE* xf_cliprdr_process_requested_dib(BYTE* data, int* size)
/* length should be at least BMP header (14) + sizeof(BITMAPINFOHEADER) */
if (*size < 54)
{
DEBUG_X11_CLIPRDR("bmp length %d too short", *size);
return NULL;
}
*size -= 14;
outbuf = (BYTE*) calloc(1, *size);
@@ -559,7 +512,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL has_d
if (!clipboard->xfixes_supported)
{
/* Resend the format list, otherwise the server won't request again for the next paste */
xf_cliprdr_send_format_list(clipboard);
xf_cliprdr_send_client_format_list(clipboard);
}
}
@@ -716,26 +669,19 @@ static BOOL xf_cliprdr_process_dib(xfClipboard* clipboard, BYTE* data, int size)
/* size should be at least sizeof(BITMAPINFOHEADER) */
if (size < 40)
{
DEBUG_X11_CLIPRDR("dib size %d too short", size);
return FALSE;
}
s = Stream_New(data, size);
Stream_Seek(s, 14);
Stream_Read_UINT16(s, bpp);
if ((bpp < 1) || (bpp > 32))
{
WLog_ERR(TAG, "invalid bpp value %d", bpp);
return FALSE;
}
Stream_Read_UINT32(s, ncolors);
offset = 14 + 40 + (bpp <= 8 ? (ncolors == 0 ? (1 << bpp) : ncolors) * 4 : 0);
Stream_Free(s, FALSE);
DEBUG_X11_CLIPRDR("offset=%d bpp=%d ncolors=%d", offset, bpp, ncolors);
s = Stream_New(NULL, 14 + size);
Stream_Write_UINT8(s, 'B');
Stream_Write_UINT8(s, 'M');
@@ -747,6 +693,7 @@ static BOOL xf_cliprdr_process_dib(xfClipboard* clipboard, BYTE* data, int size)
clipboard->data = Stream_Buffer(s);
clipboard->data_length = Stream_GetPosition(s);
Stream_Free(s, FALSE);
return TRUE;
}
@@ -761,19 +708,13 @@ static void xf_cliprdr_process_html(xfClipboard* clipboard, BYTE* data, int size
end_str = strstr((char*) data, "EndHTML:");
if (!start_str || !end_str)
{
DEBUG_X11_CLIPRDR("invalid HTML clipboard format");
return;
}
start = atoi(start_str + 10);
end = atoi(end_str + 8);
if ((start > size) || (end > size) || (start >= end))
{
DEBUG_X11_CLIPRDR("invalid HTML offset");
return;
}
clipboard->data = (BYTE*) malloc(size - start + 1);
CopyMemory(clipboard->data, data + start, end - start);
@@ -856,8 +797,9 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, XEvent*
clipboard->property_atom, 0, 4, 0, XA_INTEGER,
&type, &fmt, &length, &bytes_left, &data) != Success)
{
DEBUG_X11_CLIPRDR("XGetWindowProperty failed");
}
if (data)
{
CopyMemory(&altFormatId, data, 4);
@@ -873,7 +815,7 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, XEvent*
}
else if (clipboard->respond)
{
DEBUG_X11_CLIPRDR("duplicated request");
/* duplicate request */
}
else
{
@@ -933,7 +875,7 @@ static BOOL xf_cliprdr_process_property_notify(xfClipboard* clipboard, XEvent* x
if (xevent->xproperty.window == clipboard->root_window)
{
xf_cliprdr_send_format_list(clipboard);
xf_cliprdr_send_client_format_list(clipboard);
}
else if ((xevent->xproperty.window == xfc->drawable) &&
(xevent->xproperty.state == PropertyNewValue) && clipboard->incr_starts)
@@ -959,7 +901,7 @@ static void xf_cliprdr_check_owner(xfClipboard* clipboard)
if (clipboard->owner != owner)
{
clipboard->owner = owner;
xf_cliprdr_send_format_list(clipboard);
xf_cliprdr_send_client_format_list(clipboard);
}
}
}
@@ -1045,7 +987,64 @@ int xf_cliprdr_send_client_capabilities(xfClipboard* clipboard)
int xf_cliprdr_send_client_format_list(xfClipboard* clipboard)
{
xf_cliprdr_send_format_list(clipboard);
CLIPRDR_FORMAT_LIST formatList;
xfContext* xfc = clipboard->xfc;
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
if (!clipboard->sync)
{
UINT32 i, numFormats;
CLIPRDR_FORMAT* formats;
numFormats = clipboard->numClientFormats;
formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT));
for (i = 0; i < numFormats; i++)
{
formats[i].formatId = clipboard->clientFormats[i].formatId;
formats[i].formatName = clipboard->clientFormats[i].formatName;
}
formatList.msgFlags = CB_RESPONSE_OK;
formatList.cFormats = numFormats;
formatList.formats = formats;
clipboard->context->ClientFormatList(clipboard->context, &formatList);
free(formats);
return 1;
}
if (xf_cliprdr_is_self_owned(clipboard))
{
/**
* TODO: handle (raw?) format data
* The original code appears to be sending back the original,
* unmodified server format list here.
*/
formatList.msgFlags = CB_RESPONSE_OK;
formatList.cFormats = clipboard->numServerFormats;
formatList.formats = clipboard->serverFormats;
clipboard->context->ClientFormatList(clipboard->context, &formatList);
}
else if (clipboard->owner == None)
{
formatList.msgFlags = CB_RESPONSE_OK;
formatList.cFormats = 0;
formatList.formats = NULL;
clipboard->context->ClientFormatList(clipboard->context, &formatList);
}
else if (clipboard->owner != xfc->drawable)
{
/* Request the owner for TARGETS, and wait for SelectionNotify event */
XConvertSelection(xfc->display, clipboard->clipboard_atom,
clipboard->targets[1], clipboard->property_atom, xfc->drawable, CurrentTime);
}
return 1;
}
@@ -1154,6 +1153,9 @@ static int xf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR_
if (clipboard->serverFormats)
{
for (i = 0; i < clipboard->numServerFormats; i++)
free(clipboard->serverFormats[i].formatName);
free(clipboard->serverFormats);
clipboard->serverFormats = NULL;
}
@@ -1186,25 +1188,13 @@ static int xf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR_
}
}
xf_cliprdr_send_client_format_list_response(clipboard, TRUE);
XSetSelectionOwner(xfc->display, clipboard->clipboard_atom, xfc->drawable, CurrentTime);
XFlush(xfc->display);
return 1;
xf_cliprdr_send_client_format_list_response(clipboard, TRUE);
for (i = 0; i < formatList->cFormats; i++)
{
format = &formatList->formats[i];
if (format->formatId == CLIPRDR_FORMAT_UNICODETEXT)
{
xf_cliprdr_send_client_format_data_request(clipboard, format->formatId);
}
}
return 1;
}
static int xf_cliprdr_server_format_list_response(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
@@ -1362,9 +1352,9 @@ xfClipboard* xf_clipboard_new(xfContext* xfc)
if (XFixesQueryExtension(xfc->display, &clipboard->xfixes_event_base, &clipboard->xfixes_error_base))
{
int xfmajor, xfminor;
if (XFixesQueryVersion(xfc->display, &xfmajor, &xfminor))
{
DEBUG_X11_CLIPRDR("Found X Fixes extension version %d.%d", xfmajor, xfminor);
XFixesSelectSelectionInput(xfc->display, clipboard->root_window,
clipboard->clipboard_atom, XFixesSetSelectionOwnerNotifyMask);
clipboard->xfixes_supported = TRUE;