ReactOS 0.4.15-dev-8408-g466a198
xclip.c File Reference
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "rdesktop.h"
Include dependency graph for xclip.c:

Go to the source code of this file.

Macros

#define RDP_CF_TEXT   CF_TEXT
 

Functions

static void crlf2lf (uint8 *data, uint32 *length)
 
static uint8lf2crlf (uint8 *data, uint32 *length)
 
static void xclip_provide_selection (RDPCLIENT *This, XSelectionRequestEvent *req, Atom type, unsigned int format, uint8 *data, uint32 length)
 
static void xclip_refuse_selection (RDPCLIENT *This, XSelectionRequestEvent *req)
 
static void helper_cliprdr_send_response (RDPCLIENT *This, uint8 *data, uint32 length)
 
static void helper_cliprdr_send_empty_response (RDPCLIENT *This)
 
static Bool xclip_send_data_with_convert (RDPCLIENT *This, uint8 *source, size_t source_size, Atom target)
 
static void xclip_clear_target_props (RDPCLIENT *This)
 
static void xclip_notify_change (RDPCLIENT *This)
 
static void xclip_probe_selections (RDPCLIENT *This)
 
void xclip_handle_SelectionNotify (RDPCLIENT *This, XSelectionEvent *event)
 
void xclip_handle_SelectionRequest (RDPCLIENT *This, XSelectionRequestEvent *event)
 
void xclip_handle_SelectionClear (RDPCLIENT *This)
 
void xclip_handle_PropertyNotify (RDPCLIENT *This, XPropertyEvent *event)
 
void ui_clip_format_announce (RDPCLIENT *This, uint8 *data, uint32 length)
 
void ui_clip_handle_data (RDPCLIENT *This, uint8 *data, uint32 length)
 
void ui_clip_request_failed (RDPCLIENT *This)
 
void ui_clip_request_data (RDPCLIENT *This, uint32 format)
 
void ui_clip_sync (RDPCLIENT *This)
 
void ui_clip_set_mode (RDPCLIENT *This, const char *optarg)
 
void xclip_init (RDPCLIENT *This)
 
void xclip_deinit (RDPCLIENT *This)
 

Macro Definition Documentation

◆ RDP_CF_TEXT

#define RDP_CF_TEXT   CF_TEXT

Definition at line 48 of file xclip.c.

Function Documentation

◆ crlf2lf()

static void crlf2lf ( uint8 data,
uint32 length 
)
static

Definition at line 57 of file xclip.c.

58{
59 uint8 *dst, *src;
60 src = dst = data;
61 while (src < data + *length)
62 {
63 if (*src != '\x0d')
64 *dst++ = *src;
65 src++;
66 }
67 *length = dst - data;
68}
unsigned char uint8
Definition: types.h:28
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLenum src
Definition: glext.h:6340
GLenum GLenum dst
Definition: glext.h:6340
GLuint GLsizei GLsizei * length
Definition: glext.h:6040

Referenced by ui_clip_handle_data().

◆ helper_cliprdr_send_empty_response()

static void helper_cliprdr_send_empty_response ( RDPCLIENT This)
static

Definition at line 197 of file xclip.c.

198{
200}
#define NULL
Definition: types.h:112
static void helper_cliprdr_send_response(RDPCLIENT *This, uint8 *data, uint32 length)
Definition: xclip.c:182

Referenced by ui_clip_request_data(), xclip_handle_PropertyNotify(), and xclip_handle_SelectionNotify().

◆ helper_cliprdr_send_response()

static void helper_cliprdr_send_response ( RDPCLIENT This,
uint8 data,
uint32  length 
)
static

Definition at line 182 of file xclip.c.

183{
184 if (This->xclip.rdp_clipboard_request_format != 0)
185 {
187 This->xclip.rdp_clipboard_request_format = 0;
188 if (!This->xclip.rdesktop_is_selection_owner)
190 }
191}
void cliprdr_send_simple_native_format_announce(uint32 format)
void cliprdr_send_data(uint8 *data, uint32 length)
#define RDP_CF_TEXT
Definition: xclip.c:48

Referenced by helper_cliprdr_send_empty_response(), and xclip_send_data_with_convert().

◆ lf2crlf()

static uint8 * lf2crlf ( uint8 data,
uint32 length 
)
static

Definition at line 110 of file xclip.c.

111{
112 uint8 *result, *p, *o;
113
114 /* Worst case: Every char is LF */
115 result = xmalloc(*length * 2);
116
117 p = data;
118 o = result;
119
120 while (p < data + *length)
121 {
122 if (*p == '\x0a')
123 *o++ = '\x0d';
124 *o++ = *p++;
125 }
126 *length = o - result;
127
128 /* Convenience */
129 *o++ = '\0';
130
131 return result;
132}
void * xmalloc(int size)
Definition: uimain.c:747
GLfloat GLfloat p
Definition: glext.h:8902
GLuint64EXT * result
Definition: glext.h:11304

Referenced by xclip_send_data_with_convert().

◆ ui_clip_format_announce()

void ui_clip_format_announce ( RDPCLIENT This,
uint8 data,
uint32  length 
)

Definition at line 855 of file xclip.c.

