/[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 1038 by astrand, Thu Jan 5 11:56:57 2006 UTC revision 1214 by ossman_, Tue Mar 28 13:56:08 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;
55  extern Time g_last_gesturetime;  extern Time g_last_gesturetime;
56    extern BOOL g_rdpclip;
57    
58    /* Mode of operation.
59       - Auto: Look at both PRIMARY and CLIPBOARD and use the most recent.
60       - Non-auto: Look at just CLIPBOARD. */
61    static BOOL auto_mode = True;
62  /* Atoms of the two X selections we're dealing with: CLIPBOARD (explicit-copy) and PRIMARY (selection-copy) */  /* Atoms of the two X selections we're dealing with: CLIPBOARD (explicit-copy) and PRIMARY (selection-copy) */
63  static Atom clipboard_atom, primary_atom;  static Atom clipboard_atom, primary_atom;
64  /* Atom of the TARGETS clipboard target */  /* Atom of the TARGETS clipboard target */
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  /* Atom _RDESKTOP_CLIPBOARD_FORMATS which has multiple uses:  /* Atoms _RDESKTOP_PRIMARY_TIMESTAMP_TARGET and _RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET
73     - The clipboard target (X jargon for "clipboard format") for rdesktop-to-rdesktop interchange     are used to store the timestamps for when a window got ownership of the selections.
74       of Windows native clipboard data.     We use these to determine which is more recent and should be used. */
75       This target cannot be used standalone; the requestor must keep the  static Atom rdesktop_primary_timestamp_target_atom, rdesktop_clipboard_timestamp_target_atom;
76       _RDESKTOP_CLIPBOARD_TARGET property on his window denoting  /* Storage for timestamps since we get them in two separate notifications. */
77       the Windows native clipboard format being requested.  static Time primary_timestamp, clipboard_timestamp;
78     - The root window property set by rdesktop when it owns the clipboard,  /* Clipboard target for getting a list of native Windows clipboard formats. The
79       denoting all Windows native clipboard formats it offers via     presence of this target indicates that the selection owner is another rdesktop. */
      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 98  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 201  xclip_provide_selection(XSelectionReques Line 218  xclip_provide_selection(XSelectionReques
218  {  {
219          XEvent xev;          XEvent xev;
220    
221            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));
222    
223          XChangeProperty(g_display, req->requestor, req->property,          XChangeProperty(g_display, req->requestor, req->property,
224                          type, format, PropModeReplace, data, length);                          type, format, PropModeReplace, data, length);
225    
# Line 223  xclip_refuse_selection(XSelectionRequest Line 242  xclip_refuse_selection(XSelectionRequest
242  {  {
243          XEvent xev;          XEvent xev;
244    
245            DEBUG_CLIPBOARD(("xclip_refuse_selection: requestor=0x%08x, target=%s, property=%s\n",
246                             (unsigned) req->requestor, XGetAtomName(g_display, req->target),
247                             XGetAtomName(g_display, req->property)));
248    
249          xev.xselection.type = SelectionNotify;          xev.xselection.type = SelectionNotify;
250          xev.xselection.serial = 0;          xev.xselection.serial = 0;
251          xev.xselection.send_event = True;          xev.xselection.send_event = True;
# Line 262  helper_cliprdr_send_empty_response() Line 285  helper_cliprdr_send_empty_response()
285  static Bool  static Bool
286  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)
287  {  {
288            DEBUG_CLIPBOARD(("xclip_send_data_with_convert: target=%s, size=%u\n",
289                             XGetAtomName(g_display, target), (unsigned) source_size));
290    
291  #ifdef USE_UNICODE_CLIPBOARD  #ifdef USE_UNICODE_CLIPBOARD
292          if (target == format_string_atom ||          if (target == format_string_atom ||
293              target == format_unicode_atom || target == format_utf8_string_atom)              target == format_unicode_atom || target == format_utf8_string_atom)
# Line 320  xclip_send_data_with_convert(uint8 * sou Line 346  xclip_send_data_with_convert(uint8 * sou
346                  char *unicode_buffer_remaining = unicode_buffer;                  char *unicode_buffer_remaining = unicode_buffer;
347                  char *data_remaining = (char *) source;                  char *data_remaining = (char *) source;
348                  size_t data_size_remaining = source_size;                  size_t data_size_remaining = source_size;
349                  iconv(cd, &data_remaining, &data_size_remaining, &unicode_buffer_remaining,                  iconv(cd, (ICONV_CONST char **) &data_remaining, &data_size_remaining,
350                        &unicode_buffer_size_remaining);                        &unicode_buffer_remaining, &unicode_buffer_size_remaining);
351                  iconv_close(cd);                  iconv_close(cd);
352    
353                  /* translate linebreaks */                  /* translate linebreaks */
# Line 332  xclip_send_data_with_convert(uint8 * sou Line 358  xclip_send_data_with_convert(uint8 * sou
358                  {                  {
359                          DEBUG_CLIPBOARD(("Sending Unicode string of %d bytes\n",                          DEBUG_CLIPBOARD(("Sending Unicode string of %d bytes\n",
360                                           translated_data_size));                                           translated_data_size));
361                          cliprdr_send_data(translated_data, translated_data_size);                          helper_cliprdr_send_response(translated_data, translated_data_size);
362                          xfree(translated_data); /* Not the same thing as XFree! */                          xfree(translated_data); /* Not the same thing as XFree! */
363                  }                  }
364    
# Line 353  xclip_send_data_with_convert(uint8 * sou Line 379  xclip_send_data_with_convert(uint8 * sou
379                  translated_data = lf2crlf(source, &length);                  translated_data = lf2crlf(source, &length);
380                  if (translated_data != NULL)                  if (translated_data != NULL)
381                  {                  {
382                          cliprdr_send_data(translated_data, length);                          helper_cliprdr_send_response(translated_data, length);
383                          xfree(translated_data); /* Not the same thing as XFree! */                          xfree(translated_data); /* Not the same thing as XFree! */
384                  }                  }
385    
386                  return True;                  return True;
387          }          }
388  #endif  #endif
389          else if (target == rdesktop_clipboard_formats_atom)          else if (target == rdesktop_native_atom)
390          {          {
391                  helper_cliprdr_send_response(source, source_size + 1);                  helper_cliprdr_send_response(source, source_size + 1);
392    
# Line 372  xclip_send_data_with_convert(uint8 * sou Line 398  xclip_send_data_with_convert(uint8 * sou
398          }          }
399  }  }
400    
401    static void
402    xclip_clear_target_props()
403    {
404            XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
405            XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom);
406            XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom);
407    }
408    
409    static void
410    xclip_notify_change()
411    {
412            XChangeProperty(g_display, DefaultRootWindow(g_display),
413                            rdesktop_selection_notify_atom, XA_INTEGER, 32, PropModeReplace, NULL, 0);
414    }
415    
416    static void
417    xclip_probe_selections()
418    {
419            Window primary_owner, clipboard_owner;
420    
421            if (probing_selections)
422            {
423                    DEBUG_CLIPBOARD(("Already probing selections. Scheduling reprobe.\n"));
424                    reprobe_selections = True;
425                    return;
426            }
427    
428            DEBUG_CLIPBOARD(("Probing selections.\n"));
429    
430            probing_selections = True;
431            reprobe_selections = False;
432    
433            xclip_clear_target_props();
434    
435            if (auto_mode)
436                    primary_owner = XGetSelectionOwner(g_display, primary_atom);
437            else
438                    primary_owner = None;
439    
440            clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom);
441    
442            /* If we own all relevant selections then don't do anything. */
443            if (((primary_owner == g_wnd) || !auto_mode) && (clipboard_owner == g_wnd))
444                    goto end;
445    
446            /* Both available */
447            if ((primary_owner != None) && (clipboard_owner != None))
448            {
449                    primary_timestamp = 0;
450                    clipboard_timestamp = 0;
451                    XConvertSelection(g_display, primary_atom, timestamp_atom,
452                                      rdesktop_primary_timestamp_target_atom, g_wnd, CurrentTime);
453                    XConvertSelection(g_display, clipboard_atom, timestamp_atom,
454                                      rdesktop_clipboard_timestamp_target_atom, g_wnd, CurrentTime);
455                    return;
456            }
457    
458            /* Just PRIMARY */
459            if (primary_owner != None)
460            {
461                    XConvertSelection(g_display, primary_atom, targets_atom,
462                                      rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
463                    return;
464            }
465    
466            /* Just CLIPBOARD */
467            if (clipboard_owner != None)
468            {
469                    XConvertSelection(g_display, clipboard_atom, targets_atom,
470                                      rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
471                    return;
472            }
473    
474            DEBUG_CLIPBOARD(("No owner of any selection.\n"));
475    
476            /* FIXME:
477               Without XFIXES, we cannot reliably know the formats offered by an
478               upcoming selection owner, so we just lie about him offering
479               RDP_CF_TEXT. */
480            cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);
481    
482          end:
483            probing_selections = False;
484    }
485    
486  /* This function is called for SelectionNotify events.  /* This function is called for SelectionNotify events.
487     The SelectionNotify event is sent from the clipboard owner to the requestor     The SelectionNotify event is sent from the clipboard owner to the requestor
488     after his request was satisfied.     after his request was satisfied.
# Line 385  xclip_handle_SelectionNotify(XSelectionE Line 496  xclip_handle_SelectionNotify(XSelectionE
496          Atom type;          Atom type;
497          Atom *supported_targets;          Atom *supported_targets;
498          int res, i, format;          int res, i, format;
499          uint8 *data;          uint8 *data = NULL;
500    
501          if (event->property == None)          if (event->property == None)
502                  goto fail;                  goto fail;
# Line 395  xclip_handle_SelectionNotify(XSelectionE Line 506  xclip_handle_SelectionNotify(XSelectionE
506                           XGetAtomName(g_display, event->target),                           XGetAtomName(g_display, event->target),
507                           XGetAtomName(g_display, event->property)));                           XGetAtomName(g_display, event->property)));
508    
509          if (event->property == None)          if (event->target == timestamp_atom)
510                  goto fail;          {
511                    if (event->selection == primary_atom)
512                    {
513                            res = XGetWindowProperty(g_display, g_wnd,
514                                                     rdesktop_primary_timestamp_target_atom, 0,
515                                                     XMaxRequestSize(g_display), False, XA_INTEGER,
516                                                     &type, &format, &nitems, &bytes_left, &data);
517                    }
518                    else
519                    {
520                            res = XGetWindowProperty(g_display, g_wnd,
521                                                     rdesktop_clipboard_timestamp_target_atom, 0,
522                                                     XMaxRequestSize(g_display), False, XA_INTEGER,
523                                                     &type, &format, &nitems, &bytes_left, &data);
524                    }
525    
526    
527                    if ((res != Success) || (nitems != 1))
528                    {
529                            DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
530                            goto fail;
531                    }
532    
533                    if (event->selection == primary_atom)
534                    {
535                            primary_timestamp = *(Time *) data;
536                            if (primary_timestamp == 0)
537                                    primary_timestamp++;
538                            XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom);
539                            DEBUG_CLIPBOARD(("Got PRIMARY timestamp: %u\n",
540                                             (unsigned) primary_timestamp));
541                    }
542                    else
543                    {
544                            clipboard_timestamp = *(Time *) data;
545                            if (clipboard_timestamp == 0)
546                                    clipboard_timestamp++;
547                            XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom);
548                            DEBUG_CLIPBOARD(("Got CLIPBOARD timestamp: %u\n",
549                                             (unsigned) clipboard_timestamp));
550                    }
551    
552                    XFree(data);
553    
554                    if (primary_timestamp && clipboard_timestamp)
555                    {
556                            if (primary_timestamp > clipboard_timestamp)
557                            {
558                                    DEBUG_CLIPBOARD(("PRIMARY is most recent selection.\n"));
559                                    XConvertSelection(g_display, primary_atom, targets_atom,
560                                                      rdesktop_clipboard_target_atom, g_wnd,
561                                                      event->time);
562                            }
563                            else
564                            {
565                                    DEBUG_CLIPBOARD(("CLIPBOARD is most recent selection.\n"));
566                                    XConvertSelection(g_display, clipboard_atom, targets_atom,
567                                                      rdesktop_clipboard_target_atom, g_wnd,
568                                                      event->time);
569                            }
570                    }
571    
572                    return;
573            }
574    
575            if (probing_selections && reprobe_selections)
576            {
577                    probing_selections = False;
578                    xclip_probe_selections();
579                    return;
580            }
581    
582          res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,          res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
583                                   0, XMaxRequestSize(g_display), False, AnyPropertyType,                                   0, XMaxRequestSize(g_display), False, AnyPropertyType,
584                                   &type, &format, &nitems, &bytes_left, &data);                                   &type, &format, &nitems, &bytes_left, &data);
585    
586            xclip_clear_target_props();
587    
588          if (res != Success)          if (res != Success)
589          {          {
590                  DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));                  DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
# Line 417  xclip_handle_SelectionNotify(XSelectionE Line 600  xclip_handle_SelectionNotify(XSelectionE
600                  {                  {
601                          XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask));                          XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask));
602                  }                  }
                 XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);  
603                  XFree(data);                  XFree(data);
604                  g_incr_target = event->target;                  g_incr_target = event->target;
605                  g_waiting_for_INCR = 1;                  g_waiting_for_INCR = 1;
606                  return;                  goto end;
607          }          }
608    
         XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);  
   
609          /* Negotiate target format */          /* Negotiate target format */
610          if (event->target == targets_atom)          if (event->target == targets_atom)
611          {          {
# Line 471  xclip_handle_SelectionNotify(XSelectionE Line 651  xclip_handle_SelectionNotify(XSelectionE
651                                          }                                          }
652                                  }                                  }
653  #endif  #endif
654                                    else if (supported_targets[i] == rdesktop_clipboard_formats_atom)
655                                    {
656                                            if (probing_selections && (text_target_satisfaction < 4))
657                                            {
658                                                    DEBUG_CLIPBOARD(("Other party supports native formats, choosing that as best_target\n"));
659                                                    best_text_target = supported_targets[i];
660                                                    text_target_satisfaction = 4;
661                                            }
662                                    }
663                          }                          }
664                  }                  }
665    
666                  /* Kickstarting the next step in the process of satisfying RDP's                  /* Kickstarting the next step in the process of satisfying RDP's
667                     clipboard request -- specifically, requesting the actual clipboard data.                     clipboard request -- specifically, requesting the actual clipboard data.
668                   */                   */
669                  if (best_text_target != 0)                  if ((best_text_target != 0)
670                        && (!probing_selections
671                            || (best_text_target == rdesktop_clipboard_formats_atom)))
672                  {                  {
673                          XConvertSelection(g_display, clipboard_atom, best_text_target,                          XConvertSelection(g_display, event->selection, best_text_target,
674                                            rdesktop_clipboard_target_atom, g_wnd, event->time);                                            rdesktop_clipboard_target_atom, g_wnd, event->time);
675                          return;                          goto end;
676                  }                  }
677                  else                  else
678                  {                  {
# Line 491  xclip_handle_SelectionNotify(XSelectionE Line 682  xclip_handle_SelectionNotify(XSelectionE
682          }          }
683          else          else
684          {          {
685                  if (!xclip_send_data_with_convert(data, nitems, event->target))                  if (probing_selections)
686                    {
687                            Window primary_owner, clipboard_owner;
688    
689                            /* FIXME:
690                               Without XFIXES, we must make sure that the other
691                               rdesktop owns all relevant selections or we might try
692                               to get a native format from non-rdesktop window later
693                               on. */
694    
695                            clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom);
696    
697                            if (auto_mode)
698                                    primary_owner = XGetSelectionOwner(g_display, primary_atom);
699                            else
700                                    primary_owner = clipboard_owner;
701    
702                            if (primary_owner != clipboard_owner)
703                                    goto fail;
704    
705                            DEBUG_CLIPBOARD(("Got fellow rdesktop formats\n"));
706                            probing_selections = False;
707                            rdesktop_is_selection_owner = True;
708                            cliprdr_send_native_format_announce(data, nitems);
709                    }
710                    else if (!xclip_send_data_with_convert(data, nitems, event->target))
711                  {                  {
712                          goto fail;                          goto fail;
713                  }                  }
714          }          }
715    
716          XFree(data);        end:
717            if (data)
718                    XFree(data);
719    
720          return;          return;
721    
722        fail:        fail:
723          XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);          xclip_clear_target_props();
724          XFree(data);          if (probing_selections)
725          helper_cliprdr_send_empty_response();          {
726                    DEBUG_CLIPBOARD(("Unable to find suitable target. Using default text format.\n"));
727                    probing_selections = False;
728                    rdesktop_is_selection_owner = False;
729    
730                    /* FIXME:
731                       Without XFIXES, we cannot reliably know the formats offered by an
732                       upcoming selection owner, so we just lie about him offering
733                       RDP_CF_TEXT. */
734                    cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);
735            }
736            else
737            {
738                    helper_cliprdr_send_empty_response();
739            }
740            goto end;
741  }  }
742    
743  /* This function is called for SelectionRequest events.  /* This function is called for SelectionRequest events.
# Line 516  xclip_handle_SelectionRequest(XSelection Line 749  xclip_handle_SelectionRequest(XSelection
749  {  {
750          unsigned long nitems, bytes_left;          unsigned long nitems, bytes_left;
751          unsigned char *prop_return;          unsigned char *prop_return;
         uint32 *wanted_format;  
752          int format, res;          int format, res;
753          Atom type;          Atom type;
754    
# Line 532  xclip_handle_SelectionRequest(XSelection Line 764  xclip_handle_SelectionRequest(XSelection
764          }          }
765          else if (event->target == timestamp_atom)          else if (event->target == timestamp_atom)
766          {          {
767                  xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & g_last_gesturetime, 1);                  xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & acquire_time, 1);
768                  return;                  return;
769          }          }
770            else if (event->target == rdesktop_clipboard_formats_atom)
771            {
772                    xclip_provide_selection(event, XA_STRING, 8, formats_data, formats_data_length);
773            }
774          else          else
775          {          {
776                  /* 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 546  xclip_handle_SelectionRequest(XSelection Line 782  xclip_handle_SelectionRequest(XSelection
782                          xclip_refuse_selection(event);                          xclip_refuse_selection(event);
783                          return;                          return;
784                  }                  }
785                  if (event->target == rdesktop_clipboard_formats_atom)                  if (event->target == rdesktop_native_atom)
786                  {                  {
787                          /* Before the requestor makes a request for the _RDESKTOP_CLIPBOARD_FORMATS target,                          /* Before the requestor makes a request for the _RDESKTOP_NATIVE target,
788                             he should declare requestor[_RDESKTOP_CLIPBOARD_TARGET] = CF_SOMETHING.                             he should declare requestor[property] = CF_SOMETHING. */
                            Otherwise, we default to RDP_CF_TEXT.  
                          */  
