/[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 435 by astrand, Wed Jul 9 09:18:20 2003 UTC revision 1026 by forsberg, Wed Nov 9 15:15:28 2005 UTC
# Line 25  Line 25 
25    
26  #define NUM_TARGETS 6  #define NUM_TARGETS 6
27    
28  extern Display *display;  extern Display *g_display;
29  extern Window wnd;  extern Window g_wnd;
30  extern Time last_gesturetime;  extern Time g_last_gesturetime;
31    
32  static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom;  static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom;
33  static Atom rdesktop_clipboard_target_atom, rdesktop_clipboard_formats_atom, incr_atom;  static Atom rdesktop_clipboard_target_atom, rdesktop_clipboard_formats_atom, incr_atom;
# Line 36  static Atom targets[NUM_TARGETS]; Line 36  static Atom targets[NUM_TARGETS];
36  static int have_primary = 0;  static int have_primary = 0;
37  static int rdesktop_is_selection_owner = 0;  static int rdesktop_is_selection_owner = 0;
38    
39    static int g_waiting_for_INCR = 0;
40    static uint8 *g_clip_buffer = 0;
41    static uint32 g_clip_buflen = 0;
42    
43    /* Replace CR-LF to LF (well, rather removing all CR:s) This is done
44       in-place. The length is updated. Handles embedded nulls */
45    static void
46    crlf2lf(uint8 * data, uint32 * length)
47    {
48            uint8 *dst, *src;
49            src = dst = data;
50            while (src < data + *length)
51            {
52                    if (*src != '\x0d')
53                            *dst++ = *src;
54                    src++;
55            }
56            *length = dst - data;
57    }
58    
59    /* Translate LF to CR-LF. To do this, we must allocate more memory.  
60       The length is updated. */
61    static uint8 *
62    lf2crlf(uint8 * data, uint32 * length)
63    {
64            uint8 *result, *p, *o;
65    
66            /* Worst case: Every char is LF */
67            result = xmalloc(*length * 2);
68    
69            p = data;
70            o = result;
71    
72            while (p < data + *length)
73            {
74                    if (*p == '\x0a')
75                            *o++ = '\x0d';
76                    *o++ = *p++;
77            }
78            *length = o - result;
79    
80            /* Convenience */
81            *o++ = '\0';
82    
83            return result;
84    }
85    
86    
87  static void  static void
88  xclip_provide_selection(XSelectionRequestEvent * req, Atom type, unsigned int format, uint8 * data,  xclip_provide_selection(XSelectionRequestEvent * req, Atom type, unsigned int format, uint8 * data,
89                          uint32 length)                          uint32 length)
90  {  {
91          XEvent xev;          XEvent xev;
92    
93          XChangeProperty(display, req->requestor, req->property,          XChangeProperty(g_display, req->requestor, req->property,
94                          type, format, PropModeReplace, data, length);                          type, format, PropModeReplace, data, length);
95    
96          xev.xselection.type = SelectionNotify;          xev.xselection.type = SelectionNotify;
# Line 53  xclip_provide_selection(XSelectionReques Line 101  xclip_provide_selection(XSelectionReques
101          xev.xselection.target = req->target;          xev.xselection.target = req->target;
102          xev.xselection.property = req->property;          xev.xselection.property = req->property;
103          xev.xselection.time = req->time;          xev.xselection.time = req->time;
104          XSendEvent(display, req->requestor, False, NoEventMask, &xev);          XSendEvent(g_display, req->requestor, False, NoEventMask, &xev);
105  }  }
106    
107    #ifndef MAKE_PROTO
108  void  void
109  xclip_handle_SelectionNotify(XSelectionEvent * event)  xclip_handle_SelectionNotify(XSelectionEvent * event)
110  {  {
111          unsigned long nitems, bytes_left;          unsigned long nitems, bytes_left;
112            XWindowAttributes wa;
113          Atom type, best_target, text_target;          Atom type, best_target, text_target;
114          Atom *supported_targets;          Atom *supported_targets;
115          int res, i, format;          int res, i, format;
# Line 69  xclip_handle_SelectionNotify(XSelectionE Line 119  xclip_handle_SelectionNotify(XSelectionE
119                  goto fail;                  goto fail;
120    
121          DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n",          DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n",
122                           XGetAtomName(display, event->selection),                           XGetAtomName(g_display, event->selection),
123                           XGetAtomName(display, event->target),                           XGetAtomName(g_display, event->target),
124                           XGetAtomName(display, event->property)));                           XGetAtomName(g_display, event->property)));
125    
126          if (event->property == None)          if (event->property == None)
127                  goto fail;                  goto fail;
128    
129          res = XGetWindowProperty(display, wnd, rdesktop_clipboard_target_atom,          res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
130                                   0, XMaxRequestSize(display), True, AnyPropertyType,                                   0, XMaxRequestSize(g_display), False, AnyPropertyType,
131                                   &type, &format, &nitems, &bytes_left, &data);                                   &type, &format, &nitems, &bytes_left, &data);
132    
133          if (res != Success)          if (res != Success)
# Line 86  xclip_handle_SelectionNotify(XSelectionE Line 136  xclip_handle_SelectionNotify(XSelectionE
136                  goto fail;                  goto fail;
137          }          }
138    
139    
140            if (type == incr_atom)
141            {
142                    DEBUG_CLIPBOARD(("Received INCR.\n"));
143    
144                    XGetWindowAttributes(g_display, g_wnd, &wa);
145                    if ((wa.your_event_mask | PropertyChangeMask) != wa.your_event_mask)
146                    {
147                            XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask));
148                    }
149                    XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
150                    XFree(data);
151                    g_waiting_for_INCR = 1;
152                    return;
153            }
154            
155            XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
156                    
157            /* Negotiate target format */
158          if (event->target == targets_atom)          if (event->target == targets_atom)
159          {          {
160                  /* FIXME: We should choose format here based on what the server wanted */                  /* FIXME: We should choose format here based on what the server wanted */
# Line 93  xclip_handle_SelectionNotify(XSelectionE Line 162  xclip_handle_SelectionNotify(XSelectionE
162                  if (type != None)                  if (type != None)
163                  {                  {
164                          supported_targets = (Atom *) data;                          supported_targets = (Atom *) data;
165                          text_target = XInternAtom(display, "TEXT", False);                          text_target = XInternAtom(g_display, "TEXT", False);
166                          for (i = 0; i < nitems; i++)                          for (i = 0; i < nitems; i++)
167                          {                          {
168                                  DEBUG_CLIPBOARD(("Target %d: %s\n", i,                                  DEBUG_CLIPBOARD(("Target %d: %s\n", i,
169                                                   XGetAtomName(display, supported_targets[i])));                                                   XGetAtomName(g_display, supported_targets[i])));
170                                  if (supported_targets[i] == text_target)                                  if (supported_targets[i] == text_target)
171                                  {                                  {
172                                          DEBUG_CLIPBOARD(("Other party supports TEXT, choosing that as best_target\n"));                                          DEBUG_CLIPBOARD(("Other party supports TEXT, choosing that as best_target\n"));
173                                          best_target = text_target;                                          best_target = text_target;
174                                            break;
175                                  }                                  }
176                          }                          }
177                          XFree(data);                          XFree(data);
178                  }                  }
179    
180                  XConvertSelection(display, primary_atom, best_target,                  XConvertSelection(g_display, primary_atom, best_target,
181                                    rdesktop_clipboard_target_atom, wnd, event->time);                                    rdesktop_clipboard_target_atom, g_wnd, event->time);
182                  return;                  return;
183          }          }
184    
185          if (type == incr_atom)          /* Translate linebreaks, but only if not getting data from
186               other rdesktop instance */
187            if (event->target != rdesktop_clipboard_formats_atom)
188            {
189                    uint8 *translated_data;
190                    uint32 length = nitems;
191    
192                    DEBUG_CLIPBOARD(("Translating linebreaks before sending data\n"));
193                    translated_data = lf2crlf(data, &length);
194                    cliprdr_send_data(translated_data, length + 1);
195                    xfree(translated_data); /* Not the same thing as XFree! */
196            }
197            else
198          {          {
199                  warning("We don't support INCR transfers at this time. Try cutting less data.\n");                  cliprdr_send_data(data, nitems + 1);
                 goto fail;  
200          }          }
   
         cliprdr_send_data(data, nitems + 1);  
