/[rdesktop]/sourceforge.net/trunk/rdesktop/xclip.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/trunk/rdesktop/xclip.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1207 by ossman_, Mon Mar 27 09:20:24 2006 UTC revision 1223 by astrand, Sun Apr 9 20:11:42 2006 UTC
# Line 48  Line 48 
48  #define RDP_CF_TEXT CF_TEXT  #define RDP_CF_TEXT CF_TEXT
49  #endif  #endif
50    
51  #define MAX_TARGETS 7  #define MAX_TARGETS 8
52    
53  extern Display *g_display;  extern Display *g_display;
54  extern Window g_wnd;  extern Window g_wnd;
# Line 65  static Atom clipboard_atom, primary_atom Line 65  static Atom clipboard_atom, primary_atom
65  static Atom targets_atom;  static Atom targets_atom;
66  /* Atom of the TIMESTAMP clipboard target */  /* Atom of the TIMESTAMP clipboard target */
67  static Atom timestamp_atom;  static Atom timestamp_atom;
68  /* Atom _RDESKTOP_CLIPBOARD_TARGET which has multiple uses:  /* Atom _RDESKTOP_CLIPBOARD_TARGET which is used as the 'property' argument in
69     - The 'property' argument in XConvertSelection calls: This is the property of our     XConvertSelection calls: This is the property of our window into which
70       window into which XConvertSelection will store the received clipboard data.     XConvertSelection will store the received clipboard data. */
    - In a clipboard request of target _RDESKTOP_CLIPBOARD_FORMATS, an XA_INTEGER-typed  
      property carrying the Windows native (CF_...) format desired by the requestor.  
      Requestor set this property (e.g. requestor_wnd[_RDESKTOP_CLIPBOARD_TARGET] = CF_TEXT)  
      before requesting clipboard data from a fellow rdesktop using  
      the _RDESKTOP_CLIPBOARD_FORMATS target. */  
71  static Atom rdesktop_clipboard_target_atom;  static Atom rdesktop_clipboard_target_atom;
72  /* Atoms _RDESKTOP_PRIMARY_TIMESTAMP_TARGET and _RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET  /* Atoms _RDESKTOP_PRIMARY_TIMESTAMP_TARGET and _RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET
73     are used to store the timestamps for when a window got ownership of the selections.     are used to store the timestamps for when a window got ownership of the selections.
# Line 80  static Atom rdesktop_clipboard_target_at Line 75  static Atom rdesktop_clipboard_target_at
75  static Atom rdesktop_primary_timestamp_target_atom, rdesktop_clipboard_timestamp_target_atom;  static Atom rdesktop_primary_timestamp_target_atom, rdesktop_clipboard_timestamp_target_atom;
76  /* Storage for timestamps since we get them in two separate notifications. */  /* Storage for timestamps since we get them in two separate notifications. */
77  static Time primary_timestamp, clipboard_timestamp;  static Time primary_timestamp, clipboard_timestamp;
78  /* Atom _RDESKTOP_CLIPBOARD_FORMATS which has multiple uses:  /* Clipboard target for getting a list of native Windows clipboard formats. The
79     - The clipboard target (X jargon for "clipboard format") for rdesktop-to-rdesktop interchange     presence of this target indicates that the selection owner is another rdesktop. */
      of Windows native clipboard data.  
      This target cannot be used standalone; the requestor must keep the  
      _RDESKTOP_CLIPBOARD_TARGET property on his window denoting  
      the Windows native clipboard format being requested.  
    - The root window property set by rdesktop when it owns the clipboard,  
      denoting all Windows native clipboard formats it offers via  
      requests of the _RDESKTOP_CLIPBOARD_FORMATS target. */  
