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