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