856{
857 This->xclip.acquire_time = This->last_gesturetime;
858
859 XSetSelectionOwner(This->display, This->xclip.primary_atom, This->wnd, This->xclip.acquire_time);
860 if (XGetSelectionOwner(This->display, This->xclip.primary_atom) != This->wnd)
861 warning("Failed to aquire ownership of PRIMARY clipboard\n");
862
863 XSetSelectionOwner(This->display, This->xclip.clipboard_atom, This->wnd, This->xclip.acquire_time);
864 if (XGetSelectionOwner(This->display, This->xclip.clipboard_atom) != This->wnd)
865 warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
866
867 if (This->xclip.formats_data)
868 xfree(This->xclip.formats_data);
869 This->xclip.formats_data = xmalloc(length);
870 memcpy(This->xclip.formats_data, data, length);
871 This->xclip.formats_data_length = length;
872
874}
void xfree(void *mem)
Definition: uimain.c:758
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define warning(s)
Definition: debug.h:83
static void xclip_notify_change(RDPCLIENT *This)
Definition: xclip.c:335

◆ ui_clip_handle_data()

void ui_clip_handle_data ( RDPCLIENT This,
uint8 data,
uint32  length 
)

Definition at line 878 of file xclip.c.

879{
880 BOOL free_data = False;
881
882 if (length == 0)
883 {
884 xclip_refuse_selection(This, &This->xclip.selection_request);
885 This->xclip.has_selection_request = False;
886 return;
887 }
888
889 if (This->xclip.selection_request.target == This->xclip.format_string_atom || This->xclip.selection_request.target == XA_STRING)
890 {
891 /* We're expecting a CF_TEXT response */
892 uint8 *firstnull;
893
894 /* translate linebreaks */
896
897 /* Only send data up to null byte, if any */
898 firstnull = (uint8 *) strchr((char *) data, '\0');
899 if (firstnull)
900 {
901 length = firstnull - data + 1;
902 }
903 }
904#ifdef USE_UNICODE_CLIPBOARD
905 else if (This->xclip.selection_request.target == This->xclip.format_utf8_string_atom)
906 {
907 /* We're expecting a CF_UNICODETEXT response */
909 if (cd != (iconv_t) - 1)
910 {
911 size_t utf8_length = length * 2;
912 char *utf8_data = malloc(utf8_length);
913 size_t utf8_length_remaining = utf8_length;
914 char *utf8_data_remaining = utf8_data;
915 char *data_remaining = (char *) data;
916 size_t length_remaining = (size_t) length;
917 if (utf8_data == NULL)
918 {
920 return;
921 }
922 iconv(cd, (ICONV_CONST char **) &data_remaining, &length_remaining,
923 &utf8_data_remaining, &utf8_length_remaining);
925 free_data = True;
926 data = (uint8 *) utf8_data;
927 length = utf8_length - utf8_length_remaining;
928 }
929 }
930 else if (This->xclip.selection_request.target == This->xclip.format_unicode_atom)
931 {
932 /* We're expecting a CF_UNICODETEXT response, so what we're
933 receiving matches our requirements and there's no need
934 for further conversions. */
935 }
936#endif
937 else if (This->xclip.selection_request.target == This->xclip.rdesktop_native_atom)
938 {
939 /* Pass as-is */
940 }
941 else
942 {
943 DEBUG_CLIPBOARD(("ui_clip_handle_data: BUG! I don't know how to convert selection target %s!\n", XGetAtomName(This->display, This->xclip.selection_request.target)));
944 xclip_refuse_selection(This, &This->xclip.selection_request);
945 This->xclip.has_selection_request = False;
946 return;
947 }
948
949 xclip_provide_selection(This, &This->xclip.selection_request, This->xclip.selection_request.target, 8, data, length - 1);
950 This->xclip.has_selection_request = False;
951
952 if (free_data)
953 free(data);
954}
InitDirComponents & cd
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define WINDOWS_CODEPAGE
Definition: constants.h:24
#define DEBUG_CLIPBOARD(args)
Definition: rdesktop.h:147
#define False
Definition: types.h:25
#define True
Definition: types.h:24
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
__kernel_size_t size_t
Definition: linux.h:237
unsigned int BOOL
Definition: ntddk_ex.h:94
int iconv_close(iconv_t cd)
Definition: win_iconv.c:756
iconv_t iconv_open(const char *tocode, const char *fromcode)
Definition: win_iconv.c:730
size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
Definition: win_iconv.c:771
static const char utf8_length[128]
Definition: utf8.c:28
static void crlf2lf(uint8 *data, uint32 *length)
Definition: xclip.c:57
static void xclip_provide_selection(RDPCLIENT *This, XSelectionRequestEvent *req, Atom type, unsigned int format, uint8 *data, uint32 length)
Definition: xclip.c:136
static void xclip_refuse_selection(RDPCLIENT *This, XSelectionRequestEvent *req)
Definition: xclip.c:161

◆ ui_clip_request_data()

void ui_clip_request_data ( RDPCLIENT This,
uint32  format 
)

Definition at line 964 of file xclip.c.

