1 #include "ecore_xcb_private.h"
4 # define MIN(a, b) (((a) < (b)) ? (a) : (b))
8 typedef struct _Version_Cache_Item
14 /* local function prototypes */
15 static Eina_Bool _ecore_xcb_dnd_converter_copy(char *target __UNUSED__,
20 Ecore_X_Atom *tprop __UNUSED__,
21 int *count __UNUSED__);
24 static int _ecore_xcb_dnd_init_count = 0;
25 static Ecore_X_DND_Source *_source = NULL;
26 static Ecore_X_DND_Target *_target = NULL;
27 static Version_Cache_Item *_version_cache = NULL;
28 static int _version_cache_num = 0, _version_cache_alloc = 0;
29 static void (*_posupdatecb)(void *,
30 Ecore_X_Xdnd_Position *);
31 static void *_posupdatedata;
33 /* external variables */
34 EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
35 EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
36 EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
37 EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
38 EAPI int ECORE_X_EVENT_XDND_DROP = 0;
39 EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
42 _ecore_xcb_dnd_init(void)
44 LOGFN(__FILE__, __LINE__, __FUNCTION__);
46 if (!_ecore_xcb_dnd_init_count)
48 _source = calloc(1, sizeof(Ecore_X_DND_Source));
50 _source->version = ECORE_X_DND_VERSION;
51 _source->win = XCB_NONE;
52 _source->dest = XCB_NONE;
53 _source->state = ECORE_X_DND_SOURCE_IDLE;
54 _source->prev.window = 0;
56 _target = calloc(1, sizeof(Ecore_X_DND_Target));
63 _target->win = XCB_NONE;
64 _target->source = XCB_NONE;
65 _target->state = ECORE_X_DND_TARGET_IDLE;
67 ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
68 ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
69 ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
70 ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
71 ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
72 ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
74 _ecore_xcb_dnd_init_count++;
78 _ecore_xcb_dnd_shutdown(void)
80 LOGFN(__FILE__, __LINE__, __FUNCTION__);
82 _ecore_xcb_dnd_init_count--;
83 if (_ecore_xcb_dnd_init_count > 0) return;
84 if (_source) free(_source);
86 if (_target) free(_target);
88 _ecore_xcb_dnd_init_count = 0;
92 ecore_x_dnd_send_status(Eina_Bool will_accept,
94 Ecore_X_Rectangle rect,
97 xcb_client_message_event_t ev;
99 LOGFN(__FILE__, __LINE__, __FUNCTION__);
102 if (_target->state == ECORE_X_DND_TARGET_IDLE) return;
104 memset(&ev, 0, sizeof(xcb_client_message_event_t));
106 _target->will_accept = will_accept;
108 ev.response_type = XCB_CLIENT_MESSAGE;
109 ev.type = ECORE_X_ATOM_XDND_STATUS;
111 ev.window = _target->source;
112 ev.data.data32[0] = _target->win;
113 ev.data.data32[1] = 0;
114 if (will_accept) ev.data.data32[1] |= 0x1UL;
115 if (!suppress) ev.data.data32[1] |= 0x2UL;
117 ev.data.data32[2] = rect.x;
118 ev.data.data32[2] <<= 16;
119 ev.data.data32[2] |= rect.y;
120 ev.data.data32[3] = rect.width;
121 ev.data.data32[3] <<= 16;
122 ev.data.data32[3] |= rect.height;
125 ev.data.data32[4] = action;
127 ev.data.data32[4] = XCB_NONE;
128 _target->accepted_action = action;
130 xcb_send_event(_ecore_xcb_conn, 0, _target->source,
131 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
136 ecore_x_dnd_drop(void)
138 xcb_client_message_event_t ev;
139 Eina_Bool status = EINA_FALSE;
141 LOGFN(__FILE__, __LINE__, __FUNCTION__);
144 memset(&ev, 0, sizeof(xcb_client_message_event_t));
148 ev.response_type = XCB_CLIENT_MESSAGE;
150 ev.window = _source->dest;
152 if (_source->will_accept)
154 ev.type = ECORE_X_ATOM_XDND_DROP;
155 ev.data.data32[0] = _source->win;
156 ev.data.data32[1] = 0;
157 ev.data.data32[2] = _source->time;
159 xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
160 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
162 _source->state = ECORE_X_DND_SOURCE_DROPPED;
167 ev.type = ECORE_X_ATOM_XDND_LEAVE;
168 ev.data.data32[0] = _source->win;
169 ev.data.data32[1] = 0;
171 xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
172 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
174 _source->state = ECORE_X_DND_SOURCE_IDLE;
179 ecore_x_selection_xdnd_clear();
180 _source->state = ECORE_X_DND_SOURCE_IDLE;
183 ecore_x_window_ignore_set(_source->win, 0);
184 _source->prev.window = 0;
190 ecore_x_dnd_aware_set(Ecore_X_Window win,
193 Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
195 LOGFN(__FILE__, __LINE__, __FUNCTION__);
198 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE,
199 ECORE_X_ATOM_ATOM, 32, &prop_data, 1);
201 ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE);
205 ecore_x_dnd_version_get(Ecore_X_Window win)
209 Version_Cache_Item *t;
211 LOGFN(__FILE__, __LINE__, __FUNCTION__);
213 if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
219 for (i = 0; i < _version_cache_num; i++)
221 if (_version_cache[i].win == win)
222 return _version_cache[i].ver;
227 if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE,
228 ECORE_X_ATOM_ATOM, 32, &data, &num))
232 version = (int)*data;
234 if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
236 _version_cache_num++;
237 if (_version_cache_num > _version_cache_alloc)
238 _version_cache_alloc += 16;
239 t = realloc(_version_cache,
240 _version_cache_alloc * sizeof(Version_Cache_Item));
243 _version_cache[_version_cache_num - 1].win = win;
244 _version_cache[_version_cache_num - 1].ver = version;
249 if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
251 _version_cache_num++;
252 if (_version_cache_num > _version_cache_alloc)
253 _version_cache_alloc += 16;
254 t = realloc(_version_cache,
255 _version_cache_alloc * sizeof(Version_Cache_Item));
258 _version_cache[_version_cache_num - 1].win = win;
259 _version_cache[_version_cache_num - 1].ver = 0;
266 ecore_x_dnd_type_isset(Ecore_X_Window win,
270 Eina_Bool ret = EINA_FALSE;
272 Ecore_X_Atom *atoms, atom;
274 LOGFN(__FILE__, __LINE__, __FUNCTION__);
277 if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
278 ECORE_X_ATOM_ATOM, 32, &data, &num))
281 atom = ecore_x_atom_get(type);
282 atoms = (Ecore_X_Atom *)data;
283 for (i = 0; i < num; ++i)
285 if (atom == atoms[i])
297 ecore_x_dnd_type_set(Ecore_X_Window win,
301 Ecore_X_Atom atom, *oldset = NULL, *newset = NULL;
302 int i = 0, j = 0, num = 0;
303 unsigned char *data = NULL, *old_data = NULL;
305 LOGFN(__FILE__, __LINE__, __FUNCTION__);
308 atom = ecore_x_atom_get(type);
309 ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
310 ECORE_X_ATOM_ATOM, 32, &old_data, &num);
311 oldset = (Ecore_X_Atom *)old_data;
314 if (ecore_x_dnd_type_isset(win, type))
319 newset = calloc(num + 1, sizeof(Ecore_X_Atom));
321 data = (unsigned char *)newset;
322 for (i = 0; i < num; i++)
323 newset[i + 1] = oldset[i];
325 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
326 ECORE_X_ATOM_ATOM, 32, data, num + 1);
330 if (!ecore_x_dnd_type_isset(win, type))
335 newset = calloc(num - 1, sizeof(Ecore_X_Atom));
341 data = (unsigned char *)newset;
342 for (i = 0; i < num; i++)
343 if (oldset[i] != atom)
344 newset[j++] = oldset[i];
345 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
346 ECORE_X_ATOM_ATOM, 32, data, num - 1);
353 ecore_x_dnd_types_set(Ecore_X_Window win,
355 unsigned int num_types)
357 Ecore_X_Atom *newset = NULL;
359 unsigned char *data = NULL;
361 LOGFN(__FILE__, __LINE__, __FUNCTION__);
365 ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST);
368 newset = calloc(num_types, sizeof(Ecore_X_Atom));
371 data = (unsigned char *)newset;
372 for (i = 0; i < num_types; i++)
374 newset[i] = ecore_x_atom_get(types[i]);
375 ecore_x_selection_converter_atom_add(newset[i],
376 _ecore_xcb_dnd_converter_copy);
378 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
379 ECORE_X_ATOM_ATOM, 32, data,
386 ecore_x_dnd_actions_set(Ecore_X_Window win,
387 Ecore_X_Atom *actions,
388 unsigned int num_actions)
391 unsigned char *data = NULL;
393 LOGFN(__FILE__, __LINE__, __FUNCTION__);
397 ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST);
400 data = (unsigned char *)actions;
401 for (i = 0; i < num_actions; i++)
402 ecore_x_selection_converter_atom_add(actions[i],
403 _ecore_xcb_dnd_converter_copy);
404 ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST,
405 ECORE_X_ATOM_ATOM, 32, data,
411 * The DND position update cb is called Ecore_X sends a DND position to a
414 * It essentially mirrors some of the data sent in the position message.
415 * Generally this cb should be set just before position update is called.
416 * Please note well you need to look after your own data pointer if someone
417 * trashes you position update cb set.
419 * It is considered good form to clear this when the dnd event finishes.
421 * @param cb Callback to updated each time ecore_x sends a position update.
422 * @param data User data.
425 ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, Ecore_X_Xdnd_Position *data),
429 _posupdatedata = (void *)data;
433 ecore_x_dnd_begin(Ecore_X_Window source,
437 LOGFN(__FILE__, __LINE__, __FUNCTION__);
439 if (!ecore_x_dnd_version_get(source)) return EINA_FALSE;
441 /* Take ownership of XdndSelection */
442 if (!ecore_x_selection_xdnd_set(source, data, size)) return EINA_FALSE;
446 free(_version_cache);
447 _version_cache = NULL;
448 _version_cache_num = 0;
449 _version_cache_alloc = 0;
452 ecore_x_window_shadow_tree_flush();
454 _source->win = source;
455 ecore_x_window_ignore_set(_source->win, 1);
456 _source->state = ECORE_X_DND_SOURCE_DRAGGING;
457 _source->time = _ecore_xcb_events_last_time_get();
458 _source->prev.window = 0;
460 /* Default Accepted Action: move */
461 _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE;
462 _source->accepted_action = XCB_NONE;
463 _source->dest = XCB_NONE;
469 ecore_x_dnd_send_finished(void)
471 xcb_client_message_event_t ev;
473 LOGFN(__FILE__, __LINE__, __FUNCTION__);
476 if (_target->state == ECORE_X_DND_TARGET_IDLE) return;
478 memset(&ev, 0, sizeof(xcb_client_message_event_t));
480 ev.response_type = XCB_CLIENT_MESSAGE;
482 ev.type = ECORE_X_ATOM_XDND_FINISHED;
483 ev.window = _target->source;
484 ev.data.data32[0] = _target->win;
485 ev.data.data32[1] = 0;
486 ev.data.data32[2] = 0;
487 if (_target->will_accept)
489 ev.data.data32[1] |= 0x1UL;
490 ev.data.data32[2] = _target->accepted_action;
493 xcb_send_event(_ecore_xcb_conn, 0, _target->source,
494 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
496 _target->state = ECORE_X_DND_TARGET_IDLE;
500 ecore_x_dnd_source_action_set(Ecore_X_Atom action)
502 LOGFN(__FILE__, __LINE__, __FUNCTION__);
504 _source->action = action;
505 if (_source->prev.window)
506 _ecore_xcb_dnd_drag(_source->prev.window,
507 _source->prev.x, _source->prev.y);
511 _ecore_xcb_dnd_source_get(void)
517 _ecore_xcb_dnd_target_get(void)
523 _ecore_xcb_dnd_drag(Ecore_X_Window root,
527 xcb_client_message_event_t ev;
528 Ecore_X_Window win, *skip;
529 Ecore_X_Xdnd_Position pos;
532 if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) return;
534 LOGFN(__FILE__, __LINE__, __FUNCTION__);
537 memset(&ev, 0, sizeof(xcb_client_message_event_t));
539 ev.response_type = XCB_CLIENT_MESSAGE;
542 skip = ecore_x_window_ignore_list(&num);
543 win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
544 while ((win) && !(ecore_x_dnd_version_get(win)))
545 win = ecore_x_window_shadow_parent_get(root, win);
547 if ((_source->dest) && (win != _source->dest))
549 ev.window = _source->dest;
550 ev.type = ECORE_X_ATOM_XDND_LEAVE;
551 ev.data.data32[0] = _source->win;
552 ev.data.data32[1] = 0;
554 xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
555 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
557 _source->suppress = 0;
564 _source->version = MIN(ECORE_X_DND_VERSION,
565 ecore_x_dnd_version_get(win));
566 if (win != _source->dest)
572 ecore_x_window_prop_property_get(_source->win,
573 ECORE_X_ATOM_XDND_TYPE_LIST,
574 ECORE_X_ATOM_ATOM, 32,
576 types = (Ecore_X_Atom *)data;
578 ev.type = ECORE_X_ATOM_XDND_ENTER;
579 ev.data.data32[0] = _source->win;
580 ev.data.data32[1] = 0;
582 ev.data.data32[1] |= 0x1UL;
584 ev.data.data32[1] &= 0xfffffffeUL;
585 ev.data.data32[1] |= ((unsigned long)_source->version) << 24;
587 for (i = 2; i < 5; i++)
588 ev.data.data32[i] = 0;
589 for (i = 0; i < MIN(num, 3); ++i)
590 ev.data.data32[i + 2] = types[i];
593 xcb_send_event(_ecore_xcb_conn, 0, win,
594 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
596 _source->await_status = 0;
597 _source->will_accept = 0;
600 x1 = _source->rectangle.x;
601 x2 = _source->rectangle.x + _source->rectangle.width;
602 y1 = _source->rectangle.y;
603 y2 = _source->rectangle.y + _source->rectangle.height;
605 if ((!_source->await_status) || (!_source->suppress) ||
606 ((x < x1) || (x > x2) || (y < y1) || (y > y2)))
609 ev.type = ECORE_X_ATOM_XDND_POSITION;
610 ev.data.data32[0] = _source->win;
611 ev.data.data32[1] = 0;
612 ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
613 ev.data.data32[3] = _source->time;
614 ev.data.data32[4] = _source->action;
616 xcb_send_event(_ecore_xcb_conn, 0, win,
617 XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
619 _source->await_status = 1;
628 pos.prev = _source->dest;
629 _posupdatecb(_posupdatedata, &pos);
634 _source->prev.window = root;
639 ecore_x_dnd_source_action_get(void)
641 return _source->action;
644 /* local functions */
646 _ecore_xcb_dnd_converter_copy(char *target __UNUSED__,
651 Ecore_X_Atom *tprop __UNUSED__,
652 int *count __UNUSED__)
654 Ecore_Xcb_Textproperty text_prop;
655 Ecore_Xcb_Encoding_Style style = XcbTextStyle;
658 LOGFN(__FILE__, __LINE__, __FUNCTION__);
660 if ((!data) || (!size)) return EINA_FALSE;
662 mystr = calloc(1, size + 1);
663 if (!mystr) return EINA_FALSE;
665 memcpy(mystr, data, size);
666 if (_ecore_xcb_mb_textlist_to_textproperty(&mystr, 1, style, &text_prop))
670 len = strlen((char *)text_prop.value) + 1;
671 if (!(*data_ret = malloc(len)))
676 memcpy(*data_ret, text_prop.value, len);
678 free(text_prop.value);