80  static Atom rdesktop_clipboard_formats_atom;  static Atom rdesktop_clipboard_formats_atom;
81    /* The clipboard target (X jargon for "clipboard format") for rdesktop-to-rdesktop
82       interchange of Windows native clipboard data. The requestor must supply the
83       desired native Windows clipboard format in the associated property. */
84    static Atom rdesktop_native_atom;
85    /* Local copy of the list of native Windows clipboard formats. */
86    static uint8 *formats_data = NULL;
87    static uint32 formats_data_length = 0;
88    /* We need to know when another rdesktop process gets or loses ownership of a
89       selection. Without XFixes we do this by touching a property on the root window
90       which will generate PropertyNotify notifications. */
91    static Atom rdesktop_selection_notify_atom;
92    /* State variables that indicate if we're currently probing the targets of the
93       selection owner. reprobe_selections indicate that the ownership changed in
94       the middle of the current probe so it should be restarted. */
95    static BOOL probing_selections, reprobe_selections;
96    /* Atoms _RDESKTOP_PRIMARY_OWNER and _RDESKTOP_CLIPBOARD_OWNER. Used as properties
97       on the root window to indicate which selections that are owned by rdesktop. */
98    static Atom rdesktop_primary_owner_atom, rdesktop_clipboard_owner_atom;
99  static Atom format_string_atom, format_utf8_string_atom, format_unicode_atom;  static Atom format_string_atom, format_utf8_string_atom, format_unicode_atom;
100  /* Atom of the INCR clipboard type (see ICCCM on "INCR Properties") */  /* Atom of the INCR clipboard type (see ICCCM on "INCR Properties") */
101  static Atom incr_atom;  static Atom incr_atom;
# Line 109  static int rdp_clipboard_request_format; Line 115  static int rdp_clipboard_request_format;
115  /* Array of offered clipboard targets that will be sent to fellow X clients upon a TARGETS request. */  /* Array of offered clipboard targets that will be sent to fellow X clients upon a TARGETS request. */
116  static Atom targets[MAX_TARGETS];  static Atom targets[MAX_TARGETS];
117  static int num_targets;  static int num_targets;
 /* Denotes that this client currently holds the PRIMARY selection. */  
 static int have_primary = 0;  