965{
966 Window primary_owner, clipboard_owner;
967
968 DEBUG_CLIPBOARD(("Request from server for format %d\n", format));
969 This->xclip.rdp_clipboard_request_format = format;
970
971 if (This->xclip.probing_selections)
972 {
973 DEBUG_CLIPBOARD(("ui_clip_request_data: Selection probe in progress. Cannot handle request.\n"));
975 return;
976 }
977
979
980 if (This->xclip.rdesktop_is_selection_owner)
981 {
982 XChangeProperty(This->display, This->wnd, This->xclip.rdesktop_clipboard_target_atom,
983 XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);
984
985 XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.rdesktop_native_atom,
986 This->xclip.rdesktop_clipboard_target_atom, This->wnd, CurrentTime);
987 return;
988 }
989
990 if (This->xclip.auto_mode)
991 primary_owner = XGetSelectionOwner(This->display, This->xclip.primary_atom);
992 else
993 primary_owner = None;
994
995 clipboard_owner = XGetSelectionOwner(This->display, This->xclip.clipboard_atom);
996
997 /* Both available */
998 if ((primary_owner != None) && (clipboard_owner != None))
999 {
1000 This->xclip.primary_timestamp = 0;
1001 This->xclip.clipboard_timestamp = 0;
1002 XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.timestamp_atom,
1003 This->xclip.rdesktop_primary_timestamp_target_atom, This->wnd, CurrentTime);
1004 XConvertSelection(This->display, This->xclip.clipboard_atom, This->xclip.timestamp_atom,
1005 This->xclip.rdesktop_clipboard_timestamp_target_atom, This->wnd, CurrentTime);
1006 return;
1007 }
1008
1009 /* Just PRIMARY */
1010 if (primary_owner != None)
1011 {
1012 XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.targets_atom,
1013 This->xclip.rdesktop_clipboard_target_atom, This->wnd, CurrentTime);
1014 return;
1015 }
1016
1017 /* Just CLIPBOARD */
1018 if (clipboard_owner != None)
1019 {
1020 XConvertSelection(This->display, This->xclip.clipboard_atom, This->xclip.targets_atom,
1021 This->xclip.rdesktop_clipboard_target_atom, This->wnd, CurrentTime);
1022 return;
1023 }
1024
1025 /* No data available */
1027}
@ None
Definition: install.h:14
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
Definition: window.c:28
static void xclip_clear_target_props(RDPCLIENT *This)
Definition: xclip.c:327
static void helper_cliprdr_send_empty_response(RDPCLIENT *This)
Definition: xclip.c:197

◆ ui_clip_request_failed()

void ui_clip_request_failed ( RDPCLIENT This)

Definition at line 957 of file xclip.c.

958{
959 xclip_refuse_selection(This, &This->xclip.selection_request);
960 This->xclip.has_selection_request = False;
961}

◆ ui_clip_set_mode()

void ui_clip_set_mode ( RDPCLIENT This,
const char optarg 
)

Definition at line 1036 of file xclip.c.

1037{
1038 This->rdpclip = True;
1039
1040 if (str_startswith(optarg, "PRIMARYCLIPBOARD"))
1041 This->xclip.auto_mode = True;
1042 else if (str_startswith(optarg, "CLIPBOARD"))
1043 This->xclip.auto_mode = False;
1044 else
1045 {
1046 warning("Invalid clipboard mode '%s'.\n", optarg);
1047 This->rdpclip = False;
1048 }
1049}
RD_BOOL str_startswith(const char *s, const char *prefix)
Definition: rdesktop.c:1235
const char * optarg
Definition: getopt.c:49

◆ ui_clip_sync()

void ui_clip_sync ( RDPCLIENT This)

Definition at line 1030 of file xclip.c.

1031{
1033}
static void xclip_probe_selections(RDPCLIENT *This)
Definition: xclip.c:342

◆ xclip_clear_target_props()

static void xclip_clear_target_props ( RDPCLIENT This)
static

Definition at line 327 of file xclip.c.

328{
329 XDeleteProperty(This->display, This->wnd, This->xclip.rdesktop_clipboard_target_atom);
330 XDeleteProperty(This->display, This->wnd, This->xclip.rdesktop_primary_timestamp_target_atom);
331 XDeleteProperty(This->display, This->wnd, This->xclip.rdesktop_clipboard_timestamp_target_atom);
332}

Referenced by ui_clip_request_data(), xclip_handle_SelectionNotify(), and xclip_probe_selections().

◆ xclip_deinit()

void xclip_deinit ( RDPCLIENT This)

Definition at line 1102 of file xclip.c.

1103{
1104 if (XGetSelectionOwner(This->display, This->xclip.primary_atom) == This->wnd)
1105 XSetSelectionOwner(This->display, This->xclip.primary_atom, None, This->xclip.acquire_time);
1106 if (XGetSelectionOwner(This->display, This->xclip.clipboard_atom) == This->wnd)
1107 XSetSelectionOwner(This->display, This->xclip.clipboard_atom, None, This->xclip.acquire_time);
1109}

◆ xclip_handle_PropertyNotify()

void xclip_handle_PropertyNotify ( RDPCLIENT This,
XPropertyEvent *  event 
)

Definition at line 779 of file xclip.c.

780{
781 unsigned long nitems;
782 unsigned long offset = 0;
783 unsigned long bytes_left = 1;
784 int format;
785 XWindowAttributes wa;
786 uint8 *data;
787 Atom type;
788
789 if (event->state == PropertyNewValue && This->xclip.waiting_for_INCR)
790 {
791 DEBUG_CLIPBOARD(("x_clip_handle_PropertyNotify: This->xclip.waiting_for_INCR != 0\n"));
792
793 while (bytes_left > 0)
794 {
795 /* Unlike the specification, we don't set the 'delete' arugment to True
796 since we slurp the INCR's chunks in even-smaller chunks of 4096 bytes. */
797 if ((XGetWindowProperty
798 (This->display, This->wnd, This->xclip.rdesktop_clipboard_target_atom, offset, 4096L,
799 False, AnyPropertyType, &type, &format, &nitems, &bytes_left,
800 &data) != Success))
801 {
802 XFree(data);
803 return;
804 }
805
806 if (nitems == 0)
807 {
808 /* INCR transfer finished */
809 XGetWindowAttributes(This->display, This->wnd, &wa);
810 XSelectInput(This->display, This->wnd,
811 (wa.your_event_mask ^ PropertyChangeMask));
812 XFree(data);
813 This->xclip.waiting_for_INCR = 0;
814
815 if (This->xclip.clip_buflen > 0)
816 {
818 (This, This->xclip.clip_buffer, This->xclip.clip_buflen, This->xclip.incr_target))
819 {
821 }
822 xfree(This->xclip.clip_buffer);
823 This->xclip.clip_buffer = NULL;
824 This->xclip.clip_buflen = 0;
825 }
826 }
827 else
828 {
829 /* Another chunk in the INCR transfer */
830 offset += (nitems / 4); /* offset at which to begin the next slurp */
831 This->xclip.clip_buffer = xrealloc(This->xclip.clip_buffer, This->xclip.clip_buflen + nitems);
832 memcpy(This->xclip.clip_buffer + This->xclip.clip_buflen, data, nitems);
833 This->xclip.clip_buflen += nitems;
834
835 XFree(data);
836 }
837 }
838 XDeleteProperty(This->display, This->wnd, This->xclip.rdesktop_clipboard_target_atom);
839 return;
840 }
841
842 if ((event->atom == This->xclip.rdesktop_selection_notify_atom) &&
843 (event->window == DefaultRootWindow(This->display)))
845}
void * xrealloc(void *oldmem, size_t size)
Definition: uimain.c:736
_Out_ RTL_ATOM * Atom
Definition: class.h:54
@ Success
Definition: eventcreate.c:712
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
struct _cl_event * event
Definition: glext.h:7739
GLintptr offset
Definition: glext.h:5920
static Bool xclip_send_data_with_convert(RDPCLIENT *This, uint8 *source, size_t source_size, Atom target)
Definition: xclip.c:206

