File: | plugins/clipboard/csd_clipboard-manager.c |
Warning: | line 204, column 48 the computation of the size of the memory allocation may overflow |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (C) 2007 Matthias Clasen |
3 | * Copyright (C) 2007 Anders Carlsson |
4 | * Copyright (C) 2007 Rodrigo Moya |
5 | * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> |
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | * |
21 | */ |
22 | |
23 | #include "config.h" |
24 | |
25 | #include <sys/types.h> |
26 | #include <sys/wait.h> |
27 | #include <stdlib.h> |
28 | #include <stdio.h> |
29 | #include <unistd.h> |
30 | #include <string.h> |
31 | #include <errno(*__errno_location ()).h> |
32 | |
33 | #include <locale.h> |
34 | |
35 | #include <glib.h> |
36 | #include <glib/gi18n.h> |
37 | #include <cdk/cdk.h> |
38 | #include <cdk/cdkx.h> |
39 | #include <X11/Xlib.h> |
40 | #include <X11/Xatom.h> |
41 | |
42 | #include "xutils.h" |
43 | #include "list.h" |
44 | |
45 | #include "cafe-settings-profile.h" |
46 | #include "csd_clipboard-manager.h" |
47 | |
48 | struct CsdClipboardManagerPrivate |
49 | { |
50 | Display *display; |
51 | Window window; |
52 | Time timestamp; |
53 | |
54 | List *contents; |
55 | List *conversions; |
56 | |
57 | Window requestor; |
58 | Atom property; |
59 | Time time; |
60 | }; |
61 | |
62 | typedef struct |
63 | { |
64 | unsigned char *data; |
65 | int length; |
66 | Atom target; |
67 | Atom type; |
68 | int format; |
69 | int refcount; |
70 | } TargetData; |
71 | |
72 | typedef struct |
73 | { |
74 | Atom target; |
75 | TargetData *data; |
76 | Atom property; |
77 | Window requestor; |
78 | int offset; |
79 | } IncrConversion; |
80 | |
81 | static void csd_clipboard_manager_finalize (GObject *object); |
82 | |
83 | static void clipboard_manager_watch_cb (CsdClipboardManager *manager, |
84 | Window window, |
85 | Boolint is_start, |
86 | long mask, |
87 | void *cb_data); |
88 | |
89 | G_DEFINE_TYPE_WITH_PRIVATE (CsdClipboardManager, csd_clipboard_manager, G_TYPE_OBJECT)static void csd_clipboard_manager_init (CsdClipboardManager * self); static void csd_clipboard_manager_class_init (CsdClipboardManagerClass *klass); static GType csd_clipboard_manager_get_type_once (void ); static gpointer csd_clipboard_manager_parent_class = ((void *)0); static gint CsdClipboardManager_private_offset; static void csd_clipboard_manager_class_intern_init (gpointer klass) { csd_clipboard_manager_parent_class = g_type_class_peek_parent (klass); if (CsdClipboardManager_private_offset != 0) g_type_class_adjust_private_offset (klass, &CsdClipboardManager_private_offset ); csd_clipboard_manager_class_init ((CsdClipboardManagerClass *) klass); } __attribute__ ((__unused__)) static inline gpointer csd_clipboard_manager_get_instance_private (CsdClipboardManager *self) { return (((gpointer) ((guint8*) (self) + (glong) (CsdClipboardManager_private_offset )))); } GType csd_clipboard_manager_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); (void) (0 ? (gpointer) * ( &static_g_define_type_id) : ((void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = csd_clipboard_manager_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id ) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer ((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id )); })) ; } return static_g_define_type_id; } __attribute__ ( (__noinline__)) static GType csd_clipboard_manager_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple (((GType) ((20) << (2))), g_intern_static_string ("CsdClipboardManager" ), sizeof (CsdClipboardManagerClass), (GClassInitFunc)(void ( *)(void)) csd_clipboard_manager_class_intern_init, sizeof (CsdClipboardManager ), (GInstanceInitFunc)(void (*)(void)) csd_clipboard_manager_init , (GTypeFlags) 0); { {{ CsdClipboardManager_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (CsdClipboardManagerPrivate)); };} } return g_define_type_id; } |
90 | |
91 | static gpointer manager_object = NULL((void*)0); |
92 | |
93 | /* We need to use reference counting for the target data, since we may |
94 | * need to keep the data around after loosing the CLIPBOARD ownership |
95 | * to complete incremental transfers. |
96 | */ |
97 | static TargetData * |
98 | target_data_ref (TargetData *data) |
99 | { |
100 | data->refcount++; |
101 | return data; |
102 | } |
103 | |
104 | static void |
105 | target_data_unref (TargetData *data) |
106 | { |
107 | data->refcount--; |
108 | if (data->refcount == 0) { |
109 | free (data->data); |
110 | free (data); |
111 | } |
112 | } |
113 | |
114 | static void |
115 | conversion_free (IncrConversion *rdata) |
116 | { |
117 | if (rdata->data) { |
118 | target_data_unref (rdata->data); |
119 | } |
120 | free (rdata); |
121 | } |
122 | |
123 | static void |
124 | send_selection_notify (CsdClipboardManager *manager, |
125 | Boolint success) |
126 | { |
127 | XSelectionEvent notify; |
128 | CdkDisplay *display; |
129 | |
130 | notify.type = SelectionNotify31; |
131 | notify.serial = 0; |
132 | notify.send_event = True1; |
133 | notify.display = manager->priv->display; |
134 | notify.requestor = manager->priv->requestor; |
135 | notify.selection = XA_CLIPBOARD_MANAGER; |
136 | notify.target = XA_SAVE_TARGETS; |
137 | notify.property = success ? manager->priv->property : None0L; |
138 | notify.time = manager->priv->time; |
139 | |
140 | display = cdk_display_get_default (); |
141 | cdk_x11_display_error_trap_push (display); |
142 | |
143 | XSendEvent (manager->priv->display, |
144 | manager->priv->requestor, |
145 | False0, |
146 | NoEventMask0L, |
147 | (XEvent *)¬ify); |
148 | XSync (manager->priv->display, False0); |
149 | |
150 | cdk_x11_display_error_trap_pop_ignored (display); |
151 | } |
152 | |
153 | static void |
154 | finish_selection_request (CsdClipboardManager *manager, |
155 | XEvent *xev, |
156 | Boolint success) |
157 | { |
158 | XSelectionEvent notify; |
159 | CdkDisplay *display; |
160 | |
161 | notify.type = SelectionNotify31; |
162 | notify.serial = 0; |
163 | notify.send_event = True1; |
164 | notify.display = xev->xselectionrequest.display; |
165 | notify.requestor = xev->xselectionrequest.requestor; |
166 | notify.selection = xev->xselectionrequest.selection; |
167 | notify.target = xev->xselectionrequest.target; |
168 | notify.property = success ? xev->xselectionrequest.property : None0L; |
169 | notify.time = xev->xselectionrequest.time; |
170 | |
171 | display = cdk_display_get_default (); |
172 | cdk_x11_display_error_trap_push (display); |
173 | |
174 | XSendEvent (xev->xselectionrequest.display, |
175 | xev->xselectionrequest.requestor, |
176 | False0, NoEventMask0L, (XEvent *) ¬ify); |
177 | XSync (manager->priv->display, False0); |
178 | |
179 | cdk_x11_display_error_trap_pop_ignored (display); |
180 | } |
181 | |
182 | static int |
183 | clipboard_bytes_per_item (int format) |
184 | { |
185 | switch (format) { |
186 | case 8: return sizeof (char); |
187 | case 16: return sizeof (short); |
188 | case 32: return sizeof (long); |
189 | default: ; |
190 | } |
191 | |
192 | return 0; |
193 | } |
194 | |
195 | static void |
196 | save_targets (CsdClipboardManager *manager, |
197 | Atom *save_targets, |
198 | int nitems) |
199 | { |
200 | int nout, i; |
201 | Atom *multiple; |
202 | TargetData *tdata; |
203 | |
204 | multiple = (Atom *) malloc (2 * nitems * sizeof (Atom)); |
the computation of the size of the memory allocation may overflow | |
205 | |
206 | nout = 0; |
207 | for (i = 0; i < nitems; i++) { |
208 | if (save_targets[i] != XA_TARGETS && |
209 | save_targets[i] != XA_MULTIPLE && |
210 | save_targets[i] != XA_DELETE && |
211 | save_targets[i] != XA_INSERT_PROPERTY && |
212 | save_targets[i] != XA_INSERT_SELECTION && |
213 | save_targets[i] != XA_PIXMAP((Atom) 20)) { |
214 | tdata = (TargetData *) malloc (sizeof (TargetData)); |
215 | tdata->data = NULL((void*)0); |
216 | tdata->length = 0; |
217 | tdata->target = save_targets[i]; |
218 | tdata->type = None0L; |
219 | tdata->format = 0; |
220 | tdata->refcount = 1; |
221 | manager->priv->contents = list_prepend (manager->priv->contents, tdata); |
222 | |
223 | multiple[nout++] = save_targets[i]; |
224 | multiple[nout++] = save_targets[i]; |
225 | } |
226 | } |
227 | |
228 | XFree (save_targets); |
229 | |
230 | XChangeProperty (manager->priv->display, manager->priv->window, |
231 | XA_MULTIPLE, XA_ATOM_PAIR, |
232 | 32, PropModeReplace0, (const unsigned char *) multiple, nout); |
233 | free (multiple); |
234 | |
235 | XConvertSelection (manager->priv->display, XA_CLIPBOARD, |
236 | XA_MULTIPLE, XA_MULTIPLE, |
237 | manager->priv->window, manager->priv->time); |
238 | } |
239 | |
240 | static int |
241 | find_content_target (TargetData *tdata, |
242 | Atom target) |
243 | { |
244 | return tdata->target == target; |
245 | } |
246 | |
247 | static int |
248 | find_content_type (TargetData *tdata, |
249 | Atom type) |
250 | { |
251 | return tdata->type == type; |
252 | } |
253 | |
254 | static int |
255 | find_conversion_requestor (IncrConversion *rdata, |
256 | XEvent *xev) |
257 | { |
258 | return (rdata->requestor == xev->xproperty.window && |
259 | rdata->property == xev->xproperty.atom); |
260 | } |
261 | |
262 | static void |
263 | get_property (TargetData *tdata, |
264 | CsdClipboardManager *manager) |
265 | { |
266 | Atom type; |
267 | int format; |
268 | unsigned long length; |
269 | unsigned long remaining; |
270 | unsigned char *data; |
271 | |
272 | XGetWindowProperty (manager->priv->display, |
273 | manager->priv->window, |
274 | tdata->target, |
275 | 0, |
276 | 0x1FFFFFFF, |
277 | True1, |
278 | AnyPropertyType0L, |
279 | &type, |
280 | &format, |
281 | &length, |
282 | &remaining, |
283 | &data); |
284 | |
285 | if (type == None0L) { |
286 | manager->priv->contents = list_remove (manager->priv->contents, tdata); |
287 | free (tdata); |
288 | } else if (type == XA_INCR) { |
289 | tdata->type = type; |
290 | tdata->length = 0; |
291 | XFree (data); |
292 | } else { |
293 | tdata->type = type; |
294 | tdata->data = data; |
295 | tdata->length = length * clipboard_bytes_per_item (format); |
296 | tdata->format = format; |
297 | } |
298 | } |
299 | |
300 | static Boolint |
301 | receive_incrementally (CsdClipboardManager *manager, |
302 | XEvent *xev) |
303 | { |
304 | List *list; |
305 | TargetData *tdata; |
306 | Atom type; |
307 | int format; |
308 | unsigned long length, nitems, remaining; |
309 | unsigned char *data; |
310 | |
311 | if (xev->xproperty.window != manager->priv->window) |
312 | return False0; |
313 | |
314 | list = list_find (manager->priv->contents, |
315 | (ListFindFunc) find_content_target, (void *) xev->xproperty.atom); |
316 | |
317 | if (!list) |
318 | return False0; |
319 | |
320 | tdata = (TargetData *) list->data; |
321 | |
322 | if (tdata->type != XA_INCR) |
323 | return False0; |
324 | |
325 | XGetWindowProperty (xev->xproperty.display, |
326 | xev->xproperty.window, |
327 | xev->xproperty.atom, |
328 | 0, 0x1FFFFFFF, True1, AnyPropertyType0L, |
329 | &type, &format, &nitems, &remaining, &data); |
330 | |
331 | length = nitems * clipboard_bytes_per_item (format); |
332 | if (length == 0) { |
333 | tdata->type = type; |
334 | tdata->format = format; |
335 | |
336 | if (!list_find (manager->priv->contents, |
337 | (ListFindFunc) find_content_type, (void *)XA_INCR)) { |
338 | /* all incremental transfers done */ |
339 | send_selection_notify (manager, True1); |
340 | manager->priv->requestor = None0L; |
341 | } |
342 | |
343 | XFree (data); |
344 | } else { |
345 | if (!tdata->data) { |
346 | tdata->data = data; |
347 | tdata->length = length; |
348 | } else { |
349 | tdata->data = realloc (tdata->data, tdata->length + length + 1); |
350 | memcpy (tdata->data + tdata->length, data, length + 1); |
351 | tdata->length += length; |
352 | XFree (data); |
353 | } |
354 | } |
355 | |
356 | return True1; |
357 | } |
358 | |
359 | static Boolint |
360 | send_incrementally (CsdClipboardManager *manager, |
361 | XEvent *xev) |
362 | { |
363 | List *list; |
364 | IncrConversion *rdata; |
365 | unsigned long length; |
366 | unsigned long items; |
367 | unsigned char *data; |
368 | |
369 | list = list_find (manager->priv->conversions, |
370 | (ListFindFunc) find_conversion_requestor, xev); |
371 | if (list == NULL((void*)0)) |
372 | return False0; |
373 | |
374 | rdata = (IncrConversion *) list->data; |
375 | |
376 | data = rdata->data->data + rdata->offset; |
377 | length = rdata->data->length - rdata->offset; |
378 | if (length > SELECTION_MAX_SIZE) |
379 | length = SELECTION_MAX_SIZE; |
380 | |
381 | rdata->offset += length; |
382 | |
383 | items = length / clipboard_bytes_per_item (rdata->data->format); |
384 | XChangeProperty (manager->priv->display, rdata->requestor, |
385 | rdata->property, rdata->data->type, |
386 | rdata->data->format, PropModeAppend2, |
387 | data, items); |
388 | |
389 | if (length == 0) { |
390 | manager->priv->conversions = list_remove (manager->priv->conversions, rdata); |
391 | conversion_free (rdata); |
392 | } |
393 | |
394 | return True1; |
395 | } |
396 | |
397 | static void |
398 | convert_clipboard_manager (CsdClipboardManager *manager, |
399 | XEvent *xev) |
400 | { |
401 | CdkDisplay *display; |
402 | Atom type = None0L; |
403 | int format; |
404 | unsigned long nitems; |
405 | unsigned long remaining; |
406 | Atom *targets = NULL((void*)0); |
407 | |
408 | display = cdk_display_get_default (); |
409 | |
410 | if (xev->xselectionrequest.target == XA_SAVE_TARGETS) { |
411 | if (manager->priv->requestor != None0L || manager->priv->contents != NULL((void*)0)) { |
412 | /* We're in the middle of a conversion request, or own |
413 | * the CLIPBOARD already |
414 | */ |
415 | finish_selection_request (manager, xev, False0); |
416 | } else { |
417 | cdk_x11_display_error_trap_push (display); |
418 | |
419 | clipboard_manager_watch_cb (manager, |
420 | xev->xselectionrequest.requestor, |
421 | True1, |
422 | StructureNotifyMask(1L<<17), |
423 | NULL((void*)0)); |
424 | XSelectInput (manager->priv->display, |
425 | xev->xselectionrequest.requestor, |
426 | StructureNotifyMask(1L<<17)); |
427 | XSync (manager->priv->display, False0); |
428 | |
429 | if (cdk_x11_display_error_trap_pop (display) != Success0) |
430 | return; |
431 | |
432 | cdk_x11_display_error_trap_push (display); |
433 | |
434 | if (xev->xselectionrequest.property != None0L) { |
435 | XGetWindowProperty (manager->priv->display, |
436 | xev->xselectionrequest.requestor, |
437 | xev->xselectionrequest.property, |
438 | 0, 0x1FFFFFFF, False0, XA_ATOM((Atom) 4), |
439 | &type, &format, &nitems, &remaining, |
440 | (unsigned char **) &targets); |
441 | |
442 | if (cdk_x11_display_error_trap_pop (display) != Success0) { |
443 | if (targets) |
444 | XFree (targets); |
445 | |
446 | return; |
447 | } |
448 | } |
449 | |
450 | manager->priv->requestor = xev->xselectionrequest.requestor; |
451 | manager->priv->property = xev->xselectionrequest.property; |
452 | manager->priv->time = xev->xselectionrequest.time; |
453 | |
454 | if (type == None0L) |
455 | XConvertSelection (manager->priv->display, XA_CLIPBOARD, |
456 | XA_TARGETS, XA_TARGETS, |
457 | manager->priv->window, manager->priv->time); |
458 | else |
459 | save_targets (manager, targets, nitems); |
460 | } |
461 | } else if (xev->xselectionrequest.target == XA_TIMESTAMP) { |
462 | XChangeProperty (manager->priv->display, |
463 | xev->xselectionrequest.requestor, |
464 | xev->xselectionrequest.property, |
465 | XA_INTEGER((Atom) 19), 32, PropModeReplace0, |
466 | (unsigned char *) &manager->priv->timestamp, 1); |
467 | |
468 | finish_selection_request (manager, xev, True1); |
469 | } else if (xev->xselectionrequest.target == XA_TARGETS) { |
470 | int n_targets = 0; |
471 | Atom targets[3]; |
472 | |
473 | targets[n_targets++] = XA_TARGETS; |
474 | targets[n_targets++] = XA_TIMESTAMP; |
475 | targets[n_targets++] = XA_SAVE_TARGETS; |
476 | |
477 | XChangeProperty (manager->priv->display, |
478 | xev->xselectionrequest.requestor, |
479 | xev->xselectionrequest.property, |
480 | XA_ATOM((Atom) 4), 32, PropModeReplace0, |
481 | (unsigned char *) targets, n_targets); |
482 | |
483 | finish_selection_request (manager, xev, True1); |
484 | } else |
485 | finish_selection_request (manager, xev, False0); |
486 | } |
487 | |
488 | static void |
489 | convert_clipboard_target (IncrConversion *rdata, |
490 | CsdClipboardManager *manager) |
491 | { |
492 | CdkDisplay *display; |
493 | TargetData *tdata; |
494 | Atom *targets; |
495 | int n_targets; |
496 | List *list; |
497 | unsigned long items; |
498 | XWindowAttributes atts; |
499 | |
500 | display = cdk_display_get_default (); |
501 | |
502 | if (rdata->target == XA_TARGETS) { |
503 | n_targets = list_length (manager->priv->contents) + 2; |
504 | targets = (Atom *) malloc (n_targets * sizeof (Atom)); |
505 | |
506 | n_targets = 0; |
507 | |
508 | targets[n_targets++] = XA_TARGETS; |
509 | targets[n_targets++] = XA_MULTIPLE; |
510 | |
511 | for (list = manager->priv->contents; list; list = list->next) { |
512 | tdata = (TargetData *) list->data; |
513 | targets[n_targets++] = tdata->target; |
514 | } |
515 | |
516 | XChangeProperty (manager->priv->display, rdata->requestor, |
517 | rdata->property, |
518 | XA_ATOM((Atom) 4), 32, PropModeReplace0, |
519 | (unsigned char *) targets, n_targets); |
520 | free (targets); |
521 | } else { |
522 | /* Convert from stored CLIPBOARD data */ |
523 | list = list_find (manager->priv->contents, |
524 | (ListFindFunc) find_content_target, (void *) rdata->target); |
525 | |
526 | /* We got a target that we don't support */ |
527 | if (!list) |
528 | return; |
529 | |
530 | tdata = (TargetData *)list->data; |
531 | if (tdata->type == XA_INCR) { |
532 | /* we haven't completely received this target yet */ |
533 | rdata->property = None0L; |
534 | return; |
535 | } |
536 | |
537 | rdata->data = target_data_ref (tdata); |
538 | items = tdata->length / clipboard_bytes_per_item (tdata->format); |
539 | if (tdata->length <= SELECTION_MAX_SIZE) |
540 | XChangeProperty (manager->priv->display, rdata->requestor, |
541 | rdata->property, |
542 | tdata->type, tdata->format, PropModeReplace0, |
543 | tdata->data, items); |
544 | else { |
545 | /* start incremental transfer */ |
546 | rdata->offset = 0; |
547 | |
548 | cdk_x11_display_error_trap_push (display); |
549 | |
550 | XGetWindowAttributes (manager->priv->display, rdata->requestor, &atts); |
551 | XSelectInput (manager->priv->display, rdata->requestor, |
552 | atts.your_event_mask | PropertyChangeMask(1L<<22)); |
553 | |
554 | XChangeProperty (manager->priv->display, rdata->requestor, |
555 | rdata->property, |
556 | XA_INCR, 32, PropModeReplace0, |
557 | (unsigned char *) &items, 1); |
558 | |
559 | XSync (manager->priv->display, False0); |
560 | |
561 | cdk_x11_display_error_trap_pop_ignored (display); |
562 | } |
563 | } |
564 | } |
565 | |
566 | static void |
567 | collect_incremental (IncrConversion *rdata, |
568 | CsdClipboardManager *manager) |
569 | { |
570 | if (rdata->offset >= 0) |
571 | manager->priv->conversions = list_prepend (manager->priv->conversions, rdata); |
572 | else { |
573 | if (rdata->data) { |
574 | target_data_unref (rdata->data); |
575 | rdata->data = NULL((void*)0); |
576 | } |
577 | free (rdata); |
578 | } |
579 | } |
580 | |
581 | static void |
582 | convert_clipboard (CsdClipboardManager *manager, |
583 | XEvent *xev) |
584 | { |
585 | List *list; |
586 | List *conversions; |
587 | IncrConversion *rdata; |
588 | Atom type; |
589 | int i; |
590 | int format; |
591 | unsigned long nitems; |
592 | unsigned long remaining; |
593 | Atom *multiple; |
594 | |
595 | conversions = NULL((void*)0); |
596 | type = None0L; |
597 | |
598 | if (xev->xselectionrequest.target == XA_MULTIPLE) { |
599 | XGetWindowProperty (xev->xselectionrequest.display, |
600 | xev->xselectionrequest.requestor, |
601 | xev->xselectionrequest.property, |
602 | 0, 0x1FFFFFFF, False0, XA_ATOM_PAIR, |
603 | &type, &format, &nitems, &remaining, |
604 | (unsigned char **) &multiple); |
605 | |
606 | if (type != XA_ATOM_PAIR || nitems == 0) { |
607 | if (multiple) |
608 | free (multiple); |
609 | return; |
610 | } |
611 | |
612 | for (i = 0; i < nitems; i += 2) { |
613 | rdata = (IncrConversion *) malloc (sizeof (IncrConversion)); |
614 | rdata->requestor = xev->xselectionrequest.requestor; |
615 | rdata->target = multiple[i]; |
616 | rdata->property = multiple[i+1]; |
617 | rdata->data = NULL((void*)0); |
618 | rdata->offset = -1; |
619 | conversions = list_prepend (conversions, rdata); |
620 | } |
621 | } else { |
622 | multiple = NULL((void*)0); |
623 | |
624 | rdata = (IncrConversion *) malloc (sizeof (IncrConversion)); |
625 | rdata->requestor = xev->xselectionrequest.requestor; |
626 | rdata->target = xev->xselectionrequest.target; |
627 | rdata->property = xev->xselectionrequest.property; |
628 | rdata->data = NULL((void*)0); |
629 | rdata->offset = -1; |
630 | conversions = list_prepend (conversions, rdata); |
631 | } |
632 | |
633 | list_foreach (conversions, (Callback) convert_clipboard_target, manager); |
634 | |
635 | if (conversions->next == NULL((void*)0) && |
636 | ((IncrConversion *) conversions->data)->property == None0L) { |
637 | finish_selection_request (manager, xev, False0); |
638 | } else { |
639 | if (multiple) { |
640 | i = 0; |
641 | for (list = conversions; list; list = list->next) { |
642 | rdata = (IncrConversion *)list->data; |
643 | multiple[i++] = rdata->target; |
644 | multiple[i++] = rdata->property; |
645 | } |
646 | XChangeProperty (xev->xselectionrequest.display, |
647 | xev->xselectionrequest.requestor, |
648 | xev->xselectionrequest.property, |
649 | XA_ATOM_PAIR, 32, PropModeReplace0, |
650 | (unsigned char *) multiple, nitems); |
651 | } |
652 | finish_selection_request (manager, xev, True1); |
653 | } |
654 | |
655 | list_foreach (conversions, (Callback) collect_incremental, manager); |
656 | list_free (conversions); |
657 | |
658 | if (multiple) |
659 | free (multiple); |
660 | } |
661 | |
662 | static Boolint |
663 | clipboard_manager_process_event (CsdClipboardManager *manager, |
664 | XEvent *xev) |
665 | { |
666 | Atom type; |
667 | int format; |
668 | unsigned long nitems; |
669 | unsigned long remaining; |
670 | Atom *targets; |
671 | |
672 | targets = NULL((void*)0); |
673 | |
674 | switch (xev->xany.type) { |
675 | case DestroyNotify17: |
676 | if (xev->xdestroywindow.window == manager->priv->requestor) { |
677 | list_foreach (manager->priv->contents, (Callback)target_data_unref, NULL((void*)0)); |
678 | list_free (manager->priv->contents); |
679 | manager->priv->contents = NULL((void*)0); |
680 | |
681 | clipboard_manager_watch_cb (manager, |
682 | manager->priv->requestor, |
683 | False0, |
684 | 0, |
685 | NULL((void*)0)); |
686 | manager->priv->requestor = None0L; |
687 | } |
688 | break; |
689 | case PropertyNotify28: |
690 | if (xev->xproperty.state == PropertyNewValue0) { |
691 | return receive_incrementally (manager, xev); |
692 | } else { |
693 | return send_incrementally (manager, xev); |
694 | } |
695 | |
696 | case SelectionClear29: |
697 | if (xev->xany.window != manager->priv->window) |
698 | return False0; |
699 | |
700 | if (xev->xselectionclear.selection == XA_CLIPBOARD_MANAGER) { |
701 | /* We lost the manager selection */ |
702 | if (manager->priv->contents) { |
703 | list_foreach (manager->priv->contents, (Callback)target_data_unref, NULL((void*)0)); |
704 | list_free (manager->priv->contents); |
705 | manager->priv->contents = NULL((void*)0); |
706 | |
707 | XSetSelectionOwner (manager->priv->display, |
708 | XA_CLIPBOARD, |
709 | None0L, manager->priv->time); |
710 | } |
711 | |
712 | return True1; |
713 | } |
714 | if (xev->xselectionclear.selection == XA_CLIPBOARD) { |
715 | /* We lost the clipboard selection */ |
716 | list_foreach (manager->priv->contents, (Callback)target_data_unref, NULL((void*)0)); |
717 | list_free (manager->priv->contents); |
718 | manager->priv->contents = NULL((void*)0); |
719 | clipboard_manager_watch_cb (manager, |
720 | manager->priv->requestor, |
721 | False0, |
722 | 0, |
723 | NULL((void*)0)); |
724 | manager->priv->requestor = None0L; |
725 | |
726 | return True1; |
727 | } |
728 | break; |
729 | |
730 | case SelectionNotify31: |
731 | if (xev->xany.window != manager->priv->window) |
732 | return False0; |
733 | |
734 | if (xev->xselection.selection == XA_CLIPBOARD) { |
735 | /* a CLIPBOARD conversion is done */ |
736 | if (xev->xselection.property == XA_TARGETS) { |
737 | XGetWindowProperty (xev->xselection.display, |
738 | xev->xselection.requestor, |
739 | xev->xselection.property, |
740 | 0, 0x1FFFFFFF, True1, XA_ATOM((Atom) 4), |
741 | &type, &format, &nitems, &remaining, |
742 | (unsigned char **) &targets); |
743 | |
744 | save_targets (manager, targets, nitems); |
745 | } else if (xev->xselection.property == XA_MULTIPLE) { |
746 | List *tmp; |
747 | |
748 | tmp = list_copy (manager->priv->contents); |
749 | list_foreach (tmp, (Callback) get_property, manager); |
750 | list_free (tmp); |
751 | |
752 | manager->priv->time = xev->xselection.time; |
753 | XSetSelectionOwner (manager->priv->display, XA_CLIPBOARD, |
754 | manager->priv->window, manager->priv->time); |
755 | |
756 | if (manager->priv->property != None0L) |
757 | XChangeProperty (manager->priv->display, |
758 | manager->priv->requestor, |
759 | manager->priv->property, |
760 | XA_ATOM((Atom) 4), 32, PropModeReplace0, |
761 | (unsigned char *)&XA_NULL, 1); |
762 | |
763 | if (!list_find (manager->priv->contents, |
764 | (ListFindFunc)find_content_type, (void *)XA_INCR)) { |
765 | /* all transfers done */ |
766 | send_selection_notify (manager, True1); |
767 | clipboard_manager_watch_cb (manager, |
768 | manager->priv->requestor, |
769 | False0, |
770 | 0, |
771 | NULL((void*)0)); |
772 | manager->priv->requestor = None0L; |
773 | } |
774 | } |
775 | else if (xev->xselection.property == None0L) { |
776 | send_selection_notify (manager, False0); |
777 | clipboard_manager_watch_cb (manager, |
778 | manager->priv->requestor, |
779 | False0, |
780 | 0, |
781 | NULL((void*)0)); |
782 | manager->priv->requestor = None0L; |
783 | } |
784 | |
785 | return True1; |
786 | } |
787 | break; |
788 | |
789 | case SelectionRequest30: |
790 | if (xev->xany.window != manager->priv->window) { |
791 | return False0; |
792 | } |
793 | |
794 | if (xev->xselectionrequest.selection == XA_CLIPBOARD_MANAGER) { |
795 | convert_clipboard_manager (manager, xev); |
796 | return True1; |
797 | } else if (xev->xselectionrequest.selection == XA_CLIPBOARD) { |
798 | convert_clipboard (manager, xev); |
799 | return True1; |
800 | } |
801 | break; |
802 | |
803 | default: ; |
804 | } |
805 | |
806 | return False0; |
807 | } |
808 | |
809 | static CdkFilterReturn |
810 | clipboard_manager_event_filter (CdkXEvent *xevent, |
811 | CdkEvent *event G_GNUC_UNUSED__attribute__ ((__unused__)), |
812 | CsdClipboardManager *manager) |
813 | { |
814 | if (clipboard_manager_process_event (manager, (XEvent *)xevent)) { |
815 | return CDK_FILTER_REMOVE; |
816 | } else { |
817 | return CDK_FILTER_CONTINUE; |
818 | } |
819 | } |
820 | |
821 | static void |
822 | clipboard_manager_watch_cb (CsdClipboardManager *manager, |
823 | Window window, |
824 | Boolint is_start, |
825 | long mask G_GNUC_UNUSED__attribute__ ((__unused__)), |
826 | void *cb_data G_GNUC_UNUSED__attribute__ ((__unused__))) |
827 | { |
828 | CdkWindow *cdkwin; |
829 | CdkDisplay *display; |
830 | |
831 | display = cdk_display_get_default (); |
832 | cdkwin = cdk_x11_window_lookup_for_display (display, window); |
833 | |
834 | if (is_start) { |
835 | if (cdkwin == NULL((void*)0)) { |
836 | cdkwin = cdk_x11_window_foreign_new_for_display (display, window); |
837 | } else { |
838 | g_object_ref (cdkwin)((__typeof__ (cdkwin)) (g_object_ref) (cdkwin)); |
839 | } |
840 | |
841 | cdk_window_add_filter (cdkwin, |
842 | (CdkFilterFunc)clipboard_manager_event_filter, |
843 | manager); |
844 | } else { |
845 | if (cdkwin == NULL((void*)0)) { |
846 | return; |
847 | } |
848 | cdk_window_remove_filter (cdkwin, |
849 | (CdkFilterFunc)clipboard_manager_event_filter, |
850 | manager); |
851 | g_object_unref (cdkwin); |
852 | } |
853 | } |
854 | |
855 | static gboolean |
856 | start_clipboard_idle_cb (CsdClipboardManager *manager) |
857 | { |
858 | XClientMessageEvent xev; |
859 | |
860 | |
861 | cafe_settings_profile_start (NULL); |
862 | |
863 | init_atoms (manager->priv->display); |
864 | |
865 | /* check if there is a clipboard manager running */ |
866 | if (XGetSelectionOwner (manager->priv->display, XA_CLIPBOARD_MANAGER)) { |
867 | g_warning ("Clipboard manager is already running."); |
868 | return FALSE(0); |
869 | } |
870 | |
871 | manager->priv->contents = NULL((void*)0); |
872 | manager->priv->conversions = NULL((void*)0); |
873 | manager->priv->requestor = None0L; |
874 | |
875 | manager->priv->window = XCreateSimpleWindow (manager->priv->display, |
876 | DefaultRootWindow (manager->priv->display)((&((_XPrivDisplay)(manager->priv->display))->screens [(((_XPrivDisplay)(manager->priv->display))->default_screen )])->root), |
877 | 0, 0, 10, 10, 0, |
878 | WhitePixel (manager->priv->display,((&((_XPrivDisplay)(manager->priv->display))->screens [(((_XPrivDisplay)(manager->priv->display))->default_screen )])->white_pixel) |
879 | DefaultScreen (manager->priv->display))((&((_XPrivDisplay)(manager->priv->display))->screens [(((_XPrivDisplay)(manager->priv->display))->default_screen )])->white_pixel), |
880 | WhitePixel (manager->priv->display,((&((_XPrivDisplay)(manager->priv->display))->screens [(((_XPrivDisplay)(manager->priv->display))->default_screen )])->white_pixel) |
881 | DefaultScreen (manager->priv->display))((&((_XPrivDisplay)(manager->priv->display))->screens [(((_XPrivDisplay)(manager->priv->display))->default_screen )])->white_pixel)); |
882 | clipboard_manager_watch_cb (manager, |
883 | manager->priv->window, |
884 | True1, |
885 | PropertyChangeMask(1L<<22), |
886 | NULL((void*)0)); |
887 | XSelectInput (manager->priv->display, |
888 | manager->priv->window, |
889 | PropertyChangeMask(1L<<22)); |
890 | manager->priv->timestamp = get_server_time (manager->priv->display, manager->priv->window); |
891 | |
892 | XSetSelectionOwner (manager->priv->display, |
893 | XA_CLIPBOARD_MANAGER, |
894 | manager->priv->window, |
895 | manager->priv->timestamp); |
896 | |
897 | /* Check to see if we managed to claim the selection. If not, |
898 | * we treat it as if we got it then immediately lost it |
899 | */ |
900 | if (XGetSelectionOwner (manager->priv->display, XA_CLIPBOARD_MANAGER) == manager->priv->window) { |
901 | xev.type = ClientMessage33; |
902 | xev.window = DefaultRootWindow (manager->priv->display)((&((_XPrivDisplay)(manager->priv->display))->screens [(((_XPrivDisplay)(manager->priv->display))->default_screen )])->root); |
903 | xev.message_type = XA_MANAGER; |
904 | xev.format = 32; |
905 | xev.data.l[0] = manager->priv->timestamp; |
906 | xev.data.l[1] = XA_CLIPBOARD_MANAGER; |
907 | xev.data.l[2] = manager->priv->window; |
908 | xev.data.l[3] = 0; /* manager specific data */ |
909 | xev.data.l[4] = 0; /* manager specific data */ |
910 | |
911 | XSendEvent (manager->priv->display, |
912 | DefaultRootWindow (manager->priv->display)((&((_XPrivDisplay)(manager->priv->display))->screens [(((_XPrivDisplay)(manager->priv->display))->default_screen )])->root), |
913 | False0, |
914 | StructureNotifyMask(1L<<17), |
915 | (XEvent *)&xev); |
916 | } else { |
917 | clipboard_manager_watch_cb (manager, |
918 | manager->priv->window, |
919 | False0, |
920 | 0, |
921 | NULL((void*)0)); |
922 | /* FIXME: manager->priv->terminate (manager->priv->cb_data); */ |
923 | } |
924 | |
925 | cafe_settings_profile_end (NULL); |
926 | |
927 | return FALSE(0); |
928 | } |
929 | |
930 | gboolean |
931 | csd_clipboard_manager_start (CsdClipboardManager *manager, |
932 | GError **error G_GNUC_UNUSED__attribute__ ((__unused__))) |
933 | { |
934 | cafe_settings_profile_start (NULL); |
935 | |
936 | g_idle_add ((GSourceFunc) start_clipboard_idle_cb, manager); |
937 | |
938 | cafe_settings_profile_end (NULL); |
939 | |
940 | return TRUE(!(0)); |
941 | } |
942 | |
943 | void |
944 | csd_clipboard_manager_stop (CsdClipboardManager *manager) |
945 | { |
946 | g_debug ("Stopping clipboard manager"); |
947 | |
948 | clipboard_manager_watch_cb (manager, |
949 | manager->priv->window, |
950 | FALSE(0), |
951 | 0, |
952 | NULL((void*)0)); |
953 | XDestroyWindow (manager->priv->display, manager->priv->window); |
954 | |
955 | list_foreach (manager->priv->conversions, (Callback) conversion_free, NULL((void*)0)); |
956 | list_free (manager->priv->conversions); |
957 | |
958 | list_foreach (manager->priv->contents, (Callback) target_data_unref, NULL((void*)0)); |
959 | list_free (manager->priv->contents); |
960 | } |
961 | |
962 | static void |
963 | csd_clipboard_manager_class_init (CsdClipboardManagerClass *klass) |
964 | { |
965 | GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), (((GType) ((20) << (2)))))))); |
966 | |
967 | object_class->finalize = csd_clipboard_manager_finalize; |
968 | } |
969 | |
970 | static void |
971 | csd_clipboard_manager_init (CsdClipboardManager *manager) |
972 | { |
973 | manager->priv = csd_clipboard_manager_get_instance_private (manager); |
974 | |
975 | manager->priv->display = CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())); |
976 | |
977 | } |
978 | |
979 | static void |
980 | csd_clipboard_manager_finalize (GObject *object) |
981 | { |
982 | CsdClipboardManager *clipboard_manager; |
983 | |
984 | g_return_if_fail (object != NULL)do { if ((object != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "object != NULL") ; return; } } while (0); |
985 | g_return_if_fail (CSD_IS_CLIPBOARD_MANAGER (object))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((object)); GType __t = ((csd_clipboard_manager_get_type ( ))); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "CSD_IS_CLIPBOARD_MANAGER (object)" ); return; } } while (0); |
986 | |
987 | clipboard_manager = CSD_CLIPBOARD_MANAGER (object)((((CsdClipboardManager*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((object)), ((csd_clipboard_manager_get_type ())))))); |
988 | |
989 | g_return_if_fail (clipboard_manager->priv != NULL)do { if ((clipboard_manager->priv != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "clipboard_manager->priv != NULL"); return; } } while ( 0); |
990 | |
991 | G_OBJECT_CLASS (csd_clipboard_manager_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((csd_clipboard_manager_parent_class)), (((GType) ((20) << (2))))))))->finalize (object); |
992 | } |
993 | |
994 | CsdClipboardManager * |
995 | csd_clipboard_manager_new (void) |
996 | { |
997 | if (manager_object != NULL((void*)0)) { |
998 | g_object_ref (manager_object)((__typeof__ (manager_object)) (g_object_ref) (manager_object )); |
999 | } else { |
1000 | manager_object = g_object_new (CSD_TYPE_CLIPBOARD_MANAGER(csd_clipboard_manager_get_type ()), NULL((void*)0)); |
1001 | g_object_add_weak_pointer (manager_object, |
1002 | (gpointer *) &manager_object); |
1003 | } |
1004 | |
1005 | return CSD_CLIPBOARD_MANAGER (manager_object)((((CsdClipboardManager*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((manager_object)), ((csd_clipboard_manager_get_type ())))))); |
1006 | } |