~ubuntu-branches/ubuntu/precise/gnome-control-center/precise-updates

« back to all changes in this revision

Viewing changes to gnome-settings-daemon/clipboard-manager.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-05-02 17:07:13 UTC
  • Revision ID: james.westby@ubuntu.com-20070502170713-t7f816n7kr57w340
Tags: upstream-2.19.1
ImportĀ upstreamĀ versionĀ 2.19.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright Ā© 2004 Red Hat, Inc.
 
3
 * Copyright Ā© 2004 Nokia Corporation
 
4
 *
 
5
 * Permission to use, copy, modify, distribute, and sell this software and its
 
6
 * documentation for any purpose is hereby granted without fee, provided that
 
7
 * the above copyright notice appear in all copies and that both that
 
8
 * copyright notice and this permission notice appear in supporting
 
9
 * documentation, and that the name of Red Hat not be used in advertising or
 
10
 * publicity pertaining to distribution of the software without specific,
 
11
 * written prior permission.  Red Hat makes no representations about the
 
12
 * suitability of this software for any purpose.  It is provided "as is"
 
13
 * without express or implied warranty.
 
14
 *
 
15
 * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
 
17
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
18
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 
19
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
 
20
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
21
 *
 
22
 * Authors:  Matthias Clasen, Red Hat, Inc.
 
23
 *           Anders Carlsson, Imendio AB
 
24
 */
 
25
 
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
 
 
30
#include <X11/Xlib.h>
 
31
#include <X11/Xatom.h>
 
32
 
 
33
#include "clipboard-manager.h"
 
34
#include "xutils.h"
 
35
#include "list.h"
 
36
 
 
37
 
 
38
struct _ClipboardManager
 
39
{
 
40
  Display *display;
 
41
  Window window;
 
42
  Time timestamp;
 
43
 
 
44
  ClipboardTerminateFunc terminate;
 
45
  ClipboardWatchFunc watch;
 
46
  void *cb_data;
 
47
 
 
48
  ClipboardErrorTrapPushFunc error_trap_push;
 
49
  ClipboardErrorTrapPopFunc  error_trap_pop;
 
50
  
 
51
  List *contents;
 
52
  List *conversions;
 
53
 
 
54
  Window requestor;
 
55
  Atom property;
 
56
  Time time;
 
57
};
 
58
 
 
59
typedef struct
 
60
{
 
61
  unsigned char *data;
 
62
  int            length;
 
63
  Atom           target;
 
64
  Atom           type;
 
65
  int            format;
 
66
  int            refcount;
 
67
} TargetData;
 
68
 
 
69
typedef struct
 
70
{
 
71
  Atom target;
 
72
  TargetData *data;
 
73
  Atom property;
 
74
  Window requestor;
 
75
  int  offset;
 
76
} IncrConversion;
 
77
 
 
78
 
 
79
/* We need to use reference counting for the target data, since we may 
 
80
 * need to keep the data around after loosing the CLIPBOARD ownership
 
81
 * to complete incremental transfers. 
 
82
 */
 
83
static TargetData *
 
84
target_data_ref (TargetData *data)
 
85
{
 
86
  data->refcount++;
 
87
  return data;
 
88
}
 
89
 
 
90
static void
 
91
target_data_unref (TargetData *data)
 
92
{
 
93
  data->refcount--;
 
94
  if (data->refcount == 0)
 
95
    {
 
96
      free (data->data);
 
97
      free (data);
 
98
    }
 
99
}
 
100
 
 
101
static void
 
102
conversion_free (IncrConversion *rdata)
 
103
{
 
104
  if (rdata->data)
 
105
    target_data_unref (rdata->data);
 
106
  free (rdata);
 
107
}
 
108
 
 
109
static void
 
110
send_selection_notify (ClipboardManager *manager,
 
111
                       Bool              success)
 
112
{
 
113
  XSelectionEvent notify;
 
114
 
 
115
  notify.type = SelectionNotify;
 
116
  notify.serial = 0;
 
117
  notify.send_event = True;
 
118
  notify.display = manager->display;
 
119
  notify.requestor = manager->requestor;
 
120
  notify.selection = XA_CLIPBOARD_MANAGER;
 
121
  notify.target = XA_SAVE_TARGETS;
 
122
  notify.property = success ? manager->property : None;
 
123
  notify.time = manager->time;
 
124
 
 
125
  manager->error_trap_push ();
 
126
 
 
127
  XSendEvent (manager->display, manager->requestor,
 
128
              False, NoEventMask, (XEvent *)&notify);
 
129
  XSync (manager->display, False);
 
130
  
 
131
  manager->error_trap_pop ();
 
132
}
 
