/[rdesktop]/jpeg/rdesktop/trunk/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

Annotation of /jpeg/rdesktop/trunk/xclip.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 707 - (hide annotations)
Fri Jun 4 08:42:11 2004 UTC (19 years, 11 months ago) by forsberg
Original Path: sourceforge.net/trunk/rdesktop/xclip.c
File MIME type: text/plain
File size: 10613 byte(s)
Don't advertise UTF8_STRING. Use STRING instead. This gives much
better interoperability between MS Word and Star/OpenOffice when it
comes to highbit characters (åäö and friends).

1 matthewc 432 /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.
3     Protocol services - Clipboard functions
4     Copyright (C) Erik Forsberg <forsberg@cendio.se> 2003
5     Copyright (C) Matthew Chapman 2003
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20     */
21    
22     #include <X11/Xlib.h>
23     #include <X11/Xatom.h>
24     #include "rdesktop.h"
25    
26     #define NUM_TARGETS 6
27    
28 jsorg71 450 extern Display *g_display;
29     extern Window g_wnd;
30     extern Time g_last_gesturetime;
31 matthewc 432
32     static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom;
33     static Atom rdesktop_clipboard_target_atom, rdesktop_clipboard_formats_atom, incr_atom;
34     static XSelectionRequestEvent selection_request;
35     static Atom targets[NUM_TARGETS];
36     static int have_primary = 0;
37     static int rdesktop_is_selection_owner = 0;
38    
39 astrand 551
40     /* Replace CR-LF to LF (well, rather removing all CR:s) This is done
41     in-place. The length is updated. Handles embedded nulls */
42 matthewc 432 static void
43 astrand 551 crlf2lf(uint8 * data, uint32 * length)
44     {
45     uint8 *dst, *src;
46     src = dst = data;
47     while (src < data + *length)
48     {
49     if (*src != '\x0d')
50     *dst++ = *src;
51     src++;
52     }
53     *length = dst - data;
54     }
55    
56     /* Translate LF to CR-LF. To do this, we must allocate more memory.
57     The length is updated. */
58     static uint8 *
59     lf2crlf(uint8 * data, uint32 * length)
60     {
61     uint8 *result, *p, *o;
62    
63     /* Worst case: Every char is LF */
64     result = xmalloc(*length * 2);
65    
66     p = data;
67     o = result;
68    
69     while (p < data + *length)
70     {
71     if (*p == '\x0a')
72     *o++ = '\x0d';
73     *o++ = *p++;
74     }
75     *length = o - result;
76    
77     /* Convenience */
78     *o++ = '\0';
79    
80     return result;
81     }
82    
83    
84     static void
85 astrand 435 xclip_provide_selection(XSelectionRequestEvent * req, Atom type, unsigned int format, uint8 * data,
86     uint32 length)
87 matthewc 432 {
88     XEvent xev;
89    
90 jsorg71 450 XChangeProperty(g_display, req->requestor, req->property,
91 matthewc 432 type, format, PropModeReplace, data, length);
92    
93     xev.xselection.type = SelectionNotify;
94     xev.xselection.serial = 0;
95     xev.xselection.send_event = True;
96     xev.xselection.requestor = req->requestor;
97     xev.xselection.selection = req->selection;
98     xev.xselection.target = req->target;
99     xev.xselection.property = req->property;
100     xev.xselection.time = req->time;
101 jsorg71 450 XSendEvent(g_display, req->requestor, False, NoEventMask, &xev);
102 matthewc 432 }
103    
104 astrand 462 void
105 matthewc 432 xclip_handle_SelectionNotify(XSelectionEvent * event)
106     {
107     unsigned long nitems, bytes_left;
108     Atom type, best_target, text_target;
109     Atom *supported_targets;
110     int res, i, format;
111     uint8 *data;
112    
113     if (event->property == None)
114     goto fail;
115    
116     DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n",
117 jsorg71 450 XGetAtomName(g_display, event->selection),
118     XGetAtomName(g_display, event->target),
119     XGetAtomName(g_display, event->property)));
120 matthewc 432
121     if (event->property == None)
122     goto fail;
123    
124 jsorg71 450 res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
125     0, XMaxRequestSize(g_display), True, AnyPropertyType,
126 matthewc 432 &type, &format, &nitems, &bytes_left, &data);
127    
128     if (res != Success)
129     {
130     DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
131     goto fail;
132     }
133    
134 astrand 551 /* Negotiate target format */
135 matthewc 432 if (event->target == targets_atom)
136     {
137     /* FIXME: We should choose format here based on what the server wanted */
138     best_target = XA_STRING;
139     if (type != None)
140     {
141     supported_targets = (Atom *) data;
142 jsorg71 450 text_target = XInternAtom(g_display, "TEXT", False);
143 matthewc 432 for (i = 0; i < nitems; i++)
144     {
145 astrand 435 DEBUG_CLIPBOARD(("Target %d: %s\n", i,
146 jsorg71 450 XGetAtomName(g_display, supported_targets[i])));
147 matthewc 432 if (supported_targets[i] == text_target)
148     {
149     DEBUG_CLIPBOARD(("Other party supports TEXT, choosing that as best_target\n"));
150     best_target = text_target;
151 astrand 551 break;
152 matthewc 432 }
153     }
154     XFree(data);
155     }
156    
157 jsorg71 450 XConvertSelection(g_display, primary_atom, best_target,
158     rdesktop_clipboard_target_atom, g_wnd, event->time);
159 matthewc 432 return;
160     }
161    
162     if (type == incr_atom)
163     {
164     warning("We don't support INCR transfers at this time. Try cutting less data.\n");
165     goto fail;
166     }
167    
168 astrand 551 /* Translate linebreaks, but only if not getting data from
169     other rdesktop instance */
170     if (event->target != rdesktop_clipboard_formats_atom)
171     {
172     uint8 *translated_data;
173     uint32 length = nitems;
174    
175     DEBUG_CLIPBOARD(("Translating linebreaks before sending data\n"));
176     translated_data = lf2crlf(data, &length);
177     cliprdr_send_data(translated_data, length + 1);
178     xfree(translated_data); /* Not the same thing as XFree! */
179     }
180     else
181     {
182     cliprdr_send_data(data, nitems + 1);
183     }
184 matthewc 432 XFree(data);
185    
186     if (!rdesktop_is_selection_owner)
187     cliprdr_send_text_format_announce();
188     return;
189    
190 astrand 435 fail:
191 matthewc 432 cliprdr_send_data(NULL, 0);
192     }
193    
194 astrand 462 void
195 astrand 435 xclip_handle_SelectionRequest(XSelectionRequestEvent * event)
196 matthewc 432 {
197     unsigned long nitems, bytes_left;
198 astrand 465 unsigned char *prop_return;
199 matthewc 432 uint32 *wanted_format;
200     int format, res;
201     Atom type;
202    
203     DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n",
204 jsorg71 450 XGetAtomName(g_display, event->selection),
205     XGetAtomName(g_display, event->target),
206     XGetAtomName(g_display, event->property)));
207 matthewc 432
208     if (event->target == targets_atom)
209     {
210 astrand 435 xclip_provide_selection(event, XA_ATOM, 32, (uint8 *) & targets, NUM_TARGETS);
211 matthewc 432 return;
212     }
213     else if (event->target == timestamp_atom)
214     {
215 jsorg71 450 xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & g_last_gesturetime, 1);
216 matthewc 432 return;
217     }
218     else if (event->target == rdesktop_clipboard_formats_atom)
219     {
220 jsorg71 450 res = XGetWindowProperty(g_display, event->requestor,
221 astrand 435 rdesktop_clipboard_target_atom, 0, 1, True, XA_INTEGER,
222 astrand 468 &type, &format, &nitems, &bytes_left, &prop_return);
223 astrand 465 wanted_format = (uint32 *) prop_return;
224 matthewc 432 format = (res == Success) ? *wanted_format : CF_TEXT;
225 astrand 465 /* FIXME: Need to free returned data? */
226 matthewc 432 }
227     else
228     {
229     format = CF_TEXT;
230     }
231    
232     cliprdr_send_data_request(format);
233     selection_request = *event;
234     /* wait for data */
235     }
236    
237 astrand 462 void
238 matthewc 432 xclip_handle_SelectionClear(void)
239     {
240     DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));
241     have_primary = 0;
242 jsorg71 450 XDeleteProperty(g_display, DefaultRootWindow(g_display), rdesktop_clipboard_formats_atom);
243 matthewc 432 cliprdr_send_text_format_announce();
244     }
245    
246 astrand 462 void
247 astrand 435 xclip_handle_PropertyNotify(XPropertyEvent * event)
248 matthewc 432 {
249     unsigned long nitems, bytes_left;
250     int format, res;
251     uint8 *data;
252     Atom type;
253    
254     if (event->atom != rdesktop_clipboard_formats_atom)
255     return;
256    
257 astrand 435 if (have_primary) /* from us */
258 matthewc 432 return;
259    
260     if (event->state == PropertyNewValue)
261     {
262 jsorg71 450 res = XGetWindowProperty(g_display, DefaultRootWindow(g_display),
263 astrand 435 rdesktop_clipboard_formats_atom, 0,
264 astrand 456 XMaxRequestSize(g_display), False, XA_STRING, &type,
265     &format, &nitems, &bytes_left, &data);
266 matthewc 432
267     if ((res == Success) && (nitems > 0))
268     {
269     cliprdr_send_native_format_announce(data, nitems);
270     rdesktop_is_selection_owner = 1;
271     return;
272     }
273     }
274    
275     /* PropertyDelete, or XGetWindowProperty failed */
276     cliprdr_send_text_format_announce();
277     rdesktop_is_selection_owner = 0;
278     }
279    
280    
281     void
282 astrand 542 ui_clip_format_announce(uint8 * data, uint32 length)
283 matthewc 432 {
284 jsorg71 450 XSetSelectionOwner(g_display, primary_atom, g_wnd, g_last_gesturetime);
285     if (XGetSelectionOwner(g_display, primary_atom) != g_wnd)
286 matthewc 432 {
287     warning("Failed to aquire ownership of PRIMARY clipboard\n");
288     return;
289     }
290    
291     have_primary = 1;
292 jsorg71 450 XChangeProperty(g_display, DefaultRootWindow(g_display),
293 astrand 435 rdesktop_clipboard_formats_atom, XA_STRING, 8, PropModeReplace, data,
294     length);
295 matthewc 432
296 jsorg71 450 XSetSelectionOwner(g_display, clipboard_atom, g_wnd, g_last_gesturetime);
297     if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd)
298 matthewc 432 warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
299     }
300    
301    
302     void
303 astrand 542 ui_clip_handle_data(uint8 * data, uint32 length)
304 matthewc 432 {
305 astrand 551 if (selection_request.target != rdesktop_clipboard_formats_atom)
306     {
307     uint8 *firstnull;
308    
309     /* translate linebreaks */
310     crlf2lf(data, &length);
311    
312     /* Only send data up to null byte, if any */
313 astrand 608 firstnull = (uint8 *) strchr((char *) data, '\0');
314 astrand 551 if (firstnull)
315     {
316     length = firstnull - data + 1;
317     }
318     }
319    
320 astrand 435 xclip_provide_selection(&selection_request, XA_STRING, 8, data, length - 1);
321 matthewc 432 }
322    
323     void
324     ui_clip_request_data(uint32 format)
325     {
326     Window selectionowner;
327    
328     DEBUG_CLIPBOARD(("Request from server for format %d\n", format));
329    
330     if (rdesktop_is_selection_owner)
331     {
332 jsorg71 450 XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
333 matthewc 432 XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);
334    
335 jsorg71 450 XConvertSelection(g_display, primary_atom, rdesktop_clipboard_formats_atom,
336     rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
337 matthewc 432 return;
338     }
339    
340 jsorg71 450 selectionowner = XGetSelectionOwner(g_display, primary_atom);
341 matthewc 432 if (selectionowner != None)
342     {
343 jsorg71 450 XConvertSelection(g_display, primary_atom, targets_atom,
344     rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
345 matthewc 432 return;
346     }
347    
348     /* No PRIMARY, try CLIPBOARD */
349 jsorg71 450 selectionowner = XGetSelectionOwner(g_display, clipboard_atom);
350 matthewc 432 if (selectionowner != None)
351     {
352 jsorg71 450 XConvertSelection(g_display, clipboard_atom, targets_atom,
353     rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
354 matthewc 432 return;
355     }
356    
357     /* No data available */
358     cliprdr_send_data(NULL, 0);
359     }
360    
361     void
362     ui_clip_sync(void)
363     {
364     cliprdr_send_text_format_announce();
365     }
366    
367    
368     void
369     xclip_init(void)
370     {
371     if (!cliprdr_init())
372     return;
373    
374 jsorg71 450 primary_atom = XInternAtom(g_display, "PRIMARY", False);
375     clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False);
376     targets_atom = XInternAtom(g_display, "TARGETS", False);
377     timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False);
378 astrand 456 rdesktop_clipboard_target_atom =
379     XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False);
380 jsorg71 450 incr_atom = XInternAtom(g_display, "INCR", False);
381 matthewc 432 targets[0] = targets_atom;
382 jsorg71 450 targets[1] = XInternAtom(g_display, "TEXT", False);
383 forsberg 707 targets[2] = XInternAtom(g_display, "STRING", False);
384 jsorg71 450 targets[3] = XInternAtom(g_display, "text/unicode", False);
385     targets[4] = XInternAtom(g_display, "TIMESTAMP", False);
386 matthewc 432 targets[5] = XA_STRING;
387    
388     /* rdesktop sets _RDESKTOP_CLIPBOARD_FORMATS on the root window when acquiring the clipboard.
389     Other interested rdesktops can use this to notify their server of the available formats. */
390 astrand 435 rdesktop_clipboard_formats_atom =
391 jsorg71 450 XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False);
392     XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask);
393 matthewc 432 }

  ViewVC Help
Powered by ViewVC 1.1.26