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