133
 
 
134
static void
 
135
finish_selection_request (ClipboardManager *manager,
 
136
                          XEvent           *xev,
 
137
                          Bool              success)
 
138
{
 
139
  XSelectionEvent notify;
 
140
 
 
141
  notify.type = SelectionNotify;
 
142
  notify.serial = 0;
 
143
  notify.send_event = True;
 
144
  notify.display = xev->xselectionrequest.display;
 
145
  notify.requestor = xev->xselectionrequest.requestor;
 
146
  notify.selection = xev->xselectionrequest.selection;
 
147
  notify.target = xev->xselectionrequest.target;
 
148
  notify.property = success ? xev->xselectionrequest.property : None;
 
149
  notify.time = xev->xselectionrequest.time;
 
150
 
 
151
  manager->error_trap_push ();
 
152
 
 
153
  XSendEvent (xev->xselectionrequest.display, 
 
154
              xev->xselectionrequest.requestor,
 
155
              False, NoEventMask, (XEvent *)&notify);
 
156
  XSync (manager->display, False);
 
157
 
 
158
  manager->error_trap_pop ();
 
159
}
 
160
 
 
161
static int 
 
162
clipboard_bytes_per_item (int format)
 
163
{
 
164
  switch (format)
 
165
    {
 
166
    case 8:
 
167
      return sizeof (char);
 
168
    case 16:
 
169
      return sizeof (short);
 
170
    case 32:
 
171
      return sizeof (long);
 
172
    default: ;
 
173
    }
 
174
  return 0;
 
175
}
 
176
 
 
177
static void
 
178
save_targets (ClipboardManager *manager, 
 
179
              Atom             *save_targets,
 
180
              int               nitems)
 
181
{
 
182
  int nout, i;
 
183
  Atom *multiple;
 
184
  TargetData *tdata;
 
185
 
 
186
  multiple = (Atom *) malloc (2 * nitems * sizeof (Atom));
 
187
 
 
188
  nout = 0;
 
189
  for (i = 0; i < nitems; i++)
 
190
    {
 
191
      if (save_targets[i] != XA_TARGETS &&
 
192
          save_targets[i] != XA_MULTIPLE &&
 
193
          save_targets[i] != XA_DELETE &&
 
194
          save_targets[i] != XA_INSERT_PROPERTY &&
 
195
          save_targets[i] != XA_INSERT_SELECTION &&
 
196
          save_targets[i] != XA_PIXMAP)
 
197
        {
 
198
          
 
199
          tdata = (TargetData *) malloc (sizeof (TargetData));
 
200
          tdata->data = NULL;
 
201
          tdata->length = 0;
 
202
          tdata->target = save_targets[i];
 
203
          tdata->type = None;
 
204
          tdata->format = 0;
 
205
          tdata->refcount = 1;
 
206
          manager->contents = list_prepend (manager->contents, tdata);
 
207
          
 
208
          multiple[nout++] = save_targets[i];
 
209
          multiple[nout++] = save_targets[i];
 
210
        }
 
211
    }
 
212
 
 
213
  XFree (save_targets);
 
214
  
 
215
  XChangeProperty (manager->display, manager->window,
 
216
                   XA_MULTIPLE, XA_ATOM_PAIR, 
 
217
                   32, PropModeReplace, (char *)multiple, nout);
 
218
  free (multiple);
 
219
 
 
220
  XConvertSelection (manager->display, XA_CLIPBOARD,
 
221
                     XA_MULTIPLE, XA_MULTIPLE,
 
222
                     manager->window, manager->time);
 
223
}
 
224
 
 
225
static int
 
226
find_content_target (TargetData *tdata,
 
227
                     Atom        target)
 
228
{
 
229
  return tdata->target == target;
 
230
}
 
231
 
 
232
static int
 
233
find_content_type (TargetData *tdata,
 
234
                   Atom        type)
 
235
{
 
236
  return tdata->type == type;
 
237
}
 
