FreeRDP/client/X11/xf_cliprdr.c

1518 lines
38 KiB
C
Raw Normal View History

2011-09-23 07:37:17 +04:00
/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
2011-09-23 07:37:17 +04:00
* X11 Clipboard Redirection
*
* Copyright 2010-2011 Vic Lee
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
2011-09-23 07:37:17 +04:00
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2011-09-23 07:37:17 +04:00
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#ifdef WITH_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#include <winpr/crt.h>
#include <winpr/image.h>
#include <winpr/stream.h>
#include <winpr/clipboard.h>
2014-09-12 19:13:01 +04:00
#include <freerdp/log.h>
#include <freerdp/client/cliprdr.h>
#include <freerdp/channels/channels.h>
2011-09-23 07:37:17 +04:00
#include "xf_cliprdr.h"
2014-09-12 19:13:01 +04:00
#define TAG CLIENT_TAG("x11")
#define MAX_CLIPBOARD_FORMATS 255
2014-10-15 23:49:57 +04:00
struct xf_cliprdr_format
2011-09-23 07:37:17 +04:00
{
2014-10-15 23:49:57 +04:00
Atom atom;
UINT32 formatId;
char* formatName;
2011-09-23 07:37:17 +04:00
};
2014-10-15 23:49:57 +04:00
typedef struct xf_cliprdr_format xfCliprdrFormat;
2011-09-23 07:37:17 +04:00
2014-10-15 06:24:07 +04:00
struct xf_clipboard
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
xfContext* xfc;
rdpChannels* channels;
CliprdrClientContext* context;
wClipboard* system;
2011-09-23 07:37:17 +04:00
Window root_window;
Atom clipboard_atom;
Atom property_atom;
Atom raw_transfer_atom;
Atom raw_format_list_atom;
2014-10-15 23:49:57 +04:00
int numClientFormats;
xfCliprdrFormat clientFormats[20];
int numServerFormats;
CLIPRDR_FORMAT* serverFormats;
2011-09-23 07:37:17 +04:00
2014-10-15 23:49:57 +04:00
int numTargets;
2011-09-23 07:37:17 +04:00
Atom targets[20];
2014-10-15 23:49:57 +04:00
int requestedFormatId;
BYTE* data;
BOOL data_raw_format;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
UINT32 data_format_id;
const char* data_format_name;
2011-09-23 07:37:17 +04:00
int data_length;
XEvent* respond;
Window owner;
BOOL sync;
2011-09-23 07:37:17 +04:00
/* INCR mechanism */
Atom incr_atom;
BOOL incr_starts;
BYTE* incr_data;
2011-09-23 07:37:17 +04:00
int incr_data_length;
/* XFixes extension */
int xfixes_event_base;
int xfixes_error_base;
BOOL xfixes_supported;
2011-09-23 07:37:17 +04:00
};
UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard);
2014-10-16 06:48:18 +04:00
static void xf_cliprdr_check_owner(xfClipboard* clipboard)
{
Window owner;
xfContext* xfc = clipboard->xfc;
if (clipboard->sync)
{
owner = XGetSelectionOwner(xfc->display, clipboard->clipboard_atom);
if (clipboard->owner != owner)
{
clipboard->owner = owner;
xf_cliprdr_send_client_format_list(clipboard);
}
}
}
2014-10-15 06:24:07 +04:00
static BOOL xf_cliprdr_is_self_owned(xfClipboard* clipboard)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
xfContext* xfc = clipboard->xfc;
2016-10-06 14:31:25 +03:00
return XGetSelectionOwner(xfc->display,
clipboard->clipboard_atom) == xfc->drawable;
2011-09-23 07:37:17 +04:00
}
2016-10-06 14:31:25 +03:00
static void xf_cliprdr_set_raw_transfer_enabled(xfClipboard* clipboard,
BOOL enabled)
{
UINT32 data = enabled;
xfContext* xfc = clipboard->xfc;
XChangeProperty(xfc->display, xfc->drawable, clipboard->raw_transfer_atom,
2016-10-06 14:31:25 +03:00
XA_INTEGER, 32, PropModeReplace, (BYTE*) &data, 1);
}
static BOOL xf_cliprdr_is_raw_transfer_available(xfClipboard* clipboard)
{
Atom type;
int format;
int result = 0;
unsigned long length;
unsigned long bytes_left;
UINT32* data = NULL;
UINT32 is_enabled = 0;
Window owner = None;
xfContext* xfc = clipboard->xfc;
owner = XGetSelectionOwner(xfc->display, clipboard->clipboard_atom);
if (owner != None)
{
result = XGetWindowProperty(xfc->display, owner,
2016-10-06 14:31:25 +03:00
clipboard->raw_transfer_atom, 0, 4, 0, XA_INTEGER,
&type, &format, &length, &bytes_left, (BYTE**) &data);
}
if (data)
{
is_enabled = *data;
XFree(data);
}
if ((owner == None) || (owner == xfc->drawable))
return FALSE;
if (result != Success)
return FALSE;
return is_enabled ? TRUE : FALSE;
}
2016-10-06 14:31:25 +03:00
static BOOL xf_cliprdr_formats_equal(const CLIPRDR_FORMAT* server,
const xfCliprdrFormat* client)
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
{
if (server->formatName && client->formatName)
{
/* The server may be using short format names while we store them in full form. */
2016-10-06 14:31:25 +03:00
return (0 == strncmp(server->formatName, client->formatName,
strlen(server->formatName)));
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
}
if (!server->formatName && !client->formatName)
{
return (server->formatId == client->formatId);
}
return FALSE;
}
2016-10-06 14:31:25 +03:00
static xfCliprdrFormat* xf_cliprdr_get_client_format_by_id(
xfClipboard* clipboard, UINT32 formatId)
2011-09-23 07:37:17 +04:00
{
int index;
2014-10-15 23:49:57 +04:00
xfCliprdrFormat* format;
2011-09-23 07:37:17 +04:00
2014-10-15 23:49:57 +04:00
for (index = 0; index < clipboard->numClientFormats; index++)
2011-09-23 07:37:17 +04:00
{
2014-10-15 23:49:57 +04:00
format = &(clipboard->clientFormats[index]);
if (format->formatId == formatId)
return format;
2011-09-23 07:37:17 +04:00
}
2014-10-15 23:49:57 +04:00
return NULL;
2011-09-23 07:37:17 +04:00
}
2016-10-06 14:31:25 +03:00
static xfCliprdrFormat* xf_cliprdr_get_client_format_by_atom(
xfClipboard* clipboard, Atom atom)
2011-09-23 07:37:17 +04:00
{
int i;
2014-10-15 23:49:57 +04:00
xfCliprdrFormat* format;
2011-09-23 07:37:17 +04:00
2014-10-15 23:49:57 +04:00
for (i = 0; i < clipboard->numClientFormats; i++)
2011-09-23 07:37:17 +04:00
{
2014-10-15 23:49:57 +04:00
format = &(clipboard->clientFormats[i]);
if (format->atom == atom)
2014-10-15 23:49:57 +04:00
return format;
}
return NULL;
}
2016-10-06 14:31:25 +03:00
static CLIPRDR_FORMAT* xf_cliprdr_get_server_format_by_atom(
xfClipboard* clipboard, Atom atom)
{
int i, j;
xfCliprdrFormat* client_format;
CLIPRDR_FORMAT* server_format;
for (i = 0; i < clipboard->numClientFormats; i++)
{
client_format = &(clipboard->clientFormats[i]);
2011-09-23 07:37:17 +04:00
if (client_format->atom == atom)
2011-09-23 07:37:17 +04:00
{
for (j = 0; j < clipboard->numServerFormats; j++)
{
server_format = &(clipboard->serverFormats[j]);
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
if (xf_cliprdr_formats_equal(server_format, client_format))
return server_format;
}
2011-09-23 07:37:17 +04:00
}
}
2014-10-15 23:49:57 +04:00
return NULL;
2011-09-23 07:37:17 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
static UINT xf_cliprdr_send_data_request(xfClipboard* clipboard,
UINT32 formatId)
{
CLIPRDR_FORMAT_DATA_REQUEST request;
ZeroMemory(&request, sizeof(CLIPRDR_FORMAT_DATA_REQUEST));
request.requestedFormatId = formatId;
2016-10-06 14:31:25 +03:00
return clipboard->context->ClientFormatDataRequest(clipboard->context,
&request);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
static UINT xf_cliprdr_send_data_response(xfClipboard* clipboard, BYTE* data,
int size)
{
CLIPRDR_FORMAT_DATA_RESPONSE response;
ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE));
response.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
response.dataLen = size;
response.requestedFormatData = data;
2016-10-06 14:31:25 +03:00
return clipboard->context->ClientFormatDataResponse(clipboard->context,
&response);
}
static wStream* xf_cliprdr_serialize_server_format_list(xfClipboard* clipboard)
{
UINT32 i;
UINT32 formatCount;
wStream* s = NULL;
/* Typical MS Word format list is about 80 bytes long. */
if (!(s = Stream_New(NULL, 128)))
{
WLog_ERR(TAG, "failed to allocate serialized format list");
goto error;
}
/* If present, the last format is always synthetic CF_RAW. Do not include it. */
2016-10-06 14:31:25 +03:00
formatCount = (clipboard->numServerFormats > 0) ? clipboard->numServerFormats -
1 : 0;
Stream_Write_UINT32(s, formatCount);
for (i = 0; i < formatCount; i++)
{
CLIPRDR_FORMAT* format = &clipboard->serverFormats[i];
size_t name_length = format->formatName ? strlen(format->formatName) : 0;
if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32) + name_length + 1))
{
WLog_ERR(TAG, "failed to expand serialized format list");
goto error;
}
Stream_Write_UINT32(s, format->formatId);
Stream_Write(s, format->formatName, name_length);
Stream_Write_UINT8(s, '\0');
}
Stream_SealLength(s);
return s;
error:
Stream_Free(s, TRUE);
return NULL;
}
2016-10-06 14:31:25 +03:00
static CLIPRDR_FORMAT* xf_cliprdr_parse_server_format_list(BYTE* data,
size_t length, UINT32* numFormats)
{
UINT32 i;
wStream* s = NULL;
CLIPRDR_FORMAT* formats = NULL;
if (!(s = Stream_New(data, length)))
{
WLog_ERR(TAG, "failed to allocate stream for parsing serialized format list");
goto error;
}
if (Stream_GetRemainingLength(s) < sizeof(UINT32))
{
WLog_ERR(TAG, "too short serialized format list");
goto error;
}
Stream_Read_UINT32(s, *numFormats);
if (*numFormats > MAX_CLIPBOARD_FORMATS)
{
WLog_ERR(TAG, "unexpectedly large number of formats: %u", *numFormats);
goto error;
}
if (!(formats = (CLIPRDR_FORMAT*) calloc(*numFormats, sizeof(CLIPRDR_FORMAT))))
{
WLog_ERR(TAG, "failed to allocate format list");
goto error;
}
for (i = 0; i < *numFormats; i++)
{
const char* formatName = NULL;
size_t formatNameLength = 0;
if (Stream_GetRemainingLength(s) < sizeof(UINT32))
{
WLog_ERR(TAG, "unexpected end of serialized format list");
goto error;
}
Stream_Read_UINT32(s, formats[i].formatId);
formatName = (const char*) Stream_Pointer(s);
formatNameLength = strnlen(formatName, Stream_GetRemainingLength(s));
if (formatNameLength == Stream_GetRemainingLength(s))
{
2016-10-06 14:31:25 +03:00
WLog_ERR(TAG, "missing terminating null byte, %zu bytes left to read",
formatNameLength);
goto error;
}
formats[i].formatName = strndup(formatName, formatNameLength);
Stream_Seek(s, formatNameLength + 1);
}
Stream_Free(s, FALSE);
return formats;
error:
Stream_Free(s, FALSE);
free(formats);
*numFormats = 0;
return NULL;
}
static void xf_cliprdr_free_formats(CLIPRDR_FORMAT* formats, UINT32 numFormats)
{
UINT32 i;
for (i = 0; i < numFormats; i++)
{
free(formats[i].formatName);
}
free(formats);
}
2016-10-06 14:31:25 +03:00
static CLIPRDR_FORMAT* xf_cliprdr_get_raw_server_formats(xfClipboard* clipboard,
UINT32* numFormats)
{
Atom type = None;
int format = 0;
unsigned long length = 0;
unsigned long remaining;
BYTE* data = NULL;
CLIPRDR_FORMAT* formats = NULL;
xfContext* xfc = clipboard->xfc;
*numFormats = 0;
2016-10-06 14:31:25 +03:00
XGetWindowProperty(xfc->display, clipboard->owner,
clipboard->raw_format_list_atom,
0, 4096, False, clipboard->raw_format_list_atom, &type, &format,
&length, &remaining, &data);
2016-10-06 14:31:25 +03:00
if (data && length > 0 && format == 8
&& type == clipboard->raw_format_list_atom)
{
formats = xf_cliprdr_parse_server_format_list(data, length, numFormats);
}
else
{
2016-10-06 14:31:25 +03:00
WLog_ERR(TAG,
"failed to retrieve raw format list: data=%p, length=%lu, format=%d, type=%d (expected=%d)",
data, length, format, type, clipboard->raw_format_list_atom);
}
if (data)
XFree(data);
return formats;
}
2016-10-06 14:31:25 +03:00
static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets(
xfClipboard* clipboard, UINT32* numFormats)
{
int i;
Atom atom;
BYTE* data = NULL;
int format_property;
unsigned long length;
unsigned long bytes_left;
xfCliprdrFormat* format = NULL;
CLIPRDR_FORMAT* formats = NULL;
xfContext* xfc = clipboard->xfc;
*numFormats = 0;
XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom,
2016-10-06 14:31:25 +03:00
0, 200, 0, XA_ATOM, &atom, &format_property, &length, &bytes_left, &data);
if (length > 0)
{
if (!data)
{
WLog_ERR(TAG, "XGetWindowProperty set length = %d but data is NULL", length);
goto out;
}
2016-10-06 14:31:25 +03:00
if (!(formats = (CLIPRDR_FORMAT*) calloc(length, sizeof(CLIPRDR_FORMAT))))
{
WLog_ERR(TAG, "failed to allocate %d CLIPRDR_FORMAT structs", length);
goto out;
}
}
for (i = 0; i < length; i++)
{
atom = ((Atom*) data)[i];
format = xf_cliprdr_get_client_format_by_atom(clipboard, atom);
if (format)
{
formats[*numFormats].formatId = format->formatId;
formats[*numFormats].formatName = _strdup(format->formatName);
*numFormats += 1;
}
}
out:
2016-10-06 14:31:25 +03:00
if (data)
XFree(data);
return formats;
}
2016-10-06 14:31:25 +03:00
static CLIPRDR_FORMAT* xf_cliprdr_get_client_formats(xfClipboard* clipboard,
UINT32* numFormats)
{
CLIPRDR_FORMAT* formats = NULL;
*numFormats = 0;
if (xf_cliprdr_is_raw_transfer_available(clipboard))
{
formats = xf_cliprdr_get_raw_server_formats(clipboard, numFormats);
}
if (*numFormats == 0)
{
xf_cliprdr_free_formats(formats, *numFormats);
formats = xf_cliprdr_get_formats_from_targets(clipboard, numFormats);
}
return formats;
}
static void xf_cliprdr_provide_server_format_list(xfClipboard* clipboard)
{
wStream* formats = NULL;
xfContext* xfc = clipboard->xfc;
formats = xf_cliprdr_serialize_server_format_list(clipboard);
if (formats)
{
XChangeProperty(xfc->display, xfc->drawable, clipboard->raw_format_list_atom,
2016-10-06 14:31:25 +03:00
clipboard->raw_format_list_atom, 8, PropModeReplace,
Stream_Buffer(formats), Stream_Length(formats));
}
else
{
XDeleteProperty(xfc->display, xfc->drawable, clipboard->raw_format_list_atom);
}
Stream_Free(formats, TRUE);
}
static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard)
{
UINT32 numFormats = 0;
CLIPRDR_FORMAT* formats = NULL;
CLIPRDR_FORMAT_LIST formatList;
formats = xf_cliprdr_get_client_formats(clipboard, &numFormats);
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
formatList.msgFlags = CB_RESPONSE_OK;
formatList.numFormats = numFormats;
formatList.formats = formats;
clipboard->context->ClientFormatList(clipboard->context, &formatList);
xf_cliprdr_free_formats(formats, numFormats);
}
2016-10-06 14:31:25 +03:00
static void xf_cliprdr_process_requested_data(xfClipboard* clipboard,
BOOL hasData, BYTE* data, int size)
2011-09-23 07:37:17 +04:00
{
BOOL bSuccess;
UINT32 SrcSize;
UINT32 DstSize;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
UINT32 srcFormatId;
UINT32 dstFormatId;
BYTE* pDstData = NULL;
2014-10-15 23:49:57 +04:00
xfCliprdrFormat* format;
2011-09-23 07:37:17 +04:00
if (clipboard->incr_starts && hasData)
2011-09-23 07:37:17 +04:00
return;
2016-10-06 14:31:25 +03:00
format = xf_cliprdr_get_client_format_by_id(clipboard,
clipboard->requestedFormatId);
2014-10-15 23:49:57 +04:00
if (!hasData || !data || !format)
2011-09-23 07:37:17 +04:00
{
2014-10-15 23:49:57 +04:00
xf_cliprdr_send_data_response(clipboard, NULL, 0);
2011-09-23 07:37:17 +04:00
return;
}
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
srcFormatId = 0;
2014-10-15 23:49:57 +04:00
switch (format->formatId)
2011-09-23 07:37:17 +04:00
{
case CF_RAW:
srcFormatId = CF_RAW;
break;
case CF_TEXT:
case CF_OEMTEXT:
case CF_UNICODETEXT:
size = strlen((char*) data) + 1;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
srcFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING");
2011-09-23 07:37:17 +04:00
break;
case CF_DIB:
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
srcFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp");
2011-09-23 07:37:17 +04:00
break;
case CB_FORMAT_HTML:
size = strlen((char*) data) + 1;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
srcFormatId = ClipboardGetFormatId(clipboard->system, "text/html");
2011-09-23 07:37:17 +04:00
break;
}
SrcSize = (UINT32) size;
2016-10-06 14:31:25 +03:00
bSuccess = ClipboardSetData(clipboard->system, srcFormatId, data, SrcSize);
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
if (format->formatName)
dstFormatId = ClipboardGetFormatId(clipboard->system, format->formatName);
else
dstFormatId = format->formatId;
2011-09-23 07:37:17 +04:00
if (bSuccess)
{
DstSize = 0;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize);
}
if (!pDstData)
{
xf_cliprdr_send_data_response(clipboard, NULL, 0);
return;
}
xf_cliprdr_send_data_response(clipboard, pDstData, (int) DstSize);
free(pDstData);
2011-09-23 07:37:17 +04:00
}
2014-10-15 06:24:07 +04:00
static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target)
2011-09-23 07:37:17 +04:00
{
Atom type;
BYTE* data = NULL;
BOOL has_data = FALSE;
2014-10-15 23:49:57 +04:00
int format_property;
unsigned long dummy;
unsigned long length;
unsigned long bytes_left;
xfCliprdrFormat* format;
2014-10-15 06:24:07 +04:00
xfContext* xfc = clipboard->xfc;
2016-10-06 14:31:25 +03:00
format = xf_cliprdr_get_client_format_by_id(clipboard,
clipboard->requestedFormatId);
2014-10-15 23:49:57 +04:00
if (!format || (format->atom != target))
2011-09-23 07:37:17 +04:00
{
2014-10-15 23:49:57 +04:00
xf_cliprdr_send_data_response(clipboard, NULL, 0);
return FALSE;
2011-09-23 07:37:17 +04:00
}
XGetWindowProperty(xfc->display, xfc->drawable,
2016-10-06 14:31:25 +03:00
clipboard->property_atom, 0, 0, 0, target,
&type, &format_property, &length, &bytes_left, &data);
2011-09-23 07:37:17 +04:00
if (data)
{
XFree(data);
data = NULL;
}
2014-10-15 06:24:07 +04:00
if (bytes_left <= 0 && !clipboard->incr_starts)
2011-09-23 07:37:17 +04:00
{
}
2014-10-15 06:24:07 +04:00
else if (type == clipboard->incr_atom)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
clipboard->incr_starts = TRUE;
2014-10-15 06:24:07 +04:00
if (clipboard->incr_data)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
free(clipboard->incr_data);
clipboard->incr_data = NULL;
2011-09-23 07:37:17 +04:00
}
2014-10-15 06:24:07 +04:00
clipboard->incr_data_length = 0;
has_data = TRUE; /* data will be followed in PropertyNotify event */
2011-09-23 07:37:17 +04:00
}
else
{
if (bytes_left <= 0)
{
/* INCR finish */
2014-10-15 06:24:07 +04:00
data = clipboard->incr_data;
clipboard->incr_data = NULL;
bytes_left = clipboard->incr_data_length;
clipboard->incr_data_length = 0;
clipboard->incr_starts = 0;
has_data = TRUE;
2011-09-23 07:37:17 +04:00
}
else if (XGetWindowProperty(xfc->display, xfc->drawable,
2016-10-06 14:31:25 +03:00
clipboard->property_atom, 0, bytes_left, 0, target,
&type, &format_property, &length, &dummy, &data) == Success)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
if (clipboard->incr_starts)
2011-09-23 07:37:17 +04:00
{
2016-10-06 14:31:25 +03:00
BYTE* new_data;
2014-10-15 23:49:57 +04:00
bytes_left = length * format_property / 8;
2016-10-06 14:31:25 +03:00
new_data = (BYTE*) realloc(clipboard->incr_data,
clipboard->incr_data_length + bytes_left);
if (!new_data)
return FALSE;
2016-10-06 14:31:25 +03:00
clipboard->incr_data = new_data;
2016-10-06 14:31:25 +03:00
CopyMemory(clipboard->incr_data + clipboard->incr_data_length, data,
bytes_left);
2014-10-15 06:24:07 +04:00
clipboard->incr_data_length += bytes_left;
2011-09-23 07:37:17 +04:00
XFree(data);
data = NULL;
}
2016-10-06 14:31:25 +03:00
has_data = TRUE;
2011-09-23 07:37:17 +04:00
}
else
{
}
}
2014-10-15 23:49:57 +04:00
2014-10-15 06:24:07 +04:00
XDeleteProperty(xfc->display, xfc->drawable, clipboard->property_atom);
xf_cliprdr_process_requested_data(clipboard, has_data, data, (int) bytes_left);
2011-09-23 07:37:17 +04:00
if (data)
XFree(data);
return TRUE;
2011-09-23 07:37:17 +04:00
}
2014-10-15 06:24:07 +04:00
static void xf_cliprdr_append_target(xfClipboard* clipboard, Atom target)
2011-09-23 07:37:17 +04:00
{
int i;
2014-10-15 23:49:57 +04:00
if (clipboard->numTargets >= ARRAYSIZE(clipboard->targets))
2011-09-23 07:37:17 +04:00
return;
2014-10-15 23:49:57 +04:00
for (i = 0; i < clipboard->numTargets; i++)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
if (clipboard->targets[i] == target)
2011-09-23 07:37:17 +04:00
return;
}
2014-10-15 23:49:57 +04:00
clipboard->targets[clipboard->numTargets++] = target;
2011-09-23 07:37:17 +04:00
}
2014-10-15 06:24:07 +04:00
static void xf_cliprdr_provide_targets(xfClipboard* clipboard, XEvent* respond)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
xfContext* xfc = clipboard->xfc;
2011-09-23 07:37:17 +04:00
if (respond->xselection.property != None)
{
2014-10-15 23:49:57 +04:00
XChangeProperty(xfc->display, respond->xselection.requestor,
2016-10-06 14:31:25 +03:00
respond->xselection.property, XA_ATOM, 32, PropModeReplace,
(BYTE*) clipboard->targets, clipboard->numTargets);
2011-09-23 07:37:17 +04:00
}
}
2016-10-06 14:31:25 +03:00
static void xf_cliprdr_provide_data(xfClipboard* clipboard, XEvent* respond,
BYTE* data, UINT32 size)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
xfContext* xfc = clipboard->xfc;
2011-09-23 07:37:17 +04:00
if (respond->xselection.property != None)
{
2014-10-15 23:49:57 +04:00
XChangeProperty(xfc->display, respond->xselection.requestor,
2016-10-06 14:31:25 +03:00
respond->xselection.property, respond->xselection.target,
8, PropModeReplace, data, size);
2011-09-23 07:37:17 +04:00
}
}
2016-10-06 14:31:25 +03:00
static BOOL xf_cliprdr_process_selection_notify(xfClipboard* clipboard,
XEvent* xevent)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
if (xevent->xselection.target == clipboard->targets[1])
2011-09-23 07:37:17 +04:00
{
if (xevent->xselection.property == None)
{
2014-10-16 23:05:06 +04:00
xf_cliprdr_send_client_format_list(clipboard);
2011-09-23 07:37:17 +04:00
}
else
{
2014-10-15 06:24:07 +04:00
xf_cliprdr_get_requested_targets(clipboard);
2011-09-23 07:37:17 +04:00
}
return TRUE;
2011-09-23 07:37:17 +04:00
}
else
{
2014-10-15 06:24:07 +04:00
return xf_cliprdr_get_requested_data(clipboard, xevent->xselection.target);
2011-09-23 07:37:17 +04:00
}
}
2016-10-06 14:31:25 +03:00
static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard,
XEvent* xevent)
2011-09-23 07:37:17 +04:00
{
int fmt;
Atom type;
2014-10-15 23:49:57 +04:00
UINT32 formatId;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
const char* formatName;
2011-09-23 07:37:17 +04:00
XEvent* respond;
BYTE* data = NULL;
BOOL delayRespond;
BOOL rawTransfer;
2014-10-15 23:49:57 +04:00
unsigned long length;
unsigned long bytes_left;
CLIPRDR_FORMAT* format;
2014-10-15 06:24:07 +04:00
xfContext* xfc = clipboard->xfc;
2011-09-23 07:37:17 +04:00
if (xevent->xselectionrequest.owner != xfc->drawable)
return FALSE;
2011-09-23 07:37:17 +04:00
delayRespond = FALSE;
if (!(respond = (XEvent*) calloc(1, sizeof(XEvent))))
{
WLog_ERR(TAG, "failed to allocate XEvent data");
return FALSE;
}
2011-09-23 07:37:17 +04:00
respond->xselection.property = None;
respond->xselection.type = SelectionNotify;
respond->xselection.display = xevent->xselectionrequest.display;
respond->xselection.requestor = xevent->xselectionrequest.requestor;
respond->xselection.selection = xevent->xselectionrequest.selection;
respond->xselection.target = xevent->xselectionrequest.target;
respond->xselection.time = xevent->xselectionrequest.time;
2014-10-15 06:24:07 +04:00
if (xevent->xselectionrequest.target == clipboard->targets[0]) /* TIMESTAMP */
2011-09-23 07:37:17 +04:00
{
/* TODO */
}
2016-10-06 14:31:25 +03:00
else if (xevent->xselectionrequest.target ==
clipboard->targets[1]) /* TARGETS */
2011-09-23 07:37:17 +04:00
{
/* Someone else requests our available formats */
respond->xselection.property = xevent->xselectionrequest.property;
2014-10-15 06:24:07 +04:00
xf_cliprdr_provide_targets(clipboard, respond);
2011-09-23 07:37:17 +04:00
}
else
{
2016-10-06 14:31:25 +03:00
format = xf_cliprdr_get_server_format_by_atom(clipboard,
xevent->xselectionrequest.target);
2014-10-15 23:49:57 +04:00
if (format && (xevent->xselectionrequest.requestor != xfc->drawable))
2011-09-23 07:37:17 +04:00
{
2014-10-15 23:49:57 +04:00
formatId = format->formatId;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
formatName = format->formatName;
rawTransfer = FALSE;
if (formatId == CF_RAW)
2011-09-23 07:37:17 +04:00
{
if (XGetWindowProperty(xfc->display, xevent->xselectionrequest.requestor,
2016-10-06 14:31:25 +03:00
clipboard->property_atom, 0, 4, 0, XA_INTEGER,
&type, &fmt, &length, &bytes_left, &data) != Success)
2011-09-23 07:37:17 +04:00
{
}
2014-10-16 06:48:18 +04:00
2011-09-23 07:37:17 +04:00
if (data)
{
rawTransfer = TRUE;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
CopyMemory(&formatId, data, 4);
2011-09-23 07:37:17 +04:00
XFree(data);
}
}
2016-10-06 14:31:25 +03:00
if ((clipboard->data != 0) && (formatId == clipboard->data_format_id)
&& (formatName == clipboard->data_format_name))
2011-09-23 07:37:17 +04:00
{
/* Cached clipboard data available. Send it now */
respond->xselection.property = xevent->xselectionrequest.property;
2016-10-06 14:31:25 +03:00
xf_cliprdr_provide_data(clipboard, respond, clipboard->data,
clipboard->data_length);
2011-09-23 07:37:17 +04:00
}
2014-10-15 06:24:07 +04:00
else if (clipboard->respond)
2011-09-23 07:37:17 +04:00
{
2014-10-16 06:48:18 +04:00
/* duplicate request */
2011-09-23 07:37:17 +04:00
}
else
{
/**
* Send clipboard data request to the server.
* Response will be postponed after receiving the data
*/
2014-10-15 06:24:07 +04:00
if (clipboard->data)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
free(clipboard->data);
clipboard->data = NULL;
2011-09-23 07:37:17 +04:00
}
2011-09-23 07:37:17 +04:00
respond->xselection.property = xevent->xselectionrequest.property;
2014-10-15 06:24:07 +04:00
clipboard->respond = respond;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
clipboard->data_format_id = formatId;
clipboard->data_format_name = formatName;
clipboard->data_raw_format = rawTransfer;
delayRespond = TRUE;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
xf_cliprdr_send_data_request(clipboard, formatId);
2011-09-23 07:37:17 +04:00
}
}
}
if (!delayRespond)
2011-09-23 07:37:17 +04:00
{
XSendEvent(xfc->display, xevent->xselectionrequest.requestor, 0, 0, respond);
XFlush(xfc->display);
free(respond);
2011-09-23 07:37:17 +04:00
}
return TRUE;
2011-09-23 07:37:17 +04:00
}
2016-10-06 14:31:25 +03:00
static BOOL xf_cliprdr_process_selection_clear(xfClipboard* clipboard,
XEvent* xevent)
2011-09-23 07:37:17 +04:00
{
2014-10-15 06:24:07 +04:00
xfContext* xfc = clipboard->xfc;
2011-09-23 07:37:17 +04:00
2014-10-15 06:24:07 +04:00
if (xf_cliprdr_is_self_owned(clipboard))
return FALSE;
2011-09-23 07:37:17 +04:00
2014-10-15 06:24:07 +04:00
XDeleteProperty(xfc->display, clipboard->root_window, clipboard->property_atom);
return TRUE;
2011-09-23 07:37:17 +04:00
}
2016-10-06 14:31:25 +03:00
static BOOL xf_cliprdr_process_property_notify(xfClipboard* clipboard,
XEvent* xevent)
2011-09-23 07:37:17 +04:00
{
2014-10-15 23:49:57 +04:00
xfCliprdrFormat* format;
2014-10-15 06:24:07 +04:00
xfContext* xfc = clipboard->xfc;
2011-09-23 07:37:17 +04:00
2014-10-15 06:24:07 +04:00
if (!clipboard)
return TRUE;
2014-10-15 06:24:07 +04:00
if (xevent->xproperty.atom != clipboard->property_atom)
return FALSE; /* Not cliprdr-related */
2011-09-23 07:37:17 +04:00
2014-10-15 06:24:07 +04:00
if (xevent->xproperty.window == clipboard->root_window)
2011-09-23 07:37:17 +04:00
{
2014-10-16 06:48:18 +04:00
xf_cliprdr_send_client_format_list(clipboard);
2011-09-23 07:37:17 +04:00
}
2014-10-15 23:49:57 +04:00
else if ((xevent->xproperty.window == xfc->drawable) &&
2016-10-06 14:31:25 +03:00
(xevent->xproperty.state == PropertyNewValue) && clipboard->incr_starts)
2011-09-23 07:37:17 +04:00
{
2016-10-06 14:31:25 +03:00
format = xf_cliprdr_get_client_format_by_id(clipboard,
clipboard->requestedFormatId);
2014-10-15 23:49:57 +04:00
if (format)
xf_cliprdr_get_requested_data(clipboard, format->atom);
2011-09-23 07:37:17 +04:00
}
return TRUE;
2011-09-23 07:37:17 +04:00
}
void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event)
{
2014-10-15 06:24:07 +04:00
xfClipboard* clipboard;
if (!xfc || !event)
return;
2014-10-15 23:49:57 +04:00
clipboard = xfc->clipboard;
if (!clipboard)
return;
#ifdef WITH_XFIXES
2016-10-06 14:31:25 +03:00
if (clipboard->xfixes_supported
&& event->type == XFixesSelectionNotify + clipboard->xfixes_event_base)
{
XFixesSelectionNotifyEvent* se = (XFixesSelectionNotifyEvent*) event;
2014-10-15 06:24:07 +04:00
if (se->subtype == XFixesSetSelectionOwnerNotify)
{
2014-10-15 06:24:07 +04:00
if (se->selection != clipboard->clipboard_atom)
return;
if (XGetSelectionOwner(xfc->display, se->selection) == xfc->drawable)
return;
2014-10-15 06:24:07 +04:00
clipboard->owner = None;
2014-10-15 23:49:57 +04:00
xf_cliprdr_check_owner(clipboard);
}
2014-10-15 06:24:07 +04:00
return;
}
2016-10-06 14:31:25 +03:00
#endif
2014-10-15 06:24:07 +04:00
switch (event->type)
{
case SelectionNotify:
2014-10-15 23:49:57 +04:00
xf_cliprdr_process_selection_notify(clipboard, event);
break;
2014-10-15 06:24:07 +04:00
case SelectionRequest:
2014-10-15 23:49:57 +04:00
xf_cliprdr_process_selection_request(clipboard, event);
break;
2014-10-15 06:24:07 +04:00
case SelectionClear:
2014-10-15 23:49:57 +04:00
xf_cliprdr_process_selection_clear(clipboard, event);
break;
2014-10-15 06:24:07 +04:00
case PropertyNotify:
2014-10-15 23:49:57 +04:00
xf_cliprdr_process_property_notify(clipboard, event);
break;
2014-10-15 06:24:07 +04:00
case FocusIn:
2014-10-15 06:24:07 +04:00
if (!clipboard->xfixes_supported)
{
2014-10-15 23:49:57 +04:00
xf_cliprdr_check_owner(clipboard);
}
2016-10-06 14:31:25 +03:00
break;
}
}
2014-10-15 06:24:07 +04:00
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT xf_cliprdr_send_client_capabilities(xfClipboard* clipboard)
2014-10-15 06:24:07 +04:00
{
CLIPRDR_CAPABILITIES capabilities;
CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
capabilities.cCapabilitiesSets = 1;
2016-10-06 14:31:25 +03:00
capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &
(generalCapabilitySet);
generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
generalCapabilitySet.capabilitySetLength = 12;
generalCapabilitySet.version = CB_CAPS_VERSION_2;
generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
2016-10-06 14:31:25 +03:00
return clipboard->context->ClientCapabilities(clipboard->context,
&capabilities);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard)
{
2014-10-16 23:05:06 +04:00
UINT32 i, numFormats;
CLIPRDR_FORMAT* formats = NULL;
2014-10-16 06:48:18 +04:00
CLIPRDR_FORMAT_LIST formatList;
xfContext* xfc = clipboard->xfc;
UINT ret;
2014-10-16 06:48:18 +04:00
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
2014-10-16 23:05:06 +04:00
numFormats = clipboard->numClientFormats;
2016-10-06 14:31:25 +03:00
if (numFormats)
{
if (!(formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT))))
{
WLog_ERR(TAG, "failed to allocate %d CLIPRDR_FORMAT structs", numFormats);
return CHANNEL_RC_NO_MEMORY;
}
}
2014-10-16 06:48:18 +04:00
2014-10-16 23:05:06 +04:00
for (i = 0; i < numFormats; i++)
{
formats[i].formatId = clipboard->clientFormats[i].formatId;
formats[i].formatName = clipboard->clientFormats[i].formatName;
2014-10-16 06:48:18 +04:00
}
2014-10-16 23:05:06 +04:00
formatList.msgFlags = CB_RESPONSE_OK;
formatList.numFormats = numFormats;
2014-10-16 23:05:06 +04:00
formatList.formats = formats;
ret = clipboard->context->ClientFormatList(clipboard->context, &formatList);
2014-10-16 23:05:06 +04:00
free(formats);
2014-10-16 06:48:18 +04:00
if (clipboard->owner && clipboard->owner != xfc->drawable)
2014-10-16 06:48:18 +04:00
{
/* Request the owner for TARGETS, and wait for SelectionNotify event */
XConvertSelection(xfc->display, clipboard->clipboard_atom,
2016-10-06 14:31:25 +03:00
clipboard->targets[1], clipboard->property_atom, xfc->drawable, CurrentTime);
2014-10-16 06:48:18 +04:00
}
return ret;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
UINT xf_cliprdr_send_client_format_list_response(xfClipboard* clipboard,
BOOL status)
{
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
formatListResponse.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
formatListResponse.dataLen = 0;
2016-10-06 14:31:25 +03:00
return clipboard->context->ClientFormatListResponse(clipboard->context,
&formatListResponse);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
static UINT xf_cliprdr_monitor_ready(CliprdrClientContext* context,
CLIPRDR_MONITOR_READY* monitorReady)
{
xfClipboard* clipboard = (xfClipboard*) context->custom;
UINT ret;
if ((ret = xf_cliprdr_send_client_capabilities(clipboard)) != CHANNEL_RC_OK)
return ret;
2016-10-06 14:31:25 +03:00
if ((ret = xf_cliprdr_send_client_format_list(clipboard)) != CHANNEL_RC_OK)
return ret;
2014-10-15 23:49:57 +04:00
clipboard->sync = TRUE;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
static UINT xf_cliprdr_server_capabilities(CliprdrClientContext* context,
CLIPRDR_CAPABILITIES* capabilities)
2014-10-15 06:24:07 +04:00
{
//xfClipboard* clipboard = (xfClipboard*) context->custom;
return CHANNEL_RC_OK;
2014-10-15 06:24:07 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
CLIPRDR_FORMAT_LIST* formatList)
2014-10-15 06:24:07 +04:00
{
2014-10-15 23:49:57 +04:00
int i, j;
CLIPRDR_FORMAT* format;
xfClipboard* clipboard = (xfClipboard*) context->custom;
xfContext* xfc = clipboard->xfc;
UINT ret;
2014-10-15 06:24:07 +04:00
2014-10-15 23:49:57 +04:00
if (clipboard->data)
{
free(clipboard->data);
clipboard->data = NULL;
}
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
clipboard->data_format_id = -1;
clipboard->data_format_name = NULL;
2014-10-15 23:49:57 +04:00
if (clipboard->serverFormats)
{
2014-10-16 06:48:18 +04:00
for (i = 0; i < clipboard->numServerFormats; i++)
free(clipboard->serverFormats[i].formatName);
2014-10-15 23:49:57 +04:00
free(clipboard->serverFormats);
clipboard->serverFormats = NULL;
2014-10-16 23:05:06 +04:00
clipboard->numServerFormats = 0;
2014-10-15 23:49:57 +04:00
}
clipboard->numServerFormats = formatList->numFormats + 1; /* +1 for CF_RAW */
2014-10-15 23:49:57 +04:00
2016-10-06 14:31:25 +03:00
if (!(clipboard->serverFormats = (CLIPRDR_FORMAT*) calloc(
clipboard->numServerFormats, sizeof(CLIPRDR_FORMAT))))
{
WLog_ERR(TAG, "failed to allocate %d CLIPRDR_FORMAT structs",
clipboard->numServerFormats);
return CHANNEL_RC_NO_MEMORY;
}
2014-10-15 23:49:57 +04:00
for (i = 0; i < formatList->numFormats; i++)
2014-10-15 23:49:57 +04:00
{
format = &formatList->formats[i];
clipboard->serverFormats[i].formatId = format->formatId;
2016-10-06 14:31:25 +03:00
if (format->formatName)
{
clipboard->serverFormats[i].formatName = _strdup(format->formatName);
2016-10-06 14:31:25 +03:00
if (!clipboard->serverFormats[i].formatName)
{
for (--i; i >= 0; --i)
free(clipboard->serverFormats[i].formatName);
clipboard->numServerFormats = 0;
free(clipboard->serverFormats);
clipboard->serverFormats = NULL;
return CHANNEL_RC_NO_MEMORY;
}
}
2014-10-15 23:49:57 +04:00
}
/* CF_RAW is always implicitly supported by the server */
format = &clipboard->serverFormats[formatList->numFormats];
format->formatId = CF_RAW;
format->formatName = NULL;
xf_cliprdr_provide_server_format_list(clipboard);
2014-10-15 23:49:57 +04:00
clipboard->numTargets = 2;
for (i = 0; i < formatList->numFormats; i++)
2014-10-15 23:49:57 +04:00
{
format = &formatList->formats[i];
for (j = 0; j < clipboard->numClientFormats; j++)
{
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
if (xf_cliprdr_formats_equal(format, &clipboard->clientFormats[j]))
2014-10-15 23:49:57 +04:00
{
xf_cliprdr_append_target(clipboard, clipboard->clientFormats[j].atom);
}
}
}
ret = xf_cliprdr_send_client_format_list_response(clipboard, TRUE);
2016-10-06 14:31:25 +03:00
XSetSelectionOwner(xfc->display, clipboard->clipboard_atom, xfc->drawable,
CurrentTime);
2014-10-16 06:48:18 +04:00
XFlush(xfc->display);
return ret;
2014-10-15 06:24:07 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
static UINT xf_cliprdr_server_format_list_response(CliprdrClientContext*
context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
2014-10-15 06:24:07 +04:00
{
//xfClipboard* clipboard = (xfClipboard*) context->custom;
return CHANNEL_RC_OK;
2014-10-15 06:24:07 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
static UINT xf_cliprdr_server_format_data_request(CliprdrClientContext* context,
CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
2014-10-15 06:24:07 +04:00
{
BOOL rawTransfer;
xfCliprdrFormat* format = NULL;
UINT32 formatId = formatDataRequest->requestedFormatId;
xfClipboard* clipboard = (xfClipboard*) context->custom;
xfContext* xfc = clipboard->xfc;
rawTransfer = xf_cliprdr_is_raw_transfer_available(clipboard);
if (rawTransfer)
{
format = xf_cliprdr_get_client_format_by_id(clipboard, CF_RAW);
XChangeProperty(xfc->display, xfc->drawable, clipboard->property_atom,
2016-10-06 14:31:25 +03:00
XA_INTEGER, 32, PropModeReplace, (BYTE*) &formatId, 1);
}
else
format = xf_cliprdr_get_client_format_by_id(clipboard, formatId);
if (!format)
return xf_cliprdr_send_data_response(clipboard, NULL, 0);
clipboard->requestedFormatId = rawTransfer ? CF_RAW : formatId;
XConvertSelection(xfc->display, clipboard->clipboard_atom,
2016-10-06 14:31:25 +03:00
format->atom, clipboard->property_atom, xfc->drawable, CurrentTime);
XFlush(xfc->display);
/* After this point, we expect a SelectionNotify event from the clipboard owner. */
return CHANNEL_RC_OK;
2014-10-15 06:24:07 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2016-10-06 14:31:25 +03:00
static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext*
context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
2014-10-15 06:24:07 +04:00
{
BOOL bSuccess;
2014-10-16 23:05:06 +04:00
BYTE* pDstData;
UINT32 DstSize;
UINT32 SrcSize;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
UINT32 srcFormatId;
UINT32 dstFormatId;
BOOL nullTerminated = FALSE;
UINT32 size = formatDataResponse->dataLen;
BYTE* data = formatDataResponse->requestedFormatData;
xfClipboard* clipboard = (xfClipboard*) context->custom;
xfContext* xfc = clipboard->xfc;
if (!clipboard->respond)
return CHANNEL_RC_OK;
if (clipboard->data)
{
free(clipboard->data);
clipboard->data = NULL;
}
pDstData = NULL;
2014-12-07 02:29:28 +03:00
DstSize = 0;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
srcFormatId = 0;
dstFormatId = 0;
if (clipboard->data_raw_format)
{
srcFormatId = CF_RAW;
dstFormatId = CF_RAW;
}
else if (clipboard->data_format_name)
{
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
if (strcmp(clipboard->data_format_name, "HTML Format") == 0)
{
srcFormatId = ClipboardGetFormatId(clipboard->system, "HTML Format");
dstFormatId = ClipboardGetFormatId(clipboard->system, "text/html");
nullTerminated = TRUE;
}
}
else
{
switch (clipboard->data_format_id)
{
2016-10-06 14:31:25 +03:00
case CF_TEXT:
srcFormatId = CF_TEXT;
dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING");
nullTerminated = TRUE;
break;
case CF_OEMTEXT:
srcFormatId = CF_OEMTEXT;
dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING");
nullTerminated = TRUE;
break;
case CF_UNICODETEXT:
srcFormatId = CF_UNICODETEXT;
dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING");
nullTerminated = TRUE;
break;
case CF_DIB:
srcFormatId = CF_DIB;
dstFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp");
break;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
}
}
SrcSize = (UINT32) size;
2016-10-06 14:31:25 +03:00
bSuccess = ClipboardSetData(clipboard->system, srcFormatId, data, SrcSize);
2014-10-16 23:05:06 +04:00
if (bSuccess)
{
DstSize = 0;
client/X11: improve named clipboard format support Clipboard formats are identified by numerical IDs and literal names. We can keep using arbitrary defined IDs for local clipboard formats as we are sure that they have some fixed meaning, but the server can and will be using its own IDs, which can be different from ours for the named formats. Therefore: 1) A correct way to compare a local format to a remote one is to check the names first, and only then compare their IDs. (Extra care should be taken to support short format names.) 2) Server IDs cannot be used with wClipboard directly when dealing with named formats. Format name should be used to extract correct local ID for the use with Clipboard{Set,Get}Data(). Also, I find the notion of 'alternate' format IDs to be confusing. We either deal with a fixed ID format (declared in <winpr/user.h>), or a format that was given an arbitrary fixed ID for local use (defined in <freerdp/channels/cliprdr.h>), or a remote format identified by a pair of an ID and a name. Format IDs can be local and remote, but there are no 'alternates'. So now: 1) A new function xf_cliprdr_formats_equal() is used to compare formats correctly in xf_cliprdr_get_server_format_by_atom() when searching for a server format corresponding to a local one, and in xf_cliprdr_server_format_list() when constructing a local TARGETS list from the server format list. 2) Correct local format IDs are used with wClipboard conversions by xf_cliprdr_process_requested_data() and xf_cliprdr_server_format_data_response(). 3) We refer to formatId and formatName when doing requests, and srcFormatId and dstFormatId when doing conversions, instead of using formatId and altFormatId for both purposes. 4) Server format ID and name are used to identify cached clipboard contents. The name is compared directly as a pointer because it will be a pointer from the same clipboard->serverFormats array. Also, the clipboard contents are invalidated when format list arrives, so xf_cliprdr_server_format_list() now also clears the format ID and name together with the data.
2015-08-17 11:35:19 +03:00
pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize);
if (nullTerminated)
{
while (DstSize > 0 && pDstData[DstSize - 1] == '\0')
DstSize--;
}
}
clipboard->data = pDstData;
clipboard->data_length = DstSize;
xf_cliprdr_provide_data(clipboard, clipboard->respond, pDstData, DstSize);
2016-10-06 14:31:25 +03:00
XSendEvent(xfc->display, clipboard->respond->xselection.requestor, 0, 0,
clipboard->respond);
XFlush(xfc->display);
free(clipboard->respond);
clipboard->respond = NULL;
return CHANNEL_RC_OK;
2014-10-15 06:24:07 +04:00
}
xfClipboard* xf_clipboard_new(xfContext* xfc)
{
int n;
rdpChannels* channels;
xfClipboard* clipboard;
if (!(clipboard = (xfClipboard*) calloc(1, sizeof(xfClipboard))))
{
WLog_ERR(TAG, "failed to allocate xfClipboard data");
return NULL;
}
2014-10-15 06:24:07 +04:00
xfc->clipboard = clipboard;
clipboard->xfc = xfc;
channels = ((rdpContext*) xfc)->channels;
clipboard->channels = channels;
clipboard->system = ClipboardCreate();
2014-10-15 23:49:57 +04:00
clipboard->requestedFormatId = -1;
2014-10-15 06:24:07 +04:00
clipboard->root_window = DefaultRootWindow(xfc->display);
clipboard->clipboard_atom = XInternAtom(xfc->display, "CLIPBOARD", FALSE);
if (clipboard->clipboard_atom == None)
{
WLog_ERR(TAG, "unable to get CLIPBOARD atom");
2014-10-16 06:56:25 +04:00
free(clipboard);
return NULL;
2014-10-15 06:24:07 +04:00
}
clipboard->property_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR", FALSE);
2016-10-06 14:31:25 +03:00
clipboard->raw_transfer_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_RAW",
FALSE);
clipboard->raw_format_list_atom = XInternAtom(xfc->display,
"_FREERDP_CLIPRDR_FORMATS", FALSE);
xf_cliprdr_set_raw_transfer_enabled(clipboard, TRUE);
2014-10-15 06:24:07 +04:00
XSelectInput(xfc->display, clipboard->root_window, PropertyChangeMask);
#ifdef WITH_XFIXES
2016-10-06 14:31:25 +03:00
if (XFixesQueryExtension(xfc->display, &clipboard->xfixes_event_base,
&clipboard->xfixes_error_base))
2014-10-15 06:24:07 +04:00
{
int xfmajor, xfminor;
2014-10-16 06:48:18 +04:00
2014-10-15 06:24:07 +04:00
if (XFixesQueryVersion(xfc->display, &xfmajor, &xfminor))
{
XFixesSelectSelectionInput(xfc->display, clipboard->root_window,
2016-10-06 14:31:25 +03:00
clipboard->clipboard_atom, XFixesSetSelectionOwnerNotifyMask);
2014-10-15 06:24:07 +04:00
clipboard->xfixes_supported = TRUE;
}
else
{
WLog_ERR(TAG, "Error querying X Fixes extension version");
}
}
else
{
WLog_ERR(TAG, "Error loading X Fixes extension");
}
2016-10-06 14:31:25 +03:00
2014-10-15 06:24:07 +04:00
#else
2016-10-06 14:31:25 +03:00
WLog_ERR(TAG,
"Warning: Using clipboard redirection without XFIXES extension is strongly discouraged!");
2014-10-15 06:24:07 +04:00
#endif
n = 0;
2016-10-06 14:31:25 +03:00
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "_FREERDP_RAW",
False);
clipboard->clientFormats[n].formatId = CF_RAW;
2014-10-15 23:49:57 +04:00
n++;
2016-10-06 14:31:25 +03:00
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "UTF8_STRING",
False);
clipboard->clientFormats[n].formatId = CF_UNICODETEXT;
2014-10-15 06:24:07 +04:00
n++;
2014-10-15 23:49:57 +04:00
clipboard->clientFormats[n].atom = XA_STRING;
clipboard->clientFormats[n].formatId = CF_TEXT;
2014-10-15 06:24:07 +04:00
n++;
2016-10-06 14:31:25 +03:00
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/png",
False);
2014-10-15 23:49:57 +04:00
clipboard->clientFormats[n].formatId = CB_FORMAT_PNG;
2014-10-15 06:24:07 +04:00
n++;
2016-10-06 14:31:25 +03:00
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/jpeg",
False);
2014-10-15 23:49:57 +04:00
clipboard->clientFormats[n].formatId = CB_FORMAT_JPEG;
2014-10-15 06:24:07 +04:00
n++;
2016-10-06 14:31:25 +03:00
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/gif",
False);
2014-10-15 23:49:57 +04:00
clipboard->clientFormats[n].formatId = CB_FORMAT_GIF;
2014-10-15 06:24:07 +04:00
n++;
2016-10-06 14:31:25 +03:00
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/bmp",
False);
clipboard->clientFormats[n].formatId = CF_DIB;
2014-10-15 06:24:07 +04:00
n++;
2016-10-06 14:31:25 +03:00
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "text/html",
False);
2014-10-15 23:49:57 +04:00
clipboard->clientFormats[n].formatId = CB_FORMAT_HTML;
clipboard->clientFormats[n].formatName = _strdup("HTML Format");
2016-10-06 14:31:25 +03:00
if (!clipboard->clientFormats[n].formatName)
{
ClipboardDestroy(clipboard->system);
free(clipboard);
return NULL;
}
2014-10-15 06:24:07 +04:00
2016-10-06 14:31:25 +03:00
n++;
2014-10-15 23:49:57 +04:00
clipboard->numClientFormats = n;
2014-10-15 06:24:07 +04:00
clipboard->targets[0] = XInternAtom(xfc->display, "TIMESTAMP", FALSE);
clipboard->targets[1] = XInternAtom(xfc->display, "TARGETS", FALSE);
2014-10-15 23:49:57 +04:00
clipboard->numTargets = 2;
2014-10-15 06:24:07 +04:00
clipboard->incr_atom = XInternAtom(xfc->display, "INCR", FALSE);
return clipboard;
}
void xf_clipboard_free(xfClipboard* clipboard)
{
2014-10-16 06:56:25 +04:00
int i;
2014-10-15 06:24:07 +04:00
if (!clipboard)
return;
2014-10-16 06:56:25 +04:00
if (clipboard->serverFormats)
{
for (i = 0; i < clipboard->numServerFormats; i++)
free(clipboard->serverFormats[i].formatName);
free(clipboard->serverFormats);
clipboard->serverFormats = NULL;
}
2014-12-03 22:17:27 +03:00
if (clipboard->numClientFormats)
{
for (i = 0; i < clipboard->numClientFormats; i++)
free(clipboard->clientFormats[i].formatName);
}
ClipboardDestroy(clipboard->system);
2014-10-15 06:24:07 +04:00
free(clipboard->data);
free(clipboard->respond);
free(clipboard->incr_data);
free(clipboard);
}
void xf_cliprdr_init(xfContext* xfc, CliprdrClientContext* cliprdr)
{
xfc->cliprdr = cliprdr;
xfc->clipboard->context = cliprdr;
2014-10-15 06:24:07 +04:00
cliprdr->custom = (void*) xfc->clipboard;
cliprdr->MonitorReady = xf_cliprdr_monitor_ready;
cliprdr->ServerCapabilities = xf_cliprdr_server_capabilities;
cliprdr->ServerFormatList = xf_cliprdr_server_format_list;
cliprdr->ServerFormatListResponse = xf_cliprdr_server_format_list_response;
cliprdr->ServerFormatDataRequest = xf_cliprdr_server_format_data_request;
cliprdr->ServerFormatDataResponse = xf_cliprdr_server_format_data_response;
}
void xf_cliprdr_uninit(xfContext* xfc, CliprdrClientContext* cliprdr)
{
xfc->cliprdr = NULL;
cliprdr->custom = NULL;
if (xfc->clipboard)
xfc->clipboard->context = NULL;
2014-10-15 06:24:07 +04:00
}