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