Referenced by xwin_process_events().

◆ xclip_handle_SelectionClear()

void xclip_handle_SelectionClear ( RDPCLIENT This)

Definition at line 770 of file xclip.c.

771{
772 DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));
775}

Referenced by xwin_process_events().

◆ xclip_handle_SelectionNotify()

void xclip_handle_SelectionNotify ( RDPCLIENT This,
XSelectionEvent *  event 
)

Definition at line 417 of file xclip.c.

418{
419 unsigned long nitems, bytes_left;
420 XWindowAttributes wa;
421 Atom type;
422 Atom *supported_targets;
423 int res, i, format;
424 uint8 *data = NULL;
425
426 if (event->property == None)
427 goto fail;
428
429 DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n",
430 XGetAtomName(This->display, event->selection),
431 XGetAtomName(This->display, event->target),
432 XGetAtomName(This->display, event->property)));
433
434 if (event->target == This->xclip.timestamp_atom)
435 {
436 if (event->selection == This->xclip.primary_atom)
437 {
438 res = XGetWindowProperty(This->display, This->wnd,
439 This->xclip.rdesktop_primary_timestamp_target_atom, 0,
440 XMaxRequestSize(This->display), False, AnyPropertyType,
441 &type, &format, &nitems, &bytes_left, &data);
442 }
443 else
444 {
445 res = XGetWindowProperty(This->display, This->wnd,
446 This->xclip.rdesktop_clipboard_timestamp_target_atom, 0,
447 XMaxRequestSize(This->display), False, AnyPropertyType,
448 &type, &format, &nitems, &bytes_left, &data);
449 }
450
451
452 if ((res != Success) || (nitems != 1) || (format != 32))
453 {
454 DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
455 goto fail;
456 }
457
458 if (event->selection == This->xclip.primary_atom)
459 {
460 This->xclip.primary_timestamp = *(Time *) data;
461 if (This->xclip.primary_timestamp == 0)
462 This->xclip.primary_timestamp++;
463 XDeleteProperty(This->display, This->wnd, This->xclip.rdesktop_primary_timestamp_target_atom);
464 DEBUG_CLIPBOARD(("Got PRIMARY timestamp: %u\n",
465 (unsigned) This->xclip.primary_timestamp));
466 }
467 else
468 {
469 This->xclip.clipboard_timestamp = *(Time *) data;
470 if (This->xclip.clipboard_timestamp == 0)
471 This->xclip.clipboard_timestamp++;
472 XDeleteProperty(This->display, This->wnd, This->xclip.rdesktop_clipboard_timestamp_target_atom);
473 DEBUG_CLIPBOARD(("Got CLIPBOARD timestamp: %u\n",
474 (unsigned) This->xclip.clipboard_timestamp));
475 }
476
477 XFree(data);
478
479 if (This->xclip.primary_timestamp && This->xclip.clipboard_timestamp)
480 {
481 if (This->xclip.primary_timestamp > This->xclip.clipboard_timestamp)
482 {
483 DEBUG_CLIPBOARD(("PRIMARY is most recent selection.\n"));
484 XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.targets_atom,
485 This->xclip.rdesktop_clipboard_target_atom, This->wnd,
486 event->time);
487 }
488 else
489 {
490 DEBUG_CLIPBOARD(("CLIPBOARD is most recent selection.\n"));
491 XConvertSelection(This->display, This->xclip.clipboard_atom, This->xclip.targets_atom,
492 This->xclip.rdesktop_clipboard_target_atom, This->wnd,
493 event->time);
494 }
495 }
496
497 return;
498 }
499
500 if (This->xclip.probing_selections && This->xclip.reprobe_selections)
501 {
502 This->xclip.probing_selections = False;
504 return;
505 }
506
507 res = XGetWindowProperty(This->display, This->wnd, This->xclip.rdesktop_clipboard_target_atom,
508 0, XMaxRequestSize(This->display), False, AnyPropertyType,
509 &type, &format, &nitems, &bytes_left, &data);
510
512
513 if (res != Success)
514 {
515 DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
516 goto fail;
517 }
518
519 if (type == This->xclip.incr_atom)
520 {
521 DEBUG_CLIPBOARD(("Received INCR.\n"));
522
523 XGetWindowAttributes(This->display, This->wnd, &wa);
524 if ((wa.your_event_mask | PropertyChangeMask) != wa.your_event_mask)
525 {
526 XSelectInput(This->display, This->wnd, (wa.your_event_mask | PropertyChangeMask));
527 }
528 XFree(data);
529 This->xclip.incr_target = event->target;
530 This->xclip.waiting_for_INCR = 1;
531 goto end;
532 }
533
534 /* Negotiate target format */
535 if (event->target == This->xclip.targets_atom)
536 {
537 /* Determine the best of text This->xclip.targets that we have available:
538 Prefer UTF8_STRING > text/unicode (unspecified encoding) > STRING
539 (ignore TEXT and COMPOUND_TEXT because we don't have code to handle them)
540 */
541 int text_target_satisfaction = 0;
542 Atom best_text_target = 0; /* measures how much we're satisfied with what we found */
543 if (type != None)
544 {
545 supported_targets = (Atom *) data;
546 for (i = 0; i < nitems; i++)
547 {
548 DEBUG_CLIPBOARD(("Target %d: %s\n", i,
549 XGetAtomName(This->display, supported_targets[i])));
550 if (supported_targets[i] == This->xclip.format_string_atom)
551 {
552 if (text_target_satisfaction < 1)
553 {
554 DEBUG_CLIPBOARD(("Other party supports STRING, choosing that as best_target\n"));
555 best_text_target = supported_targets[i];
556 text_target_satisfaction = 1;
557 }
558 }
559#ifdef USE_UNICODE_CLIPBOARD
560 else if (supported_targets[i] == This->xclip.format_unicode_atom)
561 {
562 if (text_target_satisfaction < 2)
563 {
564 DEBUG_CLIPBOARD(("Other party supports text/unicode, choosing that as best_target\n"));
565 best_text_target = supported_targets[i];
566 text_target_satisfaction = 2;
567 }
568 }
569 else if (supported_targets[i] == This->xclip.format_utf8_string_atom)
570 {
571 if (text_target_satisfaction < 3)
572 {
573 DEBUG_CLIPBOARD(("Other party supports UTF8_STRING, choosing that as best_target\n"));
574 best_text_target = supported_targets[i];
575 text_target_satisfaction = 3;
576 }
577 }
578#endif
579 else if (supported_targets[i] == This->xclip.rdesktop_clipboard_formats_atom)
580 {
581 if (This->xclip.probing_selections && (text_target_satisfaction < 4))
582 {
583 DEBUG_CLIPBOARD(("Other party supports native formats, choosing that as best_target\n"));
584 best_text_target = supported_targets[i];
585 text_target_satisfaction = 4;
586 }
587 }
588 }
589 }
590
591 /* Kickstarting the next step in the process of satisfying RDP's
592 clipboard request -- specifically, requesting the actual clipboard data.
593 */
594 if ((best_text_target != 0)
595 && (!This->xclip.probing_selections
596 || (best_text_target == This->xclip.rdesktop_clipboard_formats_atom)))
597 {
598 XConvertSelection(This->display, event->selection, best_text_target,
599 This->xclip.rdesktop_clipboard_target_atom, This->wnd, event->time);
600 goto end;
601 }
602 else
603 {
604 DEBUG_CLIPBOARD(("Unable to find a textual target to satisfy RDP clipboard text request\n"));
605 goto fail;
606 }
607 }
608 else
609 {
610 if (This->xclip.probing_selections)
611 {
612 Window primary_owner, clipboard_owner;
613
614 /* FIXME:
615 Without XFIXES, we must make sure that the other
616 rdesktop owns all relevant selections or we might try
617 to get a native format from non-rdesktop window later
618 on. */
619
620 clipboard_owner = XGetSelectionOwner(This->display, This->xclip.clipboard_atom);
621
622 if (This->xclip.auto_mode)
623 primary_owner = XGetSelectionOwner(This->display, This->xclip.primary_atom);
624 else
625 primary_owner = clipboard_owner;
626
627 if (primary_owner != clipboard_owner)
628 goto fail;
629
630 DEBUG_CLIPBOARD(("Got fellow rdesktop formats\n"));
631 This->xclip.probing_selections = False;
632 This->xclip.rdesktop_is_selection_owner = True;
634 }
635 else if (!xclip_send_data_with_convert(This, data, nitems, event->target))
636 {
637 goto fail;
638 }
639 }
640
641 end:
642 if (data)
643 XFree(data);
644
645 return;
646
647 fail:
649 if (This->xclip.probing_selections)
650 {
651 DEBUG_CLIPBOARD(("Unable to find suitable target. Using default text format.\n"));
652 This->xclip.probing_selections = False;
653 This->xclip.rdesktop_is_selection_owner = False;
654
655 /* FIXME:
656 Without XFIXES, we cannot reliably know the formats offered by an
657 upcoming selection owner, so we just lie about him offering
658 RDP_CF_TEXT. */
660 }
661 else
662 {
664 }
665 goto end;
666}
void cliprdr_send_native_format_announce(uint8 *formats_data, uint32 formats_data_length)
GLuint GLuint end
Definition: gl.h:1545
GLuint res
Definition: glext.h:9613
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static PLARGE_INTEGER Time
Definition: time.c:105

Referenced by xwin_process_events().

◆ xclip_handle_SelectionRequest()

void xclip_handle_SelectionRequest ( RDPCLIENT This,
XSelectionRequestEvent *  event 
)

Definition at line 673 of file xclip.c.

674{
675 unsigned long nitems, bytes_left;
676 unsigned char *prop_return;
677 int format, res;
678 Atom type;
679
680 DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n",
681 XGetAtomName(This->display, event->selection),
682 XGetAtomName(This->display, event->target),
683 XGetAtomName(This->display, event->property)));
684
685 if (event->target == This->xclip.targets_atom)
686 {
687 xclip_provide_selection(This, event, XA_ATOM, 32, (uint8 *) & This->xclip.targets, This->xclip.num_targets);
688 return;
689 }
690 else if (event->target == This->xclip.timestamp_atom)
691 {
692 xclip_provide_selection(This, event, XA_INTEGER, 32, (uint8 *) & This->xclip.acquire_time, 1);
693 return;
694 }
695 else if (event->target == This->xclip.rdesktop_clipboard_formats_atom)
696 {
697 xclip_provide_selection(This, event, XA_STRING, 8, This->xclip.formats_data, This->xclip.formats_data_length);
698 }
699 else
700 {
701 /* All the following This->xclip.targets require an async operation with the RDP server
702 and currently we don't do X clipboard request queueing so we can only
703 handle one such request at a time. */
704 if (This->xclip.has_selection_request)
705 {
706 DEBUG_CLIPBOARD(("Error: Another clipboard request was already sent to the RDP server and not yet responded. Refusing this request.\n"));
708 return;
709 }
710 if (event->target == This->xclip.rdesktop_native_atom)
711 {
712 /* Before the requestor makes a request for the _RDESKTOP_NATIVE target,
713 he should declare requestor[property] = CF_SOMETHING. */
714 res = XGetWindowProperty(This->display, event->requestor,
715 event->property, 0, 1, True,
716 XA_INTEGER, &type, &format, &nitems, &bytes_left,
717 &prop_return);
718 if (res != Success)
719 {
720 DEBUG_CLIPBOARD(("Requested native format but didn't specifiy which.\n"));
722 return;
723 }
724
725 format = *(uint32 *) prop_return;
726 XFree(prop_return);
727 }
728 else if (event->target == This->xclip.format_string_atom || event->target == XA_STRING)
729 {
730 /* STRING and XA_STRING are defined to be ISO8859-1 */
731 format = CF_TEXT;
732 }
733 else if (event->target == This->xclip.format_utf8_string_atom)
734 {
735#ifdef USE_UNICODE_CLIPBOARD
737#else
738 DEBUG_CLIPBOARD(("Requested target unavailable due to lack of Unicode support. (It was not in TARGETS, so why did you ask for it?!)\n"));
740 return;
741#endif
742 }
743 else if (event->target == This->xclip.format_unicode_atom)
744 {
745 /* Assuming text/unicode to be UTF-16 */
747 }
748 else
749 {
750 DEBUG_CLIPBOARD(("Requested target unavailable. (It was not in TARGETS, so why did you ask for it?!)\n"));
752 return;
753 }
754
756 This->xclip.selection_request = *event;
757 This->xclip.has_selection_request = True;
758 return; /* wait for data */
759 }
760}
#define CF_UNICODETEXT
Definition: constants.h:408
#define CF_TEXT
Definition: constants.h:396
void cliprdr_send_data_request(uint32 format)
unsigned int uint32
Definition: types.h:32

