[ecore] merged svn latest code (svn54830)
[profile/ivi/ecore.git] / src / lib / ecore_x / xcb / ecore_xcb_dnd.c
1 #include <string.h>
2
3 #include "Ecore.h"
4 #include "ecore_xcb_private.h"
5 #include "Ecore_X_Atoms.h"
6
7 EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
8 EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
9 EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
10 EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
11 EAPI int ECORE_X_EVENT_XDND_DROP = 0;
12 EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
13
14 static Ecore_X_DND_Source *_source = NULL;
15 static Ecore_X_DND_Target *_target = NULL;
16 static int _ecore_x_dnd_init_count = 0;
17
18 void
19 _ecore_x_dnd_init(void)
20 {
21    if (!_ecore_x_dnd_init_count)
22      {
23         _source = calloc(1, sizeof(Ecore_X_DND_Source));
24         _source->version = ECORE_X_DND_VERSION;
25         _source->win = XCB_NONE;
26         _source->dest = XCB_NONE;
27         _source->state = ECORE_X_DND_SOURCE_IDLE;
28         _source->prev.window = 0;
29
30         _target = calloc(1, sizeof(Ecore_X_DND_Target));
31         _target->win = XCB_NONE;
32         _target->source = XCB_NONE;
33         _target->state = ECORE_X_DND_TARGET_IDLE;
34
35         ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
36         ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
37         ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
38         ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
39         ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
40         ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
41      }
42
43    _ecore_x_dnd_init_count++;
44 } /* _ecore_x_dnd_init */
45
46 void
47 _ecore_x_dnd_shutdown(void)
48 {
49    _ecore_x_dnd_init_count--;
50    if (_ecore_x_dnd_init_count > 0)
51       return;
52
53    if (_source)
54       free(_source);
55
56    _source = NULL;
57
58    if (_target)
59       free(_target);
60
61    _target = NULL;
62
63    _ecore_x_dnd_init_count = 0;
64 } /* _ecore_x_dnd_shutdown */
65
66 EAPI void
67 ecore_x_dnd_aware_set(Ecore_X_Window window,
68                       Eina_Bool      on)
69 {
70    Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
71
72    if (on)
73       ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_AWARE,
74                                        ECORE_X_ATOM_ATOM, 32, &prop_data, 1);
75    else
76       ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_AWARE);
77 } /* ecore_x_dnd_aware_set */
78
79 /**
80  * Sends the GetProperty request.
81  * @param window Window whose properties are requested.
82  */
83 EAPI void
84 ecore_x_dnd_version_get_prefetch(Ecore_X_Window window)
85 {
86    xcb_get_property_cookie_t cookie;
87
88    cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
89                                        window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root,
90                                        ECORE_X_ATOM_XDND_AWARE,
91                                        ECORE_X_ATOM_ATOM,
92                                        0, LONG_MAX);
93    _ecore_xcb_cookie_cache(cookie.sequence);
94 } /* ecore_x_dnd_version_get_prefetch */
95
96 /**
97  * Gets the reply of the GetProperty request sent by ecore_x_dnd_version_get_prefetch().
98  */
99 EAPI void
100 ecore_x_dnd_version_get_fetch(void)
101 {
102    xcb_get_property_cookie_t cookie;
103    xcb_get_property_reply_t *reply;
104
105    cookie.sequence = _ecore_xcb_cookie_get();
106    reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
107    _ecore_xcb_reply_cache(reply);
108 } /* ecore_x_dnd_version_get_fetch */
109
110 /**
111  * Get the DnD version.
112  * @param  window Unused.
113  * @return        0 on failure, the version otherwise.
114  *
115  * Get the DnD version. Returns 0 on failure, the version otherwise.
116  *
117  * To use this function, you must call before, and in order,
118  * ecore_x_dnd_version_get_prefetch(), which sends the GetProperty request,
119  * then ecore_x_dnd_version_get_fetch(), which gets the reply.
120  */
121 EAPI int
122 ecore_x_dnd_version_get(Ecore_X_Window window)
123 {
124    unsigned char *prop_data;
125    int num;
126
127    if (ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_AWARE,
128                                         ECORE_X_ATOM_ATOM, 32, &prop_data, &num))
129      {
130         int version = (int)*prop_data;
131         free(prop_data);
132         return version;
133      }
134    else
135       return 0;
136 } /* ecore_x_dnd_version_get */
137
138 /**
139  * Sends the GetProperty request.
140  * @param window Window whose properties are requested.
141  */
142 EAPI void
143 ecore_x_dnd_type_get_prefetch(Ecore_X_Window window)
144 {
145    xcb_get_property_cookie_t cookie;
146
147    cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
148                                        window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root,
149                                        ECORE_X_ATOM_XDND_TYPE_LIST,
150                                        ECORE_X_ATOM_ATOM,
151                                        0, LONG_MAX);
152    _ecore_xcb_cookie_cache(cookie.sequence);
153 } /* ecore_x_dnd_type_get_prefetch */
154
155 /**
156  * Gets the reply of the GetProperty request sent by ecore_x_dnd_type_get_prefetch().
157  */
158 EAPI void
159 ecore_x_dnd_type_get_fetch(void)
160 {
161    xcb_get_property_cookie_t cookie;
162    xcb_get_property_reply_t *reply;
163
164    cookie.sequence = _ecore_xcb_cookie_get();
165    reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
166    _ecore_xcb_reply_cache(reply);
167 } /* ecore_x_dnd_type_get_fetch */
168
169 /* FIXME: round trip (InternAtomGet request) */
170
171 /**
172  * Check if the type is set.
173  * @param   window Unused.
174  * @param   type   The type to check
175  * @return         0 on failure, 1 otherwise.
176  *
177  * Check if the type is set. 0 on failure, 1 otherwise.
178  *
179  * To use this function, you must call before, and in order,
180  * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
181  * then ecore_x_dnd_type_get_fetch(), which gets the reply.
182  */
183 EAPI Eina_Bool
184 ecore_x_dnd_type_isset(Ecore_X_Window window,
185                        const char    *type)
186 {
187    xcb_intern_atom_cookie_t cookie;
188    xcb_intern_atom_reply_t *reply;
189    Ecore_X_Atom *atoms;
190    unsigned char *data;
191    int num;
192    int i;
193    uint8_t ret = 0;
194
195    cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
196                                       strlen(type), type);
197
198    if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST,
199                                          ECORE_X_ATOM_ATOM, 32, &data, &num))
200      {
201         reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
202         if (reply)
203            free(reply);
204
205         return ret;
206      }
207
208    reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
209    if (!reply)
210      {
211         free(data);
212         return 0;
213      }
214
215    atoms = (Ecore_X_Atom *)data;
216
217    for (i = 0; i < num; ++i)
218      {
219         if (reply->atom == atoms[i])
220           {
221              ret = 1;
222              break;
223           }
224      }
225
226    free(data);
227    free(reply);
228
229    return ret;
230 } /* ecore_x_dnd_type_isset */
231
232 /* FIXME: round trip (InternAtomGet request) */
233
234 /**
235  * Set the type.
236  * @param   window Unused.
237  * @param   type   The type to set
238  * @param   on     0 or non 0...
239  *
240  * Set the type.
241  *
242  * To use this function, you must call before, and in order,
243  * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
244  * then ecore_x_dnd_type_get_fetch(), which gets the reply.
245  */
246 EAPI void
247 ecore_x_dnd_type_set(Ecore_X_Window window,
248                      const char    *type,
249                      Eina_Bool      on)
250 {
251    xcb_intern_atom_cookie_t cookie;
252    xcb_intern_atom_reply_t *reply;
253    Ecore_X_Atom *oldset = NULL;
254    Ecore_X_Atom *newset = NULL;
255    unsigned char *data = NULL;
256    unsigned char *old_data = NULL;
257    Ecore_X_Atom atom;
258    int i, j = 0, num = 0;
259
260    cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
261                                       strlen(type), type);
262
263    atom = ecore_x_atom_get(type);
264    if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST,
265                                          ECORE_X_ATOM_ATOM,
266                                          32, &old_data, &num))
267      {
268         reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
269         if (reply)
270            free(reply);
271
272         return;
273      }
274
275    oldset = (Ecore_X_Atom *)old_data;
276
277    if (on)
278      {
279         if (ecore_x_dnd_type_isset(window, type))
280           {
281              free(old_data);
282              reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
283              if (reply)
284                 free(reply);
285
286              return;
287           }
288
289         data = calloc(num + 1, sizeof(Ecore_X_Atom));
290         if (!data)
291           {
292              free(old_data);
293              reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
294              if (reply)
295                 free(reply);
296
297              return;
298           }
299
300         newset = (Ecore_X_Atom *)data;
301
302         for (i = 0; i < num; i++)
303            newset[i + 1] = oldset[i];
304         /* prepend the new type */
305
306         reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
307         if (!reply)
308           {
309              free(old_data);
310              return;
311           }
312
313         newset[0] = reply->atom;
314         free(reply);
315
316         ecore_x_window_prop_property_set(window,
317                                          ECORE_X_ATOM_XDND_TYPE_LIST,
318                                          ECORE_X_ATOM_ATOM,
319                                          32, data, num + 1);
320      }
321    else
322      {
323         if (!ecore_x_dnd_type_isset(window, type))
324           {
325              free(old_data);
326              return;
327           }
328
329         newset = calloc(num - 1, sizeof(Ecore_X_Atom));
330         if (!newset)
331           {
332              free(old_data);
333              return;
334           }
335
336         data = (unsigned char *)newset;
337         for (i = 0; i < num; i++)
338            if (oldset[i] != atom)
339               newset[j++] = oldset[i];
340
341         ecore_x_window_prop_property_set(window,
342                                          ECORE_X_ATOM_XDND_TYPE_LIST,
343                                          ECORE_X_ATOM_ATOM,
344                                          32, data, num - 1);
345      }
346
347    free(oldset);
348    free(newset);
349 } /* ecore_x_dnd_type_set */
350
351 /* FIXME: round trips, but I don't think we can do much, here */
352
353 /**
354  * Set the types.
355  * @param   window Unused.
356  * @param   types  The types to set
357  * @param   num_types The number of types
358  *
359  * Set the types.
360  *
361  * To use this function, you must call before, and in order,
362  * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
363  * then ecore_x_dnd_type_get_fetch(), which gets the reply.
364  */
365 EAPI void
366 ecore_x_dnd_types_set(Ecore_X_Window window,
367                       const char   **types,
368                       unsigned int   num_types)
369 {
370    Ecore_X_Atom *newset = NULL;
371    void *data = NULL;
372    uint32_t i;
373
374    if (!num_types)
375      {
376         ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_TYPE_LIST);
377      }
378    else
379      {
380         xcb_intern_atom_cookie_t *cookies;
381         xcb_intern_atom_reply_t *reply;
382
383         cookies = (xcb_intern_atom_cookie_t *)malloc(sizeof(xcb_intern_atom_cookie_t));
384         if (!cookies)
385            return;
386
387         for (i = 0; i < num_types; i++)
388            cookies[i] = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
389                                                   strlen(types[i]), types[i]);
390         data = calloc(num_types, sizeof(Ecore_X_Atom));
391         if (!data)
392           {
393              for (i = 0; i < num_types; i++)
394                {
395                   reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL);
396                   if (reply)
397                      free(reply);
398                }
399              free(cookies);
400              return;
401           }
402
403         newset = data;
404         for (i = 0; i < num_types; i++)
405           {
406              reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL);
407              if (reply)
408                {
409                   newset[i] = reply->atom;
410                   free(reply);
411                }
412              else
413                 newset[i] = XCB_NONE;
414           }
415         free(cookies);
416         ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_TYPE_LIST,
417                                          ECORE_X_ATOM_ATOM, 32, data, num_types);
418         free(data);
419      }
420 } /* ecore_x_dnd_types_set */
421
422 Ecore_X_DND_Source *
423 _ecore_x_dnd_source_get(void)
424 {
425    return _source;
426 } /* _ecore_x_dnd_source_get */
427
428 Ecore_X_DND_Target *
429 _ecore_x_dnd_target_get(void)
430 {
431    return _target;
432 } /* _ecore_x_dnd_target_get */
433
434 /**
435  * Sends the GetProperty request.
436  * @param source Window whose properties are requested.
437  */
438 EAPI void
439 ecore_x_dnd_begin_prefetch(Ecore_X_Window source)
440 {
441    xcb_get_property_cookie_t cookie;
442
443    cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
444                                        source ? source : ((xcb_screen_t *)_ecore_xcb_screen)->root,
445                                        ECORE_X_ATOM_XDND_AWARE,
446                                        ECORE_X_ATOM_ATOM,
447                                        0, LONG_MAX);
448    _ecore_xcb_cookie_cache(cookie.sequence);
449 } /* ecore_x_dnd_begin_prefetch */
450
451 /**
452  * Gets the reply of the GetProperty request sent by ecore_x_dnd_begin_prefetch().
453  */
454 EAPI void
455 ecore_x_dnd_begin_fetch(void)
456 {
457    xcb_get_property_cookie_t cookie;
458    xcb_get_property_reply_t *reply;
459
460    cookie.sequence = _ecore_xcb_cookie_get();
461    reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
462    _ecore_xcb_reply_cache(reply);
463 } /* ecore_x_dnd_begin_fetch */
464
465 /* FIXME: round trip */
466
467 /**
468  * Begins the DnD.
469  * @param  source Unused.
470  * @param  data   The data.
471  * @param  size   The size of the data.
472  * @return        0 on failure, 1 otherwise.
473  *
474  * Begins the DnD. Returns 0 on failure, 1 otherwise.
475  *
476  * To use this function, you must call before, and in order,
477  * ecore_x_dnd_begin_prefetch(), which sends the GetProperty request,
478  * then ecore_x_dnd_begin_fetch(), which gets the reply.
479  */
480 EAPI Eina_Bool
481 ecore_x_dnd_begin(Ecore_X_Window source,
482                   unsigned char *data,
483                   int            size)
484 {
485    ecore_x_selection_xdnd_prefetch();
486    if (!ecore_x_dnd_version_get(source))
487      {
488         ecore_x_selection_xdnd_fetch();
489         return 0;
490      }
491
492    /* Take ownership of XdndSelection */
493    ecore_x_selection_xdnd_prefetch();
494    ecore_x_selection_xdnd_fetch();
495    if (!ecore_x_selection_xdnd_set(source, data, size))
496       return 0;
497
498    _source->win = source;
499    ecore_x_window_ignore_set(_source->win, 1);
500    _source->state = ECORE_X_DND_SOURCE_DRAGGING;
501    _source->time = _ecore_xcb_event_last_time;
502    _source->prev.window = 0;
503
504    /* Default Accepted Action: ask */
505    _source->action = ECORE_X_ATOM_XDND_ACTION_COPY;
506    _source->accepted_action = XCB_NONE;
507    return 1;
508 } /* ecore_x_dnd_begin */
509
510 EAPI Eina_Bool
511 ecore_x_dnd_drop(void)
512 {
513    uint8_t status = 0;
514
515    if (_source->dest)
516      {
517         xcb_client_message_event_t ev;
518
519         ev.response_type = XCB_CLIENT_MESSAGE;
520         ev.format = 32;
521         ev.window = _source->dest;
522
523         if (_source->will_accept)
524           {
525              ev.type = ECORE_X_ATOM_XDND_DROP;
526              ev.data.data32[0] = _source->win;
527              ev.data.data32[1] = 0;
528              ev.data.data32[2] = _source->time;
529              xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
530              _source->state = ECORE_X_DND_SOURCE_DROPPED;
531              status = 1;
532           }
533         else
534           {
535              ev.type = ECORE_X_ATOM_XDND_LEAVE;
536              ev.data.data32[0] = _source->win;
537              ev.data.data32[1] = 0;
538              xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
539              _source->state = ECORE_X_DND_SOURCE_IDLE;
540           }
541      }
542    else
543      {
544         /* Dropping on nothing */
545         ecore_x_selection_xdnd_clear();
546         _source->state = ECORE_X_DND_SOURCE_IDLE;
547      }
548
549    ecore_x_window_ignore_set(_source->win, 0);
550
551    _source->prev.window = 0;
552    _source->dest = XCB_NONE;
553
554    return status;
555 } /* ecore_x_dnd_drop */
556
557 EAPI void
558 ecore_x_dnd_send_status(Eina_Bool         will_accept,
559                         Eina_Bool         suppress,
560                         Ecore_X_Rectangle rectangle,
561                         Ecore_X_Atom      action)
562 {
563    xcb_client_message_event_t ev;
564
565    if (_target->state == ECORE_X_DND_TARGET_IDLE)
566       return;
567
568    _target->will_accept = will_accept;
569
570    ev.response_type = XCB_CLIENT_MESSAGE;
571    ev.format = 32;
572    ev.window = _target->source;
573    ev.type = ECORE_X_ATOM_XDND_STATUS;
574
575    ev.data.data32[0] = _target->win;
576    ev.data.data32[1] = 0;
577    if (will_accept)
578       ev.data.data32[1] |= 0x1UL;
579
580    if (!suppress)
581       ev.data.data32[1] |= 0x2UL;
582
583    /* Set rectangle information */
584    ev.data.data32[2] = rectangle.x;
585    ev.data.data32[2] <<= 16;
586    ev.data.data32[2] |= rectangle.y;
587    ev.data.data32[3] = rectangle.width;
588    ev.data.data32[3] <<= 16;
589    ev.data.data32[3] |= rectangle.height;
590
591    if (will_accept)
592      {
593         ev.data.data32[4] = action;
594         _target->accepted_action = action;
595      }
596    else
597      {
598         ev.data.data32[4] = XCB_NONE;
599         _target->accepted_action = action;
600      }
601
602    xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev);
603 } /* ecore_x_dnd_send_status */
604
605 EAPI void
606 ecore_x_dnd_send_finished(void)
607 {
608    xcb_client_message_event_t ev;
609
610    if (_target->state == ECORE_X_DND_TARGET_IDLE)
611       return;
612
613    ev.response_type = XCB_CLIENT_MESSAGE;
614    ev.format = 32;
615    ev.window = _target->source;
616    ev.type = ECORE_X_ATOM_XDND_FINISHED;
617
618    ev.data.data32[0] = _target->win;
619    ev.data.data32[1] = 0;
620    ev.data.data32[2] = 0;
621    if (_target->will_accept)
622      {
623         ev.data.data32[1] |= 0x1UL;
624         ev.data.data32[2] = _target->accepted_action;
625      }
626
627    xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev);
628
629    _target->state = ECORE_X_DND_TARGET_IDLE;
630 } /* ecore_x_dnd_send_finished */
631
632 void
633 ecore_x_dnd_source_action_set(Ecore_X_Atom action)
634 {
635    _source->action = action;
636    if (_source->prev.window)
637       _ecore_x_dnd_drag(_source->prev.window, _source->prev.x, _source->prev.y);
638 } /* ecore_x_dnd_source_action_set */
639
640 Ecore_X_Atom
641 ecore_x_dnd_source_action_get(void)
642 {
643    return _source->action;
644 } /* ecore_x_dnd_source_action_get */
645
646 void
647 _ecore_x_dnd_drag(Ecore_X_Window root,
648                   int            x,
649                   int            y)
650 {
651    xcb_client_message_event_t ev;
652    Ecore_X_Window win;
653    Ecore_X_Window *skip;
654    int num;
655
656    if (_source->state != ECORE_X_DND_SOURCE_DRAGGING)
657       return;
658
659    ev.response_type = XCB_CLIENT_MESSAGE;
660    ev.format = 32;
661
662    /* Attempt to find a DND-capable window under the cursor */
663    skip = ecore_x_window_ignore_list(&num);
664 //   win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num);
665    win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
666    while (win)
667      {
668         xcb_query_tree_cookie_t cookie_tree;
669         xcb_query_tree_reply_t *reply_tree;
670
671         ecore_x_dnd_version_get_prefetch(win);
672         cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, win);
673
674         ecore_x_dnd_version_get_fetch();
675         /* We found the correct window ? */
676         if (ecore_x_dnd_version_get(win))
677           {
678              reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
679              if (reply_tree)
680                 free(reply_tree);
681
682              break;
683           }
684
685         reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
686         if (reply_tree)
687           {
688              win = reply_tree->parent;
689              free(reply_tree);
690           }
691      }
692
693    /* Send XdndLeave to current destination window if we have left it */
694    if ((_source->dest) && (win != _source->dest))
695      {
696         ev.window = _source->dest;
697         ev.type = ECORE_X_ATOM_XDND_LEAVE;
698         ev.data.data32[0] = _source->win;
699         ev.data.data32[1] = 0;
700
701         xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
702         _source->suppress = 0;
703      }
704
705    if (win)
706      {
707         int16_t x1;
708         int16_t x2;
709         int16_t y1;
710         int16_t y2;
711
712         ecore_x_dnd_version_get_prefetch(win);
713         ecore_x_dnd_type_get_prefetch(_source->win);
714
715         ecore_x_dnd_version_get_fetch();
716         if (!ecore_x_dnd_version_get(win))
717           {
718              ecore_x_dnd_type_get_fetch();
719              return;
720           }
721
722         _source->version = MIN(ECORE_X_DND_VERSION,
723                                ecore_x_dnd_version_get(win));
724         if (win != _source->dest)
725           {
726              unsigned char *data;
727              Ecore_X_Atom *types;
728              int num;
729              int i;
730
731              ecore_x_dnd_type_get_fetch();
732              if (!ecore_x_window_prop_property_get(_source->win,
733                                                    ECORE_X_ATOM_XDND_TYPE_LIST,
734                                                    ECORE_X_ATOM_ATOM,
735                                                    32, &data, &num))
736                 return;
737
738              types = (Ecore_X_Atom *)data;
739
740              /* Entered new window, send XdndEnter */
741              ev.window = win;
742              ev.type = ECORE_X_ATOM_XDND_ENTER;
743              ev.data.data32[0] = _source->win;
744              ev.data.data32[1] = 0;
745              if (num > 3)
746                 ev.data.data32[1] |= 0x1UL;
747              else
748                 ev.data.data32[1] &= 0xfffffffeUL;
749
750              ev.data.data32[1] |= ((unsigned long)_source->version) << 24;
751
752              for (i = 2; i < 5; i++)
753                 ev.data.data32[i] = 0;
754              for (i = 0; i < MIN(num, 3); ++i)
755                 ev.data.data32[i + 2] = types[i];
756              free(data);
757              xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev);
758              _source->await_status = 0;
759              _source->will_accept = 0;
760           }
761         else
762            ecore_x_dnd_type_get_fetch();
763
764         /* Determine if we're still in the rectangle from the last status */
765         x1 = _source->rectangle.x;
766         x2 = _source->rectangle.x + _source->rectangle.width;
767         y1 = _source->rectangle.y;
768         y2 = _source->rectangle.y + _source->rectangle.height;
769
770         if ((!_source->await_status) ||
771             (!_source->suppress) ||
772             ((x < x1) || (x > x2) || (y < y1) || (y > y2)))
773           {
774              ev.window = win;
775              ev.type = ECORE_X_ATOM_XDND_POSITION;
776              ev.data.data32[0] = _source->win;
777              ev.data.data32[1] = 0; /* Reserved */
778              ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
779              ev.data.data32[3] = _source->time; /* Version 1 */
780              ev.data.data32[4] = _source->action; /* Version 2, Needs to be pre-set */
781              xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev);
782
783              _source->await_status = 1;
784           }
785      }
786
787    _source->prev.x = x;
788    _source->prev.y = y;
789    _source->prev.window = root;
790    _source->dest = win;
791 } /* _ecore_x_dnd_drag */
792