118  /* Denotes that an rdesktop (not this rdesktop) is owning the selection,  /* Denotes that an rdesktop (not this rdesktop) is owning the selection,
119     allowing us to interchange Windows native clipboard data directly. */     allowing us to interchange Windows native clipboard data directly. */
120  static int rdesktop_is_selection_owner = 0;  static BOOL rdesktop_is_selection_owner = False;
121    /* Time when we acquired the selection. */
122    static Time acquire_time = 0;
123    
124  /* Denotes that an INCR ("chunked") transfer is in progress. */  /* Denotes that an INCR ("chunked") transfer is in progress. */
125  static int g_waiting_for_INCR = 0;  static int g_waiting_for_INCR = 0;
# Line 151  utf16_lf2crlf(uint8 * data, uint32 * siz Line 157  utf16_lf2crlf(uint8 * data, uint32 * siz
157  {  {
158          uint8 *result;          uint8 *result;
159          uint16 *inptr, *outptr;          uint16 *inptr, *outptr;
160            Bool swap_endianess;
161    
162          /* Worst case: Every char is LF */          /* Worst case: Every char is LF */
163          result = xmalloc((*size * 2) + 2);          result = xmalloc((*size * 2) + 2);
# Line 161  utf16_lf2crlf(uint8 * data, uint32 * siz Line 168  utf16_lf2crlf(uint8 * data, uint32 * siz
168          outptr = (uint16 *) result;          outptr = (uint16 *) result;
169    
170          /* Check for a reversed BOM */          /* Check for a reversed BOM */
171          Bool swap_endianess = (*inptr == 0xfffe);          swap_endianess = (*inptr == 0xfffe);
172    
173          while ((uint8 *) inptr < data + *size)          while ((uint8 *) inptr < data + *size)
174          {          {
# Line 212  xclip_provide_selection(XSelectionReques Line 219  xclip_provide_selection(XSelectionReques
219  {  {
220          XEvent xev;          XEvent xev;
221    
222            DEBUG_CLIPBOARD(("xclip_provide_selection: requestor=0x%08x, target=%s, property=%s, length=%u\n", (unsigned) req->requestor, XGetAtomName(g_display, req->target), XGetAtomName(g_display, req->property), (unsigned) length));
223    
224          XChangeProperty(g_display, req->requestor, req->property,          XChangeProperty(g_display, req->requestor, req->property,
225                          type, format, PropModeReplace, data, length);                          type, format, PropModeReplace, data, length);
226    
# Line 234  xclip_refuse_selection(XSelectionRequest Line 243  xclip_refuse_selection(XSelectionRequest
243  {  {
244          XEvent xev;          XEvent xev;
245    
246            DEBUG_CLIPBOARD(("xclip_refuse_selection: requestor=0x%08x, target=%s, property=%s\n",
247                             (unsigned) req->requestor, XGetAtomName(g_display, req->target),
248                             XGetAtomName(g_display, req->property)));
249    
250          xev.xselection.type = SelectionNotify;          xev.xselection.type = SelectionNotify;
251          xev.xselection.serial = 0;          xev.xselection.serial = 0;
252          xev.xselection.send_event = True;          xev.xselection.send_event = True;
# Line 273  helper_cliprdr_send_empty_response() Line 286  helper_cliprdr_send_empty_response()
286  static Bool  static Bool
287  xclip_send_data_with_convert(uint8 * source, size_t source_size, Atom target)  xclip_send_data_with_convert(uint8 * source, size_t source_size, Atom target)
288  {  {
289            DEBUG_CLIPBOARD(("xclip_send_data_with_convert: target=%s, size=%u\n",
290                             XGetAtomName(g_display, target), (unsigned) source_size));
291    
292  #ifdef USE_UNICODE_CLIPBOARD  #ifdef USE_UNICODE_CLIPBOARD
293          if (target == format_string_atom ||          if (target == format_string_atom ||
294              target == format_unicode_atom || target == format_utf8_string_atom)              target == format_unicode_atom || target == format_utf8_string_atom)
295          {          {
296                    size_t unicode_buffer_size;
297                    char *unicode_buffer;
298                    iconv_t cd;
299                    size_t unicode_buffer_size_remaining;
300                    char *unicode_buffer_remaining;
301                    char *data_remaining;
302                    size_t data_size_remaining;
303                    uint32 translated_data_size;
304                    uint8 *translated_data;
305    
306                  if (rdp_clipboard_request_format != RDP_CF_TEXT)                  if (rdp_clipboard_request_format != RDP_CF_TEXT)
307                          return False;                          return False;
308    
# Line 285  xclip_send_data_with_convert(uint8 * sou Line 311  xclip_send_data_with_convert(uint8 * sou
311                     to it, so using CF_TEXT is not safe (and is unnecessary, since all                     to it, so using CF_TEXT is not safe (and is unnecessary, since all
312                     WinNT versions are Unicode-minded).                     WinNT versions are Unicode-minded).
313                   */                   */
                 size_t unicode_buffer_size;  
                 char *unicode_buffer;  
                 iconv_t cd;  
   
314                  if (target == format_string_atom)                  if (target == format_string_atom)
315                  {                  {
316                          char *locale_charset = nl_langinfo(CODESET);                          char *locale_charset = nl_langinfo(CODESET);
# Line 327  xclip_send_data_with_convert(uint8 * sou Line 349  xclip_send_data_with_convert(uint8 * sou
349                  }                  }
350    
351                  unicode_buffer = xmalloc(unicode_buffer_size);                  unicode_buffer = xmalloc(unicode_buffer_size);
352                  size_t unicode_buffer_size_remaining = unicode_buffer_size;                  unicode_buffer_size_remaining = unicode_buffer_size;
353                  char *unicode_buffer_remaining = unicode_buffer;                  unicode_buffer_remaining = unicode_buffer;
354                  char *data_remaining = (char *) source;                  data_remaining = (char *) source;
355                  size_t data_size_remaining = source_size;                  data_size_remaining = source_size;
356                  iconv(cd, (ICONV_CONST char **) &data_remaining, &data_size_remaining,                  iconv(cd, (ICONV_CONST char **) &data_remaining, &data_size_remaining,
357                        &unicode_buffer_remaining, &unicode_buffer_size_remaining);                        &unicode_buffer_remaining, &unicode_buffer_size_remaining);
358                  iconv_close(cd);                  iconv_close(cd);
359    
360                  /* translate linebreaks */                  /* translate linebreaks */
361                  uint32 translated_data_size = unicode_buffer_size - unicode_buffer_size_remaining;                  translated_data_size = unicode_buffer_size - unicode_buffer_size_remaining;
362                  uint8 *translated_data =                  translated_data = utf16_lf2crlf((uint8 *) unicode_buffer, &translated_data_size);
                         utf16_lf2crlf((uint8 *) unicode_buffer, &translated_data_size);  
363                  if (translated_data != NULL)                  if (translated_data != NULL)
364                  {                  {
365                          DEBUG_CLIPBOARD(("Sending Unicode string of %d bytes\n",                          DEBUG_CLIPBOARD(("Sending Unicode string of %d bytes\n",
# Line 371  xclip_send_data_with_convert(uint8 * sou Line 392  xclip_send_data_with_convert(uint8 * sou
392                  return True;                  return True;
393          }          }
394  #endif  #endif
395          else if (target == rdesktop_clipboard_formats_atom)          else if (target == rdesktop_native_atom)
396          {          {
397                  helper_cliprdr_send_response(source, source_size + 1);                  helper_cliprdr_send_response(source, source_size + 1);
398    
# Line 391  xclip_clear_target_props() Line 412  xclip_clear_target_props()
412          XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom);          XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom);
413  }  }
414    
415    static void
416    xclip_notify_change()
417    {
418            XChangeProperty(g_display, DefaultRootWindow(g_display),
419                            rdesktop_selection_notify_atom, XA_INTEGER, 32, PropModeReplace, NULL, 0);
420    }
421    
422    static void
423    xclip_probe_selections()
424    {
425            Window primary_owner, clipboard_owner;
426    
427            if (probing_selections)
428            {
429                    DEBUG_CLIPBOARD(("Already probing selections. Scheduling reprobe.\n"));
430                    reprobe_selections = True;
431                    return;
432            }
433    
434            DEBUG_CLIPBOARD(("Probing selections.\n"));
435    
436            probing_selections = True;
437            reprobe_selections = False;
438    
439            xclip_clear_target_props();
440    
441            if (auto_mode)
442                    primary_owner = XGetSelectionOwner(g_display, primary_atom);
443            else
444                    primary_owner = None;
445    
446            clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom);
447    
448            /* If we own all relevant selections then don't do anything. */
449            if (((primary_owner == g_wnd) || !auto_mode) && (clipboard_owner == g_wnd))
450                    goto end;
451    
452            /* Both available */
453            if ((primary_owner != None) && (clipboard_owner != None))
454            {
455                    primary_timestamp = 0;
456                    clipboard_timestamp = 0;
457                    XConvertSelection(g_display, primary_atom, timestamp_atom,
458                                      rdesktop_primary_timestamp_target_atom, g_wnd, CurrentTime);
459                    XConvertSelection(g_display, clipboard_atom, timestamp_atom,
460                                      rdesktop_clipboard_timestamp_target_atom, g_wnd, CurrentTime);
461                    return;
462            }
463    
464            /* Just PRIMARY */
465            if (primary_owner != None)
466            {
467                    XConvertSelection(g_display, primary_atom, targets_atom,
468                                      rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
469                    return;
470            }
471    
472            /* Just CLIPBOARD */
473            if (clipboard_owner != None)
474            {
475                    XConvertSelection(g_display, clipboard_atom, targets_atom,
476                                      rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
477                    return;
478            }
479    
480            DEBUG_CLIPBOARD(("No owner of any selection.\n"));
481    
482            /* FIXME:
483               Without XFIXES, we cannot reliably know the formats offered by an
484               upcoming selection owner, so we just lie about him offering
485               RDP_CF_TEXT. */
486            cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);
487    
488          end:
489            probing_selections = False;
490    }
491    
492  /* This function is called for SelectionNotify events.  /* This function is called for SelectionNotify events.
493     The SelectionNotify event is sent from the clipboard owner to the requestor     The SelectionNotify event is sent from the clipboard owner to the requestor
494     after his request was satisfied.     after his request was satisfied.
# Line 480  xclip_handle_SelectionNotify(XSelectionE Line 578  xclip_handle_SelectionNotify(XSelectionE
578                  return;                  return;
579          }          }
580    
581            if (probing_selections && reprobe_selections)
582            {
583                    probing_selections = False;
584                    xclip_probe_selections();
585                    return;
586            }
587    
588          res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,          res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
589                                   0, XMaxRequestSize(g_display), False, AnyPropertyType,                                   0, XMaxRequestSize(g_display), False, AnyPropertyType,
590                                   &type, &format, &nitems, &bytes_left, &data);                                   &type, &format, &nitems, &bytes_left, &data);
# Line 504  xclip_handle_SelectionNotify(XSelectionE Line 609  xclip_handle_SelectionNotify(XSelectionE
609                  XFree(data);                  XFree(data);
610                  g_incr_target = event->target;                  g_incr_target = event->target;
611                  g_waiting_for_INCR = 1;                  g_waiting_for_INCR = 1;
612                  return;                  goto end;
613          }          }
614    
615          /* Negotiate target format */          /* Negotiate target format */
# Line 552  xclip_handle_SelectionNotify(XSelectionE Line 657  xclip_handle_SelectionNotify(XSelectionE
657                                          }                                          }
658                                  }                                  }
659  #endif  #endif
660                                    else if (supported_targets[i] == rdesktop_clipboard_formats_atom)
661                                    {
662                                            if (probing_selections && (text_target_satisfaction < 4))
663                                            {
664                                                    DEBUG_CLIPBOARD(("Other party supports native formats, choosing that as best_target\n"));
665                                                    best_text_target = supported_targets[i];
666                                                    text_target_satisfaction = 4;
667                                            }
668                                    }
669                          }                          }
670                  }                  }
671    
672                  /* Kickstarting the next step in the process of satisfying RDP's                  /* Kickstarting the next step in the process of satisfying RDP's
673                     clipboard request -- specifically, requesting the actual clipboard data.                     clipboard request -- specifically, requesting the actual clipboard data.
674                   */                   */
675                  if (best_text_target != 0)                  if ((best_text_target != 0)
676                        && (!probing_selections
677                            || (best_text_target == rdesktop_clipboard_formats_atom)))
678                  {                  {
679                          XConvertSelection(g_display, event->selection, best_text_target,                          XConvertSelection(g_display, event->selection, best_text_target,
680                                            rdesktop_clipboard_target_atom, g_wnd, event->time);                                            rdesktop_clipboard_target_atom, g_wnd, event->time);
681                          return;                          goto end;
682                  }                  }
683                  else                  else
684                  {                  {
# Line 572  xclip_handle_SelectionNotify(XSelectionE Line 688  xclip_handle_SelectionNotify(XSelectionE
688          }          }
689          else          else
690          {          {
691                  if (!xclip_send_data_with_convert(data, nitems, event->target))                  if (probing_selections)
692                    {
693                            Window primary_owner, clipboard_owner;
694    
695                            /* FIXME:
696                               Without XFIXES, we must make sure that the other
697                               rdesktop owns all relevant selections or we might try
698                               to get a native format from non-rdesktop window later
699                               on. */
700    
701                            clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom);
702    
703                            if (auto_mode)
704                                    primary_owner = XGetSelectionOwner(g_display, primary_atom);
705                            else
706                                    primary_owner = clipboard_owner;
707    
708                            if (primary_owner != clipboard_owner)
709                                    goto fail;
710    
711                            DEBUG_CLIPBOARD(("Got fellow rdesktop formats\n"));
712                            probing_selections = False;
713                            rdesktop_is_selection_owner = True;
714                            cliprdr_send_native_format_announce(data, nitems);
715                    }
716                    else if (!xclip_send_data_with_convert(data, nitems, event->target))
717                  {                  {
718                          goto fail;                          goto fail;
719                  }                  }
720          }          }
721    
722          XFree(data);        end:
723            if (data)
724                    XFree(data);
725    
726          return;          return;
727    
728        fail:        fail:
729          xclip_clear_target_props();          xclip_clear_target_props();
730          if (data)          if (probing_selections)
731                  XFree(data);          {
732          helper_cliprdr_send_empty_response();                  DEBUG_CLIPBOARD(("Unable to find suitable target. Using default text format.\n"));
733                    probing_selections = False;
734                    rdesktop_is_selection_owner = False;
735    
736                    /* FIXME:
737                       Without XFIXES, we cannot reliably know the formats offered by an
738                       upcoming selection owner, so we just lie about him offering
739                       RDP_CF_TEXT. */
740                    cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);
741            }
742            else
743            {
744                    helper_cliprdr_send_empty_response();
745            }
746            goto end;
747  }  }
748    
749  /* This function is called for SelectionRequest events.  /* This function is called for SelectionRequest events.
# Line 598  xclip_handle_SelectionRequest(XSelection Line 755  xclip_handle_SelectionRequest(XSelection
755  {  {
756          unsigned long nitems, bytes_left;          unsigned long nitems, bytes_left;
757          unsigned char *prop_return;          unsigned char *prop_return;
         uint32 *wanted_format;  
758          int format, res;          int format, res;
759          Atom type;          Atom type;
760    
# Line 614  xclip_handle_SelectionRequest(XSelection Line 770  xclip_handle_SelectionRequest(XSelection
770          }          }
771          else if (event->target == timestamp_atom)          else if (event->target == timestamp_atom)
772          {          {
773                  xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & g_last_gesturetime, 1);                  xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & acquire_time, 1);
774                  return;                  return;
775          }          }
776            else if (event->target == rdesktop_clipboard_formats_atom)
777            {
778                    xclip_provide_selection(event, XA_STRING, 8, formats_data, formats_data_length);
779            }
780          else          else
781          {          {
782                  /* All the following targets require an async operation with the RDP server                  /* All the following targets require an async operation with the RDP server
# Line 628  xclip_handle_SelectionRequest(XSelection Line 788  xclip_handle_SelectionRequest(XSelection
788                          xclip_refuse_selection(event);                          xclip_refuse_selection(event);
789                          return;                          return;
790                  }                  }
791                  if (event->target == rdesktop_clipboard_formats_atom)                  if (event->target == rdesktop_native_atom)
792                  {                  {
793                          /* Before the requestor makes a request for the _RDESKTOP_CLIPBOARD_FORMATS target,                          /* Before the requestor makes a request for the _RDESKTOP_NATIVE target,
794                             he should declare requestor[_RDESKTOP_CLIPBOARD_TARGET] = CF_SOMETHING.                             he should declare requestor[property] = CF_SOMETHING. */
                            Otherwise, we default to RDP_CF_TEXT.  
                          */  
795                          res = XGetWindowProperty(g_display, event->requestor,                          res = XGetWindowProperty(g_display, event->requestor,
796                                                   rdesktop_clipboard_target_atom, 0, 1, True,                                                   event->property, 0, 1, True,
797                                                   XA_INTEGER, &type, &format, &nitems, &bytes_left,                                                   XA_INTEGER, &type, &format, &nitems, &bytes_left,
798                                                   &prop_return);                                                   &prop_return);
799                          wanted_format = (uint32 *) prop_return;                          if (res != Success)
800                          format = (res == Success) ? *wanted_format : RDP_CF_TEXT;                          {
801                                    DEBUG_CLIPBOARD(("Requested native format but didn't specifiy which.\n"));
802                                    xclip_refuse_selection(event);
803                                    return;
804                            }
805    
806                            format = *(uint32 *) prop_return;
807                          XFree(prop_return);                          XFree(prop_return);
808                  }                  }
809                  else if (event->target == format_string_atom || event->target == XA_STRING)                  else if (event->target == format_string_atom || event->target == XA_STRING)
# Line 687  void Line 851  void
851  xclip_handle_SelectionClear(void)  xclip_handle_SelectionClear(void)
852  {  {
853          DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));          DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));
854          have_primary = 0;          xclip_notify_change();
855          XDeleteProperty(g_display, DefaultRootWindow(g_display), rdesktop_clipboard_formats_atom);          xclip_probe_selections();
         /* FIXME:  
            Without XFIXES, we cannot reliably know the formats offered by the  
            new owner of the X11 clipboard, so we just lie about him  
            offering RDP_CF_TEXT. */  
         cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);  