201          XFree(data);          XFree(data);
202    
203          if (!rdesktop_is_selection_owner)          if (!rdesktop_is_selection_owner)
204                  cliprdr_send_text_format_announce();                  cliprdr_send_simple_native_format_announce(CF_TEXT);
205          return;          return;
206    
207        fail:   fail:
208            XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
209            XFree(data);
210          cliprdr_send_data(NULL, 0);          cliprdr_send_data(NULL, 0);
211  }  }
212    
# Line 133  void Line 214  void
214  xclip_handle_SelectionRequest(XSelectionRequestEvent * event)  xclip_handle_SelectionRequest(XSelectionRequestEvent * event)
215  {  {
216          unsigned long nitems, bytes_left;          unsigned long nitems, bytes_left;
217            unsigned char *prop_return;
218          uint32 *wanted_format;          uint32 *wanted_format;
219          int format, res;          int format, res;
220          Atom type;          Atom type;
221    
222          DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n",          DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n",
223                           XGetAtomName(display, event->selection),                           XGetAtomName(g_display, event->selection),
224                           XGetAtomName(display, event->target),                           XGetAtomName(g_display, event->target),
225                           XGetAtomName(display, event->property)));                           XGetAtomName(g_display, event->property)));
226    
227          if (event->target == targets_atom)          if (event->target == targets_atom)
228          {          {
# Line 149  xclip_handle_SelectionRequest(XSelection Line 231  xclip_handle_SelectionRequest(XSelection
231          }          }
232          else if (event->target == timestamp_atom)          else if (event->target == timestamp_atom)
233          {          {
234                  xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & last_gesturetime, 1);                  xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & g_last_gesturetime, 1);
235                  return;                  return;
236          }          }
237          else if (event->target == rdesktop_clipboard_formats_atom)          else if (event->target == rdesktop_clipboard_formats_atom)
238          {          {
239                  res = XGetWindowProperty(display, event->requestor,                  res = XGetWindowProperty(g_display, event->requestor,
240                                           rdesktop_clipboard_target_atom, 0, 1, True, XA_INTEGER,                                           rdesktop_clipboard_target_atom, 0, 1, True, XA_INTEGER,
241                                           &type, &format, &nitems, &bytes_left,                                           &type, &format, &nitems, &bytes_left, &prop_return);
242                                           (unsigned char **) &wanted_format);                  wanted_format = (uint32 *) prop_return;
243                  format = (res == Success) ? *wanted_format : CF_TEXT;                  format = (res == Success) ? *wanted_format : CF_TEXT;
244                    /* FIXME: Need to free returned data? */
245          }          }
246          else          else
247          {          {
# Line 175  xclip_handle_SelectionClear(void) Line 258  xclip_handle_SelectionClear(void)
258  {  {
259          DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));          DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));
260          have_primary = 0;          have_primary = 0;
261          XDeleteProperty(display, DefaultRootWindow(display), rdesktop_clipboard_formats_atom);          XDeleteProperty(g_display, DefaultRootWindow(g_display), rdesktop_clipboard_formats_atom);
262          cliprdr_send_text_format_announce();          cliprdr_send_simple_native_format_announce(CF_TEXT);
263  }  }
264    
265  void  void
266  xclip_handle_PropertyNotify(XPropertyEvent * event)  xclip_handle_PropertyNotify(XPropertyEvent * event)
267  {  {
268          unsigned long nitems, bytes_left;          unsigned long nitems;
269            unsigned long offset = 0;
270            unsigned long bytes_left = 1;
271          int format, res;          int format, res;
272            XWindowAttributes wa;
273          uint8 *data;          uint8 *data;
274          Atom type;          Atom type;
275    
276            if (event->state == PropertyNewValue && g_waiting_for_INCR)
277            {
278                    DEBUG_CLIPBOARD(("x_clip_handle_PropertyNotify: g_waiting_for_INCR != 0\n"));
279    
280                    while (bytes_left > 0) {
281                            if ((XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, offset,
282                                                    4096L, False, AnyPropertyType,
283                                                    &type, &format, &nitems, &bytes_left, &data) != Success))
284                            {
285                                    XFree(data);
286                                    return;
287                            }
288    
289                            if (nitems == 0)
290                            {
291                                    XGetWindowAttributes(g_display, g_wnd, &wa);
292                                    XSelectInput(g_display, g_wnd, (wa.your_event_mask ^ PropertyChangeMask));
293                                    XFree(data);
294                                    g_waiting_for_INCR = 0;
295    
296                                    if (g_clip_buflen > 0)
297                                    {
298                                            cliprdr_send_data(g_clip_buffer, g_clip_buflen + 1);
299    
300                                            if (!rdesktop_is_selection_owner)
301                                                    cliprdr_send_simple_native_format_announce(CF_TEXT);
302    
303                                            xfree(g_clip_buffer);
304                                            g_clip_buffer = 0;
305                                            g_clip_buflen = 0;
306                                    }
307                            }
308                            else
309                            {
310                                    uint8 *translated_data;
311                                    uint32 length = nitems;
312                                    uint8 *tmp;
313    
314                                    offset += (length/4);
315                                    DEBUG_CLIPBOARD(("Translating linebreaks before sending data\n"));
316                                    translated_data = lf2crlf(data, &length);
317    
318                                    tmp = xmalloc(length + g_clip_buflen);
319                                    strncpy((char *) tmp, (char *) g_clip_buffer, g_clip_buflen);
320                                    xfree(g_clip_buffer);
321    
322                                    strncpy((char *) (tmp + g_clip_buflen), (char *) translated_data, length);
323                                    xfree(translated_data);
324    
325                                    g_clip_buffer = tmp;
326                                    g_clip_buflen += length;
327    
328                                    XFree(data);
329                            }
330                    }
331                    XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
332            }
333    
334          if (event->atom != rdesktop_clipboard_formats_atom)          if (event->atom != rdesktop_clipboard_formats_atom)
335                  return;                  return;
336    
# Line 195  xclip_handle_PropertyNotify(XPropertyEve Line 339  xclip_handle_PropertyNotify(XPropertyEve
339    
340          if (event->state == PropertyNewValue)          if (event->state == PropertyNewValue)
341          {          {
342                  res = XGetWindowProperty(display, DefaultRootWindow(display),                  res = XGetWindowProperty(g_display, DefaultRootWindow(g_display),
343                                           rdesktop_clipboard_formats_atom, 0,                                           rdesktop_clipboard_formats_atom, 0,
344                                           XMaxRequestSize(display), False, XA_STRING, &type, &format,                                           XMaxRequestSize(g_display), False, XA_STRING, &type,
345                                           &nitems, &bytes_left, &data);                                           &format, &nitems, &bytes_left, &data);
346    
347                  if ((res == Success) && (nitems > 0))                  if ((res == Success) && (nitems > 0))
348                  {                  {
# Line 209  xclip_handle_PropertyNotify(XPropertyEve Line 353  xclip_handle_PropertyNotify(XPropertyEve
353          }          }
354    
355          /* PropertyDelete, or XGetWindowProperty failed */          /* PropertyDelete, or XGetWindowProperty failed */
356          cliprdr_send_text_format_announce();          cliprdr_send_simple_native_format_announce(CF_TEXT);
357          rdesktop_is_selection_owner = 0;          rdesktop_is_selection_owner = 0;
358  }  }
359    #endif
360    
361    
362  void  void
363  ui_clip_format_announce(char *data, uint32 length)  ui_clip_format_announce(uint8 * data, uint32 length)
364  {  {
365          XSetSelectionOwner(display, primary_atom, wnd, last_gesturetime);          XSetSelectionOwner(g_display, primary_atom, g_wnd, g_last_gesturetime);
366          if (XGetSelectionOwner(display, primary_atom) != wnd)          if (XGetSelectionOwner(g_display, primary_atom) != g_wnd)
367          {          {
368                  warning("Failed to aquire ownership of PRIMARY clipboard\n");                  warning("Failed to aquire ownership of PRIMARY clipboard\n");
369                  return;                  return;
370          }          }
371    
372          have_primary = 1;          have_primary = 1;
373          XChangeProperty(display, DefaultRootWindow(display),          XChangeProperty(g_display, DefaultRootWindow(g_display),
374                          rdesktop_clipboard_formats_atom, XA_STRING, 8, PropModeReplace, data,                          rdesktop_clipboard_formats_atom, XA_STRING, 8, PropModeReplace, data,
375                          length);                          length);
376    
377          XSetSelectionOwner(display, clipboard_atom, wnd, last_gesturetime);          XSetSelectionOwner(g_display, clipboard_atom, g_wnd, g_last_gesturetime);
378          if (XGetSelectionOwner(display, clipboard_atom) != wnd)          if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd)
379                  warning("Failed to aquire ownership of CLIPBOARD clipboard\n");                  warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
380  }  }
381    
382    
383  void  void
384  ui_clip_handle_data(char *data, uint32 length)  ui_clip_handle_data(uint8 * data, uint32 length)
385  {  {
386            if (selection_request.target != rdesktop_clipboard_formats_atom)
387            {
388                    uint8 *firstnull;
389    
390                    /* translate linebreaks */
391                    crlf2lf(data, &length);
392    
393                    /* Only send data up to null byte, if any */
394                    firstnull = (uint8 *) strchr((char *) data, '\0');
395                    if (firstnull)
396                    {
397                            length = firstnull - data + 1;
398                    }
399            }
400    
401          xclip_provide_selection(&selection_request, XA_STRING, 8, data, length - 1);          xclip_provide_selection(&selection_request, XA_STRING, 8, data, length - 1);
402  }  }
403    
# Line 250  ui_clip_request_data(uint32 format) Line 410  ui_clip_request_data(uint32 format)
410    
411          if (rdesktop_is_selection_owner)          if (rdesktop_is_selection_owner)
412          {          {
413                  XChangeProperty(display, wnd, rdesktop_clipboard_target_atom,                  XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
414                                  XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);                                  XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);
415    
416                  XConvertSelection(display, primary_atom, rdesktop_clipboard_formats_atom,                  XConvertSelection(g_display, primary_atom, rdesktop_clipboard_formats_atom,
417                                    rdesktop_clipboard_target_atom, wnd, CurrentTime);                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
418                  return;                  return;
419          }          }
420    
421          selectionowner = XGetSelectionOwner(display, primary_atom);          selectionowner = XGetSelectionOwner(g_display, primary_atom);
422          if (selectionowner != None)          if (selectionowner != None)
423          {          {
424                  XConvertSelection(display, primary_atom, targets_atom,                  XConvertSelection(g_display, primary_atom, targets_atom,
425                                    rdesktop_clipboard_target_atom, wnd, CurrentTime);                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
426                  return;                  return;
427          }          }
428    
429          /* No PRIMARY, try CLIPBOARD */          /* No PRIMARY, try CLIPBOARD */
430          selectionowner = XGetSelectionOwner(display, clipboard_atom);          selectionowner = XGetSelectionOwner(g_display, clipboard_atom);
431          if (selectionowner != None)          if (selectionowner != None)
432          {          {
433                  XConvertSelection(display, clipboard_atom, targets_atom,                  XConvertSelection(g_display, clipboard_atom, targets_atom,
434                                    rdesktop_clipboard_target_atom, wnd, CurrentTime);                                    rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
435                  return;                  return;
436          }          }
437    
# Line 282  ui_clip_request_data(uint32 format) Line 442  ui_clip_request_data(uint32 format)
442  void  void
443  ui_clip_sync(void)  ui_clip_sync(void)
444  {  {
445          cliprdr_send_text_format_announce();          cliprdr_send_simple_native_format_announce(CF_TEXT);
446  }  }
447    
448    
# Line 292  xclip_init(void) Line 452  xclip_init(void)
452          if (!cliprdr_init())          if (!cliprdr_init())
453                  return;                  return;
454    
455          primary_atom = XInternAtom(display, "PRIMARY", False);          primary_atom = XInternAtom(g_display, "PRIMARY", False);
456          clipboard_atom = XInternAtom(display, "CLIPBOARD", False);          clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False);
457          targets_atom = XInternAtom(display, "TARGETS", False);          targets_atom = XInternAtom(g_display, "TARGETS", False);
458          timestamp_atom = XInternAtom(display, "TIMESTAMP", False);          timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False);
459          rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False);          rdesktop_clipboard_target_atom =
460          incr_atom = XInternAtom(display, "INCR", False);                  XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False);
461            incr_atom = XInternAtom(g_display, "INCR", False);
462          targets[0] = targets_atom;          targets[0] = targets_atom;
463          targets[1] = XInternAtom(display, "TEXT", False);          targets[1] = XInternAtom(g_display, "TEXT", False);
464          targets[2] = XInternAtom(display, "UTF8_STRING", False);          targets[2] = XInternAtom(g_display, "STRING", False);
465          targets[3] = XInternAtom(display, "text/unicode", False);          targets[3] = XInternAtom(g_display, "text/unicode", False);
466          targets[4] = XInternAtom(display, "TIMESTAMP", False);          targets[4] = XInternAtom(g_display, "TIMESTAMP", False);
467          targets[5] = XA_STRING;          targets[5] = XA_STRING;
468    
469          /* rdesktop sets _RDESKTOP_CLIPBOARD_FORMATS on the root window when acquiring the clipboard.          /* rdesktop sets _RDESKTOP_CLIPBOARD_FORMATS on the root window when acquiring the clipboard.
470             Other interested rdesktops can use this to notify their server of the available formats. */             Other interested rdesktops can use this to notify their server of the available formats. */
471          rdesktop_clipboard_formats_atom =          rdesktop_clipboard_formats_atom =
472                  XInternAtom(display, "_RDESKTOP_CLIPBOARD_FORMATS", False);                  XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False);
473          XSelectInput(display, DefaultRootWindow(display), PropertyChangeMask);          XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask);
474  }  }

Legend:
Removed from v.435  
changed lines
  Added in v.1026

  ViewVC Help
Powered by ViewVC 1.1.26