Merge pull request #10385 from akallabeth/clipboard-fix

Clipboard fix
This commit is contained in:
akallabeth 2024-07-17 14:42:51 +02:00 committed by GitHub
commit 7d6bdbaef8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 194 additions and 50 deletions

View File

@ -41,37 +41,6 @@
const char* type_FileGroupDescriptorW = "FileGroupDescriptorW";
const char* type_FileContents = "FileContents";
static const char* CB_MSG_TYPE_STRINGS(UINT32 type)
{
switch (type)
{
case CB_MONITOR_READY:
return "CB_MONITOR_READY";
case CB_FORMAT_LIST:
return "CB_FORMAT_LIST";
case CB_FORMAT_LIST_RESPONSE:
return "CB_FORMAT_LIST_RESPONSE";
case CB_FORMAT_DATA_REQUEST:
return "CB_FORMAT_DATA_REQUEST";
case CB_FORMAT_DATA_RESPONSE:
return "CB_FORMAT_DATA_RESPONSE";
case CB_TEMP_DIRECTORY:
return "CB_TEMP_DIRECTORY";
case CB_CLIP_CAPS:
return "CB_CLIP_CAPS";
case CB_FILECONTENTS_REQUEST:
return "CB_FILECONTENTS_REQUEST";
case CB_FILECONTENTS_RESPONSE:
return "CB_FILECONTENTS_RESPONSE";
case CB_LOCK_CLIPDATA:
return "CB_LOCK_CLIPDATA";
case CB_UNLOCK_CLIPDATA:
return "CB_UNLOCK_CLIPDATA";
default:
return "UNKNOWN";
}
}
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr)
{
CliprdrClientContext* pInterface = NULL;
@ -475,8 +444,11 @@ static UINT cliprdr_order_recv(LPVOID userdata, wStream* s)
if (!Stream_CheckAndLogRequiredLength(TAG, s, dataLen))
return ERROR_INVALID_DATA;
WLog_DBG(TAG, "msgType: %s (%" PRIu16 "), msgFlags: %" PRIu16 " dataLen: %" PRIu32 "",
CB_MSG_TYPE_STRINGS(msgType), msgType, msgFlags, dataLen);
char buffer1[64] = { 0 };
char buffer2[64] = { 0 };
WLog_DBG(TAG, "msgType: %s (%" PRIu16 "), msgFlags: %s dataLen: %" PRIu32 "",
CB_MSG_TYPE_STRING(msgType, buffer1, sizeof(buffer1)), msgType,
CB_MSG_FLAGS_STRING(msgFlags, buffer2, sizeof(buffer2)), dataLen);
switch (msgType)
{

View File

@ -28,6 +28,67 @@
#include "cliprdr_common.h"
static const char* CB_MSG_TYPE_STR(UINT32 type)
{
switch (type)
{
case CB_MONITOR_READY:
return "CB_MONITOR_READY";
case CB_FORMAT_LIST:
return "CB_FORMAT_LIST";
case CB_FORMAT_LIST_RESPONSE:
return "CB_FORMAT_LIST_RESPONSE";
case CB_FORMAT_DATA_REQUEST:
return "CB_FORMAT_DATA_REQUEST";
case CB_FORMAT_DATA_RESPONSE:
return "CB_FORMAT_DATA_RESPONSE";
case CB_TEMP_DIRECTORY:
return "CB_TEMP_DIRECTORY";
case CB_CLIP_CAPS:
return "CB_CLIP_CAPS";
case CB_FILECONTENTS_REQUEST:
return "CB_FILECONTENTS_REQUEST";
case CB_FILECONTENTS_RESPONSE:
return "CB_FILECONTENTS_RESPONSE";
case CB_LOCK_CLIPDATA:
return "CB_LOCK_CLIPDATA";
case CB_UNLOCK_CLIPDATA:
return "CB_UNLOCK_CLIPDATA";
default:
return "UNKNOWN";
}
}
const char* CB_MSG_TYPE_STRING(UINT16 type, char* buffer, size_t size)
{
_snprintf(buffer, size, "%s [0x%04" PRIx16 "]", CB_MSG_TYPE_STR(type), type);
return buffer;
}
const char* CB_MSG_FLAGS_STRING(UINT16 msgFlags, char* buffer, size_t size)
{
if ((msgFlags & CB_RESPONSE_OK) != 0)
winpr_str_append("CB_RESPONSE_OK", buffer, size, "|");
if ((msgFlags & CB_RESPONSE_FAIL) != 0)
winpr_str_append("CB_RESPONSE_FAIL", buffer, size, "|");
if ((msgFlags & CB_ASCII_NAMES) != 0)
winpr_str_append("CB_ASCII_NAMES", buffer, size, "|");
const size_t len = strnlen(buffer, size);
if (len > 0)
{
/* remove trailing | */
buffer[len - 1] = '\0';
}
else
winpr_str_append("NONE", buffer, size, "");
char val[32] = { 0 };
_snprintf(val, sizeof(val), "[0x%04" PRIx16 "]", msgFlags);
winpr_str_append(val, buffer, size, "|");
return buffer;
}
static BOOL cliprdr_validate_file_contents_request(const CLIPRDR_FILE_CONTENTS_REQUEST* request)
{
/*

View File

@ -29,6 +29,9 @@
#include <freerdp/channels/cliprdr.h>
#include <freerdp/api.h>
FREERDP_LOCAL const char* CB_MSG_TYPE_STRING(UINT16 type, char* buffer, size_t size);
FREERDP_LOCAL const char* CB_MSG_FLAGS_STRING(UINT16 msgFlags, char* buffer, size_t size);
FREERDP_LOCAL wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen);
FREERDP_LOCAL wStream*
cliprdr_packet_lock_clipdata_new(const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData);

View File

@ -902,10 +902,11 @@ static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s
WINPR_ASSERT(context);
WINPR_ASSERT(header);
WLog_DBG(TAG,
"CliprdrServerReceivePdu: msgType: %" PRIu16 " msgFlags: 0x%04" PRIX16
" dataLen: %" PRIu32 "",
header->msgType, header->msgFlags, header->dataLen);
char buffer1[64] = { 0 };
char buffer2[64] = { 0 };
WLog_DBG(TAG, "CliprdrServerReceivePdu: msgType: %s, msgFlags: %s dataLen: %" PRIu32 "",
CB_MSG_TYPE_STRING(header->msgType, buffer1, sizeof(buffer1)),
CB_MSG_FLAGS_STRING(header->msgFlags, buffer2, sizeof(buffer2)), header->dataLen);
switch (header->msgType)
{

View File

@ -785,7 +785,9 @@ void xf_lock_x11_(xfContext* xfc, const char* fkt)
XLockDisplay(xfc->display);
xfc->locked++;
#ifdef WITH_DEBUG_X11
WLog_VRB(TAG, "[%" PRIu32 "] from %s", xfc->locked, fkt);
#endif
}
void xf_unlock_x11_(xfContext* xfc, const char* fkt)
@ -793,7 +795,10 @@ void xf_unlock_x11_(xfContext* xfc, const char* fkt)
if (xfc->locked == 0)
WLog_WARN(TAG, "X11: trying to unlock although not locked!");
#ifdef WITH_DEBUG_X11
WLog_VRB(TAG, "[%" PRIu32 "] from %s", xfc->locked - 1, fkt);
#endif
if (!xfc->UseXThreads)
ReleaseMutex(xfc->mutex);
else

View File

@ -124,6 +124,7 @@ struct xf_clipboard
BOOL incr_starts;
BYTE* incr_data;
int incr_data_length;
long event_mask;
/* XFixes extension */
int xfixes_event_base;
@ -607,6 +608,23 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_raw_server_formats(xfClipboard* clipboard,
return formats;
}
static BOOL xf_cliprdr_should_add_format(const CLIPRDR_FORMAT* formats, size_t count,
const xfCliprdrFormat* xformat)
{
WINPR_ASSERT(formats);
if (!xformat)
return FALSE;
for (size_t x = 0; x < count; x++)
{
const CLIPRDR_FORMAT* format = &formats[x];
if (format->formatId == xformat->formatToRequest)
return FALSE;
}
return TRUE;
}
static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets(xfClipboard* clipboard,
UINT32* numFormats)
{
@ -647,10 +665,18 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets(xfClipboard* clipboar
Atom tatom = ((Atom*)data)[i];
const xfCliprdrFormat* format = xf_cliprdr_get_client_format_by_atom(clipboard, tatom);
if (format)
if (xf_cliprdr_should_add_format(formats, *numFormats, format))
{
formats[*numFormats].formatId = format->formatToRequest;
formats[*numFormats].formatName = _strdup(format->formatName);
CLIPRDR_FORMAT* cformat = &formats[*numFormats];
cformat->formatId = format->formatToRequest;
if (format->formatName)
{
cformat->formatName = _strdup(format->formatName);
WINPR_ASSERT(cformat->formatName);
}
else
cformat->formatName = NULL;
*numFormats += 1;
}
}
@ -837,8 +863,8 @@ static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard)
xf_cliprdr_free_formats(formats, numFormats);
}
static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData, BYTE* data,
int size)
static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData,
const BYTE* data, size_t size)
{
BOOL bSuccess = 0;
UINT32 SrcSize = 0;
@ -871,7 +897,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasDa
case CF_TEXT:
case CF_OEMTEXT:
case CF_UNICODETEXT:
size = strlen((char*)data) + 1;
size = strlen((const char*)data) + 1;
srcFormatId = format->localFormat;
break;
@ -944,6 +970,37 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasDa
free(pDstData);
}
static BOOL xf_add_input_flags(xfClipboard* clipboard, long mask)
{
WINPR_ASSERT(clipboard);
xfContext* xfc = clipboard->xfc;
WINPR_ASSERT(xfc);
XWindowAttributes attr = { 0 };
XGetWindowAttributes(xfc->display, xfc->drawable, &attr);
if ((attr.all_event_masks & mask) == 0)
clipboard->event_mask = attr.all_event_masks;
XSelectInput(xfc->display, xfc->drawable, attr.all_event_masks | mask);
return TRUE;
}
static BOOL xf_restore_input_flags(xfClipboard* clipboard)
{
WINPR_ASSERT(clipboard);
xfContext* xfc = clipboard->xfc;
WINPR_ASSERT(xfc);
if (clipboard->event_mask != 0)
{
XSelectInput(xfc->display, xfc->drawable, clipboard->event_mask);
clipboard->event_mask = 0;
}
return TRUE;
}
static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target)
{
Atom type = 0;
@ -993,7 +1050,7 @@ static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target)
clipboard->incr_data_length = 0;
has_data = TRUE; /* data will be followed in PropertyNotify event */
XSelectInput(xfc->display, xfc->drawable, PropertyChangeMask);
xf_add_input_flags(clipboard, PropertyChangeMask);
}
else
{
@ -1004,7 +1061,11 @@ static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target)
clipboard->incr_data = NULL;
bytes_left = clipboard->incr_data_length;
clipboard->incr_data_length = 0;
clipboard->incr_starts = 0;
clipboard->incr_starts = FALSE;
/* Restore previous event mask */
xf_restore_input_flags(clipboard);
has_data = TRUE;
}
else if (LogTagAndXGetWindowProperty(
@ -1210,7 +1271,6 @@ void xf_cliprdr_clear_cached_data(xfClipboard* clipboard)
ClipboardLock(clipboard->system);
ClipboardEmpty(clipboard->system);
cliprdr_file_context_clear(clipboard->file);
HashTable_Clear(clipboard->cachedData);
HashTable_Clear(clipboard->cachedRawData);
@ -1683,8 +1743,9 @@ static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard, BOOL forc
if (clipboard->owner && clipboard->owner != xfc->drawable)
{
/* Request the owner for TARGETS, and wait for SelectionNotify event */
XConvertSelection(xfc->display, clipboard->clipboard_atom, clipboard->targets[1],
clipboard->property_atom, xfc->drawable, CurrentTime);
LogTagAndXConvertSelection(TAG, xfc->display, clipboard->clipboard_atom,
clipboard->targets[1], clipboard->property_atom, xfc->drawable,
CurrentTime);
}
xf_cliprdr_free_formats(formats, numFormats);
@ -1987,8 +2048,8 @@ xf_cliprdr_server_format_data_request(CliprdrClientContext* context,
DEBUG_CLIPRDR("requested format 0x%08" PRIx32 " [%s] {local 0x%08" PRIx32 "} [%s]",
format->formatToRequest, ClipboardGetFormatIdString(format->formatToRequest),
format->localFormat, format->formatName);
XConvertSelection(xfc->display, clipboard->clipboard_atom, format->atom,
clipboard->property_atom, xfc->drawable, CurrentTime);
LogTagAndXConvertSelection(TAG, xfc->display, clipboard->clipboard_atom, 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;

View File

@ -86,6 +86,34 @@ int LogDynAndXDeleteProperty_ex(wLog* log, const char* file, const char* fkt, si
return XDeleteProperty(display, w, property);
}
int LogTagAndXConvertSelection_ex(const char* tag, const char* file, const char* fkt, size_t line,
Display* display, Atom selection, Atom target, Atom property,
Window requestor, Time time)
{
wLog* log = WLog_Get(tag);
return LogDynAndXConvertSelection_ex(log, file, fkt, line, display, selection, target, property,
requestor, time);
}
int LogDynAndXConvertSelection_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Atom selection, Atom target, Atom property,
Window requestor, Time time)
{
if (WLog_IsLevelActive(log, log_level))
{
char* selectstr = Safe_XGetAtomName(log, display, selection);
char* targetstr = Safe_XGetAtomName(log, display, target);
char* propstr = Safe_XGetAtomName(log, display, property);
write_log(log, log_level, file, fkt, line,
"XConvertSelection(%p, %s [%d], %s [%d], %s [%d], %d, %lu)", display, selectstr,
selection, targetstr, target, propstr, property, requestor, time);
XFree(propstr);
XFree(targetstr);
XFree(selectstr);
}
return XConvertSelection(display, selection, target, property, requestor, time);
}
int LogTagAndXGetWindowProperty_ex(const char* tag, const char* file, const char* fkt, size_t line,
Display* display, Window w, Atom property, long long_offset,
long long_length, int delete, Atom req_type,

View File

@ -76,3 +76,16 @@ int LogTagAndXDeleteProperty_ex(const char* tag, const char* file, const char* f
LogDynAndXDeleteProperty_ex((log), __FILE__, __func__, __LINE__, (display), (w), (property))
int LogDynAndXDeleteProperty_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Window w, Atom property);
#define LogTagAndXConvertSelection(tag, display, selection, target, property, requestor, time) \
LogTagAndXConvertSelection_ex((tag), __FILE__, __func__, __LINE__, (display), (selection), \
(target), (property), (requestor), (time))
int LogTagAndXConvertSelection_ex(const char* tag, const char* file, const char* fkt, size_t line,
Display* display, Atom selection, Atom target, Atom property,
Window requestor, Time time);
#define LogDynAndXConvertSelection(log, display, selection, target, property, requestor, time) \
LogDynAndXConvertSelection_ex((log), __FILE__, __func__, __LINE__, (display), (w), (property))
int LogDynAndXConvertSelection_ex(wLog* log, const char* file, const char* fkt, size_t line,
Display* display, Atom selection, Atom target, Atom property,
Window requestor, Time time);