remove xcb support in ecore_x and evas engines as per mailing list
[platform/upstream/efl.git] / src / lib / ecore_x / ecore_x_dnd.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif /* ifdef HAVE_CONFIG_H */
4
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "Ecore.h"
9 #include "ecore_x_private.h"
10 #include "Ecore_X.h"
11 #include "Ecore_X_Atoms.h"
12
13 EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
14 EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
15 EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
16 EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
17 EAPI int ECORE_X_EVENT_XDND_DROP = 0;
18 EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
19
20 static Ecore_X_DND_Source *_source = NULL;
21 static Ecore_X_DND_Target *_target = NULL;
22 static int _ecore_x_dnd_init_count = 0;
23
24 typedef struct _Version_Cache_Item
25 {
26    Ecore_X_Window win;
27    int            ver;
28 } Version_Cache_Item;
29 static Version_Cache_Item *_version_cache = NULL;
30 static int _version_cache_num = 0, _version_cache_alloc = 0;
31 static void (*_posupdatecb)(void *,
32                             Ecore_X_Xdnd_Position *);
33 static void *_posupdatedata;
34
35 void
36 _ecore_x_dnd_init(void)
37 {
38    if (!_ecore_x_dnd_init_count)
39      {
40         _source = calloc(1, sizeof(Ecore_X_DND_Source));
41         if (!_source) return;
42         _source->version = ECORE_X_DND_VERSION;
43         _source->win = None;
44         _source->dest = None;
45         _source->state = ECORE_X_DND_SOURCE_IDLE;
46         _source->prev.window = 0;
47
48         _target = calloc(1, sizeof(Ecore_X_DND_Target));
49         if (!_target)
50           {
51              free(_source);
52              _source = NULL;
53              return;
54           }
55         _target->win = None;
56         _target->source = None;
57         _target->state = ECORE_X_DND_TARGET_IDLE;
58
59         ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
60         ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
61         ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
62         ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
63         ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
64         ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
65      }
66
67    _ecore_x_dnd_init_count++;
68 }
69
70 void
71 _ecore_x_dnd_shutdown(void)
72 {
73    _ecore_x_dnd_init_count--;
74    if (_ecore_x_dnd_init_count > 0)
75      return;
76
77    if (_source)
78      free(_source);
79
80    _source = NULL;
81
82    if (_target)
83      free(_target);
84
85    _target = NULL;
86
87    _ecore_x_dnd_init_count = 0;
88 }
89
90 static Eina_Bool
91 _ecore_x_dnd_converter_copy(char *target EINA_UNUSED,
92                             void *data,
93                             int size,
94                             void **data_ret,
95                             int *size_ret,
96                             Ecore_X_Atom *tprop EINA_UNUSED,
97                             int *count EINA_UNUSED)
98 {
99    XTextProperty text_prop;
100    char *mystr;
101    XICCEncodingStyle style = XTextStyle;
102
103    if (!data || !size)
104      return EINA_FALSE;
105
106    mystr = calloc(1, size + 1);
107    if (!mystr)
108      return EINA_FALSE;
109
110    memcpy(mystr, data, size);
111
112    if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style,
113                                  &text_prop) == Success)
114      {
115         int bufsize = strlen((char *)text_prop.value) + 1;
116         if (_ecore_xlib_sync) ecore_x_sync();
117         *data_ret = malloc(bufsize);
118         if (!*data_ret)
119           {
120              free(mystr);
121              return EINA_FALSE;
122           }
123         memcpy(*data_ret, text_prop.value, bufsize);
124         *size_ret = bufsize;
125         XFree(text_prop.value);
126         free(mystr);
127         return EINA_TRUE;
128      }
129    else
130      {
131         if (_ecore_xlib_sync) ecore_x_sync();
132         free(mystr);
133         return EINA_FALSE;
134      }
135 }
136
137 EAPI void
138 ecore_x_dnd_aware_set(Ecore_X_Window win,
139                       Eina_Bool on)
140 {
141    Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
142
143    LOGFN(__FILE__, __LINE__, __FUNCTION__);
144    if (on)
145      ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE,
146                                       XA_ATOM, 32, &prop_data, 1);
147    else
148      ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE);
149 }
150
151 EAPI int
152 ecore_x_dnd_version_get(Ecore_X_Window win)
153 {
154    unsigned char *prop_data;
155    int num;
156    Version_Cache_Item *t;
157
158    LOGFN(__FILE__, __LINE__, __FUNCTION__);
159    // this looks hacky - and it is, but we need a way of caching info about
160    // a window while dragging, because we literally query this every mouse
161    // move and going to and from x multiple times per move is EXPENSIVE
162    // and slows things down, puts lots of load on x etc.
163    if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
164      if (_version_cache)
165        {
166           int i;
167
168           for (i = 0; i < _version_cache_num; i++)
169             {
170                if (_version_cache[i].win == win)
171                  return _version_cache[i].ver;
172             }
173        }
174
175    if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE,
176                                         XA_ATOM, 32, &prop_data, &num))
177      {
178         int version = (int)*prop_data;
179         free(prop_data);
180         if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
181           {
182              _version_cache_num++;
183              if (_version_cache_num > _version_cache_alloc)
184                _version_cache_alloc += 16;
185
186              t = realloc(_version_cache,
187                          _version_cache_alloc *
188                          sizeof(Version_Cache_Item));
189              if (!t) return 0;
190              _version_cache = t;
191              _version_cache[_version_cache_num - 1].win = win;
192              _version_cache[_version_cache_num - 1].ver = version;
193           }
194
195         return version;
196      }
197
198    if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
199      {
200         _version_cache_num++;
201         if (_version_cache_num > _version_cache_alloc)
202           _version_cache_alloc += 16;
203
204         t = realloc(_version_cache, _version_cache_alloc *
205                     sizeof(Version_Cache_Item));
206         if (!t)
207           {
208              if (prop_data) free(prop_data);
209              return 0;
210           }
211
212         _version_cache = t;
213         _version_cache[_version_cache_num - 1].win = win;
214         _version_cache[_version_cache_num - 1].ver = 0;
215      }
216
217    if (prop_data) free(prop_data);
218
219    return 0;
220 }
221
222 EAPI Eina_Bool
223 ecore_x_dnd_type_isset(Ecore_X_Window win,
224                        const char *type)
225 {
226    int num, i, ret = EINA_FALSE;
227    unsigned char *data;
228    Ecore_X_Atom *atoms, atom;
229
230    LOGFN(__FILE__, __LINE__, __FUNCTION__);
231    if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
232                                          XA_ATOM, 32, &data, &num))
233      return ret;
234
235    atom = ecore_x_atom_get(type);
236    atoms = (Ecore_X_Atom *)data;
237
238    for (i = 0; i < num; ++i)
239      {
240         if (atom == atoms[i])
241           {
242              ret = EINA_TRUE;
243              break;
244           }
245      }
246
247    if (data) free(data);
248    return ret;
249 }
250
251 EAPI void
252 ecore_x_dnd_type_set(Ecore_X_Window win,
253                      const char *type,
254                      Eina_Bool on)
255 {
256    Ecore_X_Atom atom;
257    Ecore_X_Atom *oldset = NULL, *newset = NULL;
258    int i, j = 0, num = 0;
259    unsigned char *data = NULL;
260    unsigned char *old_data = NULL;
261
262    LOGFN(__FILE__, __LINE__, __FUNCTION__);
263    atom = ecore_x_atom_get(type);
264
265    LOGFN(__FILE__, __LINE__, __FUNCTION__);
266    if (on)
267      {
268         if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
269                                              XA_ATOM, 32, &old_data, &num) > 0)
270           {
271              if (ecore_x_dnd_type_isset(win, type))
272                {
273                   if (old_data) free(old_data);
274                   return;
275                }
276           }
277
278         newset = calloc(num + 1, sizeof(Ecore_X_Atom));
279         if (!newset)
280           {
281              if (old_data) free(old_data);
282              return;
283           }
284
285         oldset = (Ecore_X_Atom *)old_data;
286         data = (unsigned char *)newset;
287
288         for (i = 0; i < num; i++)
289           newset[i + 1] = oldset[i];
290         /* prepend the new type */
291         newset[0] = atom;
292
293         ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
294                                          XA_ATOM, 32, data, num + 1);
295      }
296    else
297      {
298         if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
299                                              XA_ATOM, 32, &old_data, &num) == 0)
300            return;
301         if (!ecore_x_dnd_type_isset(win, type))
302           {
303              if (old_data) free(old_data);
304              return;
305           }
306
307         newset = calloc(num - 1, sizeof(Ecore_X_Atom));
308         if (!newset)
309           {
310              if (old_data) free(old_data);
311              return;
312           }
313
314         oldset = (Ecore_X_Atom *)old_data;
315         data = (unsigned char *)newset;
316         for (i = 0; i < num; i++)
317           if (oldset[i] != atom)
318             newset[j++] = oldset[i];
319
320         ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
321                                          XA_ATOM, 32, data, num - 1);
322      }
323
324    if (oldset) XFree(oldset);
325    free(newset);
326 }
327
328 EAPI void
329 ecore_x_dnd_types_set(Ecore_X_Window win,
330                       const char **types,
331                       unsigned int num_types)
332 {
333    Ecore_X_Atom *newset = NULL;
334    unsigned int i;
335    unsigned char *data = NULL;
336
337    LOGFN(__FILE__, __LINE__, __FUNCTION__);
338    if (!num_types)
339      ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST);
340    else
341      {
342         newset = calloc(num_types, sizeof(Ecore_X_Atom));
343         if (!newset)
344           return;
345
346         data = (unsigned char *)newset;
347         for (i = 0; i < num_types; i++)
348           {
349              newset[i] = ecore_x_atom_get(types[i]);
350              ecore_x_selection_converter_atom_add(newset[i],
351                                                   _ecore_x_dnd_converter_copy);
352           }
353         ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
354                                          XA_ATOM, 32, data, num_types);
355         free(newset);
356      }
357 }
358
359 EAPI void
360 ecore_x_dnd_actions_set(Ecore_X_Window win,
361                         Ecore_X_Atom *actions,
362                         unsigned int num_actions)
363 {
364    unsigned int i;
365    unsigned char *data = NULL;
366
367    LOGFN(__FILE__, __LINE__, __FUNCTION__);
368    if (!num_actions)
369      ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST);
370    else
371      {
372         data = (unsigned char *)actions;
373         for (i = 0; i < num_actions; i++)
374           {
375              ecore_x_selection_converter_atom_add(actions[i],
376                                                   _ecore_x_dnd_converter_copy);
377           }
378         ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST,
379                                          XA_ATOM, 32, data, num_actions);
380      }
381 }
382
383 /**
384  * The DND position update cb is called Ecore_X sends a DND position to a
385  * client.
386  *
387  * It essentially mirrors some of the data sent in the position message.
388  * Generally this cb should be set just before position update is called.
389  * Please note well you need to look after your own data pointer if someone
390  * trashes you position update cb set.
391  *
392  * It is considered good form to clear this when the dnd event finishes.
393  *
394  * @param cb Callback to updated each time ecore_x sends a position update.
395  * @param data User data.
396  */
397 EAPI void
398 ecore_x_dnd_callback_pos_update_set(
399   void (*cb)(void *,
400              Ecore_X_Xdnd_Position *data),
401   const void *data)
402 {
403    _posupdatecb = cb;
404    _posupdatedata = (void *)data; /* Discard the const early */
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
421 static Eina_Bool
422 _ecore_x_dnd_begin(Ecore_X_Window source,
423                    Eina_Bool self,
424                    unsigned char *data,
425                    int size)
426 {
427    LOGFN(__FILE__, __LINE__, __FUNCTION__);
428    if (!ecore_x_dnd_version_get(source))
429      return EINA_FALSE;
430
431    /* Take ownership of XdndSelection */
432    if (!ecore_x_selection_xdnd_set(source, data, size))
433      return EINA_FALSE;
434
435    if (_version_cache)
436      {
437         free(_version_cache);
438         _version_cache = NULL;
439         _version_cache_num = 0;
440         _version_cache_alloc = 0;
441      }
442
443    ecore_x_window_shadow_tree_flush();
444
445    _source->win = source;
446    if (!self) ecore_x_window_ignore_set(_source->win, 1);
447    _source->state = ECORE_X_DND_SOURCE_DRAGGING;
448    _source->time = _ecore_x_event_last_time;
449    _source->prev.window = 0;
450
451    /* Default Accepted Action: move */
452    _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE;
453    _source->accepted_action = None;
454    _source->dest = None;
455
456    return EINA_TRUE;
457 }
458
459 static Eina_Bool
460 _ecore_x_dnd_drop(Eina_Bool self)
461 {
462    XEvent xev;
463    int status = EINA_FALSE;
464
465    LOGFN(__FILE__, __LINE__, __FUNCTION__);
466    if (_source->dest)
467      {
468         xev.xany.type = ClientMessage;
469         xev.xany.display = _ecore_x_disp;
470         xev.xclient.format = 32;
471         xev.xclient.window = _source->dest;
472
473         if (_source->will_accept)
474           {
475              xev.xclient.message_type = ECORE_X_ATOM_XDND_DROP;
476              xev.xclient.data.l[0] = _source->win;
477              xev.xclient.data.l[1] = 0;
478              xev.xclient.data.l[2] = _source->time;
479              XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev);
480              if (_ecore_xlib_sync) ecore_x_sync();
481              _source->state = ECORE_X_DND_SOURCE_DROPPED;
482              status = EINA_TRUE;
483           }
484         else
485           {
486              xev.xclient.message_type = ECORE_X_ATOM_XDND_LEAVE;
487              xev.xclient.data.l[0] = _source->win;
488              xev.xclient.data.l[1] = 0;
489              XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev);
490              if (_ecore_xlib_sync) ecore_x_sync();
491              _source->state = ECORE_X_DND_SOURCE_IDLE;
492           }
493      }
494    else
495      {
496         /* Dropping on nothing */
497         ecore_x_selection_xdnd_clear();
498         _source->state = ECORE_X_DND_SOURCE_IDLE;
499      }
500
501    if (!self) ecore_x_window_ignore_set(_source->win, 0);
502
503    _source->prev.window = 0;
504
505    return status;
506 }
507
508 EAPI Eina_Bool
509 ecore_x_dnd_begin(Ecore_X_Window source,
510                   unsigned char *data,
511                   int size)
512 {
513    return _ecore_x_dnd_begin(source, EINA_FALSE, data, size);
514 }
515
516 EAPI Eina_Bool
517 ecore_x_dnd_drop(void)
518 {
519    return _ecore_x_dnd_drop(EINA_FALSE);
520 }
521
522 EAPI Eina_Bool
523 ecore_x_dnd_self_begin(Ecore_X_Window source,
524                        unsigned char *data,
525                        int size)
526 {
527    return _ecore_x_dnd_begin(source, EINA_TRUE, data, size);
528 }
529
530 EAPI Eina_Bool
531 ecore_x_dnd_self_drop(void)
532 {
533    return _ecore_x_dnd_drop(EINA_TRUE);
534 }
535
536 EAPI void
537 ecore_x_dnd_send_status(Eina_Bool will_accept,
538                         Eina_Bool suppress,
539                         Ecore_X_Rectangle rectangle,
540                         Ecore_X_Atom action)
541 {
542    XEvent xev;
543
544    EINA_SAFETY_ON_NULL_RETURN(_ecore_x_disp);
545
546    if (_target->state == ECORE_X_DND_TARGET_IDLE)
547      return;
548
549    LOGFN(__FILE__, __LINE__, __FUNCTION__);
550    memset(&xev, 0, sizeof(XEvent));
551
552    _target->will_accept = will_accept;
553
554    xev.xclient.type = ClientMessage;
555    xev.xclient.display = _ecore_x_disp;
556    xev.xclient.message_type = ECORE_X_ATOM_XDND_STATUS;
557    xev.xclient.format = 32;
558    xev.xclient.window = _target->source;
559
560    xev.xclient.data.l[0] = _target->win;
561    xev.xclient.data.l[1] = 0;
562    if (will_accept)
563      xev.xclient.data.l[1] |= 0x1UL;
564
565    if (!suppress)
566      xev.xclient.data.l[1] |= 0x2UL;
567
568    /* Set rectangle information */
569    xev.xclient.data.l[2] = rectangle.x;
570    xev.xclient.data.l[2] <<= 16;
571    xev.xclient.data.l[2] |= rectangle.y;
572    xev.xclient.data.l[3] = rectangle.width;
573    xev.xclient.data.l[3] <<= 16;
574    xev.xclient.data.l[3] |= rectangle.height;
575
576    if (will_accept)
577      {
578         xev.xclient.data.l[4] = action;
579         _target->accepted_action = action;
580      }
581    else
582      {
583         xev.xclient.data.l[4] = None;
584         _target->accepted_action = action;
585      }
586
587    XSendEvent(_ecore_x_disp, _target->source, False, 0, &xev);
588    if (_ecore_xlib_sync) ecore_x_sync();
589 }
590
591 EAPI void
592 ecore_x_dnd_send_finished(void)
593 {
594    XEvent xev;
595
596    EINA_SAFETY_ON_NULL_RETURN(_ecore_x_disp);
597
598    if (_target->state == ECORE_X_DND_TARGET_IDLE)
599      return;
600
601    LOGFN(__FILE__, __LINE__, __FUNCTION__);
602    xev.xany.type = ClientMessage;
603    xev.xany.display = _ecore_x_disp;
604    xev.xclient.message_type = ECORE_X_ATOM_XDND_FINISHED;
605    xev.xclient.format = 32;
606    xev.xclient.window = _target->source;
607
608    xev.xclient.data.l[0] = _target->win;
609    xev.xclient.data.l[1] = 0;
610    xev.xclient.data.l[2] = 0;
611    if (_target->will_accept)
612      {
613         xev.xclient.data.l[1] |= 0x1UL;
614         xev.xclient.data.l[2] = _target->accepted_action;
615      }
616
617    XSendEvent(_ecore_x_disp, _target->source, False, 0, &xev);
618    if (_ecore_xlib_sync) ecore_x_sync();
619
620    _target->state = ECORE_X_DND_TARGET_IDLE;
621 }
622
623 EAPI void
624 ecore_x_dnd_source_action_set(Ecore_X_Atom action)
625 {
626    _source->action = action;
627    if (_source->prev.window)
628      _ecore_x_dnd_drag(_source->prev.window, _source->prev.x, _source->prev.y);
629 }
630
631 EAPI Ecore_X_Atom
632 ecore_x_dnd_source_action_get(void)
633 {
634    return _source->action;
635 }
636
637 void
638 _ecore_x_dnd_drag(Ecore_X_Window root,
639                   int x,
640                   int y)
641 {
642    XEvent xev;
643    Ecore_X_Window win;
644    Ecore_X_Window *skip;
645    Ecore_X_Xdnd_Position pos;
646    int num;
647
648    if (_source->state != ECORE_X_DND_SOURCE_DRAGGING)
649      return;
650
651    /* Preinitialize XEvent struct */
652    memset(&xev, 0, sizeof(XEvent));
653    xev.xany.type = ClientMessage;
654    xev.xany.display = _ecore_x_disp;
655    xev.xclient.format = 32;
656
657    /* Attempt to find a DND-capable window under the cursor */
658    skip = ecore_x_window_ignore_list(&num);
659 // WARNING - this function is HEAVY. it goes to and from x a LOT walking the
660 // window tree - use the SHADOW version - makes a 1-off tree copy, then uses
661 // that instead.
662 //   win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num);
663    win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
664 // NOTE: This now uses the shadow version to find parent windows
665 //   while ((win) && !(ecore_x_dnd_version_get(win)))
666 //     win = ecore_x_window_parent_get(win);
667    while ((win) && !(ecore_x_dnd_version_get(win)))
668      win = ecore_x_window_shadow_parent_get(root, win);
669
670    /* Send XdndLeave to current destination window if we have left it */
671    if ((_source->dest) && (win != _source->dest))
672      {
673         xev.xclient.window = _source->dest;
674         xev.xclient.message_type = ECORE_X_ATOM_XDND_LEAVE;
675         xev.xclient.data.l[0] = _source->win;
676         xev.xclient.data.l[1] = 0;
677
678         XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev);
679         if (_ecore_xlib_sync) ecore_x_sync();
680         _source->suppress = 0;
681      }
682
683    if (win)
684      {
685         int x1, x2, y1, y2;
686
687         _source->version = MIN(ECORE_X_DND_VERSION,
688                                ecore_x_dnd_version_get(win));
689         if (win != _source->dest)
690           {
691              int i;
692              unsigned char *data;
693              Ecore_X_Atom *types;
694
695              if (ecore_x_window_prop_property_get(_source->win,
696                                                   ECORE_X_ATOM_XDND_TYPE_LIST,
697                                                   XA_ATOM,
698                                                   32,
699                                                   &data,
700                                                   &num))
701                {
702                   types = (Ecore_X_Atom *)data;
703
704                   /* Entered new window, send XdndEnter */
705                   xev.xclient.window = win;
706                   xev.xclient.message_type = ECORE_X_ATOM_XDND_ENTER;
707                   xev.xclient.data.l[0] = _source->win;
708                   xev.xclient.data.l[1] = 0;
709                   if (num > 3)
710                      xev.xclient.data.l[1] |= 0x1UL;
711                   else
712                      xev.xclient.data.l[1] &= 0xfffffffeUL;
713
714                   xev.xclient.data.l[1] |= ((unsigned long)_source->version) << 24;
715
716                   for (i = 2; i < 5; i++)
717                      xev.xclient.data.l[i] = 0;
718                   for (i = 0; i < MIN(num, 3); ++i)
719                      xev.xclient.data.l[i + 2] = types[i];
720                   XFree(data);
721                   XSendEvent(_ecore_x_disp, win, False, 0, &xev);
722                   if (_ecore_xlib_sync) ecore_x_sync();
723                }
724              _source->await_status = 0;
725              _source->will_accept = 0;
726           }
727
728         /* Determine if we're still in the rectangle from the last status */
729         x1 = _source->rectangle.x;
730         x2 = _source->rectangle.x + _source->rectangle.width;
731         y1 = _source->rectangle.y;
732         y2 = _source->rectangle.y + _source->rectangle.height;
733
734         if ((!_source->await_status) ||
735             (!_source->suppress) ||
736             ((x < x1) || (x > x2) || (y < y1) || (y > y2)))
737           {
738              xev.xclient.window = win;
739              xev.xclient.message_type = ECORE_X_ATOM_XDND_POSITION;
740              xev.xclient.data.l[0] = _source->win;
741              xev.xclient.data.l[1] = 0; /* Reserved */
742              xev.xclient.data.l[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
743              xev.xclient.data.l[3] = _source->time; /* Version 1 */
744              xev.xclient.data.l[4] = _source->action; /* Version 2, Needs to be pre-set */
745              XSendEvent(_ecore_x_disp, win, False, 0, &xev);
746              if (_ecore_xlib_sync) ecore_x_sync();
747
748              _source->await_status = 1;
749           }
750      }
751
752    if (_posupdatecb)
753      {
754         pos.position.x = x;
755         pos.position.y = y;
756         pos.win = win;
757         pos.prev = _source->dest;
758         _posupdatecb(_posupdatedata, &pos);
759      }
760
761    _source->prev.x = x;
762    _source->prev.y = y;
763    _source->prev.window = root;
764    _source->dest = win;
765 }
766
767 EAPI Eina_Bool
768 ecore_x_dnd_abort(Ecore_X_Window xwin_source)
769 {
770    if (xwin_source == _source->win)
771      {
772         _source->will_accept = 0;
773         return ecore_x_dnd_self_drop();
774      }
775    else return EINA_FALSE;
776 }
777
778 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/