1
2 /* Handle clipboard text and data in arbitrary formats */
3
4 #include "xpclient_sdl.h"
5 /*#include <stdio.h>
6 #include <limits.h>
7
8 #include "SDL.h"
9 #include "SDL_syswm.h"*/
10
11 #include "scrap.h"
12
13 /* Miscellaneous defines */
14 #define PUBLIC
15 #define PRIVATE static
16
17 /* Determine what type of clipboard we are using */
18 #if defined(__unix__) && !defined(__QNXNTO__)
19 #define X11_SCRAP
20 #elif defined(__WIN32__)
21 #define WIN_SCRAP
22 #elif defined(__QNXNTO__)
23 #define QNX_SCRAP
24 #elif defined(MACOSX_FRAMEWORKS)
25 #define MAC_SCRAP
26 #else
27 #error Unknown window manager for clipboard handling
28 #endif /* scrap type */
29
30 #if defined(MAC_SCRAP) /* for now, these functions are stubbed out */
init_scrap(void)31 int init_scrap(void) { return 0; }
lost_scrap(void)32 int lost_scrap(void) { return 0; }
put_scrap(int type,int srclen,char * src)33 void put_scrap(int type, int srclen, char *src) { }
get_scrap(int type,int * dstlen,char ** dst)34 void get_scrap(int type, int *dstlen, char **dst) {
35 *dstlen = 0;
36 *dst = NULL;
37 }
38 #else
39
40 /* System dependent data types */
41 #if defined(X11_SCRAP)
42 /* * */
43 typedef Atom scrap_type;
44
45 #elif defined(WIN_SCRAP)
46 /* * */
47 typedef UINT scrap_type;
48
49 #elif defined(QNX_SCRAP)
50 /* * */
51 typedef uint32_t scrap_type;
52 #define Ph_CL_TEXT TextScrap('T', 'E', 'X', 'T')
53
54 #endif /* scrap type */
55
56 /* System dependent variables */
57 #if defined(X11_SCRAP)
58 /* * */
59 static Display *SDL_Display;
60 static Window SDL_Window;
61 static void (*Lock_Display)(void);
62 static void (*Unlock_Display)(void);
63
64 #elif defined(WIN_SCRAP)
65 /* * */
66 static HWND SDL_Window;
67
68 #elif defined(QNX_SCRAP)
69 /* * */
70 static unsigned short InputGroup;
71
72 #endif /* scrap type */
73
74 #define FORMAT_PREFIX "SDL_scrap_0x"
75
76 PRIVATE scrap_type
convert_format(int type)77 convert_format(int type)
78 {
79 switch (type)
80 {
81
82 case TextScrap('T', 'E', 'X', 'T'):
83 #if defined(X11_SCRAP)
84 /* * */
85 return XA_STRING;
86
87 #elif defined(WIN_SCRAP)
88 /* * */
89 return CF_TEXT;
90
91 #elif defined(QNX_SCRAP)
92 /* * */
93 return Ph_CL_TEXT;
94
95 #endif /* scrap type */
96
97 default:
98 {
99 char format[sizeof(FORMAT_PREFIX)+8+1];
100
101 sprintf(format, "%s%08lx", FORMAT_PREFIX, (unsigned long)type);
102
103 #if defined(X11_SCRAP)
104 /* * */
105 return XInternAtom(SDL_Display, format, False);
106
107 #elif defined(WIN_SCRAP)
108 /* * */
109 return RegisterClipboardFormat(format);
110
111 #endif /* scrap type */
112 }
113 }
114 }
115
116 /* Convert internal data to scrap format */
117 PRIVATE int
convert_data(int type,char * dst,char * src,int srclen)118 convert_data(int type, char *dst, char *src, int srclen)
119 {
120 int dstlen;
121
122 dstlen = 0;
123 switch (type)
124 {
125 case TextScrap('T', 'E', 'X', 'T'):
126 if ( dst )
127 {
128 while ( --srclen >= 0 )
129 {
130 #if defined(__unix__)
131 if ( *src == '\r' )
132 {
133 *dst++ = '\n';
134 ++dstlen;
135 }
136 else
137 #elif defined(__WIN32__)
138 if ( *src == '\r' )
139 {
140 *dst++ = '\r';
141 ++dstlen;
142 *dst++ = '\n';
143 ++dstlen;
144 }
145 else
146 #endif
147 {
148 *dst++ = *src;
149 ++dstlen;
150 }
151 ++src;
152 }
153 *dst = '\0';
154 ++dstlen;
155 }
156 else
157 {
158 while ( --srclen >= 0 )
159 {
160 #if defined(__unix__)
161 if ( *src == '\r' )
162 {
163 ++dstlen;
164 }
165 else
166 #elif defined(__WIN32__)
167 if ( *src == '\r' )
168 {
169 ++dstlen;
170 ++dstlen;
171 }
172 else
173 #endif
174 {
175 ++dstlen;
176 }
177 ++src;
178 }
179 ++dstlen;
180 }
181 break;
182
183 default:
184 if ( dst )
185 {
186 *(int *)dst = srclen;
187 dst += sizeof(int);
188 memcpy(dst, src, srclen);
189 }
190 dstlen = sizeof(int)+srclen;
191 break;
192 }
193 return(dstlen);
194 }
195
196 /* Convert scrap data to internal format */
197 PRIVATE int
convert_scrap(int type,char * dst,char * src,int srclen)198 convert_scrap(int type, char *dst, char *src, int srclen)
199 {
200 int dstlen;
201
202 dstlen = 0;
203 switch (type)
204 {
205 case TextScrap('T', 'E', 'X', 'T'):
206 {
207 if ( srclen == 0 )
208 srclen = strlen(src);
209 if ( dst )
210 {
211 while ( --srclen >= 0 )
212 {
213 #if defined(__WIN32__)
214 if ( *src == '\r' )
215 /* drop extraneous '\r' */;
216 else
217 #endif
218 if ( *src == '\n' )
219 {
220 *dst++ = '\r';
221 ++dstlen;
222 }
223 else
224 {
225 *dst++ = *src;
226 ++dstlen;
227 }
228 ++src;
229 }
230 *dst = '\0';
231 ++dstlen;
232 }
233 else
234 {
235 while ( --srclen >= 0 )
236 {
237 #if defined(__WIN32__)
238 if ( *src == '\r' )
239 /* drop extraneous '\r' */;
240 else
241 #endif
242 ++dstlen;
243 ++src;
244 }
245 ++dstlen;
246 }
247 }
248 break;
249
250 default:
251 dstlen = *(int *)src;
252 if ( dst )
253 {
254 if ( srclen == 0 )
255 memcpy(dst, src+sizeof(int), dstlen);
256 else
257 memcpy(dst, src+sizeof(int), srclen-sizeof(int));
258 }
259 break;
260 }
261 return dstlen;
262 }
263
264 #if defined(X11_SCRAP)
265 /* The system message filter function -- handle clipboard messages */
266 PRIVATE int clipboard_filter(const SDL_Event *event);
267 #endif
268
269 PUBLIC int
init_scrap(void)270 init_scrap(void)
271 {
272 SDL_SysWMinfo info;
273 int retval;
274
275 /* Grab the window manager specific information */
276 retval = -1;
277 SDL_SetError("SDL is not running on known window manager");
278
279 SDL_VERSION(&info.version);
280 if ( SDL_GetWMInfo(&info) )
281 {
282 /* Save the information for later use */
283 #if defined(X11_SCRAP)
284 /* * */
285 if ( info.subsystem == SDL_SYSWM_X11 )
286 {
287 SDL_Display = info.info.x11.display;
288 SDL_Window = info.info.x11.window;
289 Lock_Display = info.info.x11.lock_func;
290 Unlock_Display = info.info.x11.unlock_func;
291
292 /* Enable the special window hook events */
293 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
294 SDL_SetEventFilter(clipboard_filter);
295
296 retval = 0;
297 }
298 else
299 {
300 SDL_SetError("SDL is not running on X11");
301 }
302
303 #elif defined(WIN_SCRAP)
304 /* * */
305 SDL_Window = info.window;
306 retval = 0;
307
308 #elif defined(QNX_SCRAP)
309 /* * */
310 InputGroup=PhInputGroup(NULL);
311 retval = 0;
312
313 #endif /* scrap type */
314 }
315 return(retval);
316 }
317
318 PUBLIC int
lost_scrap(void)319 lost_scrap(void)
320 {
321 int retval;
322
323 #if defined(X11_SCRAP)
324 /* * */
325 Lock_Display();
326 retval = ( XGetSelectionOwner(SDL_Display, XA_PRIMARY) != SDL_Window );
327 Unlock_Display();
328
329 #elif defined(WIN_SCRAP)
330 /* * */
331 retval = ( GetClipboardOwner() != SDL_Window );
332
333 #elif defined(QNX_SCRAP)
334 /* * */
335 retval = ( PhInputGroup(NULL) != InputGroup );
336
337 #endif /* scrap type */
338
339 return(retval);
340 }
341
342 PUBLIC void
put_scrap(int type,int srclen,char * src)343 put_scrap(int type, int srclen, char *src)
344 {
345 scrap_type format;
346 int dstlen;
347 char *dst;
348
349 format = convert_format(type);
350 dstlen = convert_data(type, NULL, src, srclen);
351
352 #if defined(X11_SCRAP)
353 /* * */
354 dst = (char *)malloc(dstlen);
355 if ( dst != NULL )
356 {
357 Lock_Display();
358 convert_data(type, dst, src, srclen);
359 XChangeProperty(SDL_Display, DefaultRootWindow(SDL_Display),
360 XA_CUT_BUFFER0, format, 8, PropModeReplace, (unsigned char *)dst, dstlen);
361 free(dst);
362 if ( lost_scrap() )
363 XSetSelectionOwner(SDL_Display, XA_PRIMARY, SDL_Window, CurrentTime);
364 Unlock_Display();
365 }
366
367 #elif defined(WIN_SCRAP)
368 /* * */
369 if ( OpenClipboard(SDL_Window) )
370 {
371 HANDLE hMem;
372
373 hMem = GlobalAlloc((GMEM_MOVEABLE|GMEM_DDESHARE), dstlen);
374 if ( hMem != NULL )
375 {
376 dst = (char *)GlobalLock(hMem);
377 convert_data(type, dst, src, srclen);
378 GlobalUnlock(hMem);
379 EmptyClipboard();
380 SetClipboardData(format, hMem);
381 }
382 CloseClipboard();
383 }
384
385 #elif defined(QNX_SCRAP)
386 /* * */
387 #if (_NTO_VERSION < 620) /* before 6.2.0 releases */
388 {
389 PhClipHeader clheader={Ph_CLIPBOARD_TYPE_TEXT, 0, NULL};
390 int* cldata;
391 int status;
392
393 dst = (char *)malloc(dstlen+4);
394 if (dst != NULL)
395 {
396 cldata=(int*)dst;
397 *cldata=type;
398 convert_data(type, dst+4, src, srclen);
399 clheader.data=dst;
400 if (dstlen>65535)
401 {
402 clheader.length=65535; /* maximum photon clipboard size :( */
403 }
404 else
405 {
406 clheader.length=dstlen+4;
407 }
408 status=PhClipboardCopy(InputGroup, 1, &clheader);
409 if (status==-1)
410 {
411 fprintf(stderr, "Photon: copy to clipboard was failed !\n");
412 }
413 free(dst);
414 }
415 }
416 #else /* 6.2.0 and 6.2.1 and future releases */
417 {
418 PhClipboardHdr clheader={Ph_CLIPBOARD_TYPE_TEXT, 0, NULL};
419 int* cldata;
420 int status;
421
422 dst = (char *)malloc(dstlen+4);
423 if (dst != NULL)
424 {
425 cldata=(int*)dst;
426 *cldata=type;
427 convert_data(type, dst+4, src, srclen);
428 clheader.data=dst;
429 clheader.length=dstlen+4;
430 status=PhClipboardWrite(InputGroup, 1, &clheader);
431 if (status==-1)
432 {
433 fprintf(stderr, "Photon: copy to clipboard was failed !\n");
434 }
435 free(dst);
436 }
437 }
438 #endif
439 #endif /* scrap type */
440 }
441
442 PUBLIC void
get_scrap(int type,int * dstlen,char ** dst)443 get_scrap(int type, int *dstlen, char **dst)
444 {
445 scrap_type format;
446
447 *dstlen = 0;
448 format = convert_format(type);
449
450 #if defined(X11_SCRAP)
451 /* * */
452 {
453 Window owner;
454 Atom selection1;
455 Atom seln_type;
456 int seln_format;
457 unsigned long nbytes;
458 unsigned long overflow;
459 unsigned char *src;
460
461 Lock_Display();
462 owner = XGetSelectionOwner(SDL_Display, XA_PRIMARY);
463 Unlock_Display();
464 if ( (owner == None) || (owner == SDL_Window) )
465 {
466 owner = DefaultRootWindow(SDL_Display);
467 selection1 = XA_CUT_BUFFER0;
468 }
469 else
470 {
471 int selection_response = 0;
472 SDL_Event event;
473
474 owner = SDL_Window;
475 Lock_Display();
476 selection1 = XInternAtom(SDL_Display, "SDL_SELECTION", False);
477 XConvertSelection(SDL_Display, XA_PRIMARY, format,
478 selection1, owner, CurrentTime);
479 Unlock_Display();
480 while ( ! selection_response )
481 {
482 SDL_WaitEvent(&event);
483 if ( event.type == SDL_SYSWMEVENT )
484 {
485 XEvent xevent = event.syswm.msg->event.xevent;
486
487 if ( (xevent.type == SelectionNotify) &&
488 (xevent.xselection.requestor == owner) )
489 selection_response = 1;
490 }
491 }
492 }
493 Lock_Display();
494 if ( XGetWindowProperty(SDL_Display, owner, selection1, 0, INT_MAX/4,
495 False, format, &seln_type, &seln_format,
496 &nbytes, &overflow, &src) == Success )
497 {
498 if ( seln_type == format )
499 {
500 *dstlen = convert_scrap(type, NULL, (char *)src, nbytes);
501 *dst = (char *)realloc(*dst, *dstlen);
502 if ( *dst == NULL )
503 *dstlen = 0;
504 else
505 convert_scrap(type, *dst, (char *)src, nbytes);
506 }
507 XFree(src);
508 }
509 }
510 Unlock_Display();
511
512 #elif defined(WIN_SCRAP)
513 /* * */
514 if ( IsClipboardFormatAvailable(format) && OpenClipboard(SDL_Window) )
515 {
516 HANDLE hMem;
517 char *src;
518
519 hMem = GetClipboardData(format);
520 if ( hMem != NULL )
521 {
522 src = (char *)GlobalLock(hMem);
523 *dstlen = convert_scrap(type, NULL, src, 0);
524 *dst = (char *)realloc(*dst, *dstlen);
525 if ( *dst == NULL )
526 *dstlen = 0;
527 else
528 convert_scrap(type, *dst, src, 0);
529 GlobalUnlock(hMem);
530 }
531 CloseClipboard();
532 }
533 #elif defined(QNX_SCRAP)
534 /* * */
535 #if (_NTO_VERSION < 620) /* before 6.2.0 releases */
536 {
537 void* clhandle;
538 PhClipHeader* clheader;
539 int* cldata;
540
541 clhandle=PhClipboardPasteStart(InputGroup);
542 if (clhandle!=NULL)
543 {
544 clheader=PhClipboardPasteType(clhandle, Ph_CLIPBOARD_TYPE_TEXT);
545 if (clheader!=NULL)
546 {
547 cldata=clheader->data;
548 if ((clheader->length>4) && (*cldata==type))
549 {
550 *dstlen = convert_scrap(type, NULL, (char*)clheader->data+4, clheader->length-4);
551 *dst = (char *)realloc(*dst, *dstlen);
552 if (*dst == NULL)
553 {
554 *dstlen = 0;
555 }
556 else
557 {
558 convert_scrap(type, *dst, (char*)clheader->data+4, clheader->length-4);
559 }
560 }
561 }
562 PhClipboardPasteFinish(clhandle);
563 }
564 }
565 #else /* 6.2.0 and 6.2.1 and future releases */
566 {
567 void* clhandle;
568 PhClipboardHdr* clheader;
569 int* cldata;
570
571 clheader=PhClipboardRead(InputGroup, Ph_CLIPBOARD_TYPE_TEXT);
572 if (clheader!=NULL)
573 {
574 cldata=clheader->data;
575 if ((clheader->length>4) && (*cldata==type))
576 {
577 *dstlen = convert_scrap(type, NULL, (char*)clheader->data+4, clheader->length-4);
578 *dst = (char *)realloc(*dst, *dstlen);
579 if (*dst == NULL)
580 {
581 *dstlen = 0;
582 }
583 else
584 {
585 convert_scrap(type, *dst, (char*)clheader->data+4, clheader->length-4);
586 }
587 }
588 }
589 }
590 #endif
591 #endif /* scrap type */
592 }
593
594 #if defined(X11_SCRAP)
clipboard_filter(const SDL_Event * event)595 PRIVATE int clipboard_filter(const SDL_Event *event)
596 {
597 /* Post all non-window manager specific events */
598 if ( event->type != SDL_SYSWMEVENT ) {
599 return(1);
600 }
601
602 /* Handle window-manager specific clipboard events */
603 switch (event->syswm.msg->event.xevent.type) {
604 /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
605 case SelectionRequest: {
606 XSelectionRequestEvent *req;
607 XEvent sevent;
608 int seln_format;
609 unsigned long nbytes;
610 unsigned long overflow;
611 unsigned char *seln_data;
612
613 req = &event->syswm.msg->event.xevent.xselectionrequest;
614 sevent.xselection.type = SelectionNotify;
615 sevent.xselection.display = req->display;
616 sevent.xselection.selection = req->selection;
617 sevent.xselection.target = None;
618 sevent.xselection.property = None;
619 sevent.xselection.requestor = req->requestor;
620 sevent.xselection.time = req->time;
621 if ( XGetWindowProperty(SDL_Display, DefaultRootWindow(SDL_Display),
622 XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
623 &sevent.xselection.target, &seln_format,
624 &nbytes, &overflow, &seln_data) == Success )
625 {
626 if ( sevent.xselection.target == req->target )
627 {
628 if ( sevent.xselection.target == XA_STRING )
629 {
630 if ( seln_data[nbytes-1] == '\0' )
631 --nbytes;
632 }
633 XChangeProperty(SDL_Display, req->requestor, req->property,
634 sevent.xselection.target, seln_format, PropModeReplace,
635 seln_data, nbytes);
636 sevent.xselection.property = req->property;
637 }
638 XFree(seln_data);
639 }
640 XSendEvent(SDL_Display,req->requestor,False,0,&sevent);
641 XSync(SDL_Display, False);
642 }
643 break;
644 }
645
646 /* Post the event for X11 clipboard reading above */
647 return(1);
648 }
649 #endif /* X11_SCRAP */
650
651 #endif /* MAC_SCRAP */
652