Referenced by xwin_process_events().

◆ xclip_init()

void xclip_init ( RDPCLIENT This)

Definition at line 1052 of file xclip.c.

1053{
1054 if (!This->rdpclip)
1055 return;
1056
1057 if (!cliprdr_init(This))
1058 return;
1059
1060 This->xclip.primary_atom = XInternAtom(This->display, "PRIMARY", False);
1061 This->xclip.clipboard_atom = XInternAtom(This->display, "CLIPBOARD", False);
1062 This->xclip.targets_atom = XInternAtom(This->display, "TARGETS", False);
1063 This->xclip.timestamp_atom = XInternAtom(This->display, "TIMESTAMP", False);
1064 This->xclip.rdesktop_clipboard_target_atom =
1065 XInternAtom(This->display, "_RDESKTOP_CLIPBOARD_TARGET", False);
1066 This->xclip.rdesktop_primary_timestamp_target_atom =
1067 XInternAtom(This->display, "_RDESKTOP_PRIMARY_TIMESTAMP_TARGET", False);
1068 This->xclip.rdesktop_clipboard_timestamp_target_atom =
1069 XInternAtom(This->display, "_RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET", False);
1070 This->xclip.incr_atom = XInternAtom(This->display, "INCR", False);
1071 This->xclip.format_string_atom = XInternAtom(This->display, "STRING", False);
1072 This->xclip.format_utf8_string_atom = XInternAtom(This->display, "UTF8_STRING", False);
1073 This->xclip.format_unicode_atom = XInternAtom(This->display, "text/unicode", False);
1074
1075 /* rdesktop sets _RDESKTOP_SELECTION_NOTIFY on the root window when acquiring the clipboard.
1076 Other interested rdesktops can use this to notify their server of the available formats. */
1077 This->xclip.rdesktop_selection_notify_atom =
1078 XInternAtom(This->display, "_RDESKTOP_SELECTION_NOTIFY", False);
1079 XSelectInput(This->display, DefaultRootWindow(This->display), PropertyChangeMask);
1080 This->xclip.probing_selections = False;
1081
1082 This->xclip.rdesktop_native_atom = XInternAtom(This->display, "_RDESKTOP_NATIVE", False);
1083 This->xclip.rdesktop_clipboard_formats_atom =
1084 XInternAtom(This->display, "_RDESKTOP_CLIPBOARD_FORMATS", False);
1085 This->xclip.rdesktop_primary_owner_atom = XInternAtom(This->display, "_RDESKTOP_PRIMARY_OWNER", False);
1086 This->xclip.rdesktop_clipboard_owner_atom = XInternAtom(This->display, "_RDESKTOP_CLIPBOARD_OWNER", False);
1087
1088 This->xclip.num_targets = 0;
1089 This->xclip.targets[This->xclip.num_targets++] = This->xclip.targets_atom;
1090 This->xclip.targets[This->xclip.num_targets++] = This->xclip.timestamp_atom;
1091 This->xclip.targets[This->xclip.num_targets++] = This->xclip.rdesktop_native_atom;
1092 This->xclip.targets[This->xclip.num_targets++] = This->xclip.rdesktop_clipboard_formats_atom;
1093#ifdef USE_UNICODE_CLIPBOARD
1094 This->xclip.targets[This->xclip.num_targets++] = This->xclip.format_utf8_string_atom;
1095#endif
1096 This->xclip.targets[This->xclip.num_targets++] = This->xclip.format_unicode_atom;
1097 This->xclip.targets[This->xclip.num_targets++] = This->xclip.format_string_atom;
1098 This->xclip.targets[This->xclip.num_targets++] = XA_STRING;
1099}
RD_BOOL cliprdr_init(void)