856  }  }
857    
858  /* Called when any property changes in our window or the root window. */  /* Called when any property changes in our window or the root window. */
# Line 703  xclip_handle_PropertyNotify(XPropertyEve Line 862  xclip_handle_PropertyNotify(XPropertyEve
862          unsigned long nitems;          unsigned long nitems;
863          unsigned long offset = 0;          unsigned long offset = 0;
864          unsigned long bytes_left = 1;          unsigned long bytes_left = 1;
865          int format, res;          int format;
866          XWindowAttributes wa;          XWindowAttributes wa;
867          uint8 *data;          uint8 *data;
868          Atom type;          Atom type;
# Line 761  xclip_handle_PropertyNotify(XPropertyEve Line 920  xclip_handle_PropertyNotify(XPropertyEve
920                  return;                  return;
921          }          }
922    
923          if ((event->atom == rdesktop_clipboard_formats_atom) &&          if ((event->atom == rdesktop_selection_notify_atom) &&
924              (event->window == DefaultRootWindow(g_display)) &&              (event->window == DefaultRootWindow(g_display)))
925              !have_primary /* not interested in our own events */ )                  xclip_probe_selections();
         {  
                 if (event->state == PropertyNewValue)  
                 {  
                         DEBUG_CLIPBOARD(("xclip_handle_PropertyNotify: getting fellow rdesktop formats\n"));  
   
                         res = XGetWindowProperty(g_display, DefaultRootWindow(g_display),  
                                                  rdesktop_clipboard_formats_atom, 0,  
                                                  XMaxRequestSize(g_display), False, XA_STRING,  
                                                  &type, &format, &nitems, &bytes_left, &data);  
   
                         if ((res == Success) && (nitems > 0))  
                         {  
                                 cliprdr_send_native_format_announce(data, nitems);  
                                 rdesktop_is_selection_owner = 1;  
                                 return;  
                         }  
                 }  
   
                 /* For some reason, we couldn't announce the native formats */  
                 cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);  
                 rdesktop_is_selection_owner = 0;  
         }  