238
 
 
239
static int
 
240
find_conversion_requestor (IncrConversion *rdata,
 
241
                           XEvent         *xev)
 
242
{
 
243
  return (rdata->requestor == xev->xproperty.window &&
 
244
          rdata->property == xev->xproperty.atom);
 
245
}
 
246
 
 
247
static void
 
248
get_property (TargetData       *tdata,
 
249
              ClipboardManager *manager)
 
250
{
 
251
  Atom type;
 
252
  int format;
 
253
  unsigned long length;
 
254
  unsigned long remaining;
 
255
  unsigned char *data;
 
256
        
 
257
  XGetWindowProperty (manager->display, 
 
258
                      manager->window,
 
259
                      tdata->target,
 
260
                      0, 0x1FFFFFFF, True, AnyPropertyType,
 
261
                      &type, &format, &length, &remaining, 
 
262
                      &data);
 
263
 
 
264
  if (type == None)
 
265
    {
 
266
      manager->contents = list_remove (manager->contents, tdata);
 
267
      free (tdata);
 
268
    }
 
269
  else if (type == XA_INCR)
 
270
    {
 
271
      tdata->type = type;
 
272
      tdata->length = 0;
 
273
      XFree (data);
 
274
    }
 
275
  else
 
276
    {
 
277
      tdata->type = type;
 
278
      tdata->data = data;
 
279
      tdata->length = length * clipboard_bytes_per_item (format);
 
280
      tdata->format = format;
 
281
    }
 
282
}
 
283
 
 
284
static Bool
 
285
receive_incrementally (ClipboardManager *manager,
 
286
                       XEvent           *xev)
 
287
{
 
288
  List *list;
 
289
  TargetData *tdata;
 
290
  Atom type;
 
291
  int format;
 
292
  unsigned long length, nitems, remaining;
 
293
  unsigned char *data;
 
294
 
 
295
  if (xev->xproperty.window != manager->window)
 
296
    return False;
 
297
 
 
298
  list = list_find (manager->contents, 
 
299
                    (ListFindFunc)find_content_target, (void *)xev->xproperty.atom);
 
300
  
 
301
  if (!list) 
 
302
    return False;
 
303
  
 
304
  tdata = (TargetData *)list->data;
 
305
 
 
306
  if (tdata->type != XA_INCR)
 
307
    return False;
 
308
 
 
309
  XGetWindowProperty (xev->xproperty.display,
 
310
                      xev->xproperty.window,
 
311
                      xev->xproperty.atom,
 
312
                      0, 0x1FFFFFFF, True, AnyPropertyType,
 
313
                      &type, &format, &nitems, &remaining, &data);
 
314
 
 
315
  length = nitems * clipboard_bytes_per_item (format);
 
316
  
 
317
  if (length == 0)
 
318
    {
 
319
      tdata->type = type;
 
320
      tdata->format = format;
 
321
      
 
322
      if (!list_find (manager->contents, 
 
323
                      (ListFindFunc)find_content_type, (void *)XA_INCR)) 
 
324
        {
 
325
          /* all incremental transfers done */
 
326
          send_selection_notify (manager, True);
 
327
          manager->requestor = None;
 
328
        }
 
329
 
 
330
      XFree (data);
 
331
    }
 
332
  else
 
333
    {
 
334
      if (!tdata->data)
 
335
        {
 
336
          tdata->data = data;
 
337
          tdata->length = length;
 
338
        }
 
339
      else
 
340
        {
 
341
          tdata->data = realloc (tdata->data, tdata->length + length + 1);
 
342
          memcpy (tdata->data + tdata->length, data, length + 1);
 
343
          tdata->length += length;
 
344
          XFree (data);
 
345
        }
 
346
    }
 
347
 
 
348
  return True;
 
349
}
 
350
 
 
351
static Bool
 
352
send_incrementally (ClipboardManager *manager,
 
353
                    XEvent           *xev)
 