◆ xclip_notify_change()

static void xclip_notify_change ( RDPCLIENT This)
static

Definition at line 335 of file xclip.c.

336{
337 XChangeProperty(This->display, DefaultRootWindow(This->display),
338 This->xclip.rdesktop_selection_notify_atom, XA_INTEGER, 32, PropModeReplace, NULL, 0);
339}

Referenced by ui_clip_format_announce(), xclip_deinit(), and xclip_handle_SelectionClear().

◆ xclip_probe_selections()

static void xclip_probe_selections ( RDPCLIENT This)
static

Definition at line 342 of file xclip.c.

343{
344 Window primary_owner, clipboard_owner;
345
346 if (This->xclip.probing_selections)
347 {
348 DEBUG_CLIPBOARD(("Already probing selections. Scheduling reprobe.\n"));
349 This->xclip.reprobe_selections = True;
350 return;
351 }
352
353 DEBUG_CLIPBOARD(("Probing selections.\n"));
354
355 This->xclip.probing_selections = True;
356 This->xclip.reprobe_selections = False;
357
359
360 if (This->xclip.auto_mode)
361 primary_owner = XGetSelectionOwner(This->display, This->xclip.primary_atom);
362 else
363 primary_owner = None;
364
365 clipboard_owner = XGetSelectionOwner(This->display, This->xclip.clipboard_atom);
366
367 /* If we own all relevant selections then don't do anything. */
368 if (((primary_owner == This->wnd) || !This->xclip.auto_mode) && (clipboard_owner == This->wnd))
369 goto end;
370
371 /* Both available */
372 if ((primary_owner != None) && (clipboard_owner != None))
373 {
374 This->xclip.primary_timestamp = 0;
375 This->xclip.clipboard_timestamp = 0;
376 XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.timestamp_atom,
377 This->xclip.rdesktop_primary_timestamp_target_atom, This->wnd, CurrentTime);
378 XConvertSelection(This->display, This->xclip.clipboard_atom, This->xclip.timestamp_atom,
379 This->xclip.rdesktop_clipboard_timestamp_target_atom, This->wnd, CurrentTime);
380 return;
381 }
382
383 /* Just PRIMARY */
384 if (primary_owner != None)
385 {
386 XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.targets_atom,
387 This->xclip.rdesktop_clipboard_target_atom, This->wnd, CurrentTime);
388 return;
389 }
390
391 /* Just CLIPBOARD */
392 if (clipboard_owner != None)
393 {
394 XConvertSelection(This->display, This->xclip.clipboard_atom, This->xclip.targets_atom,
395 This->xclip.rdesktop_clipboard_target_atom, This->wnd, CurrentTime);
396 return;
397 }
398
399 DEBUG_CLIPBOARD(("No owner of any selection.\n"));
400
401 /* FIXME:
402 Without XFIXES, we cannot reliably know the formats offered by an
403 upcoming selection owner, so we just lie about him offering
404 RDP_CF_TEXT. */
406
407 end:
408 This->xclip.probing_selections = False;
409}

Referenced by ui_clip_sync(), xclip_handle_PropertyNotify(), xclip_handle_SelectionClear(), and xclip_handle_SelectionNotify().

◆ xclip_provide_selection()

static void xclip_provide_selection ( RDPCLIENT This,
XSelectionRequestEvent *  req,
Atom  type,
unsigned int  format,
uint8 data,
uint32  length 
)
static

Definition at line 136 of file xclip.c.

138{
139 XEvent xev;
140
141 DEBUG_CLIPBOARD(("xclip_provide_selection: requestor=0x%08x, target=%s, property=%s, length=%u\n", (unsigned) req->requestor, XGetAtomName(This->display, req->target), XGetAtomName(This->display, req->property), (unsigned) length));
142
143 XChangeProperty(This->display, req->requestor, req->property,
144 type, format, PropModeReplace, data, length);
145
146 xev.xselection.type = SelectionNotify;
147 xev.xselection.serial = 0;
148 xev.xselection.send_event = True;
149 xev.xselection.requestor = req->requestor;
150 xev.xselection.selection = req->selection;
151 xev.xselection.target = req->target;
152 xev.xselection.property = req->property;
153 xev.xselection.time = req->time;
154 XSendEvent(This->display, req->requestor, False, NoEventMask, &xev);
155}

Referenced by ui_clip_handle_data(), and xclip_handle_SelectionRequest().

◆ xclip_refuse_selection()

static void xclip_refuse_selection ( RDPCLIENT This,
XSelectionRequestEvent *  req 
)
static

