File: | plugins/clipboard/csd_clipboard-manager.c |
Warning: | line 384, column 24 Division by zero |
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 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; } | |||
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)); | |||
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 | } |