354
{
 
355
  List *list;
 
356
  IncrConversion *rdata;
 
357
  unsigned long length, items;
 
358
  unsigned char *data;
 
359
        
 
360
  list = list_find (manager->conversions, 
 
361
                    (ListFindFunc)find_conversion_requestor, xev);
 
362
  
 
363
  if (list == NULL) 
 
364
    return False;
 
365
  
 
366
  rdata = (IncrConversion *)list->data;
 
367
  
 
368
  data = rdata->data->data + rdata->offset; 
 
369
  length = rdata->data->length - rdata->offset;
 
370
  if (length > SELECTION_MAX_SIZE)
 
371
    length = SELECTION_MAX_SIZE;
 
372
  
 
373
  rdata->offset += length;
 
374
  
 
375
  items = length / clipboard_bytes_per_item (rdata->data->format);
 
376
  XChangeProperty (manager->display, rdata->requestor,
 
377
                   rdata->property, rdata->data->type,
 
378
                   rdata->data->format, PropModeAppend,
 
379
                   data, items);
 
380
  
 
381
  if (length == 0)
 
382
    {
 
383
      manager->conversions = list_remove (manager->conversions, rdata);
 
384
      conversion_free (rdata);
 
385
    }
 
386
 
 
387
  return True;
 
388
}
 
389
 
 
390
static void
 
391
convert_clipboard_manager (ClipboardManager *manager,
 
392
                           XEvent           *xev)
 
393
{
 
394
  Atom type = None;
 
395
  int format;
 
396
  unsigned long nitems, remaining;
 
397
  Atom *targets = NULL;
 
398
 
 
399
  if (xev->xselectionrequest.target == XA_SAVE_TARGETS)
 
400
    {
 
401
      if (manager->requestor != None || manager->contents != NULL)
 
402
        {
 
403
          /* We're in the middle of a conversion request, or own 
 
404
           * the CLIPBOARD already 
 
405
           */
 
406
          finish_selection_request (manager, xev, False);
 
407
        }
 
408
      else
 
409
        {
 
410
          manager->error_trap_push ();
 
411
          
 
412
          manager->watch (xev->xselectionrequest.requestor, True, StructureNotifyMask, manager->cb_data);
 
413
          XSelectInput (manager->display, xev->xselectionrequest.requestor,
 
414
                        StructureNotifyMask);
 
415
          XSync (manager->display, False);
 
416
          
 
417
          if (manager->error_trap_pop () != Success)
 
418
            return;
 
419
 
 
420
          manager->error_trap_push ();
 
421
          
 
422
          if (xev->xselectionrequest.property != None)
 
423
            {
 
424
              XGetWindowProperty (manager->display, xev->xselectionrequest.requestor,
 
425
                                  xev->xselectionrequest.property,
 
426
                                  0, 0x1FFFFFFF, False, XA_ATOM,
 
427
                                  &type, &format, &nitems, &remaining,
 
428
                                  (unsigned char **)&targets);
 
429
              
 
430
              if (manager->error_trap_pop () != Success)
 
431
                {
 
432
                  if (targets)
 
433
                    XFree (targets);
 
434
                  
 
435
                  return;
 
436
                }
 
437
            }
 
438
          
 
439
          manager->requestor = xev->xselectionrequest.requestor;
 
440
          manager->property = xev->xselectionrequest.property;
 
441
          manager->time = xev->xselectionrequest.time;
 
442
 
 
443
          if (type == None)
 
444
            XConvertSelection (manager->display, XA_CLIPBOARD,
 
445
                               XA_TARGETS, XA_TARGETS,
 
446
                               manager->window, manager->time);
 
447
          else
 
448
            save_targets (manager, targets, nitems);
 
449
        }
 
450
    }
 
451
  else if (xev->xselectionrequest.target == XA_TIMESTAMP)
 
452
    {
 
453
      XChangeProperty (manager->display,
 
454
                       xev->xselectionrequest.requestor,
 
455
                       xev->xselectionrequest.property,
 
456
                       XA_INTEGER, 32, PropModeReplace,
 
457
                       (unsigned char *)&manager->timestamp, 1);
 
458
      
 
459
      finish_selection_request (manager, xev, True);
 
460
    }
 
461
  else if (xev->xselectionrequest.target == XA_TARGETS)
 
462
    {
 
463
      int n_targets = 0;
 
464
      Atom targets[3];
 
465
      
 
466
      targets[n_targets++] = XA_TARGETS;
 
467
      targets[n_targets++] = XA_TIMESTAMP;
 
468
      targets[n_targets++] = XA_SAVE_TARGETS;
 
469
      
 
470
      XChangeProperty (manager->display,
 
471
                       xev->xselectionrequest.requestor,
 
472
                       xev->xselectionrequest.property,
 
473
                       XA_ATOM, 32, PropModeReplace,
 
474
                       (unsigned char *)targets, n_targets);
 
475
      
 
476
      finish_selection_request (manager, xev, True);
 
477
    }
 
478
  else
 
479
    {
 
480
      finish_selection_request (manager, xev, False);
 
481
    }
 
482
}
 
