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