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