483
 
 
484
static void
 
485
convert_clipboard_target (IncrConversion   *rdata,
 
486
                          ClipboardManager *manager)
 
487
{
 
488
  TargetData *tdata;
 
489
  Atom *targets;
 
490
  int n_targets;
 
491
  List *list;             
 
492
  unsigned long items;
 
493
  XWindowAttributes atts;                               
 
494
          
 
495
  if (rdata->target == XA_TARGETS)
 
496
    {
 
497
      n_targets = list_length (manager->contents) + 2;
 
498
      targets = (Atom *) malloc (n_targets * sizeof (Atom));
 
499
      
 
500
      n_targets = 0;
 
501
      
 
502
      targets[n_targets++] = XA_TARGETS;
 
503
      targets[n_targets++] = XA_MULTIPLE;
 
504
      
 
505
      for (list = manager->contents; list; list = list->next)
 
506
        {
 
507
          tdata = (TargetData *)list->data;
 
508
          targets[n_targets++] = tdata->target;
 
509
        }
 
510
      
 
511
      XChangeProperty (manager->display, rdata->requestor,
 
512
                       rdata->property,
 
513
                       XA_ATOM, 32, PropModeReplace,
 
514
                       (unsigned char *)targets, n_targets);
 
515
      free (targets);
 
516
    }
 
517
  else 
 
518
    {
 
519
      /* Convert from stored CLIPBOARD data */
 
520
      list = list_find (manager->contents, 
 
521
                        (ListFindFunc)find_content_target, (void *)rdata->target);
 
522
 
 
523
      /* We got a target that we don't support */
 
524
      if (!list)
 
525
        return;
 
526
      
 
527
      tdata = (TargetData *)list->data;
 
528
 
 
529
      if (tdata->type == XA_INCR)
 
530
        {
 
531
          /* we haven't completely received this target yet 
 
532
           */
 
533
          rdata->property = None;
 
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->display, rdata->requestor,
 
541
                         rdata->property,
 
542
                         tdata->type, tdata->format, PropModeReplace,
 
543
                         tdata->data, items);
 
544
      else
 
545
        {
 
546
          /* start incremental transfer
 
547
           */
 
548
          rdata->offset = 0;
 
549
 
 
550
          manager->error_trap_push ();
 
551
          
 
552
          XGetWindowAttributes (manager->display, rdata->requestor, &atts);
 
553
          XSelectInput (manager->display, rdata->requestor, 
 
554
                        atts.your_event_mask | PropertyChangeMask);
 
555
          
 
556
          XChangeProperty (manager->display, rdata->requestor,
 
557
                           rdata->property,
 
558
                           XA_INCR, 32, PropModeReplace,
 
559
                           (unsigned char *)&items, 1);
 
560
 
 
561
          XSync (manager->display, False);
 
562
  
 
563
          manager->error_trap_pop ();
 
564
        }
 
565
    }
 
566
}
 
567
 
 
568
static void
 
569
collect_incremental (IncrConversion   *rdata, 
 
570
                     ClipboardManager *manager)
 
571
{
 
572
  if (rdata->offset >= 0)
 
573
    manager->conversions = list_prepend (manager->conversions, rdata);
 
574
  else
 
575
    {
 
576
      if (rdata->data)
 
577
        {
 
578
          target_data_unref (rdata->data);
 
579
          rdata->data = NULL;
 
580
        }
 
581
      free (rdata);
 
582
    }
 
583
}
 
584
 
 
585
static void
 
586
convert_clipboard (ClipboardManager *manager,
 
587
                   XEvent           *xev)
 
