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