ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/clip_unix.cpp
Revision: 1.4
Committed: 2003-12-31T18:23:41Z (20 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.3: +0 -42 lines
Log Message:
Remove the "klipper" hack since it now (in KDE 3.2) checks for TIMESTAMP.
Besides, we are as smooth as before with last commits.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * clip_unix.cpp - Clipboard handling, Unix implementation
3     *
4 gbeauche 1.2 * SheepShaver (C) 1997-2003 Christian Bauer and Marc Hellwig
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21 gbeauche 1.3 /*
22     * NOTES:
23     *
24     * We must have (fast) X11 display locking routines. Otherwise, we
25     * can corrupt the X11 event queue from the emulator thread whereas
26     * the redraw thread is expected to handle them.
27     *
28     * Two functions are exported to video_x.cpp:
29     * - ClipboardSelectionClear()
30     * called when we lose the selection ownership
31     * - ClipboardSelectionRequest()
32     * called when another client wants our clipboard data
33     * The display is locked by the redraw thread during their execution.
34     *
35     * On PutScrap (Mac application wrote to clipboard), we always cache
36     * the Mac clipboard to a local structure (clip_data). Then, the
37     * selection ownership is grabbed until ClipboardSelectionClear()
38     * occurs. In that case, contents in cache becomes invalid.
39     *
40     * On GetScrap (Mac application reads clipboard), we always fetch
41     * data from the X11 clipboard and immediately put it back to Mac
42     * side. Local cache does not need to be updated. If the selection
43     * owner supports the TIMESTAMP target, we can avoid useless copies.
44     *
45     * For safety purposes, we lock the X11 display in the emulator
46     * thread during the whole GetScrap/PutScrap execution. Of course, we
47     * temporarily release the lock when waiting for SelectioNotify.
48     */
49    
50 cebix 1.1 #include "sysdeps.h"
51    
52     #include <X11/Xlib.h>
53 gbeauche 1.2 #include <X11/Xatom.h>
54     #include <pthread.h>
55     #include <vector>
56 cebix 1.1
57     #include "macos_util.h"
58     #include "clip.h"
59 gbeauche 1.2 #include "prefs.h"
60     #include "cpu_emulation.h"
61     #include "main.h"
62     #include "emul_op.h"
63 cebix 1.1
64     #define DEBUG 0
65     #include "debug.h"
66    
67 gbeauche 1.2 #ifndef NO_STD_NAMESPACE
68     using std::vector;
69     #endif
70    
71    
72     // Do we replace PutScrap()?
73     #define REPLACE_PUTSCRAP 1
74    
75     // Do we replace GetScrap()?
76     #define REPLACE_GETSCRAP 1
77    
78     // Do we want GetScrap() to check for TIMESTAMP and optimize out clipboard syncs?
79     #define GETSCRAP_REQUESTS_TIMESTAMP 0
80    
81     // Do we want GetScrap() to first check for TARGETS available from the clipboard?
82     #define GETSCRAP_REQUESTS_TARGETS 0
83    
84 cebix 1.1
85     // From main_linux.cpp
86     extern Display *x_display;
87    
88    
89     // Conversion tables
90     static const uint8 mac2iso[0x80] = {
91     0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
92     0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
93     0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
94     0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
95     0x2b, 0xb0, 0xa2, 0xa3, 0xa7, 0xb7, 0xb6, 0xdf,
96     0xae, 0xa9, 0x20, 0xb4, 0xa8, 0x23, 0xc6, 0xd8,
97     0x20, 0xb1, 0x3c, 0x3e, 0xa5, 0xb5, 0xf0, 0x53,
98     0x50, 0x70, 0x2f, 0xaa, 0xba, 0x4f, 0xe6, 0xf8,
99     0xbf, 0xa1, 0xac, 0x2f, 0x66, 0x7e, 0x44, 0xab,
100     0xbb, 0x2e, 0x20, 0xc0, 0xc3, 0xd5, 0x4f, 0x6f,
101     0x2d, 0x2d, 0x22, 0x22, 0x60, 0x27, 0xf7, 0x20,
102     0xff, 0x59, 0x2f, 0xa4, 0x3c, 0x3e, 0x66, 0x66,
103     0x23, 0xb7, 0x2c, 0x22, 0x25, 0xc2, 0xca, 0xc1,
104     0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
105     0x20, 0xd2, 0xda, 0xdb, 0xd9, 0x69, 0x5e, 0x7e,
106     0xaf, 0x20, 0xb7, 0xb0, 0xb8, 0x22, 0xb8, 0x20
107     };
108    
109 gbeauche 1.2 static const uint8 iso2mac[0x80] = {
110     0xad, 0xb0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0,
111     0xf6, 0xe4, 0xde, 0xdc, 0xce, 0xb2, 0xb3, 0xb6,
112     0xb7, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1,
113     0xf7, 0xaa, 0xdf, 0xdd, 0xcf, 0xba, 0xfd, 0xd9,
114     0xca, 0xc1, 0xa2, 0xa3, 0xdb, 0xb4, 0xbd, 0xa4,
115     0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xf0, 0xa8, 0xf8,
116     0xa1, 0xb1, 0xc3, 0xc5, 0xab, 0xb5, 0xa6, 0xe1,
117     0xfc, 0xc6, 0xbc, 0xc8, 0xf9, 0xda, 0xd7, 0xc0,
118     0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82,
119     0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec,
120     0xf5, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xfb,
121     0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xfa, 0xb8, 0xa7,
122     0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d,
123     0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95,
124     0xfe, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6,
125     0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xff, 0xb9, 0xd8
126     };
127    
128     // Flag: Don't convert clipboard text
129     static bool no_clip_conversion;
130    
131     // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the Be side
132     static bool we_put_this_data = false;
133    
134     // X11 variables
135     static int screen; // Screen number
136     static Window rootwin, clip_win; // Root window and the clipboard window
137     static Atom xa_clipboard;
138     static Atom xa_targets;
139     static Atom xa_multiple;
140     static Atom xa_timestamp;
141     static Atom xa_atom_pair;
142    
143     // Define a byte array (rewrite if it's a bottleneck)
144     struct ByteArray : public vector<uint8> {
145     void resize(int size) { reserve(size); vector<uint8>::resize(size); }
146     uint8 *data() { return &at(0); }
147     };
148    
149 gbeauche 1.3 // Clipboard data for requestors
150 gbeauche 1.2 struct ClipboardData {
151     Time time;
152 gbeauche 1.3 Atom type;
153 gbeauche 1.2 ByteArray data;
154     };
155     static ClipboardData clip_data;
156    
157 gbeauche 1.3 // Prototypes
158     static void do_putscrap(uint32 type, void *scrap, int32 length);
159     static void do_getscrap(void **handle, uint32 type, int32 offset);
160    
161 gbeauche 1.2
162     /*
163     * Read an X11 property (hack from QT 3.1.2)
164     */
165    
166     static inline int max_selection_incr(Display *dpy)
167     {
168     int max_request_size = 4 * XMaxRequestSize(dpy);
169     if (max_request_size > 4 * 65536)
170     max_request_size = 4 * 65536;
171     else if ((max_request_size -= 100) < 0)
172     max_request_size = 100;
173     return max_request_size;
174     }
175    
176     static bool read_property(Display *dpy, Window win,
177     Atom property, bool deleteProperty,
178     ByteArray & buffer, int *size, Atom *type,
179     int *format, bool nullterm)
180     {
181     int maxsize = max_selection_incr(dpy);
182     unsigned long bytes_left;
183     unsigned long length;
184     unsigned char *data;
185     Atom dummy_type;
186     int dummy_format;
187    
188     if (!type)
189     type = &dummy_type;
190     if (!format)
191     format = &dummy_format;
192    
193     // Don't read anything but get the size of the property data
194     if (XGetWindowProperty(dpy, win, property, 0, 0, False,
195     AnyPropertyType, type, format, &length, &bytes_left, &data) != Success) {
196     buffer.clear();
197     return false;
198     }
199     XFree(data);
200    
201     int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left;
202    
203     switch (*format) {
204     case 16:
205     format_inc = sizeof(short) / 2;
206     proplen *= format_inc;
207     break;
208     case 32:
209     format_inc = sizeof(long) / 4;
210     proplen *= format_inc;
211     break;
212     }
213    
214     buffer.resize(proplen + (nullterm ? 1 : 0));
215     while (bytes_left) {
216     if (XGetWindowProperty(dpy, win, property, offset, maxsize / 4,
217     False, AnyPropertyType, type, format,
218     &length, &bytes_left, &data) != Success)
219     break;
220    
221     offset += length / (32 / *format);
222     length *= format_inc * (*format / 8);
223    
224     memcpy(buffer.data() + buffer_offset, data, length);
225     buffer_offset += length;
226     XFree(data);
227     }
228    
229     if (nullterm)
230     buffer[buffer_offset] = '\0';
231    
232     if (size)
233     *size = buffer_offset;
234    
235     if (deleteProperty)
236     XDeleteProperty(dpy, win, property);
237    
238     XFlush(dpy);
239     return true;
240     }
241    
242    
243     /*
244     * Timed wait for an SelectionNotify event
245     */
246    
247     static const uint64 SELECTION_MAX_WAIT = 500000; // 500 ms
248    
249 gbeauche 1.3 static bool wait_for_selection_notify_event(Display *dpy, Window win, XEvent *event, int timeout)
250 gbeauche 1.2 {
251     uint64 start = GetTicks_usec();
252    
253     do {
254     // Wait
255 gbeauche 1.3 XDisplayUnlock();
256     Delay_usec(5000);
257     XDisplayLock();
258 gbeauche 1.2
259 gbeauche 1.3 // Check for SelectionNotify event
260     if (XCheckTypedWindowEvent(dpy, win, SelectionNotify, event))
261 gbeauche 1.2 return true;
262    
263     } while ((GetTicks_usec() - start) < timeout);
264    
265     return false;
266     }
267    
268    
269     /*
270 cebix 1.1 * Initialization
271     */
272    
273     void ClipInit(void)
274     {
275 gbeauche 1.2 no_clip_conversion = PrefsFindBool("noclipconversion");
276    
277     // Find screen and root window
278     screen = XDefaultScreen(x_display);
279     rootwin = XRootWindow(x_display, screen);
280    
281     // Create fake window to receive selection events
282     clip_win = XCreateSimpleWindow(x_display, rootwin, 0, 0, 1, 1, 0, 0, 0);
283    
284     // Initialize X11 atoms
285     xa_clipboard = XInternAtom(x_display, "CLIPBOARD", False);
286     xa_targets = XInternAtom(x_display, "TARGETS", False);
287     xa_multiple = XInternAtom(x_display, "MULTIPLE", False);
288     xa_timestamp = XInternAtom(x_display, "TIMESTAMP", False);
289     xa_atom_pair = XInternAtom(x_display, "ATOM_PAIR", False);
290 cebix 1.1 }
291    
292    
293     /*
294     * Deinitialization
295     */
296    
297     void ClipExit(void)
298     {
299 gbeauche 1.2 // Close window
300     XDestroyWindow(x_display, clip_win);
301 cebix 1.1 }
302    
303    
304     /*
305     * Mac application wrote to clipboard
306     */
307    
308     void PutScrap(uint32 type, void *scrap, int32 length)
309     {
310     D(bug("PutScrap type %08lx, data %p, length %ld\n", type, scrap, length));
311 gbeauche 1.2 if (!REPLACE_PUTSCRAP)
312     return;
313     if (we_put_this_data) {
314     we_put_this_data = false;
315     return;
316     }
317 cebix 1.1 if (length <= 0)
318     return;
319    
320 gbeauche 1.3 XDisplayLock();
321     do_putscrap(type, scrap, length);
322     XDisplayUnlock();
323     }
324    
325     static void do_putscrap(uint32 type, void *scrap, int32 length)
326     {
327     clip_data.type = None;
328 cebix 1.1 switch (type) {
329 gbeauche 1.3 case FOURCC('T','E','X','T'):
330     D(bug(" clipping TEXT\n"));
331     clip_data.type = XA_STRING;
332     clip_data.data.clear();
333     clip_data.data.reserve(length);
334    
335     // Convert text from Mac charset to ISO-Latin1
336     uint8 *p = (uint8 *)scrap;
337     for (int i=0; i<length; i++) {
338     uint8 c = *p++;
339     if (c < 0x80) {
340     if (c == 13) // CR -> LF
341     c = 10;
342     } else if (!no_clip_conversion)
343     c = mac2iso[c & 0x7f];
344     clip_data.data.push_back(c);
345     }
346     break;
347 gbeauche 1.2 }
348 cebix 1.1
349 gbeauche 1.2 // Acquire selection ownership
350 gbeauche 1.3 if (clip_data.type != None) {
351 gbeauche 1.2 clip_data.time = CurrentTime;
352     while (XGetSelectionOwner(x_display, xa_clipboard) != clip_win)
353     XSetSelectionOwner(x_display, xa_clipboard, clip_win, clip_data.time);
354 cebix 1.1 }
355     }
356    
357    
358     /*
359     * Mac application reads clipboard
360     */
361    
362     void GetScrap(void **handle, uint32 type, int32 offset)
363     {
364     D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset));
365 gbeauche 1.2 if (!REPLACE_GETSCRAP)
366     return;
367    
368 gbeauche 1.3 XDisplayLock();
369     do_getscrap(handle, type, offset);
370     XDisplayUnlock();
371     }
372    
373     static void do_getscrap(void **handle, uint32 type, int32 offset)
374     {
375     ByteArray data;
376     XEvent event;
377    
378     // If we own the selection, the data is already available on MacOS side
379     if (XGetSelectionOwner(x_display, xa_clipboard) == clip_win)
380     return;
381    
382 gbeauche 1.2 // Check TIMESTAMP
383     #if GETSCRAP_REQUESTS_TIMESTAMP
384     static Time last_timestamp = 0;
385     XConvertSelection(x_display, xa_clipboard, xa_timestamp, xa_clipboard, clip_win, CurrentTime);
386 gbeauche 1.3 if (wait_for_selection_notify_event(x_display, clip_win, &event, SELECTION_MAX_WAIT) &&
387     event.xselection.property != None &&
388     read_property(x_display,
389     event.xselection.requestor, event.xselection.property,
390     true, data, 0, 0, 0, false)) {
391     Time timestamp = ((long *)data.data())[0];
392     if (timestamp <= last_timestamp)
393     return;
394 gbeauche 1.2 }
395 gbeauche 1.3 last_timestamp = CurrentTime;
396 gbeauche 1.2 #endif
397    
398     // Get TARGETS available
399     #if GETSCRAP_REQUESTS_TARGETS
400     XConvertSelection(x_display, xa_clipboard, xa_targets, xa_clipboard, clip_win, CurrentTime);
401 gbeauche 1.3 if (!wait_for_selection_notify_event(x_display, clip_win, &event, SELECTION_MAX_WAIT) ||
402     event.xselection.property == None ||
403     !read_property(x_display,
404     event.xselection.requestor, event.xselection.property,
405 gbeauche 1.2 true, data, 0, 0, 0, false))
406     return;
407     #endif
408    
409     // Get appropriate format for requested data
410     Atom format = None;
411     #if GETSCRAP_REQUESTS_TARGETS
412     int n_atoms = data.size() / sizeof(long);
413     long *atoms = (long *)data.data();
414     for (int i = 0; i < n_atoms; i++) {
415     Atom target = atoms[i];
416     switch (type) {
417     case FOURCC('T','E','X','T'):
418     D(bug(" clipping TEXT\n"));
419     if (target == XA_STRING)
420     format = target;
421     break;
422     case FOURCC('P','I','C','T'):
423     break;
424     }
425     }
426     #else
427 cebix 1.1 switch (type) {
428 gbeauche 1.2 case FOURCC('T','E','X','T'):
429     D(bug(" clipping TEXT\n"));
430     format = XA_STRING;
431     break;
432     case FOURCC('P','I','C','T'):
433     break;
434     }
435     #endif
436     if (format == None)
437     return;
438    
439     // Get the native clipboard data
440     XConvertSelection(x_display, xa_clipboard, format, xa_clipboard, clip_win, CurrentTime);
441 gbeauche 1.3 if (!wait_for_selection_notify_event(x_display, clip_win, &event, SELECTION_MAX_WAIT) ||
442     event.xselection.property == None ||
443 gbeauche 1.2 !read_property(x_display,
444 gbeauche 1.3 event.xselection.requestor, event.xselection.property,
445     false, data, 0, 0, 0, format == XA_STRING))
446 gbeauche 1.2 return;
447    
448     // Allocate space for new scrap in MacOS side
449     M68kRegisters r;
450 gbeauche 1.3 r.d[0] = data.size();
451 gbeauche 1.2 Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
452     uint32 scrap_area = r.a[0];
453    
454     if (scrap_area) {
455     switch (type) {
456 cebix 1.1 case FOURCC('T','E','X','T'):
457 gbeauche 1.2 // Convert text from ISO-Latin1 to Mac charset
458     uint8 *p = Mac2HostAddr(scrap_area);
459 gbeauche 1.3 for (int i = 0; i < data.size(); i++) {
460     uint8 c = data[i];
461 gbeauche 1.2 if (c < 0x80) {
462     if (c == 10) // LF -> CR
463     c = 13;
464     } else if (!no_clip_conversion)
465     c = iso2mac[c & 0x7f];
466     *p++ = c;
467     }
468 cebix 1.1 break;
469 gbeauche 1.2 }
470    
471     // Add new data to clipboard
472     static uint8 proc[] = {
473     0x59, 0x8f, // subq.l #4,sp
474     0xa9, 0xfc, // ZeroScrap()
475     0x2f, 0x3c, 0, 0, 0, 0, // move.l #length,-(sp)
476     0x2f, 0x3c, 0, 0, 0, 0, // move.l #type,-(sp)
477     0x2f, 0x3c, 0, 0, 0, 0, // move.l #outbuf,-(sp)
478     0xa9, 0xfe, // PutScrap()
479     0x58, 0x8f, // addq.l #4,sp
480     M68K_RTS >> 8, M68K_RTS
481     };
482     uint32 proc_area = (uint32)proc; // FIXME: make sure 32-bit relocs are used
483 gbeauche 1.3 WriteMacInt32(proc_area + 6, data.size());
484 gbeauche 1.2 WriteMacInt32(proc_area + 12, type);
485     WriteMacInt32(proc_area + 18, scrap_area);
486     we_put_this_data = true;
487     Execute68k(proc_area, &r);
488    
489     // We are done with scratch memory
490     r.a[0] = scrap_area;
491     Execute68kTrap(0xa01f, &r); // DisposePtr
492 cebix 1.1 }
493 gbeauche 1.2 }
494    
495    
496     /*
497     * Handle X11 selection events
498     */
499    
500     void ClipboardSelectionClear(XSelectionClearEvent *xev)
501     {
502     if (xev->selection != xa_clipboard)
503     return;
504    
505     D(bug("Selection cleared, lost clipboard ownership\n"));
506 gbeauche 1.3 clip_data.type = None;
507 gbeauche 1.2 clip_data.data.clear();
508     }
509    
510     // Top level selection handler
511     static bool handle_selection(XSelectionRequestEvent *req, bool is_multiple);
512    
513     static bool handle_selection_TIMESTAMP(XSelectionRequestEvent *req)
514     {
515     // 32-bit integer values are always passed as a long whatever is its size
516     long timestamp = clip_data.time;
517    
518     // Change requestor property
519     XChangeProperty(x_display, req->requestor, req->property,
520     XA_INTEGER, 32,
521     PropModeReplace, (uint8 *)&timestamp, 1);
522    
523     return true;
524     }
525    
526     static bool handle_selection_TARGETS(XSelectionRequestEvent *req)
527     {
528     // Default supported targets
529     vector<long> targets;
530     targets.push_back(xa_targets);
531     targets.push_back(xa_multiple);
532     targets.push_back(xa_timestamp);
533    
534     // Extra targets matchin current clipboard data
535 gbeauche 1.3 if (clip_data.type != None)
536     targets.push_back(clip_data.type);
537 gbeauche 1.2
538     // Change requestor property
539     XChangeProperty(x_display, req->requestor, req->property,
540     xa_targets, 32,
541     PropModeReplace, (uint8 *)&targets.at(0), targets.size());
542    
543     return true;
544     }
545    
546     static bool handle_selection_STRING(XSelectionRequestEvent *req)
547     {
548     // Make sure we have valid data to send though ICCCM compliant
549     // clients should have first requested TARGETS to identify
550     // this possibility.
551 gbeauche 1.3 if (clip_data.type != XA_STRING)
552 gbeauche 1.2 return false;
553    
554     // Send the string, it's already encoded as ISO-8859-1
555     XChangeProperty(x_display, req->requestor, req->property,
556     XA_STRING, 8,
557     PropModeReplace, (uint8 *)clip_data.data.data(), clip_data.data.size());
558    
559     return true;
560     }
561    
562     static bool handle_selection_MULTIPLE(XSelectionRequestEvent *req)
563     {
564     Atom rtype;
565     int rformat;
566     ByteArray data;
567    
568     if (!read_property(x_display, req->requestor, req->property,
569     false, data, 0, &rtype, &rformat, 0))
570     return false;
571    
572     // rtype should be ATOM_PAIR but some clients don't honour that
573     if (rformat != 32)
574     return false;
575    
576     struct AtomPair { long target; long property; };
577     AtomPair *atom_pairs = (AtomPair *)data.data();
578     int n_atom_pairs = data.size() / sizeof(AtomPair);
579    
580     bool handled = true;
581     if (n_atom_pairs) {
582     // Setup a new XSelectionRequestEvent when servicing individual requests
583     XSelectionRequestEvent event;
584     memcpy(&event, req, sizeof(event));
585    
586     for (int i = 0; i < n_atom_pairs; i++) {
587     Atom target = atom_pairs[i].target;
588     Atom property = atom_pairs[i].property;
589    
590     // None is not a valid property
591     if (property == None)
592     continue;
593    
594     // Service this request
595     event.target = target;
596     event.property = property;
597     if (!handle_selection(&event, true)) {
598     /* FIXME: ICCCM 2.6.2:
599    
600     If the owner fails to convert the target named by an
601     atom in the MULTIPLE property, it should replace that
602     atom in the property with None.
603     */
604     handled = false;
605     }
606     }
607     }
608    
609     return handled;
610     }
611    
612     static bool handle_selection(XSelectionRequestEvent *req, bool is_multiple)
613     {
614     bool handled =false;
615    
616     if (req->target == xa_timestamp)
617     handled = handle_selection_TIMESTAMP(req);
618     else if (req->target == xa_targets)
619     handled = handle_selection_TARGETS(req);
620     else if (req->target == XA_STRING)
621     handled = handle_selection_STRING(req);
622     else if (req->target == xa_multiple)
623     handled = handle_selection_MULTIPLE(req);
624    
625     // Notify requestor only when we are done with his request
626     if (handled && !is_multiple) {
627     XEvent out_event;
628     out_event.xselection.type = SelectionNotify;
629     out_event.xselection.requestor = req->requestor;
630     out_event.xselection.selection = req->selection;
631     out_event.xselection.target = req->target;
632     out_event.xselection.property = handled ? req->property : None;
633     out_event.xselection.time = req->time;
634     XSendEvent(x_display, req->requestor, False, 0, &out_event);
635     }
636     }
637    
638     void ClipboardSelectionRequest(XSelectionRequestEvent *req)
639     {
640     if (req->requestor == clip_win || req->selection != xa_clipboard)
641     return;
642    
643     D(bug("Selection requested from 0x%lx to 0x%lx (%s) 0x%lx (%s)\n",
644     req->requestor,
645     req->selection,
646     XGetAtomName(req->display, req->selection),
647     req->target,
648     XGetAtomName(req->display, req->target)));
649    
650     handle_selection(req, false);
651 cebix 1.1 }