Bug Summary

File:plugins/clipboard/csd_clipboard-manager.c
Warning:line 539, column 39
Division by zero

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name csd_clipboard-manager.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/plugins/clipboard -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I ../../cafe-settings-daemon -D CAFE_SETTINGS_LOCALEDIR="/usr/share/locale" -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/plugins/clipboard -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-16-114257-65650-1 -x c csd_clipboard-manager.c
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
49struct 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
63typedef struct
64{
65 unsigned char *data;
66 int length;
67 Atom target;
68 Atom type;
69 int format;
70 int refcount;
71} TargetData;
72
73typedef struct
74{
75 Atom target;
76 TargetData *data;
77 Atom property;
78 Window requestor;
79 int offset;
80} IncrConversion;
81
82static void csd_clipboard_manager_finalize (GObject *object);
83
84static void clipboard_manager_watch_cb (CsdClipboardManager *manager,
85 Window window,
86 Boolint is_start,
87 long mask,
88 void *cb_data);
89
90G_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
92static 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 */
98static TargetData *
99target_data_ref (TargetData *data)
100{
101 data->refcount++;
102 return data;
8
Returning without writing to 'data->format', which participates in a condition later
103}
104
105static void
106target_data_unref (TargetData *data)
107{
108 data->refcount--;
109 if (data->refcount == 0) {
110 free (data->data);
111 free (data);
112 }
113}
114
115static void
116conversion_free (IncrConversion *rdata)
117{
118 if (rdata->data) {
119 target_data_unref (rdata->data);
120 }
121 free (rdata);
122}
123
124static void
125send_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 *)&notify);
149 XSync (manager->priv->display, False0);
150
151 cdk_x11_display_error_trap_pop_ignored (display);
152}
153
154static void
155finish_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 *) &notify);
178 XSync (manager->priv->display, False0);
179
180 cdk_x11_display_error_trap_pop_ignored (display);
181}
182
183static int
184clipboard_bytes_per_item (int format)
185{
186 switch (format) {
11
Control jumps to the 'default' case at line 190
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;
12
Returning zero
194}
195
196static void
197save_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
241static int
242find_content_target (TargetData *tdata,
243 Atom target)
244{
245 return tdata->target == target;
246}
247
248static int
249find_content_type (TargetData *tdata,
250 Atom type)
251{
252 return tdata->type == type;
253}
254
255static int
256find_conversion_requestor (IncrConversion *rdata,
257 XEvent *xev)
258{
259 return (rdata->requestor == xev->xproperty.window &&
260 rdata->property == xev->xproperty.atom);
261}
262
263static void
264get_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
301static Boolint
302receive_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
360static Boolint
361send_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
398static void
399convert_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
489static void
490convert_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) {
1
Assuming 'XA_TARGETS' is not equal to field 'target'
2
Taking false branch
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)
3
Assuming 'list' is non-null
4
Taking false branch
529 return;
530
531 tdata = (TargetData *)list->data;
532 if (tdata->type == XA_INCR) {
5
Assuming 'XA_INCR' is not equal to field 'type'
6
Taking false branch
533 /* we haven't completely received this target yet */
534 rdata->property = None0L;
535 return;
536 }
537
538 rdata->data = target_data_ref (tdata);
7
Calling 'target_data_ref'
9
Returning from 'target_data_ref'
539 items = tdata->length / clipboard_bytes_per_item (tdata->format);
10
Calling 'clipboard_bytes_per_item'
13
Returning from 'clipboard_bytes_per_item'
14
Division by zero
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
567static void
568collect_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
582static void
583convert_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
663static Boolint
664clipboard_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
810static CdkFilterReturn
811clipboard_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
822static void
823clipboard_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
856static gboolean
857start_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
931gboolean
932csd_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
944void
945csd_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
963static void
964csd_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
971static void
972csd_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
980static void
981csd_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
995CsdClipboardManager *
996csd_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}