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