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