1 #include "ecore_xcb_private.h"
4 typedef struct _Version_Cache_Item
10 /* local function prototypes */
11 static Eina_Bool _ecore_xcb_dnd_converter_copy(char *target EINA_UNUSED,
16 Ecore_X_Atom *tprop EINA_UNUSED,
17 int *count EINA_UNUSED);
20 static int _ecore_xcb_dnd_init_count = 0;
21 static Ecore_X_DND_Source *_source = NULL;
22 static Ecore_X_DND_Target *_target = NULL;
23 static Version_Cache_Item *_version_cache = NULL;
24 static int _version_cache_num = 0, _version_cache_alloc = 0;
25 static void (*_posupdatecb)(void *,
26 Ecore_X_Xdnd_Position *);
27 static void *_posupdatedata;
29 /* external variables */
30 EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
31 EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
32 EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
33 EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
34 EAPI int ECORE_X_EVENT_XDND_DROP = 0;
35 EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
38 _ecore_xcb_dnd_init(void)
40 LOGFN(__FILE__, __LINE__, __FUNCTION__);
42 if (!_ecore_xcb_dnd_init_count)
44 _source = calloc(1, sizeof(Ecore_X_DND_Source));
46 _source->version = ECORE_X_DND_VERSION;
47 _source->win = XCB_NONE;
48 _source->dest = XCB_NONE;
49 _source->state = ECORE_X_DND_SOURCE_IDLE;
50 _source->prev.window = 0;
52 _target = calloc(1, sizeof(Ecore_X_DND_Target));
59 _target->win = XCB_NONE;
60 _target->source = XCB_NONE;
61 _target->state = ECORE_X_DND_TARGET_IDLE;
63 ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
64 ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
65 ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
66 ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
67 ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
68 ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
70 _ecore_xcb_dnd_init_count++;
74 _ecore_xcb_dnd_shutdown(void)
76 LOGFN(__FILE__, __LINE__, __FUNCTION__);
78 _ecore_xcb_dnd_init_count--;
79 if (_ecore_xcb_dnd_init_count > 0) return;
80 if (_source) free(_source);
82 if (_target) free(_target);
84 _ecore_xcb_dnd_init_count = 0;
88 ecore_x_dnd_send_status(Eina_Bool will_accept,
90 Ecore_X_Rectangle rect,
93 xcb_client_message_event_t ev;
95 LOGFN(__FILE__, __LINE__, __FUNCTION__);
98 if (_target->state == ECORE_X_DND_TARGET_IDLE) return;
100 memset(&ev, 0, sizeof(xcb_client_message_event_t));
102 _target->will_accept = will_accept;
104 ev.response_type = XCB_CLIENT_MESSAGE;
105 ev.type = ECORE_X_ATOM_XDND_STATUS;
107 ev.window = _target->source;
108 ev.data.data32[0] = _target->win;
109 ev.data.data32[1] = 0;
110 if (will_accept) ev.data.data32[1] |= 0x1UL;
111 if (!suppress) ev.data.data32[1] |= 0x2UL;
113 ev.data.data32[2] = rect.x;
114 ev.data.data32[2] <<= 16;
115 ev.data.data32[2] |= rect.y;
116 ev.data.data32[3] = rect.width;
117 ev.data.data32[3] <<= 16;
118 ev.data.data32[3] |= rect.height;
121 ev.data.data32[4] = action;
123 ev.data.data32[4] = XCB_NONE;
124 _target->accepted_action = action;
126 xcb_send_event(_ecore_xcb_conn, 0, _target->source,
127 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
132 ecore_x_dnd_aware_set(Ecore_X_Window win,
135 Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
137 LOGFN(__FILE__, __LINE__, __FUNCTION__);
140 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE,
141 ECORE_X_ATOM_ATOM, 32, &prop_data, 1);
143 ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE);
147 ecore_x_dnd_version_get(Ecore_X_Window win)
151 Version_Cache_Item *t;
153 LOGFN(__FILE__, __LINE__, __FUNCTION__);
155 if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
161 for (i = 0; i < _version_cache_num; i++)
163 if (_version_cache[i].win == win)
164 return _version_cache[i].ver;
169 if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE,
170 ECORE_X_ATOM_ATOM, 32, &data, &num))
174 version = (int)*data;
176 if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
178 _version_cache_num++;
179 if (_version_cache_num > _version_cache_alloc)
180 _version_cache_alloc += 16;
181 t = realloc(_version_cache,
182 _version_cache_alloc * sizeof(Version_Cache_Item));
185 _version_cache[_version_cache_num - 1].win = win;
186 _version_cache[_version_cache_num - 1].ver = version;
191 if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
193 _version_cache_num++;
194 if (_version_cache_num > _version_cache_alloc)
195 _version_cache_alloc += 16;
196 t = realloc(_version_cache,
197 _version_cache_alloc * sizeof(Version_Cache_Item));
200 _version_cache[_version_cache_num - 1].win = win;
201 _version_cache[_version_cache_num - 1].ver = 0;
208 ecore_x_dnd_type_isset(Ecore_X_Window win,
212 Eina_Bool ret = EINA_FALSE;
214 Ecore_X_Atom *atoms, atom;
216 LOGFN(__FILE__, __LINE__, __FUNCTION__);
219 if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
220 ECORE_X_ATOM_ATOM, 32, &data, &num))
223 atom = ecore_x_atom_get(type);
224 atoms = (Ecore_X_Atom *)data;
225 for (i = 0; i < num; ++i)
227 if (atom == atoms[i])
239 ecore_x_dnd_type_set(Ecore_X_Window win,
243 Ecore_X_Atom atom, *oldset = NULL, *newset = NULL;
244 int i = 0, j = 0, num = 0;
245 unsigned char *data = NULL, *old_data = NULL;
247 LOGFN(__FILE__, __LINE__, __FUNCTION__);
250 atom = ecore_x_atom_get(type);
251 ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
252 ECORE_X_ATOM_ATOM, 32, &old_data, &num);
253 oldset = (Ecore_X_Atom *)old_data;
256 if (ecore_x_dnd_type_isset(win, type))
261 newset = calloc(num + 1, sizeof(Ecore_X_Atom));
263 data = (unsigned char *)newset;
264 for (i = 0; i < num; i++)
265 newset[i + 1] = oldset[i];
267 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
268 ECORE_X_ATOM_ATOM, 32, data, num + 1);
272 if (!ecore_x_dnd_type_isset(win, type))
277 newset = calloc(num - 1, sizeof(Ecore_X_Atom));
283 data = (unsigned char *)newset;
284 for (i = 0; i < num; i++)
285 if (oldset[i] != atom)
286 newset[j++] = oldset[i];
287 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
288 ECORE_X_ATOM_ATOM, 32, data, num - 1);
295 ecore_x_dnd_types_set(Ecore_X_Window win,
297 unsigned int num_types)
299 Ecore_X_Atom *newset = NULL;
301 unsigned char *data = NULL;
303 LOGFN(__FILE__, __LINE__, __FUNCTION__);
307 ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST);
310 newset = calloc(num_types, sizeof(Ecore_X_Atom));
313 data = (unsigned char *)newset;
314 for (i = 0; i < num_types; i++)
316 newset[i] = ecore_x_atom_get(types[i]);
317 ecore_x_selection_converter_atom_add(newset[i],
318 _ecore_xcb_dnd_converter_copy);
320 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
321 ECORE_X_ATOM_ATOM, 32, data,
328 ecore_x_dnd_actions_set(Ecore_X_Window win,
329 Ecore_X_Atom *actions,
330 unsigned int num_actions)
333 unsigned char *data = NULL;
335 LOGFN(__FILE__, __LINE__, __FUNCTION__);
339 ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST);
342 data = (unsigned char *)actions;
343 for (i = 0; i < num_actions; i++)
344 ecore_x_selection_converter_atom_add(actions[i],
345 _ecore_xcb_dnd_converter_copy);
346 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST,
347 ECORE_X_ATOM_ATOM, 32, data,
353 * The DND position update cb is called Ecore_X sends a DND position to a
356 * It essentially mirrors some of the data sent in the position message.
357 * Generally this cb should be set just before position update is called.
358 * Please note well you need to look after your own data pointer if someone
359 * trashes you position update cb set.
361 * It is considered good form to clear this when the dnd event finishes.
363 * @param cb Callback to updated each time ecore_x sends a position update.
364 * @param data User data.
367 ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, Ecore_X_Xdnd_Position *data),
371 _posupdatedata = (void *)data;
375 _ecore_x_dnd_begin(Ecore_X_Window source, Eina_Bool self, unsigned char *data, int size)
377 LOGFN(__FILE__, __LINE__, __FUNCTION__);
379 if (!ecore_x_dnd_version_get(source)) return EINA_FALSE;
381 /* Take ownership of XdndSelection */
382 if (!ecore_x_selection_xdnd_set(source, data, size)) return EINA_FALSE;
386 free(_version_cache);
387 _version_cache = NULL;
388 _version_cache_num = 0;
389 _version_cache_alloc = 0;
392 ecore_x_window_shadow_tree_flush();
394 _source->win = source;
395 if (!self) ecore_x_window_ignore_set(_source->win, 1);
396 _source->state = ECORE_X_DND_SOURCE_DRAGGING;
397 _source->time = _ecore_xcb_events_last_time_get();
398 _source->prev.window = 0;
400 /* Default Accepted Action: move */
401 _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE;
402 _source->accepted_action = XCB_NONE;
403 _source->dest = XCB_NONE;
409 _ecore_x_dnd_drop(Eina_Bool self)
411 xcb_client_message_event_t ev;
412 Eina_Bool status = EINA_FALSE;
414 LOGFN(__FILE__, __LINE__, __FUNCTION__);
417 memset(&ev, 0, sizeof(xcb_client_message_event_t));
421 ev.response_type = XCB_CLIENT_MESSAGE;
423 ev.window = _source->dest;
425 if (_source->will_accept)
427 ev.type = ECORE_X_ATOM_XDND_DROP;
428 ev.data.data32[0] = _source->win;
429 ev.data.data32[1] = 0;
430 ev.data.data32[2] = _source->time;
432 xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
433 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
435 _source->state = ECORE_X_DND_SOURCE_DROPPED;
440 ev.type = ECORE_X_ATOM_XDND_LEAVE;
441 ev.data.data32[0] = _source->win;
442 ev.data.data32[1] = 0;
444 xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
445 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
447 _source->state = ECORE_X_DND_SOURCE_IDLE;
452 ecore_x_selection_xdnd_clear();
453 _source->state = ECORE_X_DND_SOURCE_IDLE;
456 if (!self) ecore_x_window_ignore_set(_source->win, 0);
457 _source->prev.window = 0;
463 ecore_x_dnd_begin(Ecore_X_Window source,
467 return _ecore_x_dnd_begin(source, EINA_FALSE, data, size);
471 ecore_x_dnd_drop(void)
473 return _ecore_x_dnd_drop(EINA_FALSE);
477 ecore_x_dnd_self_begin(Ecore_X_Window source,
481 return _ecore_x_dnd_begin(source, EINA_TRUE, data, size);
485 ecore_x_dnd_self_drop(void)
487 return _ecore_x_dnd_drop(EINA_TRUE);
491 ecore_x_dnd_send_finished(void)
493 xcb_client_message_event_t ev;
495 LOGFN(__FILE__, __LINE__, __FUNCTION__);
498 if (_target->state == ECORE_X_DND_TARGET_IDLE) return;
500 memset(&ev, 0, sizeof(xcb_client_message_event_t));
502 ev.response_type = XCB_CLIENT_MESSAGE;
504 ev.type = ECORE_X_ATOM_XDND_FINISHED;
505 ev.window = _target->source;
506 ev.data.data32[0] = _target->win;
507 ev.data.data32[1] = 0;
508 ev.data.data32[2] = 0;
509 if (_target->will_accept)
511 ev.data.data32[1] |= 0x1UL;
512 ev.data.data32[2] = _target->accepted_action;
515 xcb_send_event(_ecore_xcb_conn, 0, _target->source,
516 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
518 _target->state = ECORE_X_DND_TARGET_IDLE;
522 ecore_x_dnd_source_action_set(Ecore_X_Atom action)
524 LOGFN(__FILE__, __LINE__, __FUNCTION__);
526 _source->action = action;
527 if (_source->prev.window)
528 _ecore_xcb_dnd_drag(_source->prev.window,
529 _source->prev.x, _source->prev.y);
533 _ecore_xcb_dnd_source_get(void)
539 _ecore_xcb_dnd_target_get(void)
545 _ecore_xcb_dnd_drag(Ecore_X_Window root,
549 xcb_client_message_event_t ev;
550 Ecore_X_Window win, *skip;
551 Ecore_X_Xdnd_Position pos;
554 LOGFN(__FILE__, __LINE__, __FUNCTION__);
557 if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) return;
559 memset(&ev, 0, sizeof(xcb_client_message_event_t));
561 ev.response_type = XCB_CLIENT_MESSAGE;
564 skip = ecore_x_window_ignore_list(&num);
565 win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
566 while ((win) && !(ecore_x_dnd_version_get(win)))
567 win = ecore_x_window_shadow_parent_get(root, win);
569 if ((_source->dest) && (win != _source->dest))
571 ev.window = _source->dest;
572 ev.type = ECORE_X_ATOM_XDND_LEAVE;
573 ev.data.data32[0] = _source->win;
574 ev.data.data32[1] = 0;
576 xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
577 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
579 _source->suppress = 0;
586 _source->version = MIN(ECORE_X_DND_VERSION,
587 ecore_x_dnd_version_get(win));
588 if (win != _source->dest)
594 ecore_x_window_prop_property_get(_source->win,
595 ECORE_X_ATOM_XDND_TYPE_LIST,
596 ECORE_X_ATOM_ATOM, 32,
598 types = (Ecore_X_Atom *)data;
600 ev.type = ECORE_X_ATOM_XDND_ENTER;
601 ev.data.data32[0] = _source->win;
602 ev.data.data32[1] = 0;
604 ev.data.data32[1] |= 0x1UL;
606 ev.data.data32[1] &= 0xfffffffeUL;
607 ev.data.data32[1] |= ((unsigned long)_source->version) << 24;
609 for (i = 2; i < 5; i++)
610 ev.data.data32[i] = 0;
611 for (i = 0; i < MIN(num, 3); ++i)
612 ev.data.data32[i + 2] = types[i];
615 xcb_send_event(_ecore_xcb_conn, 0, win,
616 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
618 _source->await_status = 0;
619 _source->will_accept = 0;
622 x1 = _source->rectangle.x;
623 x2 = _source->rectangle.x + _source->rectangle.width;
624 y1 = _source->rectangle.y;
625 y2 = _source->rectangle.y + _source->rectangle.height;
627 if ((!_source->await_status) || (!_source->suppress) ||
628 ((x < x1) || (x > x2) || (y < y1) || (y > y2)))
631 ev.type = ECORE_X_ATOM_XDND_POSITION;
632 ev.data.data32[0] = _source->win;
633 ev.data.data32[1] = 0;
634 ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
635 ev.data.data32[3] = _source->time;
636 ev.data.data32[4] = _source->action;
638 xcb_send_event(_ecore_xcb_conn, 0, win,
639 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
641 _source->await_status = 1;
650 pos.prev = _source->dest;
651 _posupdatecb(_posupdatedata, &pos);
656 _source->prev.window = root;
661 ecore_x_dnd_source_action_get(void)
663 return _source->action;
666 /* local functions */
668 _ecore_xcb_dnd_converter_copy(char *target EINA_UNUSED,
673 Ecore_X_Atom *tprop EINA_UNUSED,
674 int *count EINA_UNUSED)
676 Ecore_Xcb_Textproperty text_prop;
677 Ecore_Xcb_Encoding_Style style = XcbTextStyle;
680 LOGFN(__FILE__, __LINE__, __FUNCTION__);
682 if ((!data) || (!size)) return EINA_FALSE;
684 mystr = calloc(1, size + 1);
685 if (!mystr) return EINA_FALSE;
687 memcpy(mystr, data, size);
688 if (_ecore_xcb_mb_textlist_to_textproperty(&mystr, 1, style, &text_prop))
692 len = strlen((char *)text_prop.value) + 1;
693 if (!(*data_ret = malloc(len)))
698 memcpy(*data_ret, text_prop.value, len);
700 free(text_prop.value);
712 ecore_x_dnd_abort(Ecore_X_Window xwin_source)
714 if (xwin_source == _source->win)
716 _source->will_accept = 0;
717 return ecore_x_dnd_self_drop();
719 else return EINA_FALSE;