1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif /* ifdef HAVE_CONFIG_H */
4 
5 #ifdef STDC_HEADERS
6 # include <stdlib.h>
7 # include <stddef.h>
8 #else
9 # ifdef HAVE_STDLIB_H
10 #  include <stdlib.h>
11 # endif
12 #endif
13 
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include "Ecore.h"
18 #include "ecore_private.h"
19 #include "ecore_x_private.h"
20 #include "Ecore_X.h"
21 #include "Ecore_X_Atoms.h"
22 
23 static Ecore_X_Selection_Intern selections[4];
24 static Ecore_X_Selection_Converter *converters = NULL;
25 static Ecore_X_Selection_Parser *parsers = NULL;
26 
27 static int   _ecore_x_selection_data_default_free(void *data);
28 static void *_ecore_x_selection_parser_files(const char *target,
29                                              void *data,
30                                              int size,
31                                              int format);
32 static int   _ecore_x_selection_data_files_free(void *data);
33 static void *_ecore_x_selection_parser_text(const char *target,
34                                             void *data,
35                                             int size,
36                                             int format);
37 static void *_ecore_x_selection_parser_xmozurl(const char *target,
38                                             void *data,
39                                             int size,
40                                             int format);
41 static int   _ecore_x_selection_data_text_free(void *data);
42 static void *_ecore_x_selection_parser_targets(const char *target,
43                                                void *data,
44                                                int size,
45                                                int format);
46 static int   _ecore_x_selection_data_targets_free(void *data);
47 
48 #define ECORE_X_SELECTION_DATA(x) ((Ecore_X_Selection_Data *)(x))
49 
50 void
_ecore_x_selection_data_init(void)51 _ecore_x_selection_data_init(void)
52 {
53    /* Initialize global data */
54    memset(selections, 0, sizeof(selections));
55 
56    /* Initialize converters */
57    ecore_x_selection_converter_atom_add(ECORE_X_ATOM_TEXT,
58                                         ecore_x_selection_converter_text);
59 #ifdef X_HAVE_UTF8_STRING
60    ecore_x_selection_converter_atom_add(ECORE_X_ATOM_UTF8_STRING,
61                                         ecore_x_selection_converter_text);
62 #endif /* ifdef X_HAVE_UTF8_STRING */
63    ecore_x_selection_converter_atom_add(ECORE_X_ATOM_COMPOUND_TEXT,
64                                         ecore_x_selection_converter_text);
65    ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING,
66                                         ecore_x_selection_converter_text);
67 
68    /* Initialize parsers */
69    ecore_x_selection_parser_add("text/plain",
70                                 _ecore_x_selection_parser_text);
71    ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_UTF8_STRING,
72                                 _ecore_x_selection_parser_text);
73    ecore_x_selection_parser_add("text/uri-list",
74                                 _ecore_x_selection_parser_files);
75    ecore_x_selection_parser_add("text/x-moz-url",
76                                 _ecore_x_selection_parser_xmozurl);
77    ecore_x_selection_parser_add("_NETSCAPE_URL",
78                                 _ecore_x_selection_parser_files);
79    ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS,
80                                 _ecore_x_selection_parser_targets);
81 }
82 
83 void
_ecore_x_selection_shutdown(void)84 _ecore_x_selection_shutdown(void)
85 {
86    Ecore_X_Selection_Converter *cnv;
87    Ecore_X_Selection_Parser *prs;
88    Eina_Inlist *inlist;
89 
90    /* free the selection converters */
91    EINA_INLIST_FOREACH_SAFE(converters, inlist, cnv)
92       free(cnv);
93    converters = NULL;
94 
95    /* free the selection parsers */
96    EINA_INLIST_FOREACH_SAFE(parsers, inlist, prs)
97      {
98         free(prs->target);
99         free(prs);
100      }
101    parsers = NULL;
102 }
103 
104 Ecore_X_Selection_Intern *
_ecore_x_selection_get(Ecore_X_Atom selection)105 _ecore_x_selection_get(Ecore_X_Atom selection)
106 {
107    if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
108      return &selections[0];
109    else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
110      return &selections[1];
111    else if (selection == ECORE_X_ATOM_SELECTION_XDND)
112      return &selections[2];
113    else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
114      return &selections[3];
115    else
116      return NULL;
117 }
118 
119 Eina_Bool
_ecore_x_selection_set(Window w,const void * data,int size,Ecore_X_Atom selection)120 _ecore_x_selection_set(Window w,
121                        const void *data,
122                        int size,
123                        Ecore_X_Atom selection)
124 {
125    int in;
126    unsigned char *buf = NULL;
127 
128    XSetSelectionOwner(_ecore_x_disp, selection, w, _ecore_x_event_last_time);
129    if (XGetSelectionOwner(_ecore_x_disp, selection) != w)
130      return EINA_FALSE;
131 
132    if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
133      in = 0;
134    else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
135      in = 1;
136    else if (selection == ECORE_X_ATOM_SELECTION_XDND)
137      in = 2;
138    else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
139      in = 3;
140    else
141      return EINA_FALSE;
142 
143    if (selections[in].data)
144      {
145         free(selections[in].data);
146         memset(&selections[in], 0, sizeof(Ecore_X_Selection_Intern));
147      }
148 
149    if (data)
150      {
151         selections[in].win = w;
152         selections[in].selection = selection;
153         selections[in].length = size;
154         selections[in].time = _ecore_x_event_last_time;
155 
156         buf = malloc(size);
157         if (!buf) return EINA_FALSE;
158         memcpy(buf, data, size);
159         selections[in].data = buf;
160      }
161 
162    return EINA_TRUE;
163 }
164 
165 /**
166  * Claim ownership of the PRIMARY selection and set its data.
167  * @param w    The window to which this selection belongs
168  * @param data The data associated with the selection
169  * @param size The size of the data buffer in bytes
170  * @return     Returns 1 if the ownership of the selection was successfully
171  *             claimed, or 0 if unsuccessful.
172  */
173 EAPI Eina_Bool
ecore_x_selection_primary_set(Ecore_X_Window w,const void * data,int size)174 ecore_x_selection_primary_set(Ecore_X_Window w,
175                               const void *data,
176                               int size)
177 {
178    LOGFN;
179    return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_PRIMARY);
180 }
181 
182 /**
183  * Release ownership of the primary selection
184  * @return     Returns 1 if the selection was successfully cleared,
185  *             or 0 if unsuccessful.
186  *
187  */
188 EAPI Eina_Bool
ecore_x_selection_primary_clear(void)189 ecore_x_selection_primary_clear(void)
190 {
191    LOGFN;
192    return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_PRIMARY);
193 }
194 
195 /**
196  * Claim ownership of the SECONDARY selection and set its data.
197  * @param w    The window to which this selection belongs
198  * @param data The data associated with the selection
199  * @param size The size of the data buffer in bytes
200  * @return     Returns 1 if the ownership of the selection was successfully
201  *             claimed, or 0 if unsuccessful.
202  */
203 EAPI Eina_Bool
ecore_x_selection_secondary_set(Ecore_X_Window w,const void * data,int size)204 ecore_x_selection_secondary_set(Ecore_X_Window w,
205                                 const void *data,
206                                 int size)
207 {
208    LOGFN;
209    return _ecore_x_selection_set(w,
210                                  data,
211                                  size,
212                                  ECORE_X_ATOM_SELECTION_SECONDARY);
213 }
214 
215 /**
216  * Release ownership of the secondary selection
217  * @return     Returns 1 if the selection was successfully cleared,
218  *             or 0 if unsuccessful.
219  *
220  */
221 EAPI Eina_Bool
ecore_x_selection_secondary_clear(void)222 ecore_x_selection_secondary_clear(void)
223 {
224    LOGFN;
225    return _ecore_x_selection_set(None,
226                                  NULL,
227                                  0,
228                                  ECORE_X_ATOM_SELECTION_SECONDARY);
229 }
230 
231 /**
232  * Claim ownership of the XDND selection and set its data.
233  * @param w    The window to which this selection belongs
234  * @param data The data associated with the selection
235  * @param size The size of the data buffer in bytes
236  * @return     Returns 1 if the ownership of the selection was successfully
237  *             claimed, or 0 if unsuccessful.
238  */
239 EAPI Eina_Bool
ecore_x_selection_xdnd_set(Ecore_X_Window w,const void * data,int size)240 ecore_x_selection_xdnd_set(Ecore_X_Window w,
241                            const void *data,
242                            int size)
243 {
244    LOGFN;
245    return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_XDND);
246 }
247 
248 /**
249  * Release ownership of the XDND selection
250  * @return     Returns 1 if the selection was successfully cleared,
251  *             or 0 if unsuccessful.
252  *
253  */
254 EAPI Eina_Bool
ecore_x_selection_xdnd_clear(void)255 ecore_x_selection_xdnd_clear(void)
256 {
257    LOGFN;
258    return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_XDND);
259 }
260 
261 /**
262  * Claim ownership of the CLIPBOARD selection and set its data.
263  * @param w    The window to which this selection belongs
264  * @param data The data associated with the selection
265  * @param size The size of the data buffer in bytes
266  * @return     Returns 1 if the ownership of the selection was successfully
267  *             claimed, or 0 if unsuccessful.
268  *
269  * Get the converted data from a previous CLIPBOARD selection
270  * request. The buffer must be freed when done with.
271  */
272 EAPI Eina_Bool
ecore_x_selection_clipboard_set(Ecore_X_Window w,const void * data,int size)273 ecore_x_selection_clipboard_set(Ecore_X_Window w,
274                                 const void *data,
275                                 int size)
276 {
277    LOGFN;
278    return _ecore_x_selection_set(w,
279                                  data,
280                                  size,
281                                  ECORE_X_ATOM_SELECTION_CLIPBOARD);
282 }
283 
284 /**
285  * Release ownership of the clipboard selection
286  * @return     Returns 1 if the selection was successfully cleared,
287  *             or 0 if unsuccessful.
288  *
289  */
290 EAPI Eina_Bool
ecore_x_selection_clipboard_clear(void)291 ecore_x_selection_clipboard_clear(void)
292 {
293    LOGFN;
294    return _ecore_x_selection_set(None,
295                                  NULL,
296                                  0,
297                                  ECORE_X_ATOM_SELECTION_CLIPBOARD);
298 }
299 
300 Ecore_X_Atom
_ecore_x_selection_target_atom_get(const char * target)301 _ecore_x_selection_target_atom_get(const char *target)
302 {
303    Ecore_X_Atom x_target;
304 
305    if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
306      x_target = ECORE_X_ATOM_TEXT;
307    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
308      x_target = ECORE_X_ATOM_COMPOUND_TEXT;
309    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
310      x_target = ECORE_X_ATOM_STRING;
311    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
312      x_target = ECORE_X_ATOM_UTF8_STRING;
313    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_FILENAME))
314      x_target = ECORE_X_ATOM_FILE_NAME;
315    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_X_MOZ_URL))
316      x_target = ECORE_X_ATOM_X_MOZ_URL;
317    else
318      x_target = ecore_x_atom_get(target);
319 
320    return x_target;
321 }
322 
323 char *
_ecore_x_selection_target_get(Ecore_X_Atom target)324 _ecore_x_selection_target_get(Ecore_X_Atom target)
325 {
326    /* FIXME: Should not return mem allocated with strdup or X mixed,
327     * one should use free to free, the other XFree */
328    if (target == ECORE_X_ATOM_FILE_NAME)
329      return strdup(ECORE_X_SELECTION_TARGET_FILENAME);
330    else if (target == ECORE_X_ATOM_STRING)
331      return strdup(ECORE_X_SELECTION_TARGET_STRING);
332    else if (target == ECORE_X_ATOM_UTF8_STRING)
333      return strdup(ECORE_X_SELECTION_TARGET_UTF8_STRING);
334    else if (target == ECORE_X_ATOM_TEXT)
335      return strdup(ECORE_X_SELECTION_TARGET_TEXT);
336    else if (target == ECORE_X_ATOM_X_MOZ_URL)
337      return strdup(ECORE_X_SELECTION_TARGET_X_MOZ_URL);
338    else
339      return XGetAtomName(_ecore_x_disp, target);
340 }
341 
342 static void
_ecore_x_selection_request(Ecore_X_Window w,Ecore_X_Atom selection,const char * target_str)343 _ecore_x_selection_request(Ecore_X_Window w,
344                            Ecore_X_Atom selection,
345                            const char *target_str)
346 {
347    Ecore_X_Atom target, prop;
348 
349    target = _ecore_x_selection_target_atom_get(target_str);
350 
351    if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
352      prop = ECORE_X_ATOM_SELECTION_PROP_PRIMARY;
353    else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
354      prop = ECORE_X_ATOM_SELECTION_PROP_SECONDARY;
355    else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
356      prop = ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD;
357    else
358      return;
359 
360    XConvertSelection(_ecore_x_disp, selection, target, prop,
361                      w, CurrentTime);
362 }
363 
364 EAPI void
ecore_x_selection_primary_request(Ecore_X_Window w,const char * target)365 ecore_x_selection_primary_request(Ecore_X_Window w,
366                                   const char *target)
367 {
368    LOGFN;
369    _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_PRIMARY, target);
370 }
371 
372 EAPI void
ecore_x_selection_secondary_request(Ecore_X_Window w,const char * target)373 ecore_x_selection_secondary_request(Ecore_X_Window w,
374                                     const char *target)
375 {
376    LOGFN;
377    _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_SECONDARY, target);
378 }
379 
380 EAPI void
ecore_x_selection_xdnd_request(Ecore_X_Window w,const char * target)381 ecore_x_selection_xdnd_request(Ecore_X_Window w,
382                                const char *target)
383 {
384    Ecore_X_Atom atom;
385    Ecore_X_DND_Target *_target;
386 
387    LOGFN;
388    _target = _ecore_x_dnd_target_get();
389    atom = _ecore_x_selection_target_atom_get(target);
390    XConvertSelection(_ecore_x_disp, ECORE_X_ATOM_SELECTION_XDND, atom,
391                      ECORE_X_ATOM_SELECTION_PROP_XDND, w,
392                      _target->time);
393    if (_ecore_xlib_sync) ecore_x_sync();
394 }
395 
396 EAPI void
ecore_x_selection_clipboard_request(Ecore_X_Window w,const char * target)397 ecore_x_selection_clipboard_request(Ecore_X_Window w,
398                                     const char *target)
399 {
400    LOGFN;
401    _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_CLIPBOARD, target);
402 }
403 
404 EAPI void
ecore_x_selection_converter_atom_add(Ecore_X_Atom target,Eina_Bool (* func)(char * target,void * data,int size,void ** data_ret,int * size_ret,Ecore_X_Atom * ttype,int * tsize))405 ecore_x_selection_converter_atom_add(Ecore_X_Atom target,
406                                      Eina_Bool (*func)(char *target,
407                                                        void *data,
408                                                        int size,
409                                                        void **data_ret,
410                                                        int *size_ret,
411                                                        Ecore_X_Atom *ttype,
412                                                        int *tsize))
413 {
414    Ecore_X_Selection_Converter *cnv;
415 
416    LOGFN;
417 
418    EINA_INLIST_FOREACH(converters, cnv)
419       if (cnv->target == target)
420         {
421            cnv->convert = func;
422            return;
423         }
424 
425    cnv = calloc(1, sizeof(Ecore_X_Selection_Converter));
426    if (!cnv) return;
427 
428    cnv->target = target;
429    cnv->convert = func;
430    converters = (Ecore_X_Selection_Converter *)eina_inlist_append
431       (EINA_INLIST_GET(converters), EINA_INLIST_GET(cnv));
432 }
433 
434 EAPI void
ecore_x_selection_converter_add(char * target,Eina_Bool (* func)(char * target,void * data,int size,void ** data_ret,int * size_ret,Ecore_X_Atom *,int *))435 ecore_x_selection_converter_add(char *target,
436                                 Eina_Bool (*func)(char *target,
437                                                   void *data,
438                                                   int size,
439                                                   void **data_ret,
440                                                   int *size_ret,
441                                                   Ecore_X_Atom *,
442                                                   int *))
443 {
444    Ecore_X_Atom x_target;
445 
446    if (!func || !target)
447      return;
448 
449    LOGFN;
450    x_target = _ecore_x_selection_target_atom_get(target);
451 
452    ecore_x_selection_converter_atom_add(x_target, func);
453 }
454 
455 EAPI void
ecore_x_selection_converter_atom_del(Ecore_X_Atom target)456 ecore_x_selection_converter_atom_del(Ecore_X_Atom target)
457 {
458    Ecore_X_Selection_Converter *cnv;
459 
460    LOGFN;
461 
462    EINA_INLIST_FOREACH(converters, cnv)
463      {
464         if (cnv->target == target)
465           {
466              converters = (Ecore_X_Selection_Converter *)eina_inlist_remove
467                 (EINA_INLIST_GET(converters), EINA_INLIST_GET(cnv));
468              free(cnv);
469              return;
470           }
471      }
472 }
473 
474 EAPI void
ecore_x_selection_converter_del(char * target)475 ecore_x_selection_converter_del(char *target)
476 {
477    Ecore_X_Atom x_target;
478 
479    if (!target)
480      return;
481 
482    LOGFN;
483    x_target = _ecore_x_selection_target_atom_get(target);
484    ecore_x_selection_converter_atom_del(x_target);
485 }
486 
487 EAPI Eina_Bool
ecore_x_selection_notify_send(Ecore_X_Window requestor,Ecore_X_Atom selection,Ecore_X_Atom target,Ecore_X_Atom property,Ecore_X_Time tim)488 ecore_x_selection_notify_send(Ecore_X_Window requestor,
489                               Ecore_X_Atom selection,
490                               Ecore_X_Atom target,
491                               Ecore_X_Atom property,
492                               Ecore_X_Time tim)
493 {
494    XEvent xev = { 0 };
495    XSelectionEvent xnotify;
496 
497    LOGFN;
498    xnotify.type = SelectionNotify;
499    xnotify.display = _ecore_x_disp;
500    xnotify.requestor = requestor;
501    xnotify.selection = selection;
502    xnotify.target = target;
503    xnotify.property = property;
504    xnotify.time = tim;
505    xnotify.send_event = True;
506    xnotify.serial = 0;
507 
508    xev.xselection = xnotify;
509    return (XSendEvent(_ecore_x_disp, requestor, False, 0, &xev) > 0) ? EINA_TRUE : EINA_FALSE;
510 }
511 
512 /* Locate and run conversion callback for specified selection target */
513 EAPI Eina_Bool
ecore_x_selection_convert(Ecore_X_Atom selection,Ecore_X_Atom target,void ** data_ret,int * size,Ecore_X_Atom * targtype,int * typesize)514 ecore_x_selection_convert(Ecore_X_Atom selection,
515                           Ecore_X_Atom target,
516                           void **data_ret,
517                           int *size,
518                           Ecore_X_Atom *targtype,
519                           int *typesize)
520 {
521    Ecore_X_Selection_Intern *sel;
522    Ecore_X_Selection_Converter *cnv;
523    void *data = NULL;
524    char *tgt_str;
525 
526    LOGFN;
527    sel = _ecore_x_selection_get(selection);
528    tgt_str = _ecore_x_selection_target_get(target);
529 
530    EINA_INLIST_FOREACH(converters, cnv)
531      {
532         if (cnv->target == target)
533           {
534              int r;
535              r = cnv->convert(tgt_str, sel->data, sel->length, &data, size,
536                               targtype, typesize);
537              free(tgt_str);
538              if (r)
539                {
540                   if (data_ret) *data_ret = data;
541                   return r;
542                }
543              else
544                return EINA_FALSE;
545           }
546      }
547    free(tgt_str);
548 
549    /* ICCCM says "If the selection cannot be converted into a form based on the target (and parameters, if any), the owner should refuse the SelectionRequest as previously described." */
550    return EINA_FALSE;
551 
552    /* Default, just return the data
553     * data_ret = malloc(sel->length);
554       memcpy(*data_ret, sel->data, sel->length);
555       free(tgt_str);
556       return 1;
557     */
558 }
559 
560 /* TODO: We need to work out a mechanism for automatic conversion to any requested
561  * locale using Ecore_Txt functions */
562 /* Converter for standard non-utf8 text targets */
563 EAPI Eina_Bool
ecore_x_selection_converter_text(char * target,void * data,int size,void ** data_ret,int * size_ret,Ecore_X_Atom * targprop EINA_UNUSED,int * s EINA_UNUSED)564 ecore_x_selection_converter_text(char *target,
565                                  void *data,
566                                  int size,
567                                  void **data_ret,
568                                  int *size_ret,
569                                  Ecore_X_Atom *targprop EINA_UNUSED,
570                                  int *s EINA_UNUSED)
571 {
572    XTextProperty text_prop;
573    char *mystr;
574    XICCEncodingStyle style;
575 
576    if (!data || !size)
577      return EINA_FALSE;
578 
579    LOGFN;
580    if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
581      style = XTextStyle;
582    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
583      style = XCompoundTextStyle;
584    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
585      style = XStringStyle;
586 
587 #ifdef X_HAVE_UTF8_STRING
588    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
589      style = XUTF8StringStyle;
590 #endif /* ifdef X_HAVE_UTF8_STRING */
591    else
592      return EINA_FALSE;
593 
594    mystr = alloca(size + 1);
595    memcpy(mystr, data, size);
596    mystr[size] = '\0';
597 
598 #ifdef X_HAVE_UTF8_STRING
599    if (Xutf8TextListToTextProperty(_ecore_x_disp, &mystr, 1, style,
600                                    &text_prop) == Success)
601      {
602         int bufsize = strlen((char *)text_prop.value);
603         char *str = malloc(bufsize + 1);
604         if (!str) return EINA_FALSE;
605         *data_ret = str;
606         memcpy(str, text_prop.value, bufsize);
607         str[bufsize] = 0;
608         *size_ret = bufsize;
609         XFree(text_prop.value);
610         return EINA_TRUE;
611      }
612 
613 #else /* ifdef X_HAVE_UTF8_STRING */
614    if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style,
615                                  &text_prop) == Success)
616      {
617         int bufsize = strlen(text_prop.value);
618         *data_ret = malloc(bufsize);
619         if (!*data_ret) return EINA_FALSE;
620         memcpy(*data_ret, text_prop.value, bufsize);
621         *size_ret = bufsize;
622         XFree(text_prop.value);
623         return EINA_TRUE;
624      }
625 
626 #endif /* ifdef X_HAVE_UTF8_STRING */
627    else
628      {
629         return EINA_TRUE;
630      }
631 }
632 
633 EAPI void
ecore_x_selection_parser_add(const char * target,void * (* func)(const char * target,void * data,int size,int format))634 ecore_x_selection_parser_add(const char *target,
635                              void *(*func)(const char *target, void *data,
636                                            int size,
637                                            int format))
638 {
639    Ecore_X_Selection_Parser *prs;
640 
641    if (!target)
642      return;
643 
644    LOGFN;
645 
646    EINA_INLIST_FOREACH(parsers, prs)
647       if (!strcmp(prs->target, target))
648         {
649            prs->parse = func;
650            return;
651         }
652 
653    prs = calloc(1, sizeof(Ecore_X_Selection_Parser));
654    if (!prs) return;
655 
656    prs->target = strdup(target);
657    prs->parse = func;
658 
659    parsers = (Ecore_X_Selection_Parser *)eina_inlist_append
660       (EINA_INLIST_GET(parsers), EINA_INLIST_GET(prs));
661 }
662 
663 EAPI void
ecore_x_selection_parser_del(const char * target)664 ecore_x_selection_parser_del(const char *target)
665 {
666    Ecore_X_Selection_Parser *prs;
667 
668    if (!target)
669      return;
670 
671    LOGFN;
672 
673    EINA_INLIST_FOREACH(parsers, prs)
674      {
675         if (!strcmp(prs->target, target))
676           {
677              parsers = (Ecore_X_Selection_Parser *)eina_inlist_remove
678                 (EINA_INLIST_GET(parsers), EINA_INLIST_GET(prs));
679              free(prs->target);
680              free(prs);
681              return;
682           }
683      }
684 }
685 
686 /**
687  * Change the owner and last-change time for the specified selection.
688  * @param win The owner of the specified atom.
689  * @param atom The selection atom
690  * @param tim Specifies the time
691  * @since 1.1.0
692  */
693 EAPI void
ecore_x_selection_owner_set(Ecore_X_Window win,Ecore_X_Atom atom,Ecore_X_Time tim)694 ecore_x_selection_owner_set(Ecore_X_Window win,
695                             Ecore_X_Atom atom,
696                             Ecore_X_Time tim)
697 {
698    XSetSelectionOwner(_ecore_x_disp, atom, win, tim);
699 }
700 
701 /**
702  * Return the window that currently owns the specified selection.
703  *
704  * @param atom The specified selection atom.
705  *
706  * @return The window that currently owns the specified selection.
707  * @since 1.1.0
708  */
709 EAPI Ecore_X_Window
ecore_x_selection_owner_get(Ecore_X_Atom atom)710 ecore_x_selection_owner_get(Ecore_X_Atom atom)
711 {
712    return XGetSelectionOwner(_ecore_x_disp, atom);
713 }
714 
715 /* Locate and run conversion callback for specified selection target */
716 void *
_ecore_x_selection_parse(const char * target,void * data,int size,int format)717 _ecore_x_selection_parse(const char *target,
718                          void *data,
719                          int size,
720                          int format)
721 {
722    Ecore_X_Selection_Parser *prs;
723    Ecore_X_Selection_Data *sel;
724 
725    EINA_INLIST_FOREACH(parsers, prs)
726      {
727         if (!strcmp(prs->target, target))
728           {
729              sel = prs->parse(target, data, size, format);
730              if (sel) return sel;
731           }
732      }
733 
734    /* Default, just return the data */
735    sel = calloc(1, sizeof(Ecore_X_Selection_Data));
736    if (!sel) return NULL;
737    sel->free = _ecore_x_selection_data_default_free;
738    sel->length = size;
739    sel->format = format;
740    sel->data = data;
741    return sel;
742 }
743 
744 static int
_ecore_x_selection_data_default_free(void * data)745 _ecore_x_selection_data_default_free(void *data)
746 {
747    Ecore_X_Selection_Data *sel;
748 
749    sel = data;
750    free(sel->data);
751    free(sel);
752    return 1;
753 }
754 
755 static void *
_ecore_x_selection_parser_files(const char * target,void * _data,int size,int format EINA_UNUSED)756 _ecore_x_selection_parser_files(const char *target,
757                                 void *_data,
758                                 int size,
759                                 int format EINA_UNUSED)
760 {
761    Ecore_X_Selection_Data_Files *sel;
762    char *data = _data;
763 
764    if (strcmp(target, "text/uri-list") &&
765        strcmp(target, "_NETSCAPE_URL"))
766      return NULL;
767 
768    sel = calloc(1, sizeof(Ecore_X_Selection_Data_Files));
769    if (!sel) return NULL;
770    ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_files_free;
771 
772    if (data && (size > 0))
773      {
774         int i, is;
775         char *tmp;
776         char **t2;
777 
778         if (data[size - 1])
779           {
780              char *t;
781 
782              /* Isn't nul terminated */
783              size++;
784              t = realloc(data, size);
785              if (!t) goto done;
786              data = t;
787              data[size - 1] = 0;
788           }
789 
790         tmp = malloc(size);
791         if (!tmp) goto done;
792         i = 0;
793         is = 0;
794         while ((is < size) && (data[is]))
795           {
796              if ((i == 0) && (data[is] == '#'))
797                for (; ((data[is]) && (data[is] != '\n')); is++) ;
798              else
799                {
800                   if ((data[is] != '\r') &&
801                       (data[is] != '\n'))
802                     tmp[i++] = data[is++];
803                   else
804                     {
805                        while ((data[is] == '\r') || (data[is] == '\n'))
806                          is++;
807                        tmp[i] = 0;
808                        sel->num_files++;
809                        t2 = realloc(sel->files, sel->num_files * sizeof(char *));
810                        if (t2)
811                          {
812                             sel->files = t2;
813                             sel->files[sel->num_files - 1] = strdup(tmp);
814                          }
815                        tmp[0] = 0;
816                        i = 0;
817                     }
818                }
819           }
820         if (i > 0)
821           {
822              tmp[i] = 0;
823              sel->num_files++;
824              t2 = realloc(sel->files, sel->num_files * sizeof(char *));
825              if (t2)
826                {
827                   sel->files = t2;
828                   sel->files[sel->num_files - 1] = strdup(tmp);
829                }
830           }
831 
832         free(tmp);
833      }
834 done:
835    free(data);
836 
837    ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES;
838    ECORE_X_SELECTION_DATA(sel)->length = sel->num_files;
839 
840    return ECORE_X_SELECTION_DATA(sel);
841 }
842 
843 static int
_ecore_x_selection_data_files_free(void * data)844 _ecore_x_selection_data_files_free(void *data)
845 {
846    Ecore_X_Selection_Data_Files *sel;
847    int i;
848 
849    sel = data;
850    if (sel->files)
851      {
852         for (i = 0; i < sel->num_files; i++)
853           free(sel->files[i]);
854         free(sel->files);
855      }
856 
857    free(sel);
858    return 0;
859 }
860 
861 static void *
_ecore_x_selection_parser_text(const char * target EINA_UNUSED,void * _data,int size,int format EINA_UNUSED)862 _ecore_x_selection_parser_text(const char *target EINA_UNUSED,
863                                void *_data,
864                                int size,
865                                int format EINA_UNUSED)
866 {
867    Ecore_X_Selection_Data_Text *sel;
868    unsigned char *data = _data;
869    void *t;
870 
871    sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text));
872    if (!sel) return NULL;
873    if (data && data[size - 1])
874      {
875         /* Isn't nul terminated */
876         size++;
877         t = realloc(data, size);
878         if (!t)
879           {
880              free(sel);
881              return NULL;
882           }
883         data = t;
884         data[size - 1] = 0;
885      }
886 
887    sel->text = (char *)data;
888    ECORE_X_SELECTION_DATA(sel)->length = size;
889    ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TEXT;
890    ECORE_X_SELECTION_DATA(sel)->data = data;
891    ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_text_free;
892    return sel;
893 }
894 
895 static int
_ecore_x_selection_data_xmozurl_free(void * data)896 _ecore_x_selection_data_xmozurl_free(void *data)
897 {
898    Ecore_X_Selection_Data_X_Moz_Url *sel = data;
899    char **buf;
900 
901    buf = eina_inarray_nth(sel->links, 0);
902    free(*buf);
903    eina_inarray_free(sel->links);
904    eina_inarray_free(sel->link_names);
905    free(sel);
906    return 1;
907 }
908 #ifdef HAVE_ICONV
909 # include <errno.h>
910 # include <iconv.h>
911 #endif
912 static void *
_ecore_x_selection_parser_xmozurl(const char * target EINA_UNUSED,void * _data,int size,int format EINA_UNUSED)913 _ecore_x_selection_parser_xmozurl(const char *target EINA_UNUSED,
914                                void *_data,
915                                int size,
916                                int format EINA_UNUSED)
917 {
918    Ecore_X_Selection_Data_X_Moz_Url *sel;
919    char *prev, *n, *buf, *data = _data;
920    size_t sz;
921    int num = 0;
922 
923    buf = eina_str_convert_len("UTF-16LE", "UTF-8", data, size, &sz);
924    if (!buf) return NULL;
925    sel = calloc(1, sizeof(Ecore_X_Selection_Data_X_Moz_Url));
926    if (!sel)
927       goto error_sel;
928 
929    sz = strlen(buf);
930    sel->links = eina_inarray_new(sizeof(char*), 0);
931    if (!sel->links)
932       goto error_links;
933 
934    sel->link_names = eina_inarray_new(sizeof(char*), 0);
935    if (!sel->link_names)
936       goto error_link_names;
937 
938    prev = buf;
939    for (n = memchr(buf, '\n', sz); n; n = memchr(prev, '\n', sz - (prev - buf)))
940      {
941         n[0] = 0;
942         if (num % 2 == 0)
943           eina_inarray_push(sel->links, &prev);
944         else
945           eina_inarray_push(sel->link_names, &prev);
946         num++;
947         prev = n + 1;
948      }
949    eina_inarray_push(sel->link_names, &prev);
950 
951    ECORE_X_SELECTION_DATA(sel)->length = size;
952    ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_X_MOZ_URL;
953    ECORE_X_SELECTION_DATA(sel)->data = (void*)data;
954    ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_xmozurl_free;
955    return sel;
956 
957 error_link_names:
958    eina_inarray_free(sel->links);
959 
960 error_links:
961    free(sel);
962 
963 error_sel:
964    free(buf);
965    return NULL;
966 }
967 
968 static int
_ecore_x_selection_data_text_free(void * data)969 _ecore_x_selection_data_text_free(void *data)
970 {
971    Ecore_X_Selection_Data_Text *sel;
972 
973    sel = data;
974    free(sel->text);
975    free(sel);
976    return 1;
977 }
978 
979 static void *
_ecore_x_selection_parser_targets(const char * target EINA_UNUSED,void * data,int size,int format EINA_UNUSED)980 _ecore_x_selection_parser_targets(const char *target EINA_UNUSED,
981                                   void *data,
982                                   int size,
983                                   int format EINA_UNUSED)
984 {
985    Ecore_X_Selection_Data_Targets *sel;
986    int *targets;
987    int i;
988 
989    sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets));
990    if (!sel) return NULL;
991    targets = data;
992 
993    sel->num_targets = size;
994    sel->targets = malloc((sel->num_targets) * sizeof(char *));
995    if (!sel->targets)
996      {
997         free(sel);
998         return NULL;
999      }
1000    for (i = 0; i < size; i++)
1001      sel->targets[i] = XGetAtomName(_ecore_x_disp, targets[i]);
1002 
1003    ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_targets_free;
1004    ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS;
1005    ECORE_X_SELECTION_DATA(sel)->length = size;
1006    ECORE_X_SELECTION_DATA(sel)->data = data;
1007    return sel;
1008 }
1009 
1010 static int
_ecore_x_selection_data_targets_free(void * data)1011 _ecore_x_selection_data_targets_free(void *data)
1012 {
1013    Ecore_X_Selection_Data_Targets *sel;
1014    int i;
1015 
1016    sel = data;
1017 
1018    if (sel->targets)
1019      {
1020         for (i = 0; i < sel->num_targets; i++)
1021           XFree(sel->targets[i]);
1022         free(sel->targets);
1023      }
1024 
1025    free(ECORE_X_SELECTION_DATA(sel)->data);
1026    free(sel);
1027    return 1;
1028 }
1029 
1030