926  }  }
927  #endif  #endif
928    
# Line 798  xclip_handle_PropertyNotify(XPropertyEve Line 935  xclip_handle_PropertyNotify(XPropertyEve
935  void  void
936  ui_clip_format_announce(uint8 * data, uint32 length)  ui_clip_format_announce(uint8 * data, uint32 length)
937  {  {
938          XSetSelectionOwner(g_display, primary_atom, g_wnd, g_last_gesturetime);          acquire_time = g_last_gesturetime;
939    
940            XSetSelectionOwner(g_display, primary_atom, g_wnd, acquire_time);
941          if (XGetSelectionOwner(g_display, primary_atom) != g_wnd)          if (XGetSelectionOwner(g_display, primary_atom) != g_wnd)
         {  
942                  warning("Failed to aquire ownership of PRIMARY clipboard\n");                  warning("Failed to aquire ownership of PRIMARY clipboard\n");
                 return;  
         }  
   
         have_primary = 1;  
         XChangeProperty(g_display, DefaultRootWindow(g_display),  
                         rdesktop_clipboard_formats_atom, XA_STRING, 8, PropModeReplace, data,  
                         length);  
943    
944          XSetSelectionOwner(g_display, clipboard_atom, g_wnd, g_last_gesturetime);          XSetSelectionOwner(g_display, clipboard_atom, g_wnd, acquire_time);
945          if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd)          if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd)
946                  warning("Failed to aquire ownership of CLIPBOARD clipboard\n");                  warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
947    
948            if (formats_data)
949                    xfree(formats_data);
950            formats_data = xmalloc(length);
951            memcpy(formats_data, data, length);
952            formats_data_length = length;
953    
954            xclip_notify_change();
955  }  }
956    
957  /* Called when the RDP server responds with clipboard data (after we've requested it). */  /* Called when the RDP server responds with clipboard data (after we've requested it). */
# Line 821  ui_clip_handle_data(uint8 * data, uint32 Line 960  ui_clip_handle_data(uint8 * data, uint32
960  {  {
961          BOOL free_data = False;          BOOL free_data = False;
962    
963            if (length == 0)
964            {
965                    xclip_refuse_selection(&selection_request);
966                    has_selection_request = False;
967                    return;
968            }
969    
970          if (selection_request.target == format_string_atom || selection_request.target == XA_STRING)          if (selection_request.target == format_string_atom || selection_request.target == XA_STRING)
971          {          {
972                  /* We're expecting a CF_TEXT response */                  /* We're expecting a CF_TEXT response */
# Line 869  ui_clip_handle_data(uint8 * data, uint32 Line 1015  ui_clip_handle_data(uint8 * data, uint32
1015                     for further conversions. */                     for further conversions. */
1016          }          }
1017  #endif  #endif
1018          else if (selection_request.target == rdesktop_clipboard_formats_atom)          else if (selection_request.target == rdesktop_native_atom)
1019          {          {
1020                  /* Pass as-is */                  /* Pass as-is */
1021          }          }
1022          else          else
1023          {          {
1024                    DEBUG_CLIPBOARD(("ui_clip_handle_data: BUG! I don't know how to convert selection target %s!\n", XGetAtomName(g_display, selection_request.target)));
1025                  xclip_refuse_selection(&selection_request);                  xclip_refuse_selection(&selection_request);
1026                  has_selection_request = False;                  has_selection_request = False;
1027                  return;                  return;
# Line 888  ui_clip_handle_data(uint8 * data, uint32 Line 1035  ui_clip_handle_data(uint8 * data, uint32
1035  }  }
1036    
1037  void  void
1038    ui_clip_request_failed()
1039    {
1040            xclip_refuse_selection(&selection_request);
1041            has_selection_request = False;
1042    }
1043    
1044    void
1045  ui_clip_request_data(uint32 format)  ui_clip_request_data(uint32 format)
1046  {  {
1047          Window primary_owner, clipboard_owner;          Window primary_owner, clipboard_owner;
# Line 895  ui_clip_request_data(uint32 format) Line 1049  ui_clip_request_data(uint32 format)
1049          DEBUG_CLIPBOARD(("Request from server for format %d\n", format));          DEBUG_CLIPBOARD(("Request from server for format %d\n", format));
1050          rdp_clipboard_request_format = format;          rdp_clipboard_request_format = format;
1051    
1052            if (probing_selections)
1053            {
1054                    DEBUG_CLIPBOARD(("ui_clip_request_data: Selection probe in progress. Cannot handle request.\n"));
1055                    helper_cliprdr_send_empty_response();
1056                    return;
1057            }
1058    
1059          xclip_clear_target_props();          xclip_clear_target_props();
1060    
1061          if (rdesktop_is_selection_owner)          if (rdesktop_is_selection_owner)
# Line 902  ui_clip_request_data(uint32 format) Line 1063  ui_clip_request_data(uint32 format)
1063                  XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,                  XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
1064                                  XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);                                  XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);
1065    
1066                  XConvertSelection(g_display, primary_atom, rdesktop_clipboard_formats_atom,                  XConvertSelection(g_display, primary_atom, rdesktop_native_atom,
1067                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
1068                  return;                  return;
1069          }          }
# Line 949  ui_clip_request_data(uint32 format) Line 1110  ui_clip_request_data(uint32 format)
1110  void  void
1111  ui_clip_sync(void)  ui_clip_sync(void)
1112  {  {
1113          cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);          xclip_probe_selections();
1114  }  }
1115    
1116  void  void
# Line 957  ui_clip_set_mode(const char *optarg) Line 1118  ui_clip_set_mode(const char *optarg)
1118  {  {
1119          g_rdpclip = True;          g_rdpclip = True;
1120    
1121          if (str_startswith(optarg, "auto") || str_startswith(optarg, "on")          if (str_startswith(optarg, "PRIMARYCLIPBOARD"))
             || str_startswith(optarg, "PRIMARYCLIPBOARD"))  
1122                  auto_mode = True;                  auto_mode = True;
1123          else if (str_startswith(optarg, "CLIPBOARD"))          else if (str_startswith(optarg, "CLIPBOARD"))
1124                  auto_mode = False;                  auto_mode = False;
# Line 992  xclip_init(void) Line 1152  xclip_init(void)
1152          format_string_atom = XInternAtom(g_display, "STRING", False);          format_string_atom = XInternAtom(g_display, "STRING", False);
1153          format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);          format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);
1154          format_unicode_atom = XInternAtom(g_display, "text/unicode", False);          format_unicode_atom = XInternAtom(g_display, "text/unicode", False);
1155    
1156            /* rdesktop sets _RDESKTOP_SELECTION_NOTIFY on the root window when acquiring the clipboard.
1157               Other interested rdesktops can use this to notify their server of the available formats. */
1158            rdesktop_selection_notify_atom =
1159                    XInternAtom(g_display, "_RDESKTOP_SELECTION_NOTIFY", False);
1160            XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask);
1161            probing_selections = False;
1162    
1163            rdesktop_native_atom = XInternAtom(g_display, "_RDESKTOP_NATIVE", False);
1164            rdesktop_clipboard_formats_atom =
1165                    XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False);
1166            rdesktop_primary_owner_atom = XInternAtom(g_display, "_RDESKTOP_PRIMARY_OWNER", False);
1167            rdesktop_clipboard_owner_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_OWNER", False);
1168    
1169          num_targets = 0;          num_targets = 0;
1170          targets[num_targets++] = targets_atom;          targets[num_targets++] = targets_atom;
1171          targets[num_targets++] = timestamp_atom;          targets[num_targets++] = timestamp_atom;
1172            targets[num_targets++] = rdesktop_native_atom;
1173          targets[num_targets++] = rdesktop_clipboard_formats_atom;          targets[num_targets++] = rdesktop_clipboard_formats_atom;
         targets[num_targets++] = format_string_atom;  
