/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 602 - (show annotations)
Sat Feb 7 17:32:21 2004 UTC (20 years, 2 months ago) by stargo
File MIME type: text/plain
File size: 10615 byte(s)
Cleanup some warnings (from SUNWspro-compiler)

1 /* -*- 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 extern Display *g_display;
29 extern Window g_wnd;
30 extern Time g_last_gesturetime;
31
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
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 static void
43 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 xclip_provide_selection(XSelectionRequestEvent * req, Atom type, unsigned int format, uint8 * data,
86 uint32 length)
87 {
88 XEvent xev;
89
90 XChangeProperty(g_display, req->requestor, req->property,
91 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 XSendEvent(g_display, req->requestor, False, NoEventMask, &xev);
102 }
103
104 void
105 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 XGetAtomName(g_display, event->selection),
118 XGetAtomName(g_display, event->target),
119 XGetAtomName(g_display, event->property)));
120
121 if (event->property == None)
122 goto fail;
123
124 res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
125 0, XMaxRequestSize(g_display), True, AnyPropertyType,
126 &type, &format, &nitems, &bytes_left, &data);
127
128 if (res != Success)
129 {
130 DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
131 goto fail;
132 }
133
134 /* Negotiate target format */
135 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 text_target = XInternAtom(g_display, "TEXT", False);
143 for (i = 0; i < nitems; i++)
144 {
145 DEBUG_CLIPBOARD(("Target %d: %s\n", i,
146 XGetAtomName(g_display, supported_targets[i])));
147 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 break;
152 }
153 }
154 XFree(data);
155 }
156
157 XConvertSelection(g_display, primary_atom, best_target,
158 rdesktop_clipboard_target_atom, g_wnd, event->time);
159 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 /* 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 XFree(data);
185
186 if (!rdesktop_is_selection_owner)
187 cliprdr_send_text_format_announce();
188 return;
189
190 fail:
191 cliprdr_send_data(NULL, 0);
192 }
193
194 void
195 xclip_handle_SelectionRequest(XSelectionRequestEvent * event)
196 {
197 unsigned long nitems, bytes_left;
198 unsigned char *prop_return;
199 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 XGetAtomName(g_display, event->selection),
205 XGetAtomName(g_display, event->target),
206 XGetAtomName(g_display, event->property)));
207
208 if (event->target == targets_atom)
209 {
210 xclip_provide_selection(event, XA_ATOM, 32, (uint8 *) & targets, NUM_TARGETS);
211 return;
212 }
213 else if (event->target == timestamp_atom)
214 {
215 xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & g_last_gesturetime, 1);
216 return;
217 }
218 else if (event->target == rdesktop_clipboard_formats_atom)
219 {
220 res = XGetWindowProperty(g_display, event->requestor,
221 rdesktop_clipboard_target_atom, 0, 1, True, XA_INTEGER,
222 &type, &format, &nitems, &bytes_left, &prop_return);
223 wanted_format = (uint32 *) prop_return;
224 format = (res == Success) ? *wanted_format : CF_TEXT;
225 /* FIXME: Need to free returned data? */
226 }
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 void
238 xclip_handle_SelectionClear(void)
239 {
240 DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));
241 have_primary = 0;
242 XDeleteProperty(g_display, DefaultRootWindow(g_display), rdesktop_clipboard_formats_atom);
243 cliprdr_send_text_format_announce();
244 }
245
246 void
247 xclip_handle_PropertyNotify(XPropertyEvent * event)
248 {
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 if (have_primary) /* from us */
258 return;
259
260 if (event->state == PropertyNewValue)
261 {
262 res = XGetWindowProperty(g_display, DefaultRootWindow(g_display),
263 rdesktop_clipboard_formats_atom, 0,
264 XMaxRequestSize(g_display), False, XA_STRING, &type,
265 &format, &nitems, &bytes_left, &data);
266
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 ui_clip_format_announce(uint8 * data, uint32 length)
283 {
284 XSetSelectionOwner(g_display, primary_atom, g_wnd, g_last_gesturetime);
285 if (XGetSelectionOwner(g_display, primary_atom) != g_wnd)
286 {
287 warning("Failed to aquire ownership of PRIMARY clipboard\n");
288 return;
289 }
290
291 have_primary = 1;
292 XChangeProperty(g_display, DefaultRootWindow(g_display),
293 rdesktop_clipboard_formats_atom, XA_STRING, 8, PropModeReplace, data,
294 length);
295
296 XSetSelectionOwner(g_display, clipboard_atom, g_wnd, g_last_gesturetime);
297 if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd)
298 warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
299 }
300
301
302 void
303 ui_clip_handle_data(uint8 * data, uint32 length)
304 {
305 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 firstnull = (uint8 *)strchr((char*)data, '\0');
314 if (firstnull)
315 {
316 length = firstnull - data + 1;
317 }
318 }
319
320 xclip_provide_selection(&selection_request, XA_STRING, 8, data, length - 1);
321 }
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 XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
333 XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);
334
335 XConvertSelection(g_display, primary_atom, rdesktop_clipboard_formats_atom,
336 rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
337 return;
338 }
339
340 selectionowner = XGetSelectionOwner(g_display, primary_atom);
341 if (selectionowner != None)
342 {
343 XConvertSelection(g_display, primary_atom, targets_atom,
344 rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
345 return;
346 }
347
348 /* No PRIMARY, try CLIPBOARD */
349 selectionowner = XGetSelectionOwner(g_display, clipboard_atom);
350 if (selectionowner != None)
351 {
352 XConvertSelection(g_display, clipboard_atom, targets_atom,
353 rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
354 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 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 rdesktop_clipboard_target_atom =
379 XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False);
380 incr_atom = XInternAtom(g_display, "INCR", False);
381 targets[0] = targets_atom;
382 targets[1] = XInternAtom(g_display, "TEXT", False);
383 targets[2] = XInternAtom(g_display, "UTF8_STRING", False);
384 targets[3] = XInternAtom(g_display, "text/unicode", False);
385 targets[4] = XInternAtom(g_display, "TIMESTAMP", False);
386 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 rdesktop_clipboard_formats_atom =
391 XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False);
392 XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask);
393 }

  ViewVC Help
Powered by ViewVC 1.1.26