588
{
 
589
    List *list, *conversions;
 
590
    IncrConversion *rdata;
 
591
    Atom type;
 
592
    int i, format;
 
593
    unsigned long nitems, remaining;
 
594
    Atom *multiple;
 
595
    
 
596
    conversions = NULL;
 
597
    type = None;
 
598
    
 
599
    if (xev->xselectionrequest.target == XA_MULTIPLE)
 
600
      {
 
601
        
 
602
        XGetWindowProperty (xev->xselectionrequest.display,
 
603
                            xev->xselectionrequest.requestor,
 
604
                            xev->xselectionrequest.property,
 
605
                            0, 0x1FFFFFFF, False, XA_ATOM_PAIR,
 
606
                            &type, &format, &nitems, &remaining,
 
607
                            (unsigned char **)&multiple);
 
608
 
 
609
 
 
610
        
 
611
        if (type != XA_ATOM_PAIR)
 
612
          return;
 
613
        
 
614
        for (i = 0; i < nitems; i += 2)
 
615
          {
 
616
            rdata = (IncrConversion *) malloc (sizeof (IncrConversion));
 
617
            rdata->requestor = xev->xselectionrequest.requestor;
 
618
            rdata->target = multiple[i];
 
619
            rdata->property = multiple[i+1];
 
620
            rdata->data = NULL;
 
621
            rdata->offset = -1;
 
622
            conversions = list_prepend (conversions, rdata);
 
623
          }
 
624
      }
 
625
    else
 
626
      {
 
627
        multiple = NULL;
 
628
        
 
629
        rdata = (IncrConversion *) malloc (sizeof (IncrConversion));
 
630
        rdata->requestor = xev->xselectionrequest.requestor;
 
631
        rdata->target = xev->xselectionrequest.target;
 
632
        rdata->property = xev->xselectionrequest.property;
 
633
        rdata->data = NULL;
 
634
        rdata->offset = -1;
 
635
        conversions = list_prepend (conversions, rdata);
 
636
      }
 
637
 
 
638
    list_foreach (conversions, (Callback)convert_clipboard_target, manager);
 
639
    
 
640
    if (conversions->next == NULL &&
 
641
        ((IncrConversion *)conversions->data)->property == None)
 
642
      {
 
643
        finish_selection_request (manager, xev, False);
 
644
      }
 
645
    else
 
646
      {
 
647
        if (multiple)
 
648
          {
 
649
            i = 0;
 
650
            for (list = conversions; list; list = list->next)
 
651
              {
 
652
                rdata = (IncrConversion *)list->data;
 
653
                multiple[i++] = rdata->target;
 
654
                multiple[i++] = rdata->property;
 
655
              }
 
656
            XChangeProperty (xev->xselectionrequest.display,
 
657
                             xev->xselectionrequest.requestor,
 
658
                             xev->xselectionrequest.property,
 
659
                             XA_ATOM_PAIR, 32, PropModeReplace,
 
660
                             (unsigned char *)multiple, nitems);
 
661
          }
 
662
        finish_selection_request (manager, xev, True);
 
663
      }
 
664
    
 
665
    list_foreach (conversions, (Callback)collect_incremental, manager);
 
666
    list_free (conversions);
 
667
    
 
668
    if (multiple)
 
669
      free (multiple);
 
670
}
 
671
 
 
672
Bool
 
673
clipboard_manager_process_event (ClipboardManager *manager,
 
674
                                 XEvent           *xev)
 
