[client,x11] fixed file clipboard cache

if files are pasted in different file-browser (or e.g. xclip is used)
the data was retrieved in wrong format.
This commit is contained in:
Armin Novak 2023-02-21 16:24:41 +01:00 committed by akallabeth
parent 9cb28f47ef
commit b8a709ccda
2 changed files with 95 additions and 78 deletions

View File

@ -142,13 +142,13 @@ struct xf_clipboard
Atom raw_transfer_atom; Atom raw_transfer_atom;
Atom raw_format_list_atom; Atom raw_format_list_atom;
int numClientFormats; UINT32 numClientFormats;
xfCliprdrFormat clientFormats[20]; xfCliprdrFormat clientFormats[20];
int numServerFormats; UINT32 numServerFormats;
CLIPRDR_FORMAT* serverFormats; CLIPRDR_FORMAT* serverFormats;
int numTargets; size_t numTargets;
Atom targets[20]; Atom targets[20];
int requestedFormatId; int requestedFormatId;
@ -156,7 +156,7 @@ struct xf_clipboard
BYTE* data; BYTE* data;
BYTE* data_raw; BYTE* data_raw;
BOOL data_raw_format; BOOL data_raw_format;
UINT32 data_format_id; INT32 data_format_id;
const char* data_format_name; const char* data_format_name;
int data_length; int data_length;
int data_raw_length; int data_raw_length;
@ -205,6 +205,22 @@ static const char* mime_mate_copied_files = "x-special/mate-copied-files";
static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard, BOOL force); static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard, BOOL force);
static void xf_cliprdr_set_selection_owner(xfContext* xfc, xfClipboard* clipboard, Time timestamp); static void xf_cliprdr_set_selection_owner(xfContext* xfc, xfClipboard* clipboard, Time timestamp);
static void xf_clipboard_free_server_formats(xfClipboard* clipboard)
{
WINPR_ASSERT(clipboard);
if (clipboard->serverFormats)
{
for (size_t i = 0; i < clipboard->numServerFormats; i++)
{
CLIPRDR_FORMAT* format = &clipboard->serverFormats[i];
free(format->formatName);
}
free(clipboard->serverFormats);
clipboard->serverFormats = NULL;
}
}
static void xf_cliprdr_check_owner(xfClipboard* clipboard) static void xf_cliprdr_check_owner(xfClipboard* clipboard)
{ {
Window owner; Window owner;
@ -314,11 +330,9 @@ static BOOL xf_cliprdr_formats_equal(const CLIPRDR_FORMAT* server, const xfClipr
static const xfCliprdrFormat* xf_cliprdr_get_client_format_by_id(xfClipboard* clipboard, static const xfCliprdrFormat* xf_cliprdr_get_client_format_by_id(xfClipboard* clipboard,
UINT32 formatId) UINT32 formatId)
{ {
int index;
WINPR_ASSERT(clipboard); WINPR_ASSERT(clipboard);
for (index = 0; index < clipboard->numClientFormats; index++) for (size_t index = 0; index < clipboard->numClientFormats; index++)
{ {
const xfCliprdrFormat* format = &(clipboard->clientFormats[index]); const xfCliprdrFormat* format = &(clipboard->clientFormats[index]);
@ -332,11 +346,9 @@ static const xfCliprdrFormat* xf_cliprdr_get_client_format_by_id(xfClipboard* cl
static const xfCliprdrFormat* xf_cliprdr_get_client_format_by_atom(xfClipboard* clipboard, static const xfCliprdrFormat* xf_cliprdr_get_client_format_by_atom(xfClipboard* clipboard,
Atom atom) Atom atom)
{ {
int i;
WINPR_ASSERT(clipboard); WINPR_ASSERT(clipboard);
for (i = 0; i < clipboard->numClientFormats; i++) for (UINT32 i = 0; i < clipboard->numClientFormats; i++)
{ {
const xfCliprdrFormat* format = &(clipboard->clientFormats[i]); const xfCliprdrFormat* format = &(clipboard->clientFormats[i]);
@ -351,14 +363,13 @@ static const CLIPRDR_FORMAT* xf_cliprdr_get_server_format_by_atom(xfClipboard* c
{ {
WINPR_ASSERT(clipboard); WINPR_ASSERT(clipboard);
for (int i = 0; i < clipboard->numClientFormats; i++) for (size_t i = 0; i < clipboard->numClientFormats; i++)
{ {
const xfCliprdrFormat* client_format = &(clipboard->clientFormats[i]); const xfCliprdrFormat* client_format = &(clipboard->clientFormats[i]);
if (client_format->atom == atom) if (client_format->atom == atom)
{ {
int j; for (size_t j = 0; j < clipboard->numServerFormats; j++)
for (j = 0; j < clipboard->numServerFormats; j++)
{ {
const CLIPRDR_FORMAT* server_format = &(clipboard->serverFormats[j]); const CLIPRDR_FORMAT* server_format = &(clipboard->serverFormats[j]);
@ -845,11 +856,13 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasDa
srcFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); srcFormatId = ClipboardGetFormatId(clipboard->system, "text/html");
break; break;
case CB_FORMAT_TEXTURILIST:
srcFormatId = ClipboardGetFormatId(clipboard->system, mime_uri_list);
break;
default: default:
srcFormatId = ClipboardGetFormatId(clipboard->system, mime_uri_list);
if (srcFormatId != format->formatId)
srcFormatId = ClipboardGetFormatId(clipboard->system, mime_gnome_copied_files);
if (srcFormatId != format->formatId)
srcFormatId = ClipboardGetFormatId(clipboard->system, mime_mate_copied_files);
if (srcFormatId != format->formatId)
xf_cliprdr_send_data_response(clipboard, NULL, 0); xf_cliprdr_send_data_response(clipboard, NULL, 0);
return; return;
} }
@ -1265,10 +1278,17 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard,
if (matchingFormat && (clipboard->data != 0) && !rawTransfer) if (matchingFormat && (clipboard->data != 0) && !rawTransfer)
{ {
const xfCliprdrFormat* cformat =
xf_cliprdr_get_client_format_by_atom(clipboard, xevent->target);
UINT32 DstSize = 0;
WINPR_ASSERT(cformat);
/* Cached converted clipboard data available. Send it now */ /* Cached converted clipboard data available. Send it now */
respond->property = xevent->property; respond->property = xevent->property;
xf_cliprdr_provide_data(clipboard, respond, clipboard->data, void* data = ClipboardGetData(clipboard->system, cformat->formatId, &DstSize);
clipboard->data_length); xf_cliprdr_provide_data(clipboard, respond, data, DstSize);
} }
else if (matchingFormat && (clipboard->data_raw != 0) && rawTransfer) else if (matchingFormat && (clipboard->data_raw != 0) && rawTransfer)
{ {
@ -1499,7 +1519,7 @@ static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard, BOOL forc
} }
} }
for (i = 0; i < numFormats; i++) for (size_t i = 0; i < numFormats; i++)
{ {
const xfCliprdrFormat* clientFormat = &clipboard->clientFormats[i]; const xfCliprdrFormat* clientFormat = &clipboard->clientFormats[i];
CLIPRDR_FORMAT* format = &formats[i]; CLIPRDR_FORMAT* format = &formats[i];
@ -1813,8 +1833,6 @@ static void xf_cliprdr_set_selection_owner(xfContext* xfc, xfClipboard* clipboar
static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
const CLIPRDR_FORMAT_LIST* formatList) const CLIPRDR_FORMAT_LIST* formatList)
{ {
UINT32 i;
int j;
xfContext* xfc; xfContext* xfc;
UINT ret; UINT ret;
xfClipboard* clipboard; xfClipboard* clipboard;
@ -1837,15 +1855,7 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
clipboard->data_format_id = -1; clipboard->data_format_id = -1;
clipboard->data_format_name = NULL; clipboard->data_format_name = NULL;
if (clipboard->serverFormats) xf_clipboard_free_server_formats(clipboard);
{
for (j = 0; j < clipboard->numServerFormats; j++)
free(clipboard->serverFormats[j].formatName);
free(clipboard->serverFormats);
clipboard->serverFormats = NULL;
clipboard->numServerFormats = 0;
}
clipboard->numServerFormats = formatList->numFormats + 1; /* +1 for CF_RAW */ clipboard->numServerFormats = formatList->numFormats + 1; /* +1 for CF_RAW */
@ -1856,7 +1866,7 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
return CHANNEL_RC_NO_MEMORY; return CHANNEL_RC_NO_MEMORY;
} }
for (i = 0; i < formatList->numFormats; i++) for (size_t i = 0; i < formatList->numFormats; i++)
{ {
const CLIPRDR_FORMAT* format = &formatList->formats[i]; const CLIPRDR_FORMAT* format = &formatList->formats[i];
CLIPRDR_FORMAT* srvFormat = &clipboard->serverFormats[i]; CLIPRDR_FORMAT* srvFormat = &clipboard->serverFormats[i];
@ -1891,11 +1901,11 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
xf_cliprdr_provide_server_format_list(clipboard); xf_cliprdr_provide_server_format_list(clipboard);
clipboard->numTargets = 2; clipboard->numTargets = 2;
for (i = 0; i < formatList->numFormats; i++) for (size_t i = 0; i < formatList->numFormats; i++)
{ {
const CLIPRDR_FORMAT* format = &formatList->formats[i]; const CLIPRDR_FORMAT* format = &formatList->formats[i];
for (j = 0; j < clipboard->numClientFormats; j++) for (size_t j = 0; j < clipboard->numClientFormats; j++)
{ {
const xfCliprdrFormat* clientFormat = &clipboard->clientFormats[j]; const xfCliprdrFormat* clientFormat = &clipboard->clientFormats[j];
if (xf_cliprdr_formats_equal(format, clientFormat)) if (xf_cliprdr_formats_equal(format, clientFormat))
@ -2304,10 +2314,17 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context,
case CF_UNICODETEXT: case CF_UNICODETEXT:
dstFormatId = ClipboardGetFormatId(clipboard->system, mime_text_plain); dstFormatId = ClipboardGetFormatId(clipboard->system, mime_text_plain);
break; break;
case CB_FORMAT_TEXTURILIST:
dstFormatId = ClipboardGetFormatId(clipboard->system, mime_uri_list);
break;
default: default:
dstFormatId = ClipboardGetFormatId(clipboard->system, mime_uri_list);
if (dstFormatId != dstTargetFormat->formatId)
dstFormatId =
ClipboardGetFormatId(clipboard->system, mime_gnome_copied_files);
if (dstFormatId != dstTargetFormat->formatId)
dstFormatId =
ClipboardGetFormatId(clipboard->system, mime_mate_copied_files);
if (dstFormatId != dstTargetFormat->formatId)
dstFormatId = 0;
break; break;
} }
} }
@ -3146,7 +3163,7 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction)
if (clipboard->clipboard_atom == None) if (clipboard->clipboard_atom == None)
{ {
WLog_ERR(TAG, "unable to get %s atom", selectionAtom); WLog_ERR(TAG, "unable to get %s atom", selectionAtom);
goto error; goto fail;
} }
clipboard->timestamp_property_atom = clipboard->timestamp_property_atom =
@ -3219,7 +3236,7 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction)
clientFormat->formatName = _strdup("HTML Format"); clientFormat->formatName = _strdup("HTML Format");
if (!clientFormat->formatName) if (!clientFormat->formatName)
goto error; goto fail;
clientFormat = &clipboard->clientFormats[n++]; clientFormat = &clipboard->clientFormats[n++];
@ -3229,19 +3246,46 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction)
* registration). However, they are definitely not supported if there are no registered * registration). However, they are definitely not supported if there are no registered
* formats. In this case we should not list file formats in TARGETS. * formats. In this case we should not list file formats in TARGETS.
*/ */
if (ClipboardGetFormatId(clipboard->system, mime_uri_list)) const UINT32 uid = ClipboardGetFormatId(clipboard->system, mime_uri_list);
if (uid)
{ {
clipboard->file_formats_registered = TRUE; clipboard->file_formats_registered = TRUE;
clientFormat->atom = XInternAtom(xfc->display, mime_uri_list, False); clientFormat->atom = XInternAtom(xfc->display, mime_uri_list, False);
clientFormat->formatId = CB_FORMAT_TEXTURILIST; clientFormat->formatId = uid;
clientFormat->formatName = _strdup(mime_FileGroupDescriptorW); clientFormat->formatName = _strdup(mime_FileGroupDescriptorW);
if (!clientFormat->formatName) if (!clientFormat->formatName)
goto error; goto fail;
clientFormat = &clipboard->clientFormats[n++]; clientFormat = &clipboard->clientFormats[n++];
} }
const UINT32 gid = ClipboardGetFormatId(clipboard->system, mime_gnome_copied_files);
if (gid != 0)
{
clipboard->file_formats_registered = TRUE;
clientFormat->atom = XInternAtom(xfc->display, mime_gnome_copied_files, False);
clientFormat->formatId = gid;
clientFormat->formatName = _strdup(mime_FileGroupDescriptorW);
if (!clientFormat->formatName)
goto fail;
clientFormat = &clipboard->clientFormats[n++];
}
const UINT32 mid = ClipboardGetFormatId(clipboard->system, mime_mate_copied_files);
if (mid != 0)
{
clipboard->file_formats_registered = TRUE;
clientFormat->atom = XInternAtom(xfc->display, mime_mate_copied_files, False);
clientFormat->formatId = mid;
clientFormat->formatName = _strdup(mime_FileGroupDescriptorW);
if (!clientFormat->formatName)
goto fail;
}
clipboard->numClientFormats = n; clipboard->numClientFormats = n;
clipboard->targets[0] = XInternAtom(xfc->display, "TIMESTAMP", FALSE); clipboard->targets[0] = XInternAtom(xfc->display, "TIMESTAMP", FALSE);
clipboard->targets[1] = XInternAtom(xfc->display, "TARGETS", FALSE); clipboard->targets[1] = XInternAtom(xfc->display, "TARGETS", FALSE);
@ -3256,7 +3300,7 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction)
if (!clipboard->stream_list) if (!clipboard->stream_list)
{ {
WLog_ERR(TAG, "failed to allocate stream_list"); WLog_ERR(TAG, "failed to allocate stream_list");
goto error; goto fail;
} }
wObject* obj = ArrayList_Object(clipboard->stream_list); wObject* obj = ArrayList_Object(clipboard->stream_list);
obj->fnObjectFree = free; obj->fnObjectFree = free;
@ -3265,18 +3309,18 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction)
if (!clipboard->ino_list) if (!clipboard->ino_list)
{ {
WLog_ERR(TAG, "failed to allocate stream_list"); WLog_ERR(TAG, "failed to allocate stream_list");
goto error2; goto fail;
} }
obj = ArrayList_Object(clipboard->ino_list); obj = ArrayList_Object(clipboard->ino_list);
obj->fnObjectFree = xf_cliprdr_fuse_inode_free; obj->fnObjectFree = xf_cliprdr_fuse_inode_free;
if (!xf_fuse_repopulate(clipboard->ino_list)) if (!xf_fuse_repopulate(clipboard->ino_list))
goto error3; goto fail;
if (!(clipboard->fuse_thread = if (!(clipboard->fuse_thread =
CreateThread(NULL, 0, xf_cliprdr_fuse_thread, clipboard, 0, NULL))) CreateThread(NULL, 0, xf_cliprdr_fuse_thread, clipboard, 0, NULL)))
{ {
goto error3; goto fail;
} }
#endif #endif
@ -3293,24 +3337,8 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction)
return clipboard; return clipboard;
#if defined(WITH_FUSE2) || defined(WITH_FUSE3) fail:
error3: xf_clipboard_free(clipboard);
ArrayList_Free(clipboard->ino_list);
error2:
ArrayList_Free(clipboard->stream_list);
#endif
error:
for (i = 0; i < n; i++)
{
xfCliprdrFormat* format = &clipboard->clientFormats[i];
free(format->formatName);
}
ClipboardDestroy(clipboard->system);
free(clipboard);
return NULL; return NULL;
} }
@ -3319,17 +3347,7 @@ void xf_clipboard_free(xfClipboard* clipboard)
if (!clipboard) if (!clipboard)
return; return;
if (clipboard->serverFormats) xf_clipboard_free_server_formats(clipboard);
{
for (int i = 0; i < clipboard->numServerFormats; i++)
{
CLIPRDR_FORMAT* format = &clipboard->serverFormats[i];
free(format->formatName);
}
free(clipboard->serverFormats);
clipboard->serverFormats = NULL;
}
if (clipboard->numClientFormats) if (clipboard->numClientFormats)
{ {

View File

@ -37,8 +37,7 @@ typedef enum
CB_FORMAT_HTML = 0xD010, CB_FORMAT_HTML = 0xD010,
CB_FORMAT_PNG = 0xD011, CB_FORMAT_PNG = 0xD011,
CB_FORMAT_JPEG = 0xD012, CB_FORMAT_JPEG = 0xD012,
CB_FORMAT_GIF = 0xD013, CB_FORMAT_GIF = 0xD013
CB_FORMAT_TEXTURILIST = 0xD014
} CliprdrFormatType; } CliprdrFormatType;
/* CLIPRDR_HEADER.msgType */ /* CLIPRDR_HEADER.msgType */