2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
6 #include "ecore_xcb_private.h"
7 #include "Ecore_X_Atoms.h"
10 EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
11 EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
12 EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
13 EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
14 EAPI int ECORE_X_EVENT_XDND_DROP = 0;
15 EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
17 static Ecore_X_DND_Source *_source = NULL;
18 static Ecore_X_DND_Target *_target = NULL;
19 static int _ecore_x_dnd_init_count = 0;
23 _ecore_x_dnd_init(void)
25 if (!_ecore_x_dnd_init_count)
28 _source = calloc(1, sizeof(Ecore_X_DND_Source));
29 _source->version = ECORE_X_DND_VERSION;
30 _source->win = XCB_NONE;
31 _source->dest = XCB_NONE;
32 _source->state = ECORE_X_DND_SOURCE_IDLE;
34 _target = calloc(1, sizeof(Ecore_X_DND_Target));
35 _target->win = XCB_NONE;
36 _target->source = XCB_NONE;
37 _target->state = ECORE_X_DND_TARGET_IDLE;
39 ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
40 ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
41 ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
42 ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
43 ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
44 ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
47 _ecore_x_dnd_init_count++;
51 _ecore_x_dnd_shutdown(void)
53 _ecore_x_dnd_init_count--;
54 if (_ecore_x_dnd_init_count > 0)
65 _ecore_x_dnd_init_count = 0;
69 ecore_x_dnd_aware_set(Ecore_X_Window window,
72 Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
75 ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_AWARE,
76 ECORE_X_ATOM_ATOM, 32, &prop_data, 1);
78 ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_AWARE);
82 * Sends the GetProperty request.
83 * @param window Window whose properties are requested.
86 ecore_x_dnd_version_get_prefetch(Ecore_X_Window window)
88 xcb_get_property_cookie_t cookie;
90 cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
91 window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root,
92 ECORE_X_ATOM_XDND_AWARE,
95 _ecore_xcb_cookie_cache(cookie.sequence);
100 * Gets the reply of the GetProperty request sent by ecore_x_dnd_version_get_prefetch().
103 ecore_x_dnd_version_get_fetch(void)
105 xcb_get_property_cookie_t cookie;
106 xcb_get_property_reply_t *reply;
108 cookie.sequence = _ecore_xcb_cookie_get();
109 reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
110 _ecore_xcb_reply_cache(reply);
114 * Get the DnD version.
115 * @param window Unused.
116 * @return 0 on failure, the version otherwise.
118 * Get the DnD version. Returns 0 on failure, the version otherwise.
120 * To use this function, you must call before, and in order,
121 * ecore_x_dnd_version_get_prefetch(), which sends the GetProperty request,
122 * then ecore_x_dnd_version_get_fetch(), which gets the reply.
125 ecore_x_dnd_version_get(Ecore_X_Window window)
127 unsigned char *prop_data;
130 if (ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_AWARE,
131 ECORE_X_ATOM_ATOM, 32, &prop_data, &num))
133 int version = (int) *prop_data;
142 * Sends the GetProperty request.
143 * @param window Window whose properties are requested.
146 ecore_x_dnd_type_get_prefetch(Ecore_X_Window window)
148 xcb_get_property_cookie_t cookie;
150 cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
151 window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root,
152 ECORE_X_ATOM_XDND_TYPE_LIST,
155 _ecore_xcb_cookie_cache(cookie.sequence);
160 * Gets the reply of the GetProperty request sent by ecore_x_dnd_type_get_prefetch().
163 ecore_x_dnd_type_get_fetch(void)
165 xcb_get_property_cookie_t cookie;
166 xcb_get_property_reply_t *reply;
168 cookie.sequence = _ecore_xcb_cookie_get();
169 reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
170 _ecore_xcb_reply_cache(reply);
173 /* FIXME: round trip (InternAtomGet request) */
176 * Check if the type is set.
177 * @param window Unused.
178 * @param type The type to check
179 * @return 0 on failure, 1 otherwise.
181 * Check if the type is set. 0 on failure, 1 otherwise.
183 * To use this function, you must call before, and in order,
184 * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
185 * then ecore_x_dnd_type_get_fetch(), which gets the reply.
188 ecore_x_dnd_type_isset(Ecore_X_Window window,
191 xcb_intern_atom_cookie_t cookie;
192 xcb_intern_atom_reply_t *reply;
199 cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
202 if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST,
203 ECORE_X_ATOM_ATOM, 32, &data, &num))
205 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
206 if (reply) free(reply);
210 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
216 atoms = (Ecore_X_Atom *)data;
218 for (i = 0; i < num; ++i)
220 if (reply->atom == atoms[i])
233 /* FIXME: round trip (InternAtomGet request) */
237 * @param window Unused.
238 * @param type The type to set
239 * @param on 0 or non 0...
243 * To use this function, you must call before, and in order,
244 * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
245 * then ecore_x_dnd_type_get_fetch(), which gets the reply.
248 ecore_x_dnd_type_set(Ecore_X_Window window,
252 xcb_intern_atom_cookie_t cookie;
253 xcb_intern_atom_reply_t *reply;
254 Ecore_X_Atom *oldset = NULL;
255 Ecore_X_Atom *newset = NULL;
256 unsigned char *data = NULL;
257 unsigned char *old_data = NULL;
259 int i, j = 0, num = 0;
261 cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
264 atom = ecore_x_atom_get(type);
265 if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST,
267 32, &old_data, &num))
269 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
270 if (reply) free(reply);
273 oldset = (Ecore_X_Atom *)old_data;
277 if (ecore_x_dnd_type_isset(window, type))
280 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
281 if (reply) free(reply);
284 data = calloc(num + 1, sizeof(Ecore_X_Atom));
288 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
289 if (reply) free(reply);
292 newset = (Ecore_X_Atom *)data;
294 for (i = 0; i < num; i++)
295 newset[i + 1] = oldset[i];
296 /* prepend the new type */
298 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
304 newset[0] = reply->atom;
307 ecore_x_window_prop_property_set(window,
308 ECORE_X_ATOM_XDND_TYPE_LIST,
314 if (!ecore_x_dnd_type_isset(window, type))
319 newset = calloc(num - 1, sizeof(Ecore_X_Atom));
325 data = (unsigned char *)newset;
326 for (i = 0; i < num; i++)
327 if (oldset[i] != atom)
328 newset[j++] = oldset[i];
330 ecore_x_window_prop_property_set(window,
331 ECORE_X_ATOM_XDND_TYPE_LIST,
340 /* FIXME: round trips, but I don't think we can do much, here */
344 * @param window Unused.
345 * @param types The types to set
346 * @param num_types The number of types
350 * To use this function, you must call before, and in order,
351 * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
352 * then ecore_x_dnd_type_get_fetch(), which gets the reply.
355 ecore_x_dnd_types_set(Ecore_X_Window window,
357 unsigned int num_types)
359 Ecore_X_Atom *newset = NULL;
365 ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_TYPE_LIST);
369 xcb_intern_atom_cookie_t *cookies;
370 xcb_intern_atom_reply_t *reply;
372 cookies = (xcb_intern_atom_cookie_t *)malloc(sizeof(xcb_intern_atom_cookie_t));
373 if (!cookies) return;
374 for (i = 0; i < num_types; i++)
375 cookies[i] = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
376 strlen(types[i]), types[i]);
377 data = calloc(num_types, sizeof(Ecore_X_Atom));
380 for (i = 0; i < num_types; i++)
382 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL);
383 if (reply) free(reply);
389 for (i = 0; i < num_types; i++)
391 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL);
394 newset[i] = reply->atom;
398 newset[i] = XCB_NONE;
401 ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_TYPE_LIST,
402 ECORE_X_ATOM_ATOM, 32, data, num_types);
408 _ecore_x_dnd_source_get(void)
414 _ecore_x_dnd_target_get(void)
420 * Sends the GetProperty request.
421 * @param source Window whose properties are requested.
424 ecore_x_dnd_begin_prefetch(Ecore_X_Window source)
426 xcb_get_property_cookie_t cookie;
428 cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
429 source ? source : ((xcb_screen_t *)_ecore_xcb_screen)->root,
430 ECORE_X_ATOM_XDND_AWARE,
433 _ecore_xcb_cookie_cache(cookie.sequence);
438 * Gets the reply of the GetProperty request sent by ecore_x_dnd_begin_prefetch().
441 ecore_x_dnd_begin_fetch(void)
443 xcb_get_property_cookie_t cookie;
444 xcb_get_property_reply_t *reply;
446 cookie.sequence = _ecore_xcb_cookie_get();
447 reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
448 _ecore_xcb_reply_cache(reply);
451 /* FIXME: round trip */
455 * @param source Unused.
456 * @param data The data.
457 * @param size The size of the data.
458 * @return 0 on failure, 1 otherwise.
460 * Begins the DnD. Returns 0 on failure, 1 otherwise.
462 * To use this function, you must call before, and in order,
463 * ecore_x_dnd_begin_prefetch(), which sends the GetProperty request,
464 * then ecore_x_dnd_begin_fetch(), which gets the reply.
467 ecore_x_dnd_begin(Ecore_X_Window source,
471 ecore_x_selection_xdnd_prefetch();
472 if (!ecore_x_dnd_version_get(source))
474 ecore_x_selection_xdnd_fetch();
478 /* Take ownership of XdndSelection */
479 ecore_x_selection_xdnd_prefetch();
480 ecore_x_selection_xdnd_fetch();
481 if (!ecore_x_selection_xdnd_set(source, data, size))
484 _source->win = source;
485 ecore_x_window_ignore_set(_source->win, 1);
486 _source->state = ECORE_X_DND_SOURCE_DRAGGING;
487 _source->time = _ecore_xcb_event_last_time;
489 /* Default Accepted Action: ask */
490 _source->action = ECORE_X_ATOM_XDND_ACTION_COPY;
491 _source->accepted_action = XCB_NONE;
496 ecore_x_dnd_drop(void)
502 xcb_client_message_event_t ev;
504 ev.response_type = XCB_CLIENT_MESSAGE;
506 ev.window = _source->dest;
508 if (_source->will_accept)
510 ev.type = ECORE_X_ATOM_XDND_DROP;
511 ev.data.data32[0] = _source->win;
512 ev.data.data32[1] = 0;
513 ev.data.data32[2] = _source->time;
514 xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
515 _source->state = ECORE_X_DND_SOURCE_DROPPED;
520 ev.type = ECORE_X_ATOM_XDND_LEAVE;
521 ev.data.data32[0] = _source->win;
522 ev.data.data32[1] = 0;
523 xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
524 _source->state = ECORE_X_DND_SOURCE_IDLE;
529 /* Dropping on nothing */
530 ecore_x_selection_xdnd_clear();
531 _source->state = ECORE_X_DND_SOURCE_IDLE;
533 ecore_x_window_ignore_set(_source->win, 0);
535 _source->dest = XCB_NONE;
541 ecore_x_dnd_send_status(int will_accept,
543 Ecore_X_Rectangle rectangle,
546 xcb_client_message_event_t ev;
548 if (_target->state == ECORE_X_DND_TARGET_IDLE)
551 _target->will_accept = will_accept;
553 ev.response_type = XCB_CLIENT_MESSAGE;
555 ev.window = _target->source;
556 ev.type = ECORE_X_ATOM_XDND_STATUS;
558 ev.data.data32[0] = _target->win;
559 ev.data.data32[1] = 0;
561 ev.data.data32[1] |= 0x1UL;
563 ev.data.data32[1] |= 0x2UL;
565 /* Set rectangle information */
566 ev.data.data32[2] = rectangle.x;
567 ev.data.data32[2] <<= 16;
568 ev.data.data32[2] |= rectangle.y;
569 ev.data.data32[3] = rectangle.width;
570 ev.data.data32[3] <<= 16;
571 ev.data.data32[3] |= rectangle.height;
575 ev.data.data32[4] = action;
576 _target->accepted_action = action;
580 ev.data.data32[4] = XCB_NONE;
581 _target->accepted_action = action;
584 xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev);
588 ecore_x_dnd_send_finished(void)
590 xcb_client_message_event_t ev;
592 if (_target->state == ECORE_X_DND_TARGET_IDLE)
595 ev.response_type = XCB_CLIENT_MESSAGE;
597 ev.window = _target->source;
598 ev.type = ECORE_X_ATOM_XDND_FINISHED;
600 ev.data.data32[0] = _target->win;
601 ev.data.data32[1] = 0;
602 ev.data.data32[2] = 0;
603 if (_target->will_accept)
605 ev.data.data32[1] |= 0x1UL;
606 ev.data.data32[2] = _target->accepted_action;
608 xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev);
610 _target->state = ECORE_X_DND_TARGET_IDLE;
614 _ecore_x_dnd_drag(Ecore_X_Window root,
618 xcb_client_message_event_t ev;
620 Ecore_X_Window *skip;
623 if (_source->state != ECORE_X_DND_SOURCE_DRAGGING)
626 ev.response_type = XCB_CLIENT_MESSAGE;
629 /* Attempt to find a DND-capable window under the cursor */
630 skip = ecore_x_window_ignore_list(&num);
631 // win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num);
632 win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
635 xcb_query_tree_cookie_t cookie_tree;
636 xcb_query_tree_reply_t *reply_tree;
638 ecore_x_dnd_version_get_prefetch(win);
639 cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, win);
641 ecore_x_dnd_version_get_fetch();
642 /* We found the correct window ? */
643 if (ecore_x_dnd_version_get(win))
645 reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
646 if (reply_tree) free(reply_tree);
649 reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
652 win = reply_tree->parent;
657 /* Send XdndLeave to current destination window if we have left it */
658 if ((_source->dest) && (win != _source->dest))
660 ev.window = _source->dest;
661 ev.type = ECORE_X_ATOM_XDND_LEAVE;
662 ev.data.data32[0] = _source->win;
663 ev.data.data32[1] = 0;
665 xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
666 _source->suppress = 0;
676 ecore_x_dnd_version_get_prefetch(win);
677 ecore_x_dnd_type_get_prefetch(_source->win);
679 ecore_x_dnd_version_get_fetch();
680 if (!ecore_x_dnd_version_get(win))
682 ecore_x_dnd_type_get_fetch();
686 _source->version = MIN(ECORE_X_DND_VERSION,
687 ecore_x_dnd_version_get(win));
688 if (win != _source->dest)
695 ecore_x_dnd_type_get_fetch();
696 if (!ecore_x_window_prop_property_get(_source->win,
697 ECORE_X_ATOM_XDND_TYPE_LIST,
702 types = (Ecore_X_Atom *)data;
704 /* Entered new window, send XdndEnter */
706 ev.type = ECORE_X_ATOM_XDND_ENTER;
707 ev.data.data32[0] = _source->win;
708 ev.data.data32[1] = 0;
710 ev.data.data32[1] |= 0x1UL;
712 ev.data.data32[1] &= 0xfffffffeUL;
713 ev.data.data32[1] |= ((unsigned long) _source->version) << 24;
715 for (i = 2; i < 5; i++)
716 ev.data.data32[i] = 0;
717 for (i = 0; i < MIN(num, 3); ++i)
718 ev.data.data32[i + 2] = types[i];
720 xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev);
721 _source->await_status = 0;
722 _source->will_accept = 0;
725 ecore_x_dnd_type_get_fetch();
727 /* Determine if we're still in the rectangle from the last status */
728 x1 = _source->rectangle.x;
729 x2 = _source->rectangle.x + _source->rectangle.width;
730 y1 = _source->rectangle.y;
731 y2 = _source->rectangle.y + _source->rectangle.height;
733 if ((!_source->await_status) ||
734 (!_source->suppress) ||
735 ((x < x1) || (x > x2) || (y < y1) || (y > y2)))
738 ev.type = ECORE_X_ATOM_XDND_POSITION;
739 ev.data.data32[0] = _source->win;
740 ev.data.data32[1] = 0; /* Reserved */
741 ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
742 ev.data.data32[3] = _source->time; /* Version 1 */
743 ev.data.data32[4] = _source->action; /* Version 2, Needs to be pre-set */
744 xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev);
746 _source->await_status = 1;