675
{
 
676
  Atom type;
 
677
  int format;
 
678
  unsigned long nitems;
 
679
  unsigned long remaining;
 
680
  Atom *targets;
 
681
  
 
682
  targets = NULL;
 
683
 
 
684
  switch (xev->xany.type)
 
685
    {
 
686
    case DestroyNotify:
 
687
      if (xev->xdestroywindow.window == manager->requestor)
 
688
        {
 
689
          list_foreach (manager->contents, (Callback)target_data_unref, NULL);
 
690
          list_free (manager->contents);
 
691
          manager->contents = NULL;
 
692
 
 
693
          manager->watch (manager->requestor, False, 0, manager->cb_data);
 
694
          manager->requestor = None;
 
695
        }
 
696
      break;
 
697
    case PropertyNotify:
 
698
      
 
699
      if (xev->xproperty.state == PropertyNewValue)
 
700
        return receive_incrementally (manager, xev);
 
701
      else 
 
702
        return send_incrementally (manager, xev);
 
703
      
 
704
    case SelectionClear:
 
705
      if (xev->xany.window != manager->window)
 
706
        return False;
 
707
 
 
708
      if (xev->xselectionclear.selection == XA_CLIPBOARD_MANAGER)
 
709
        {
 
710
          /* We lost the manager selection */
 
711
          if (manager->contents)
 
712
            {
 
713
              list_foreach (manager->contents, (Callback)target_data_unref, NULL);
 
714
              list_free (manager->contents);
 
715
              manager->contents = NULL;
 
716
              
 
717
              XSetSelectionOwner (manager->display, 
 
718
                                  XA_CLIPBOARD,
 
719
                                  None, manager->time);
 
720
            }
 
721
          manager->terminate (manager->cb_data);
 
722
 
 
723
          return True;
 
724
        }
 
725
      if (xev->xselectionclear.selection == XA_CLIPBOARD)
 
726
        {
 
727
          /* We lost the clipboard selection */
 
728
          list_foreach (manager->contents, (Callback)target_data_unref, NULL);
 
729
          list_free (manager->contents);
 
730
          manager->contents = NULL;
 
731
          manager->watch (manager->requestor, False, 0, manager->cb_data);
 
732
          manager->requestor = None;
 
733
          
 
734
          return True;
 
735
        }
 
736
      break;
 
737
 
 
738
    case SelectionNotify:
 
739
      if (xev->xany.window != manager->window)
 
740
        return False;
 
741
 
 
742
      if (xev->xselection.selection == XA_CLIPBOARD)
 
743
        {
 
744
          /* a CLIPBOARD conversion is done */
 
745
          if (xev->xselection.property == XA_TARGETS)
 
746
            {
 
747
              XGetWindowProperty (xev->xselection.display,
 
748
                                  xev->xselection.requestor,
 
749
                                  xev->xselection.property,
 
750
                                  0, 0x1FFFFFFF, True, XA_ATOM,
 
751
                                  &type, &format, &nitems, &remaining,
 
752
                                  (unsigned char **)&targets);
 
753
              
 
754
              save_targets (manager, targets, nitems);
 
755
            }
 
756
          else if (xev->xselection.property == XA_MULTIPLE)
 
757
            {
 
758
              List *tmp;
 
759
 
 
760
              tmp = list_copy (manager->contents);
 
761
              list_foreach (tmp, (Callback)get_property, manager);
 
762
              list_free (tmp);
 
763
              
 
764
              manager->time = xev->xselection.time;
 
765
              XSetSelectionOwner (manager->display, XA_CLIPBOARD,
 
766
                                  manager->window, manager->time);
 
767
 
 
768
              if (manager->property != None)
 
769
                XChangeProperty (manager->display, manager->requestor,
 
770
                                 manager->property,
 
771
                                 XA_ATOM, 32, PropModeReplace,
 
772
                                 (unsigned char *)&XA_NULL, 1);
 
773
 
 
774
              if (!list_find (manager->contents, 
 
775
                              (ListFindFunc)find_content_type, (void *)XA_INCR)) 
 
776
                {
 
777
                  /* all transfers done */
 
778
                  send_selection_notify (manager, True);
 
779
                  manager->watch (manager->requestor, False, 0, manager->cb_data);
 
780
                  manager->requestor = None;
 
781
                }                 
 
782
            }
 
783
          else if (xev->xselection.property == None)
 
784
            {
 
785
              send_selection_notify (manager, False);
 
786
              manager->watch (manager->requestor, False, 0, manager->cb_data);
 
787
              manager->requestor = None;
 
788
            }
 
789
 
 
790
          return True;
 
791
        }
 
792
      break;
 
793
 
 
794
      case SelectionRequest:
 
795
        if (xev->xany.window != manager->window)
 
796
          return False;
 
797
 
 
798
        if (xev->xselectionrequest.selection == XA_CLIPBOARD_MANAGER)
 
799
          {
 
800
            convert_clipboard_manager (manager, xev);
 
801
            return True;
 
802
          }
 
803
        else if (xev->xselectionrequest.selection == XA_CLIPBOARD)
 
804
          {
 
805
            convert_clipboard (manager, xev);
 
806
            return True;
 
807
          }
 
808
        break;
 
809
 
 
810
    default: ;
 
811
    }
 
812
     
 
813
  return False;
 
814
}
 
