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