2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
8 #include "ecore_xcb_private.h"
9 #include "Ecore_X_Atoms.h"
12 EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
13 EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
14 EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
15 EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
16 EAPI int ECORE_X_EVENT_XDND_DROP = 0;
17 EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
19 static Ecore_X_DND_Source *_source = NULL;
20 static Ecore_X_DND_Target *_target = NULL;
21 static int _ecore_x_dnd_init_count = 0;
25 _ecore_x_dnd_init(void)
27 if (!_ecore_x_dnd_init_count)
30 _source = calloc(1, sizeof(Ecore_X_DND_Source));
31 _source->version = ECORE_X_DND_VERSION;
32 _source->win = XCB_NONE;
33 _source->dest = XCB_NONE;
34 _source->state = ECORE_X_DND_SOURCE_IDLE;
35 _source->prev.window = 0;
37 _target = calloc(1, sizeof(Ecore_X_DND_Target));
38 _target->win = XCB_NONE;
39 _target->source = XCB_NONE;
40 _target->state = ECORE_X_DND_TARGET_IDLE;
42 ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
43 ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
44 ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
45 ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
46 ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
47 ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
50 _ecore_x_dnd_init_count++;
54 _ecore_x_dnd_shutdown(void)
56 _ecore_x_dnd_init_count--;
57 if (_ecore_x_dnd_init_count > 0)
68 _ecore_x_dnd_init_count = 0;
72 ecore_x_dnd_aware_set(Ecore_X_Window window,
75 Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
78 ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_AWARE,
79 ECORE_X_ATOM_ATOM, 32, &prop_data, 1);
81 ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_AWARE);
85 * Sends the GetProperty request.
86 * @param window Window whose properties are requested.
89 ecore_x_dnd_version_get_prefetch(Ecore_X_Window window)
91 xcb_get_property_cookie_t cookie;
93 cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
94 window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root,
95 ECORE_X_ATOM_XDND_AWARE,
98 _ecore_xcb_cookie_cache(cookie.sequence);
103 * Gets the reply of the GetProperty request sent by ecore_x_dnd_version_get_prefetch().
106 ecore_x_dnd_version_get_fetch(void)
108 xcb_get_property_cookie_t cookie;
109 xcb_get_property_reply_t *reply;
111 cookie.sequence = _ecore_xcb_cookie_get();
112 reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
113 _ecore_xcb_reply_cache(reply);
117 * Get the DnD version.
118 * @param window Unused.
119 * @return 0 on failure, the version otherwise.
121 * Get the DnD version. Returns 0 on failure, the version otherwise.
123 * To use this function, you must call before, and in order,
124 * ecore_x_dnd_version_get_prefetch(), which sends the GetProperty request,
125 * then ecore_x_dnd_version_get_fetch(), which gets the reply.
128 ecore_x_dnd_version_get(Ecore_X_Window window)
130 unsigned char *prop_data;
133 if (ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_AWARE,
134 ECORE_X_ATOM_ATOM, 32, &prop_data, &num))
136 int version = (int) *prop_data;
145 * Sends the GetProperty request.
146 * @param window Window whose properties are requested.
149 ecore_x_dnd_type_get_prefetch(Ecore_X_Window window)
151 xcb_get_property_cookie_t cookie;
153 cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
154 window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root,
155 ECORE_X_ATOM_XDND_TYPE_LIST,
158 _ecore_xcb_cookie_cache(cookie.sequence);
163 * Gets the reply of the GetProperty request sent by ecore_x_dnd_type_get_prefetch().
166 ecore_x_dnd_type_get_fetch(void)
168 xcb_get_property_cookie_t cookie;
169 xcb_get_property_reply_t *reply;
171 cookie.sequence = _ecore_xcb_cookie_get();
172 reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
173 _ecore_xcb_reply_cache(reply);
176 /* FIXME: round trip (InternAtomGet request) */
179 * Check if the type is set.
180 * @param window Unused.
181 * @param type The type to check
182 * @return 0 on failure, 1 otherwise.
184 * Check if the type is set. 0 on failure, 1 otherwise.
186 * To use this function, you must call before, and in order,
187 * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
188 * then ecore_x_dnd_type_get_fetch(), which gets the reply.
191 ecore_x_dnd_type_isset(Ecore_X_Window window,
194 xcb_intern_atom_cookie_t cookie;
195 xcb_intern_atom_reply_t *reply;
202 cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
205 if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST,
206 ECORE_X_ATOM_ATOM, 32, &data, &num))
208 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
209 if (reply) free(reply);
213 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
219 atoms = (Ecore_X_Atom *)data;
221 for (i = 0; i < num; ++i)
223 if (reply->atom == atoms[i])
236 /* FIXME: round trip (InternAtomGet request) */
240 * @param window Unused.
241 * @param type The type to set
242 * @param on 0 or non 0...
246 * To use this function, you must call before, and in order,
247 * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
248 * then ecore_x_dnd_type_get_fetch(), which gets the reply.
251 ecore_x_dnd_type_set(Ecore_X_Window window,
255 xcb_intern_atom_cookie_t cookie;
256 xcb_intern_atom_reply_t *reply;
257 Ecore_X_Atom *oldset = NULL;
258 Ecore_X_Atom *newset = NULL;
259 unsigned char *data = NULL;
260 unsigned char *old_data = NULL;
262 int i, j = 0, num = 0;
264 cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
267 atom = ecore_x_atom_get(type);
268 if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST,
270 32, &old_data, &num))
272 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
273 if (reply) free(reply);
276 oldset = (Ecore_X_Atom *)old_data;
280 if (ecore_x_dnd_type_isset(window, type))
283 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
284 if (reply) free(reply);
287 data = calloc(num + 1, sizeof(Ecore_X_Atom));
291 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
292 if (reply) free(reply);
295 newset = (Ecore_X_Atom *)data;
297 for (i = 0; i < num; i++)
298 newset[i + 1] = oldset[i];
299 /* prepend the new type */
301 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
307 newset[0] = reply->atom;
310 ecore_x_window_prop_property_set(window,
311 ECORE_X_ATOM_XDND_TYPE_LIST,
317 if (!ecore_x_dnd_type_isset(window, type))
322 newset = calloc(num - 1, sizeof(Ecore_X_Atom));
328 data = (unsigned char *)newset;
329 for (i = 0; i < num; i++)
330 if (oldset[i] != atom)
331 newset[j++] = oldset[i];
333 ecore_x_window_prop_property_set(window,
334 ECORE_X_ATOM_XDND_TYPE_LIST,
343 /* FIXME: round trips, but I don't think we can do much, here */
347 * @param window Unused.
348 * @param types The types to set
349 * @param num_types The number of types
353 * To use this function, you must call before, and in order,
354 * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
355 * then ecore_x_dnd_type_get_fetch(), which gets the reply.
358 ecore_x_dnd_types_set(Ecore_X_Window window,
360 unsigned int num_types)
362 Ecore_X_Atom *newset = NULL;
368 ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_TYPE_LIST);
372 xcb_intern_atom_cookie_t *cookies;
373 xcb_intern_atom_reply_t *reply;
375 cookies = (xcb_intern_atom_cookie_t *)malloc(sizeof(xcb_intern_atom_cookie_t));
376 if (!cookies) return;
377 for (i = 0; i < num_types; i++)
378 cookies[i] = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
379 strlen(types[i]), types[i]);
380 data = calloc(num_types, sizeof(Ecore_X_Atom));
383 for (i = 0; i < num_types; i++)
385 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL);
386 if (reply) free(reply);
392 for (i = 0; i < num_types; i++)
394 reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL);
397 newset[i] = reply->atom;
401 newset[i] = XCB_NONE;
404 ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_TYPE_LIST,
405 ECORE_X_ATOM_ATOM, 32, data, num_types);
411 _ecore_x_dnd_source_get(void)
417 _ecore_x_dnd_target_get(void)
423 * Sends the GetProperty request.
424 * @param source Window whose properties are requested.
427 ecore_x_dnd_begin_prefetch(Ecore_X_Window source)
429 xcb_get_property_cookie_t cookie;
431 cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
432 source ? source : ((xcb_screen_t *)_ecore_xcb_screen)->root,
433 ECORE_X_ATOM_XDND_AWARE,
436 _ecore_xcb_cookie_cache(cookie.sequence);
441 * Gets the reply of the GetProperty request sent by ecore_x_dnd_begin_prefetch().
444 ecore_x_dnd_begin_fetch(void)
446 xcb_get_property_cookie_t cookie;
447 xcb_get_property_reply_t *reply;
449 cookie.sequence = _ecore_xcb_cookie_get();
450 reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
451 _ecore_xcb_reply_cache(reply);
454 /* FIXME: round trip */
458 * @param source Unused.
459 * @param data The data.
460 * @param size The size of the data.
461 * @return 0 on failure, 1 otherwise.
463 * Begins the DnD. Returns 0 on failure, 1 otherwise.
465 * To use this function, you must call before, and in order,
466 * ecore_x_dnd_begin_prefetch(), which sends the GetProperty request,
467 * then ecore_x_dnd_begin_fetch(), which gets the reply.
470 ecore_x_dnd_begin(Ecore_X_Window source,
474 ecore_x_selection_xdnd_prefetch();
475 if (!ecore_x_dnd_version_get(source))
477 ecore_x_selection_xdnd_fetch();
481 /* Take ownership of XdndSelection */
482 ecore_x_selection_xdnd_prefetch();
483 ecore_x_selection_xdnd_fetch();
484 if (!ecore_x_selection_xdnd_set(source, data, size))
487 _source->win = source;
488 ecore_x_window_ignore_set(_source->win, 1);
489 _source->state = ECORE_X_DND_SOURCE_DRAGGING;
490 _source->time = _ecore_xcb_event_last_time;
491 _source->prev.window = 0;
493 /* Default Accepted Action: ask */
494 _source->action = ECORE_X_ATOM_XDND_ACTION_COPY;
495 _source->accepted_action = XCB_NONE;
500 ecore_x_dnd_drop(void)
506 xcb_client_message_event_t ev;
508 ev.response_type = XCB_CLIENT_MESSAGE;
510 ev.window = _source->dest;
512 if (_source->will_accept)
514 ev.type = ECORE_X_ATOM_XDND_DROP;
515 ev.data.data32[0] = _source->win;
516 ev.data.data32[1] = 0;
517 ev.data.data32[2] = _source->time;
518 xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
519 _source->state = ECORE_X_DND_SOURCE_DROPPED;
524 ev.type = ECORE_X_ATOM_XDND_LEAVE;
525 ev.data.data32[0] = _source->win;
526 ev.data.data32[1] = 0;
527 xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
528 _source->state = ECORE_X_DND_SOURCE_IDLE;
533 /* Dropping on nothing */
534 ecore_x_selection_xdnd_clear();
535 _source->state = ECORE_X_DND_SOURCE_IDLE;
537 ecore_x_window_ignore_set(_source->win, 0);
539 _source->prev.window = 0;
540 _source->dest = XCB_NONE;
546 ecore_x_dnd_send_status(int will_accept,
548 Ecore_X_Rectangle rectangle,
551 xcb_client_message_event_t ev;
553 if (_target->state == ECORE_X_DND_TARGET_IDLE)
556 _target->will_accept = will_accept;
558 ev.response_type = XCB_CLIENT_MESSAGE;
560 ev.window = _target->source;
561 ev.type = ECORE_X_ATOM_XDND_STATUS;
563 ev.data.data32[0] = _target->win;
564 ev.data.data32[1] = 0;
566 ev.data.data32[1] |= 0x1UL;
568 ev.data.data32[1] |= 0x2UL;
570 /* Set rectangle information */
571 ev.data.data32[2] = rectangle.x;
572 ev.data.data32[2] <<= 16;
573 ev.data.data32[2] |= rectangle.y;
574 ev.data.data32[3] = rectangle.width;
575 ev.data.data32[3] <<= 16;
576 ev.data.data32[3] |= rectangle.height;
580 ev.data.data32[4] = action;
581 _target->accepted_action = action;
585 ev.data.data32[4] = XCB_NONE;
586 _target->accepted_action = action;
589 xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev);
593 ecore_x_dnd_send_finished(void)
595 xcb_client_message_event_t ev;
597 if (_target->state == ECORE_X_DND_TARGET_IDLE)
600 ev.response_type = XCB_CLIENT_MESSAGE;
602 ev.window = _target->source;
603 ev.type = ECORE_X_ATOM_XDND_FINISHED;
605 ev.data.data32[0] = _target->win;
606 ev.data.data32[1] = 0;
607 ev.data.data32[2] = 0;
608 if (_target->will_accept)
610 ev.data.data32[1] |= 0x1UL;
611 ev.data.data32[2] = _target->accepted_action;
613 xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev);
615 _target->state = ECORE_X_DND_TARGET_IDLE;
619 ecore_x_dnd_source_action_set(Ecore_X_Atom action)
621 _source->action = action;
622 if (_source->prev.window)
623 _ecore_x_dnd_drag(_source->prev.window, _source->prev.x, _source->prev.y);
627 ecore_x_dnd_source_action_get(void)
629 return _source->action;
633 _ecore_x_dnd_drag(Ecore_X_Window root,
637 xcb_client_message_event_t ev;
639 Ecore_X_Window *skip;
642 if (_source->state != ECORE_X_DND_SOURCE_DRAGGING)
645 ev.response_type = XCB_CLIENT_MESSAGE;
648 /* Attempt to find a DND-capable window under the cursor */
649 skip = ecore_x_window_ignore_list(&num);
650 // win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num);
651 win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
654 xcb_query_tree_cookie_t cookie_tree;
655 xcb_query_tree_reply_t *reply_tree;
657 ecore_x_dnd_version_get_prefetch(win);
658 cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, win);
660 ecore_x_dnd_version_get_fetch();
661 /* We found the correct window ? */
662 if (ecore_x_dnd_version_get(win))
664 reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
665 if (reply_tree) free(reply_tree);
668 reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
671 win = reply_tree->parent;
676 /* Send XdndLeave to current destination window if we have left it */
677 if ((_source->dest) && (win != _source->dest))
679 ev.window = _source->dest;
680 ev.type = ECORE_X_ATOM_XDND_LEAVE;
681 ev.data.data32[0] = _source->win;
682 ev.data.data32[1] = 0;
684 xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
685 _source->suppress = 0;
695 ecore_x_dnd_version_get_prefetch(win);
696 ecore_x_dnd_type_get_prefetch(_source->win);
698 ecore_x_dnd_version_get_fetch();
699 if (!ecore_x_dnd_version_get(win))
701 ecore_x_dnd_type_get_fetch();
705 _source->version = MIN(ECORE_X_DND_VERSION,
706 ecore_x_dnd_version_get(win));
707 if (win != _source->dest)
714 ecore_x_dnd_type_get_fetch();
715 if (!ecore_x_window_prop_property_get(_source->win,
716 ECORE_X_ATOM_XDND_TYPE_LIST,
721 types = (Ecore_X_Atom *)data;
723 /* Entered new window, send XdndEnter */
725 ev.type = ECORE_X_ATOM_XDND_ENTER;
726 ev.data.data32[0] = _source->win;
727 ev.data.data32[1] = 0;
729 ev.data.data32[1] |= 0x1UL;
731 ev.data.data32[1] &= 0xfffffffeUL;
732 ev.data.data32[1] |= ((unsigned long) _source->version) << 24;
734 for (i = 2; i < 5; i++)
735 ev.data.data32[i] = 0;
736 for (i = 0; i < MIN(num, 3); ++i)
737 ev.data.data32[i + 2] = types[i];
739 xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev);
740 _source->await_status = 0;
741 _source->will_accept = 0;
744 ecore_x_dnd_type_get_fetch();
746 /* Determine if we're still in the rectangle from the last status */
747 x1 = _source->rectangle.x;
748 x2 = _source->rectangle.x + _source->rectangle.width;
749 y1 = _source->rectangle.y;
750 y2 = _source->rectangle.y + _source->rectangle.height;
752 if ((!_source->await_status) ||
753 (!_source->suppress) ||
754 ((x < x1) || (x > x2) || (y < y1) || (y > y2)))
757 ev.type = ECORE_X_ATOM_XDND_POSITION;
758 ev.data.data32[0] = _source->win;
759 ev.data.data32[1] = 0; /* Reserved */
760 ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
761 ev.data.data32[3] = _source->time; /* Version 1 */
762 ev.data.data32[4] = _source->action; /* Version 2, Needs to be pre-set */
763 xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev);
765 _source->await_status = 1;
771 _source->prev.window = root;