815
 
 
816
Bool
 
817
clipboard_manager_check_running (Display *display)
 
818
{
 
819
  init_atoms (display);
 
820
 
 
821
  if (XGetSelectionOwner (display, XA_CLIPBOARD_MANAGER))
 
822
    return True;
 
823
  else
 
824
    return False;
 
825
}
 
826
 
 
827
ClipboardManager *
 
828
clipboard_manager_new (Display                   *display,
 
829
                       ClipboardErrorTrapPushFunc error_trap_push_cb,
 
830
                       ClipboardErrorTrapPopFunc  error_trap_pop_cb,
 
831
                       ClipboardTerminateFunc     terminate,
 
832
                       ClipboardWatchFunc         watch,
 
833
                       void                      *cb_data)
 
834
{
 
835
  ClipboardManager *manager;
 
836
  XClientMessageEvent xev;
 
837
 
 
838
  init_atoms (display);
 
839
 
 
840
  manager = malloc (sizeof *manager);
 
841
  if (!manager)
 
842
    return NULL;
 
843
 
 
844
  manager->display = display;
 
845
 
 
846
  manager->error_trap_push = error_trap_push_cb;
 
847
  manager->error_trap_pop = error_trap_pop_cb;
 
848
  
 
849
  manager->terminate = terminate;
 
850
  manager->watch = watch;
 
851
  manager->cb_data = cb_data;
 
852
 
 
853
  manager->contents = NULL;
 
854
  manager->conversions = NULL;
 
855
 
 
856
  manager->requestor = None;
 
857
 
 
858
  manager->window = XCreateSimpleWindow (display,
 
859
                                         DefaultRootWindow (display),
 
860
                                         0, 0, 10, 10, 0,
 
861
                                         WhitePixel (display, DefaultScreen (display)),
 
862
                                         WhitePixel (display, DefaultScreen (display)));
 
863
 
 
864
  manager->watch (manager->window, True, PropertyChangeMask, manager->cb_data);
 
865
  XSelectInput (display, manager->window, PropertyChangeMask);
 
866
  manager->timestamp = get_server_time (display, manager->window);
 
867
 
 
868
  XSetSelectionOwner (display, XA_CLIPBOARD_MANAGER,
 
869
                      manager->window, manager->timestamp);
 
870
 
 
871
  /* Check to see if we managed to claim the selection. If not,
 
872
   * we treat it as if we got it then immediately lost it
 
873
   */
 
874
 
 
875
  if (XGetSelectionOwner (display, XA_CLIPBOARD_MANAGER) == manager->window)
 
876
    {
 
877
      xev.type = ClientMessage;
 
878
      xev.window = DefaultRootWindow (display);
 
879
      xev.message_type = XA_MANAGER;
 
880
      xev.format = 32;
 
881
      xev.data.l[0] = manager->timestamp;
 
882
      xev.data.l[1] = XA_CLIPBOARD_MANAGER;
 
883
      xev.data.l[2] = manager->window;
 
884
      xev.data.l[3] = 0;        /* manager specific data */
 
885
      xev.data.l[4] = 0;        /* manager specific data */
 
886
 
 
887
      XSendEvent (display, DefaultRootWindow (display),
 
888
                  False, StructureNotifyMask, (XEvent *)&xev);
 
889
    }
 
890
  else
 
891
    {
 
892
      manager->watch (manager->window, False, 0, manager->cb_data);
 
893
      manager->terminate (manager->cb_data);
 
894
      free (manager);
 
895
      manager = NULL;
 
896
    }
 
897
  
 
898
  return manager;
 
899
}
 
900
 
 
901
void
 
902
clipboard_manager_destroy (ClipboardManager *manager)
 
903
{
 
904
  if (manager)
 
905
    {
 
906
      manager->watch (manager->window, False, 0, manager->cb_data);
 
907
      XDestroyWindow (manager->display, manager->window);
 
908
 
 
909
      list_foreach (manager->conversions, (Callback)conversion_free, NULL);
 
910
      list_free (manager->conversions);
 
911
 
 
912
      list_foreach (manager->contents, (Callback)target_data_unref, NULL);
 
913
      list_free (manager->contents);
 
914
 
 
915
      free (manager);
 
916
      manager = NULL;
 
917
    }
 
918
}
 
919