789                          res = XGetWindowProperty(g_display, event->requestor,                          res = XGetWindowProperty(g_display, event->requestor,
790                                                   rdesktop_clipboard_target_atom, 0, 1, True,                                                   event->property, 0, 1, True,
791                                                   XA_INTEGER, &type, &format, &nitems, &bytes_left,                                                   XA_INTEGER, &type, &format, &nitems, &bytes_left,
792                                                   &prop_return);                                                   &prop_return);
793                          wanted_format = (uint32 *) prop_return;                          if (res != Success)
794                          format = (res == Success) ? *wanted_format : RDP_CF_TEXT;                          {
795                                    DEBUG_CLIPBOARD(("Requested native format but didn't specifiy which.\n"));
796                                    xclip_refuse_selection(event);
797                                    return;
798                            }
799    
800                            format = *(uint32 *) prop_return;
801                          XFree(prop_return);                          XFree(prop_return);
802                  }                  }
803                  else if (event->target == format_string_atom || event->target == XA_STRING)                  else if (event->target == format_string_atom || event->target == XA_STRING)
# Line 605  void Line 845  void
845  xclip_handle_SelectionClear(void)  xclip_handle_SelectionClear(void)
846  {  {
847          DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));          DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));
848          have_primary = 0;          xclip_notify_change();
849          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);  
850  }  }
851    
852  /* 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 621  xclip_handle_PropertyNotify(XPropertyEve Line 856  xclip_handle_PropertyNotify(XPropertyEve
856          unsigned long nitems;          unsigned long nitems;
857          unsigned long offset = 0;          unsigned long offset = 0;
858          unsigned long bytes_left = 1;          unsigned long bytes_left = 1;
859          int format, res;          int format;
860          XWindowAttributes wa;          XWindowAttributes wa;
861          uint8 *data;          uint8 *data;
862          Atom type;          Atom type;
# Line 679  xclip_handle_PropertyNotify(XPropertyEve Line 914  xclip_handle_PropertyNotify(XPropertyEve
914                  return;                  return;
915          }          }
916    
917          if ((event->atom == rdesktop_clipboard_formats_atom) &&          if ((event->atom == rdesktop_selection_notify_atom) &&
918              (event->window == DefaultRootWindow(g_display)) &&              (event->window == DefaultRootWindow(g_display)))
919              !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;  
         }  
920  }  }
921  #endif  #endif
922    
# Line 716  xclip_handle_PropertyNotify(XPropertyEve Line 929  xclip_handle_PropertyNotify(XPropertyEve
929  void  void
930  ui_clip_format_announce(uint8 * data, uint32 length)  ui_clip_format_announce(uint8 * data, uint32 length)
931  {  {
932          XSetSelectionOwner(g_display, primary_atom, g_wnd, g_last_gesturetime);          acquire_time = g_last_gesturetime;
933    
934            XSetSelectionOwner(g_display, primary_atom, g_wnd, acquire_time);
935          if (XGetSelectionOwner(g_display, primary_atom) != g_wnd)          if (XGetSelectionOwner(g_display, primary_atom) != g_wnd)
         {  
936                  warning("Failed to aquire ownership of PRIMARY clipboard\n");                  warning("Failed to aquire ownership of PRIMARY clipboard\n");
                 return;  
         }  
937    
938          have_primary = 1;          XSetSelectionOwner(g_display, clipboard_atom, g_wnd, acquire_time);
         XChangeProperty(g_display, DefaultRootWindow(g_display),  
                         rdesktop_clipboard_formats_atom, XA_STRING, 8, PropModeReplace, data,  
                         length);  
   
         XSetSelectionOwner(g_display, clipboard_atom, g_wnd, g_last_gesturetime);  
939          if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd)          if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd)
940                  warning("Failed to aquire ownership of CLIPBOARD clipboard\n");                  warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
941    
942            if (formats_data)
943                    xfree(formats_data);
944            formats_data = xmalloc(length);
945            memcpy(formats_data, data, length);
946            formats_data_length = length;
947    
948            xclip_notify_change();
949  }  }
950    
951  /* 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 739  ui_clip_handle_data(uint8 * data, uint32 Line 954  ui_clip_handle_data(uint8 * data, uint32
954  {  {
955          BOOL free_data = False;          BOOL free_data = False;
956    
957            if (length == 0)
958            {
959                    xclip_refuse_selection(&selection_request);
960                    has_selection_request = False;
961                    return;
962            }
963    
964          if (selection_request.target == format_string_atom || selection_request.target == XA_STRING)          if (selection_request.target == format_string_atom || selection_request.target == XA_STRING)
965          {          {
966                  /* We're expecting a CF_TEXT response */                  /* We're expecting a CF_TEXT response */
# Line 772  ui_clip_handle_data(uint8 * data, uint32 Line 994  ui_clip_handle_data(uint8 * data, uint32
994                                  iconv_close(cd);                                  iconv_close(cd);
995                                  return;                                  return;
996                          }                          }
997                          iconv(cd, &data_remaining, &length_remaining, &utf8_data_remaining,                          iconv(cd, (ICONV_CONST char **) &data_remaining, &length_remaining,
998                                &utf8_length_remaining);                                &utf8_data_remaining, &utf8_length_remaining);
999                          iconv_close(cd);                          iconv_close(cd);
1000                          free_data = True;                          free_data = True;
1001                          data = (uint8 *) utf8_data;                          data = (uint8 *) utf8_data;
# Line 787  ui_clip_handle_data(uint8 * data, uint32 Line 1009  ui_clip_handle_data(uint8 * data, uint32
1009                     for further conversions. */                     for further conversions. */
1010          }          }
1011  #endif  #endif
1012          else if (selection_request.target == rdesktop_clipboard_formats_atom)          else if (selection_request.target == rdesktop_native_atom)
1013          {          {
1014                  /* Pass as-is */                  /* Pass as-is */
1015          }          }
1016          else          else
1017          {          {
1018                    DEBUG_CLIPBOARD(("ui_clip_handle_data: BUG! I don't know how to convert selection target %s!\n", XGetAtomName(g_display, selection_request.target)));
1019                  xclip_refuse_selection(&selection_request);                  xclip_refuse_selection(&selection_request);
1020                  has_selection_request = False;                  has_selection_request = False;
1021                  return;                  return;
# Line 806  ui_clip_handle_data(uint8 * data, uint32 Line 1029  ui_clip_handle_data(uint8 * data, uint32
1029  }  }
1030    
1031  void  void
1032    ui_clip_request_failed()
1033    {
1034            xclip_refuse_selection(&selection_request);
1035            has_selection_request = False;
1036    }
1037    
1038    void
1039  ui_clip_request_data(uint32 format)  ui_clip_request_data(uint32 format)
1040  {  {
1041          Window selectionowner;          Window primary_owner, clipboard_owner;
1042    
1043          DEBUG_CLIPBOARD(("Request from server for format %d\n", format));          DEBUG_CLIPBOARD(("Request from server for format %d\n", format));
1044          rdp_clipboard_request_format = format;          rdp_clipboard_request_format = format;
1045    
1046            if (probing_selections)
1047            {
1048                    DEBUG_CLIPBOARD(("ui_clip_request_data: Selection probe in progress. Cannot handle request.\n"));
1049                    helper_cliprdr_send_empty_response();
1050                    return;
1051            }
1052    
1053            xclip_clear_target_props();
1054    
1055          if (rdesktop_is_selection_owner)          if (rdesktop_is_selection_owner)
1056          {          {
1057                  XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,                  XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
1058                                  XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);                                  XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);
1059    
1060                  XConvertSelection(g_display, primary_atom, rdesktop_clipboard_formats_atom,                  XConvertSelection(g_display, primary_atom, rdesktop_native_atom,
1061                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
1062                  return;                  return;
1063          }          }
1064    
1065          selectionowner = XGetSelectionOwner(g_display, primary_atom);          if (auto_mode)
1066          if (selectionowner != None)                  primary_owner = XGetSelectionOwner(g_display, primary_atom);
1067            else
1068                    primary_owner = None;
1069    
1070            clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom);
1071    
1072            /* Both available */
1073            if ((primary_owner != None) && (clipboard_owner != None))
1074            {
1075                    primary_timestamp = 0;
1076                    clipboard_timestamp = 0;
1077                    XConvertSelection(g_display, primary_atom, timestamp_atom,
1078                                      rdesktop_primary_timestamp_target_atom, g_wnd, CurrentTime);
1079                    XConvertSelection(g_display, clipboard_atom, timestamp_atom,
1080                                      rdesktop_clipboard_timestamp_target_atom, g_wnd, CurrentTime);
1081                    return;
1082            }
1083    
1084            /* Just PRIMARY */
1085            if (primary_owner != None)
1086          {          {
1087                  XConvertSelection(g_display, primary_atom, targets_atom,                  XConvertSelection(g_display, primary_atom, targets_atom,
1088                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
1089                  return;                  return;
1090          }          }
1091    
1092          /* No PRIMARY, try CLIPBOARD */          /* Just CLIPBOARD */
1093          selectionowner = XGetSelectionOwner(g_display, clipboard_atom);          if (clipboard_owner != None)
         if (selectionowner != None)  
1094          {          {
1095                  XConvertSelection(g_display, clipboard_atom, targets_atom,                  XConvertSelection(g_display, clipboard_atom, targets_atom,
1096                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
# Line 841  ui_clip_request_data(uint32 format) Line 1098  ui_clip_request_data(uint32 format)
1098          }          }
1099    
1100          /* No data available */          /* No data available */
1101          cliprdr_send_data(NULL, 0);          helper_cliprdr_send_empty_response();
1102  }  }
1103    
1104  void  void
1105  ui_clip_sync(void)  ui_clip_sync(void)
1106  {  {
1107          cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);          xclip_probe_selections();
1108  }  }
1109    
1110    void
1111    ui_clip_set_mode(const char *optarg)
1112    {
1113            g_rdpclip = True;
1114    
1115            if (str_startswith(optarg, "auto") || str_startswith(optarg, "on")
1116                || str_startswith(optarg, "PRIMARYCLIPBOARD"))
1117                    auto_mode = True;
1118            else if (str_startswith(optarg, "CLIPBOARD"))
1119                    auto_mode = False;
1120            else
1121            {
1122                    warning("Invalid clipboard mode '%s'.\n", optarg);
1123                    g_rdpclip = False;
1124            }
1125    }
1126    
1127  void  void
1128  xclip_init(void)  xclip_init(void)
1129  {  {
1130            if (!g_rdpclip)
1131                    return;
1132    
1133          if (!cliprdr_init())          if (!cliprdr_init())
1134                  return;                  return;
1135    
# Line 863  xclip_init(void) Line 1139  xclip_init(void)
1139          timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False);          timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False);
1140          rdesktop_clipboard_target_atom =          rdesktop_clipboard_target_atom =
1141                  XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False);                  XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False);
1142            rdesktop_primary_timestamp_target_atom =
1143                    XInternAtom(g_display, "_RDESKTOP_PRIMARY_TIMESTAMP_TARGET", False);
1144            rdesktop_clipboard_timestamp_target_atom =
1145                    XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET", False);
1146          incr_atom = XInternAtom(g_display, "INCR", False);          incr_atom = XInternAtom(g_display, "INCR", False);
1147          format_string_atom = XInternAtom(g_display, "STRING", False);          format_string_atom = XInternAtom(g_display, "STRING", False);
1148          format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);          format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);
1149          format_unicode_atom = XInternAtom(g_display, "text/unicode", False);          format_unicode_atom = XInternAtom(g_display, "text/unicode", False);
1150    
1151            /* rdesktop sets _RDESKTOP_SELECTION_NOTIFY on the root window when acquiring the clipboard.
1152               Other interested rdesktops can use this to notify their server of the available formats. */
1153            rdesktop_selection_notify_atom =
1154                    XInternAtom(g_display, "_RDESKTOP_SELECTION_NOTIFY", False);
1155            XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask);
1156            probing_selections = False;
1157    
1158            rdesktop_native_atom = XInternAtom(g_display, "_RDESKTOP_NATIVE", False);
1159            rdesktop_clipboard_formats_atom =
1160                    XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False);
1161            rdesktop_primary_owner_atom = XInternAtom(g_display, "_RDESKTOP_PRIMARY_OWNER", False);
1162            rdesktop_clipboard_owner_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_OWNER", False);
1163    
1164          num_targets = 0;          num_targets = 0;
1165          targets[num_targets++] = targets_atom;          targets[num_targets++] = targets_atom;
1166          targets[num_targets++] = timestamp_atom;          targets[num_targets++] = timestamp_atom;
1167            targets[num_targets++] = rdesktop_native_atom;
1168          targets[num_targets++] = rdesktop_clipboard_formats_atom;          targets[num_targets++] = rdesktop_clipboard_formats_atom;
         targets[num_targets++] = format_string_atom;  