Definition at line 161 of file xclip.c.

162{
163 XEvent xev;
164
165 DEBUG_CLIPBOARD(("xclip_refuse_selection: requestor=0x%08x, target=%s, property=%s\n",
166 (unsigned) req->requestor, XGetAtomName(This->display, req->target),
167 XGetAtomName(This->display, req->property)));
168
169 xev.xselection.type = SelectionNotify;
170 xev.xselection.serial = 0;
171 xev.xselection.send_event = True;
172 xev.xselection.requestor = req->requestor;
173 xev.xselection.selection = req->selection;
174 xev.xselection.target = req->target;
175 xev.xselection.property = None;
176 xev.xselection.time = req->time;
177 XSendEvent(This->display, req->requestor, False, NoEventMask, &xev);
178}

Referenced by ui_clip_handle_data(), ui_clip_request_failed(), and xclip_handle_SelectionRequest().

◆ xclip_send_data_with_convert()

static Bool xclip_send_data_with_convert ( RDPCLIENT This,
uint8 source,
size_t  source_size,
Atom  target 
)
static

Definition at line 206 of file xclip.c.

207{
208 DEBUG_CLIPBOARD(("xclip_send_data_with_convert: target=%s, size=%u\n",
209 XGetAtomName(This->display, target), (unsigned) source_size));
210
211#ifdef USE_UNICODE_CLIPBOARD
212 if (target == This->xclip.format_string_atom ||
213 target == This->xclip.format_unicode_atom || target == This->xclip.format_utf8_string_atom)
214 {
215 size_t unicode_buffer_size;
216 char *unicode_buffer;
217 iconv_t cd;
218 size_t unicode_buffer_size_remaining;
219 char *unicode_buffer_remaining;
220 char *data_remaining;
221 size_t data_size_remaining;
222 uint32 translated_data_size;
223 uint8 *translated_data;
224
225 if (This->xclip.rdp_clipboard_request_format != RDP_CF_TEXT)
226 return False;
227
228 /* Make an attempt to convert any string we send to Unicode.
229 We don't know what the RDP server's ANSI Codepage is, or how to convert
230 to it, so using CF_TEXT is not safe (and is unnecessary, since all
231 WinNT versions are Unicode-minded).
232 */
233 if (target == This->xclip.format_string_atom)
234 {
235 char *locale_charset = nl_langinfo(CODESET);
236 cd = iconv_open(WINDOWS_CODEPAGE, locale_charset);
237 if (cd == (iconv_t) - 1)
238 {
239 DEBUG_CLIPBOARD(("Locale charset %s not found in iconv. Unable to convert clipboard text.\n", locale_charset));
240 return False;
241 }
242 unicode_buffer_size = source_size * 4;
243 }
244 else if (target == This->xclip.format_unicode_atom)
245 {
246 cd = iconv_open(WINDOWS_CODEPAGE, "UCS-2");
247 if (cd == (iconv_t) - 1)
248 {
249 return False;
250 }
251 unicode_buffer_size = source_size;
252 }
253 else if (target == This->xclip.format_utf8_string_atom)
254 {
255 cd = iconv_open(WINDOWS_CODEPAGE, "UTF-8");
256 if (cd == (iconv_t) - 1)
257 {
258 return False;
259 }
260 /* UTF-8 is guaranteed to be less or equally compact
261 as UTF-16 for all Unicode chars >=2 bytes.
262 */
263 unicode_buffer_size = source_size * 2;
264 }
265 else
266 {
267 return False;
268 }
269
270 unicode_buffer = xmalloc(unicode_buffer_size);
271 unicode_buffer_size_remaining = unicode_buffer_size;
272 unicode_buffer_remaining = unicode_buffer;
273 data_remaining = (char *) source;
274 data_size_remaining = source_size;
275 iconv(cd, (ICONV_CONST char **) &data_remaining, &data_size_remaining,
276 &unicode_buffer_remaining, &unicode_buffer_size_remaining);
278
279 /* translate linebreaks */
280 translated_data_size = unicode_buffer_size - unicode_buffer_size_remaining;
281 translated_data = utf16_lf2crlf((uint8 *) unicode_buffer, &translated_data_size);
282 if (translated_data != NULL)
283 {
284 DEBUG_CLIPBOARD(("Sending Unicode string of %d bytes\n",
285 translated_data_size));
286 helper_cliprdr_send_response(This, translated_data, translated_data_size);
287 xfree(translated_data); /* Not the same thing as XFree! */
288 }
289
290 xfree(unicode_buffer);
291
292 return True;
293 }
294#else
295 if (target == This->xclip.format_string_atom)
296 {
297 uint8 *translated_data;
298 uint32 length = source_size;
299
300 if (This->xclip.rdp_clipboard_request_format != RDP_CF_TEXT)
301 return False;
302
303 DEBUG_CLIPBOARD(("Translating linebreaks before sending data\n"));
304 translated_data = lf2crlf(source, &length);
305 if (translated_data != NULL)
306 {
307 helper_cliprdr_send_response(This, translated_data, length);
308 xfree(translated_data); /* Not the same thing as XFree! */
309 }
310
311 return True;
312 }
313#endif
314 else if (target == This->xclip.rdesktop_native_atom)
315 {
316 helper_cliprdr_send_response(This, source, source_size + 1);
317
318 return True;
319 }
320 else
321 {
322 return False;
323 }
324}
GLenum target
Definition: glext.h:7315
static uint8 * lf2crlf(uint8 *data, uint32 *length)
Definition: xclip.c:110

Referenced by xclip_handle_PropertyNotify(), and xclip_handle_SelectionNotify().