1174  #ifdef USE_UNICODE_CLIPBOARD  #ifdef USE_UNICODE_CLIPBOARD
1175          targets[num_targets++] = format_utf8_string_atom;          targets[num_targets++] = format_utf8_string_atom;
1176  #endif  #endif
1177          targets[num_targets++] = format_unicode_atom;          targets[num_targets++] = format_unicode_atom;
1178            targets[num_targets++] = format_string_atom;
1179          targets[num_targets++] = XA_STRING;          targets[num_targets++] = XA_STRING;
1180    }
1181    
1182          /* rdesktop sets _RDESKTOP_CLIPBOARD_FORMATS on the root window when acquiring the clipboard.  void
1183             Other interested rdesktops can use this to notify their server of the available formats. */  xclip_deinit(void)
1184          rdesktop_clipboard_formats_atom =  {
1185                  XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False);          if (XGetSelectionOwner(g_display, primary_atom) == g_wnd)
1186          XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask);                  XSetSelectionOwner(g_display, primary_atom, None, acquire_time);
1187            if (XGetSelectionOwner(g_display, clipboard_atom) == g_wnd)
1188                    XSetSelectionOwner(g_display, clipboard_atom, None, acquire_time);
1189            xclip_notify_change();
1190  }  }

Legend:
Removed from v.1207  
changed lines
  Added in v.1223

  ViewVC Help
Powered by ViewVC 1.1.26