1169  #ifdef USE_UNICODE_CLIPBOARD  #ifdef USE_UNICODE_CLIPBOARD
1170          targets[num_targets++] = format_utf8_string_atom;          targets[num_targets++] = format_utf8_string_atom;
1171  #endif  #endif
1172          targets[num_targets++] = format_unicode_atom;          targets[num_targets++] = format_unicode_atom;
1173            targets[num_targets++] = format_string_atom;
1174          targets[num_targets++] = XA_STRING;          targets[num_targets++] = XA_STRING;
1175    }
1176    
1177          /* rdesktop sets _RDESKTOP_CLIPBOARD_FORMATS on the root window when acquiring the clipboard.  void
1178             Other interested rdesktops can use this to notify their server of the available formats. */  xclip_deinit(void)
1179          rdesktop_clipboard_formats_atom =  {
1180                  XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False);          if (XGetSelectionOwner(g_display, primary_atom) == g_wnd)
1181          XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask);                  XSetSelectionOwner(g_display, primary_atom, None, acquire_time);
1182            if (XGetSelectionOwner(g_display, clipboard_atom) == g_wnd)
1183                    XSetSelectionOwner(g_display, clipboard_atom, None, acquire_time);
1184            xclip_notify_change();
1185  }  }

Legend:
Removed from v.1038  
changed lines
  Added in v.1214

  ViewVC Help
Powered by ViewVC 1.1.26