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