ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/clip_unix.cpp
(Generate patch)

Comparing SheepShaver/src/Unix/clip_unix.cpp (file contents):
Revision 1.1 by cebix, 2002-02-04T16:58:13Z vs.
Revision 1.2 by gbeauche, 2003-12-31T11:37:26Z

# Line 1 | Line 1
1   /*
2   *  clip_unix.cpp - Clipboard handling, Unix implementation
3   *
4 < *  SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
4 > *  SheepShaver (C) 1997-2003 Christian Bauer and Marc Hellwig
5   *
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
# Line 21 | Line 21
21   #include "sysdeps.h"
22  
23   #include <X11/Xlib.h>
24 + #include <X11/Xatom.h>
25 + #include <pthread.h>
26 + #include <set>
27 + #include <vector>
28  
29   #include "macos_util.h"
30   #include "clip.h"
31 + #include "prefs.h"
32 + #include "cpu_emulation.h"
33 + #include "main.h"
34 + #include "emul_op.h"
35  
36   #define DEBUG 0
37   #include "debug.h"
38  
39 + #ifndef NO_STD_NAMESPACE
40 + using std::set;
41 + using std::vector;
42 + #endif
43 +
44 +
45 + // Do we replace PutScrap()?
46 + #define REPLACE_PUTSCRAP 1
47 +
48 + // Do we replace GetScrap()?
49 + #define REPLACE_GETSCRAP 1
50 +
51 + // Do we want PutScrap() to ignore requests from klipper?
52 + #define PUTSCRAP_IGNORES_KLIPPER 0
53 +
54 + // Do we want GetScrap() to check for TIMESTAMP and optimize out clipboard syncs?
55 + #define GETSCRAP_REQUESTS_TIMESTAMP 0
56 +
57 + // Do we want GetScrap() to first check for TARGETS available from the clipboard?
58 + #define GETSCRAP_REQUESTS_TARGETS 0
59 +
60  
61   // From main_linux.cpp
62   extern Display *x_display;
# Line 53 | Line 82 | static const uint8 mac2iso[0x80] = {
82          0xaf, 0x20, 0xb7, 0xb0, 0xb8, 0x22, 0xb8, 0x20
83   };
84  
85 + static const uint8 iso2mac[0x80] = {
86 +        0xad, 0xb0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0,
87 +        0xf6, 0xe4, 0xde, 0xdc, 0xce, 0xb2, 0xb3, 0xb6,
88 +        0xb7, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1,
89 +        0xf7, 0xaa, 0xdf, 0xdd, 0xcf, 0xba, 0xfd, 0xd9,
90 +        0xca, 0xc1, 0xa2, 0xa3, 0xdb, 0xb4, 0xbd, 0xa4,
91 +        0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xf0, 0xa8, 0xf8,
92 +        0xa1, 0xb1, 0xc3, 0xc5, 0xab, 0xb5, 0xa6, 0xe1,
93 +        0xfc, 0xc6, 0xbc, 0xc8, 0xf9, 0xda, 0xd7, 0xc0,
94 +        0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82,
95 +        0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec,
96 +        0xf5, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xfb,
97 +        0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xfa, 0xb8, 0xa7,
98 +        0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d,
99 +        0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95,
100 +        0xfe, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6,
101 +        0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xff, 0xb9, 0xd8
102 + };
103 +
104 + // Flag: Don't convert clipboard text
105 + static bool no_clip_conversion;
106 +
107 + // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the Be side
108 + static bool we_put_this_data = false;
109 +
110 + // X11 variables
111 + static int screen;                                              // Screen number
112 + static Window rootwin, clip_win;                // Root window and the clipboard window
113 + static Atom xa_clipboard;
114 + static Atom xa_targets;
115 + static Atom xa_multiple;
116 + static Atom xa_timestamp;
117 + static Atom xa_atom_pair;
118 +
119 + // Define a byte array (rewrite if it's a bottleneck)
120 + struct ByteArray : public vector<uint8> {
121 +        void resize(int size) { reserve(size); vector<uint8>::resize(size); }
122 +        uint8 *data() { return &at(0); }
123 + };
124 +
125 + // Clipboard locks
126 + #ifdef HAVE_PTHREADS
127 + static pthread_mutex_t clip_lock = PTHREAD_MUTEX_INITIALIZER;
128 + #define LOCK_CLIPBOARD pthread_mutex_lock(&clip_lock);
129 + #define UNLOCK_CLIPBOARD pthread_mutex_unlock(&clip_lock);
130 + #elif defined(HAVE_SPINLOCKS)
131 + static spinlock_t clip_lock = SPIN_LOCK_UNLOCKED;
132 + #define LOCK_CLIPBOARD spin_lock(&clip_lock)
133 + #define UNLOCK_CLIPBOARD spin_unlock(&clip_lock)
134 + #else
135 + #define LOCK_CLIPBOARD
136 + #define UNLOCK_CLIPBOARD
137 + #endif
138 +
139 + // Clipboard data
140 + struct ClipboardData {
141 +        Time time;
142 +        uint32 type;
143 +        ByteArray data;
144 + };
145 + static ClipboardData clip_data;
146 +
147 +
148 + /*
149 + *  Read an X11 property (hack from QT 3.1.2)
150 + */
151 +
152 + static inline int max_selection_incr(Display *dpy)
153 + {
154 +        int max_request_size = 4 * XMaxRequestSize(dpy);
155 +        if (max_request_size > 4 * 65536)
156 +                max_request_size = 4 * 65536;
157 +        else if ((max_request_size -= 100) < 0)
158 +                max_request_size = 100;
159 +        return max_request_size;
160 + }
161 +
162 + static bool read_property(Display *dpy, Window win,
163 +                                                  Atom property, bool deleteProperty,
164 +                                                  ByteArray & buffer, int *size, Atom *type,
165 +                                                  int *format, bool nullterm)
166 + {
167 +        int maxsize = max_selection_incr(dpy);
168 +        unsigned long bytes_left;
169 +        unsigned long length;
170 +        unsigned char *data;
171 +        Atom dummy_type;
172 +        int dummy_format;
173 +
174 +        if (!type)
175 +                type = &dummy_type;
176 +        if (!format)
177 +                format = &dummy_format;
178 +
179 +        // Don't read anything but get the size of the property data
180 +        if (XGetWindowProperty(dpy, win, property, 0, 0, False,
181 +                                                   AnyPropertyType, type, format, &length, &bytes_left, &data) != Success) {
182 +                buffer.clear();
183 +                return false;
184 +        }
185 +        XFree(data);
186 +
187 +        int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left;
188 +
189 +        switch (*format) {
190 +        case 16:
191 +                format_inc = sizeof(short) / 2;
192 +                proplen *= format_inc;
193 +                break;
194 +        case 32:
195 +                format_inc = sizeof(long) / 4;
196 +                proplen *= format_inc;
197 +                break;
198 +        }
199 +
200 +        buffer.resize(proplen + (nullterm ? 1 : 0));
201 +        while (bytes_left) {
202 +                if (XGetWindowProperty(dpy, win, property, offset, maxsize / 4,
203 +                                                           False, AnyPropertyType, type, format,
204 +                                                           &length, &bytes_left, &data) != Success)
205 +                        break;
206 +
207 +                offset += length / (32 / *format);
208 +                length *= format_inc * (*format / 8);
209 +
210 +                memcpy(buffer.data() + buffer_offset, data, length);
211 +                buffer_offset += length;
212 +                XFree(data);
213 +        }
214 +
215 +        if (nullterm)
216 +                buffer[buffer_offset] = '\0';
217 +
218 +        if (size)
219 +                *size = buffer_offset;
220 +
221 +        if (deleteProperty)
222 +                XDeleteProperty(dpy, win, property);
223 +
224 +        XFlush(dpy);
225 +        return true;
226 + }
227 +
228 +
229 + /*
230 + *  Timed wait for an SelectionNotify event
231 + */
232 +
233 + static const uint64 SELECTION_MAX_WAIT = 500000; // 500 ms
234 + static volatile bool xselection_event_avail;
235 + static XSelectionEvent xselection_event;
236 +
237 + static bool wait_for_selection_notify_event(Display *dpy, Window win, int timeout)
238 + {
239 +        uint64 start = GetTicks_usec();
240 +
241 +        LOCK_CLIPBOARD;
242 +        xselection_event_avail = false;
243 +        UNLOCK_CLIPBOARD;
244 +
245 +        // First wait a very short period of time < the VideoRefresh() resolution
246 +        struct timespec req = {0, 5000000};
247 +        nanosleep(&req, NULL);
248 +
249 +        // FIXME: Since handle_events() is in a separate thread, wait for
250 +        // a SelectionNotify event to occur and reported here. The
251 +        // resolution of this wait action should match that of VideoRefresh()
252 +        if (xselection_event_avail)
253 +                return true;
254 +
255 +        do {
256 +                // Wait
257 +                struct timespec req = {0, 16666667};
258 +                nanosleep(&req, NULL);
259 +
260 +                // Return immediately if the event is now available
261 +                if (xselection_event_avail)
262 +                        return true;
263 +
264 +        } while ((GetTicks_usec() - start) < timeout);
265 +
266 +        return false;
267 + }
268 +
269 +
270 + /*
271 + *  Check for a "klipper" window which, in older versions (3.1), was
272 + *  polling and retrieving clipboard data several times per second.
273 + */
274 +
275 + static bool is_klipper_window_probe(Window w);
276 + static bool is_klipper_window_check(Window w);
277 + static bool (*is_klipper_window)(Window w) = is_klipper_window_probe;
278 + static Window klipper_win = None;
279 +
280 + static bool is_klipper_window_probe(Window w)
281 + {
282 +        // We expect "klipper" to be within the first clients to request
283 +        // data from our clipboard
284 +        static int clients_countdown = 2;
285 +
286 +        bool found = false;
287 +        char *window_name;
288 +        if (XFetchName(x_display, w, &window_name) && !strcmp(window_name, "klipper")) {
289 +                D(bug(" found and ignore clipboard requests from klipper window id: 0x%08x\n", w));
290 +                klipper_win = w;
291 +                found = true;
292 +        }
293 +
294 +        if (found || --clients_countdown <= 0)
295 +                is_klipper_window = is_klipper_window_check;
296 + }
297 +
298 + static bool is_klipper_window_check(Window w)
299 + {
300 +        return w == klipper_win;
301 + }
302 +
303  
304   /*
305   *  Initialization
# Line 60 | Line 307 | static const uint8 mac2iso[0x80] = {
307  
308   void ClipInit(void)
309   {
310 +        no_clip_conversion = PrefsFindBool("noclipconversion");
311 +
312 +        // Find screen and root window
313 +        screen = XDefaultScreen(x_display);
314 +        rootwin = XRootWindow(x_display, screen);
315 +
316 +        // Create fake window to receive selection events
317 +        clip_win = XCreateSimpleWindow(x_display, rootwin, 0, 0, 1, 1, 0, 0, 0);
318 +
319 +        // Initialize X11 atoms
320 +        xa_clipboard = XInternAtom(x_display, "CLIPBOARD", False);
321 +        xa_targets = XInternAtom(x_display, "TARGETS", False);
322 +        xa_multiple = XInternAtom(x_display, "MULTIPLE", False);
323 +        xa_timestamp = XInternAtom(x_display, "TIMESTAMP", False);
324 +        xa_atom_pair = XInternAtom(x_display, "ATOM_PAIR", False);
325   }
326  
327  
# Line 69 | Line 331 | void ClipInit(void)
331  
332   void ClipExit(void)
333   {
334 +        // Close window
335 +        XDestroyWindow(x_display, clip_win);
336   }
337  
338  
# Line 79 | Line 343 | void ClipExit(void)
343   void PutScrap(uint32 type, void *scrap, int32 length)
344   {
345          D(bug("PutScrap type %08lx, data %p, length %ld\n", type, scrap, length));
346 +        if (!REPLACE_PUTSCRAP)
347 +                return;
348 +        if (we_put_this_data) {
349 +                we_put_this_data = false;
350 +                return;
351 +        }
352          if (length <= 0)
353                  return;
354  
355 +        bool did_putscrap = false;
356          switch (type) {
357                  case FOURCC('T','E','X','T'):
358                          D(bug(" clipping TEXT\n"));
359 +                        clip_data.type = type;
360 +                        clip_data.data.clear();
361 +                        clip_data.data.reserve(length);
362  
363                          // Convert text from Mac charset to ISO-Latin1
90                        uint8 *buf = new uint8[length];
364                          uint8 *p = (uint8 *)scrap;
92                        uint8 *q = buf;
365                          for (int i=0; i<length; i++) {
366                                  uint8 c = *p++;
367                                  if (c < 0x80) {
368                                          if (c == 13)    // CR -> LF
369                                                  c = 10;
370 <                                } else
370 >                                } else if (!no_clip_conversion)
371                                          c = mac2iso[c & 0x7f];
372 <                                *q++ = c;
372 >                                clip_data.data.push_back(c);
373                          }
374 <
103 <                        // Put text into cut buffer
104 <                        //!! XStoreBytes(x_display, buf, length);
105 <                        delete[] buf;
374 >                        did_putscrap = true;
375                          break;
376          }
377 +
378 +        // Acquire selection ownership
379 +        if (did_putscrap) {
380 +                clip_data.time = CurrentTime;
381 +                while (XGetSelectionOwner(x_display, xa_clipboard) != clip_win)
382 +                        XSetSelectionOwner(x_display, xa_clipboard, clip_win, clip_data.time);
383 +        }
384   }
385  
386  
# Line 115 | Line 391 | void PutScrap(uint32 type, void *scrap,
391   void GetScrap(void **handle, uint32 type, int32 offset)
392   {
393          D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset));
394 <        switch (type) {
394 >        if (!REPLACE_GETSCRAP)
395 >                return;
396 >
397 >        // Check TIMESTAMP
398 > #if GETSCRAP_REQUESTS_TIMESTAMP
399 >        static Time last_timestamp = 0;
400 >        XConvertSelection(x_display, xa_clipboard, xa_timestamp, xa_clipboard, clip_win, CurrentTime);
401 >        if (wait_for_selection_notify_event(x_display, clip_win, SELECTION_MAX_WAIT) &&
402 >                xselection_event.property != None) {
403 >                ByteArray data;
404 >                if (read_property(x_display,
405 >                                                  xselection_event.requestor, xselection_event.property,
406 >                                                  true, data, 0, 0, 0, false)) {
407 >                        Time timestamp = ((long *)data.data())[0];
408 >                        if (timestamp == last_timestamp)
409 >                                return;
410 >                }
411 >        }
412 > #endif
413 >
414 >        // Get TARGETS available
415 > #if GETSCRAP_REQUESTS_TARGETS
416 >        XConvertSelection(x_display, xa_clipboard, xa_targets, xa_clipboard, clip_win, CurrentTime);
417 >        if (!wait_for_selection_notify_event(x_display, clip_win, SELECTION_MAX_WAIT) ||
418 >                xselection_event.property == None)
419 >                return;
420 >
421 >        ByteArray data;
422 >        if (!read_property(x_display,
423 >                                           xselection_event.requestor, xselection_event.property,
424 >                                           true, data, 0, 0, 0, false))
425 >                return;
426 > #endif
427 >
428 >        // Get appropriate format for requested data
429 >        Atom format = None;
430 > #if GETSCRAP_REQUESTS_TARGETS
431 >        int n_atoms = data.size() / sizeof(long);
432 >        long *atoms = (long *)data.data();
433 >        for (int i = 0; i < n_atoms; i++) {
434 >                Atom target = atoms[i];
435 >                switch (type) {
436                  case FOURCC('T','E','X','T'):
437                          D(bug(" clipping TEXT\n"));
438 <                        //!!
438 >                        if (target == XA_STRING)
439 >                                format = target;
440 >                        break;
441 >                case FOURCC('P','I','C','T'):
442 >                        break;
443 >                }
444 >        }
445 > #else
446 >        switch (type) {
447 >        case FOURCC('T','E','X','T'):
448 >                D(bug(" clipping TEXT\n"));
449 >                format = XA_STRING;
450 >                break;
451 >        case FOURCC('P','I','C','T'):
452 >                break;
453 >        }
454 > #endif
455 >        if (format == None)
456 >                return;
457 >
458 >        // Get the native clipboard data
459 >        XConvertSelection(x_display, xa_clipboard, format, xa_clipboard, clip_win, CurrentTime);
460 >        if (!wait_for_selection_notify_event(x_display, clip_win, SELECTION_MAX_WAIT) ||
461 >                xselection_event.property == None ||
462 >                !read_property(x_display,
463 >                                           xselection_event.requestor, xselection_event.property,
464 >                                           false, clip_data.data, 0, 0, 0, format == XA_STRING))
465 >                return;
466 >
467 >        clip_data.type = type;
468 >        clip_data.time = xselection_event.time;
469 >
470 >        // Allocate space for new scrap in MacOS side
471 >        M68kRegisters r;
472 >        r.d[0] = clip_data.data.size();
473 >        Execute68kTrap(0xa71e, &r);                     // NewPtrSysClear()
474 >        uint32 scrap_area = r.a[0];
475 >
476 >        if (scrap_area) {
477 >                switch (type) {
478 >                case FOURCC('T','E','X','T'):
479 >                        // Convert text from ISO-Latin1 to Mac charset
480 >                        uint8 *p = Mac2HostAddr(scrap_area);
481 >                        for (int i = 0; i < clip_data.data.size(); i++) {
482 >                                uint8 c = clip_data.data[i];
483 >                                if (c < 0x80) {
484 >                                        if (c == 10)    // LF -> CR
485 >                                                c = 13;
486 >                                } else if (!no_clip_conversion)
487 >                                        c = iso2mac[c & 0x7f];
488 >                                *p++ = c;
489 >                        }
490                          break;
491 +                }
492 +
493 +                // Add new data to clipboard
494 +                static uint8 proc[] = {
495 +                        0x59, 0x8f,                                     // subq.l       #4,sp
496 +                        0xa9, 0xfc,                                     // ZeroScrap()
497 +                        0x2f, 0x3c, 0, 0, 0, 0,         // move.l       #length,-(sp)
498 +                        0x2f, 0x3c, 0, 0, 0, 0,         // move.l       #type,-(sp)
499 +                        0x2f, 0x3c, 0, 0, 0, 0,         // move.l       #outbuf,-(sp)
500 +                        0xa9, 0xfe,                                     // PutScrap()
501 +                        0x58, 0x8f,                                     // addq.l       #4,sp
502 +                        M68K_RTS >> 8, M68K_RTS
503 +                };
504 +                uint32 proc_area = (uint32)proc; // FIXME: make sure 32-bit relocs are used
505 +                WriteMacInt32(proc_area +  6, clip_data.data.size());
506 +                WriteMacInt32(proc_area + 12, type);
507 +                WriteMacInt32(proc_area + 18, scrap_area);
508 +                we_put_this_data = true;
509 +                Execute68k(proc_area, &r);
510 +
511 +                // We are done with scratch memory
512 +                r.a[0] = scrap_area;
513 +                Execute68kTrap(0xa01f, &r);             // DisposePtr
514          }
515   }
516 +
517 +
518 + /*
519 + *      Handle X11 selection events
520 + */
521 +
522 + void ClipboardSelectionClear(XSelectionClearEvent *xev)
523 + {
524 +        if (xev->selection != xa_clipboard)
525 +                return;
526 +
527 +        D(bug("Selection cleared, lost clipboard ownership\n"));
528 +        clip_data.type = 0;
529 +        clip_data.data.clear();
530 + }
531 +
532 + // Top level selection handler
533 + static bool handle_selection(XSelectionRequestEvent *req, bool is_multiple);
534 +
535 + static bool handle_selection_TIMESTAMP(XSelectionRequestEvent *req)
536 + {
537 +        // 32-bit integer values are always passed as a long whatever is its size
538 +        long timestamp = clip_data.time;
539 +
540 +        // Change requestor property
541 +        XChangeProperty(x_display, req->requestor, req->property,
542 +                                        XA_INTEGER, 32,
543 +                                        PropModeReplace, (uint8 *)&timestamp, 1);
544 +
545 +        return true;
546 + }
547 +
548 + static bool handle_selection_TARGETS(XSelectionRequestEvent *req)
549 + {
550 +        // Default supported targets
551 +        vector<long> targets;
552 +        targets.push_back(xa_targets);
553 +        targets.push_back(xa_multiple);
554 +        targets.push_back(xa_timestamp);
555 +
556 +        // Extra targets matchin current clipboard data
557 +        switch (clip_data.type) {
558 +        case FOURCC('T','E','X','T'):
559 +                targets.push_back(XA_STRING);
560 +                break;
561 +        case FOURCC('P','I','C','T'):
562 +                break;
563 +        }
564 +
565 +        // Change requestor property
566 +        XChangeProperty(x_display, req->requestor, req->property,
567 +                                        xa_targets, 32,
568 +                                        PropModeReplace, (uint8 *)&targets.at(0), targets.size());
569 +
570 +        return true;
571 + }
572 +
573 + static bool handle_selection_STRING(XSelectionRequestEvent *req)
574 + {
575 +        // Make sure we have valid data to send though ICCCM compliant
576 +        // clients should have first requested TARGETS to identify
577 +        // this possibility.
578 +        if (clip_data.type != FOURCC('T','E','X','T'))
579 +                return false;
580 +
581 +        // Send the string, it's already encoded as ISO-8859-1
582 +        XChangeProperty(x_display, req->requestor, req->property,
583 +                                        XA_STRING, 8,
584 +                                        PropModeReplace, (uint8 *)clip_data.data.data(), clip_data.data.size());
585 +
586 +        return true;
587 + }
588 +
589 + static bool handle_selection_MULTIPLE(XSelectionRequestEvent *req)
590 + {
591 +        Atom rtype;
592 +        int rformat;
593 +        ByteArray data;
594 +
595 +        if (!read_property(x_display, req->requestor, req->property,
596 +                                          false, data, 0, &rtype, &rformat, 0))
597 +                return false;
598 +
599 +        // rtype should be ATOM_PAIR but some clients don't honour that
600 +        if (rformat != 32)
601 +                return false;
602 +
603 +        struct AtomPair { long target; long property; };
604 +        AtomPair *atom_pairs = (AtomPair *)data.data();
605 +        int n_atom_pairs = data.size() / sizeof(AtomPair);
606 +
607 +        bool handled = true;
608 +        if (n_atom_pairs) {
609 +                // Setup a new XSelectionRequestEvent when servicing individual requests
610 +                XSelectionRequestEvent event;
611 +                memcpy(&event, req, sizeof(event));
612 +
613 +                for (int i = 0; i < n_atom_pairs; i++) {
614 +                        Atom target = atom_pairs[i].target;
615 +                        Atom property = atom_pairs[i].property;
616 +
617 +                        // None is not a valid property
618 +                        if (property == None)
619 +                                continue;
620 +
621 +                        // Service this request
622 +                        event.target = target;
623 +                        event.property = property;
624 +                        if (!handle_selection(&event, true)) {
625 +                                /* FIXME: ICCCM 2.6.2:
626 +
627 +                                   If the owner fails to convert the target named by an
628 +                                   atom in the MULTIPLE property, it should replace that
629 +                                   atom in the property with None.
630 +                                */
631 +                                handled = false;
632 +                        }
633 +                }
634 +        }
635 +
636 +        return handled;
637 + }
638 +
639 + static bool handle_selection(XSelectionRequestEvent *req, bool is_multiple)
640 + {
641 +        bool handled =false;
642 +
643 +        if (req->target == xa_timestamp)
644 +                handled = handle_selection_TIMESTAMP(req);
645 +        else if (req->target == xa_targets)
646 +                handled = handle_selection_TARGETS(req);
647 +        else if (req->target == XA_STRING)
648 +                handled = handle_selection_STRING(req);
649 +        else if (req->target == xa_multiple)
650 +                handled = handle_selection_MULTIPLE(req);
651 +
652 +        // Notify requestor only when we are done with his request
653 +        if (handled && !is_multiple) {
654 +                XEvent out_event;
655 +                out_event.xselection.type      = SelectionNotify;
656 +                out_event.xselection.requestor = req->requestor;
657 +                out_event.xselection.selection = req->selection;
658 +                out_event.xselection.target    = req->target;
659 +                out_event.xselection.property  = handled ? req->property : None;
660 +                out_event.xselection.time      = req->time;
661 +                XSendEvent(x_display, req->requestor, False, 0, &out_event);
662 +        }
663 + }
664 +
665 + void ClipboardSelectionRequest(XSelectionRequestEvent *req)
666 + {
667 +        if (req->requestor == clip_win || req->selection != xa_clipboard)
668 +                return;
669 +
670 + #if PUTSCRAP_IGNORES_KLIPPER
671 +        if (is_klipper_window(req->requestor))
672 +                return;
673 + #endif
674 +
675 +        D(bug("Selection requested from 0x%lx to 0x%lx (%s) 0x%lx (%s)\n",
676 +                  req->requestor,
677 +                  req->selection,
678 +                  XGetAtomName(req->display, req->selection),
679 +                  req->target,
680 +                  XGetAtomName(req->display, req->target)));
681 +
682 +        handle_selection(req, false);
683 + }
684 +
685 + void ClipboardSelectionNotify(XSelectionEvent *req)
686 + {
687 +        if (req->requestor != clip_win || req->selection != xa_clipboard)
688 +                return;
689 +
690 +        D(bug("Selection is now available\n"));
691 +        memcpy(&xselection_event, req, sizeof(xselection_event));
692 +        LOCK_CLIPBOARD;
693 +        xselection_event_avail = true;
694 +        UNLOCK_CLIPBOARD;
695 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines