772 lines
20 KiB
C
772 lines
20 KiB
C
/*
|
|
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
|
*/
|
|
|
|
#include "Ecore.h"
|
|
#include "ecore_xcb_private.h"
|
|
#include "Ecore_X_Atoms.h"
|
|
|
|
|
|
EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
|
|
EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
|
|
EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
|
|
EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
|
|
EAPI int ECORE_X_EVENT_XDND_DROP = 0;
|
|
EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
|
|
|
|
static Ecore_X_DND_Source *_source = NULL;
|
|
static Ecore_X_DND_Target *_target = NULL;
|
|
static int _ecore_x_dnd_init_count = 0;
|
|
|
|
|
|
void
|
|
_ecore_x_dnd_init(void)
|
|
{
|
|
if (!_ecore_x_dnd_init_count)
|
|
{
|
|
|
|
_source = calloc(1, sizeof(Ecore_X_DND_Source));
|
|
_source->version = ECORE_X_DND_VERSION;
|
|
_source->win = XCB_NONE;
|
|
_source->dest = XCB_NONE;
|
|
_source->state = ECORE_X_DND_SOURCE_IDLE;
|
|
_source->prev.window = 0;
|
|
|
|
_target = calloc(1, sizeof(Ecore_X_DND_Target));
|
|
_target->win = XCB_NONE;
|
|
_target->source = XCB_NONE;
|
|
_target->state = ECORE_X_DND_TARGET_IDLE;
|
|
|
|
ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
|
|
ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
|
|
ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
|
|
ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
|
|
ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
|
|
ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
|
|
}
|
|
|
|
_ecore_x_dnd_init_count++;
|
|
}
|
|
|
|
void
|
|
_ecore_x_dnd_shutdown(void)
|
|
{
|
|
_ecore_x_dnd_init_count--;
|
|
if (_ecore_x_dnd_init_count > 0)
|
|
return;
|
|
|
|
if (_source)
|
|
free(_source);
|
|
_source = NULL;
|
|
|
|
if (_target)
|
|
free(_target);
|
|
_target = NULL;
|
|
|
|
_ecore_x_dnd_init_count = 0;
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_dnd_aware_set(Ecore_X_Window window,
|
|
int on)
|
|
{
|
|
Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
|
|
|
|
if (on)
|
|
ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_AWARE,
|
|
ECORE_X_ATOM_ATOM, 32, &prop_data, 1);
|
|
else
|
|
ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_AWARE);
|
|
}
|
|
|
|
/**
|
|
* Sends the GetProperty request.
|
|
* @param window Window whose properties are requested.
|
|
*/
|
|
EAPI void
|
|
ecore_x_dnd_version_get_prefetch(Ecore_X_Window window)
|
|
{
|
|
xcb_get_property_cookie_t cookie;
|
|
|
|
cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
|
|
window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root,
|
|
ECORE_X_ATOM_XDND_AWARE,
|
|
ECORE_X_ATOM_ATOM,
|
|
0, LONG_MAX);
|
|
_ecore_xcb_cookie_cache(cookie.sequence);
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the reply of the GetProperty request sent by ecore_x_dnd_version_get_prefetch().
|
|
*/
|
|
EAPI void
|
|
ecore_x_dnd_version_get_fetch(void)
|
|
{
|
|
xcb_get_property_cookie_t cookie;
|
|
xcb_get_property_reply_t *reply;
|
|
|
|
cookie.sequence = _ecore_xcb_cookie_get();
|
|
reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
|
|
_ecore_xcb_reply_cache(reply);
|
|
}
|
|
|
|
/**
|
|
* Get the DnD version.
|
|
* @param window Unused.
|
|
* @return 0 on failure, the version otherwise.
|
|
*
|
|
* Get the DnD version. Returns 0 on failure, the version otherwise.
|
|
*
|
|
* To use this function, you must call before, and in order,
|
|
* ecore_x_dnd_version_get_prefetch(), which sends the GetProperty request,
|
|
* then ecore_x_dnd_version_get_fetch(), which gets the reply.
|
|
*/
|
|
EAPI int
|
|
ecore_x_dnd_version_get(Ecore_X_Window window)
|
|
{
|
|
unsigned char *prop_data;
|
|
int num;
|
|
|
|
if (ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_AWARE,
|
|
ECORE_X_ATOM_ATOM, 32, &prop_data, &num))
|
|
{
|
|
int version = (int) *prop_data;
|
|
free(prop_data);
|
|
return version;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Sends the GetProperty request.
|
|
* @param window Window whose properties are requested.
|
|
*/
|
|
EAPI void
|
|
ecore_x_dnd_type_get_prefetch(Ecore_X_Window window)
|
|
{
|
|
xcb_get_property_cookie_t cookie;
|
|
|
|
cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
|
|
window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root,
|
|
ECORE_X_ATOM_XDND_TYPE_LIST,
|
|
ECORE_X_ATOM_ATOM,
|
|
0, LONG_MAX);
|
|
_ecore_xcb_cookie_cache(cookie.sequence);
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the reply of the GetProperty request sent by ecore_x_dnd_type_get_prefetch().
|
|
*/
|
|
EAPI void
|
|
ecore_x_dnd_type_get_fetch(void)
|
|
{
|
|
xcb_get_property_cookie_t cookie;
|
|
xcb_get_property_reply_t *reply;
|
|
|
|
cookie.sequence = _ecore_xcb_cookie_get();
|
|
reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
|
|
_ecore_xcb_reply_cache(reply);
|
|
}
|
|
|
|
/* FIXME: round trip (InternAtomGet request) */
|
|
|
|
/**
|
|
* Check if the type is set.
|
|
* @param window Unused.
|
|
* @param type The type to check
|
|
* @return 0 on failure, 1 otherwise.
|
|
*
|
|
* Check if the type is set. 0 on failure, 1 otherwise.
|
|
*
|
|
* To use this function, you must call before, and in order,
|
|
* ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
|
|
* then ecore_x_dnd_type_get_fetch(), which gets the reply.
|
|
*/
|
|
EAPI int
|
|
ecore_x_dnd_type_isset(Ecore_X_Window window,
|
|
const char *type)
|
|
{
|
|
xcb_intern_atom_cookie_t cookie;
|
|
xcb_intern_atom_reply_t *reply;
|
|
Ecore_X_Atom *atoms;
|
|
unsigned char *data;
|
|
int num;
|
|
int i;
|
|
uint8_t ret = 0;
|
|
|
|
cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
|
|
strlen(type), type);
|
|
|
|
if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST,
|
|
ECORE_X_ATOM_ATOM, 32, &data, &num))
|
|
{
|
|
reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (reply) free(reply);
|
|
return ret;
|
|
}
|
|
|
|
reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply)
|
|
{
|
|
free(data);
|
|
return 0;
|
|
}
|
|
atoms = (Ecore_X_Atom *)data;
|
|
|
|
for (i = 0; i < num; ++i)
|
|
{
|
|
if (reply->atom == atoms[i])
|
|
{
|
|
ret = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(data);
|
|
free(reply);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* FIXME: round trip (InternAtomGet request) */
|
|
|
|
/**
|
|
* Set the type.
|
|
* @param window Unused.
|
|
* @param type The type to set
|
|
* @param on 0 or non 0...
|
|
*
|
|
* Set the type.
|
|
*
|
|
* To use this function, you must call before, and in order,
|
|
* ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
|
|
* then ecore_x_dnd_type_get_fetch(), which gets the reply.
|
|
*/
|
|
EAPI void
|
|
ecore_x_dnd_type_set(Ecore_X_Window window,
|
|
const char *type,
|
|
int on)
|
|
{
|
|
xcb_intern_atom_cookie_t cookie;
|
|
xcb_intern_atom_reply_t *reply;
|
|
Ecore_X_Atom *oldset = NULL;
|
|
Ecore_X_Atom *newset = NULL;
|
|
unsigned char *data = NULL;
|
|
unsigned char *old_data = NULL;
|
|
Ecore_X_Atom atom;
|
|
int i, j = 0, num = 0;
|
|
|
|
cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
|
|
strlen(type), type);
|
|
|
|
atom = ecore_x_atom_get(type);
|
|
if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST,
|
|
ECORE_X_ATOM_ATOM,
|
|
32, &old_data, &num))
|
|
{
|
|
reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (reply) free(reply);
|
|
return;
|
|
}
|
|
oldset = (Ecore_X_Atom *)old_data;
|
|
|
|
if (on)
|
|
{
|
|
if (ecore_x_dnd_type_isset(window, type))
|
|
{
|
|
free(old_data);
|
|
reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (reply) free(reply);
|
|
return;
|
|
}
|
|
data = calloc(num + 1, sizeof(Ecore_X_Atom));
|
|
if (!data)
|
|
{
|
|
free(old_data);
|
|
reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (reply) free(reply);
|
|
return;
|
|
}
|
|
newset = (Ecore_X_Atom *)data;
|
|
|
|
for (i = 0; i < num; i++)
|
|
newset[i + 1] = oldset[i];
|
|
/* prepend the new type */
|
|
|
|
reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply)
|
|
{
|
|
free(old_data);
|
|
return;
|
|
}
|
|
newset[0] = reply->atom;
|
|
free(reply);
|
|
|
|
ecore_x_window_prop_property_set(window,
|
|
ECORE_X_ATOM_XDND_TYPE_LIST,
|
|
ECORE_X_ATOM_ATOM,
|
|
32, data, num + 1);
|
|
}
|
|
else
|
|
{
|
|
if (!ecore_x_dnd_type_isset(window, type))
|
|
{
|
|
free(old_data);
|
|
return;
|
|
}
|
|
newset = calloc(num - 1, sizeof(Ecore_X_Atom));
|
|
if (!newset)
|
|
{
|
|
free(old_data);
|
|
return;
|
|
}
|
|
data = (unsigned char *)newset;
|
|
for (i = 0; i < num; i++)
|
|
if (oldset[i] != atom)
|
|
newset[j++] = oldset[i];
|
|
|
|
ecore_x_window_prop_property_set(window,
|
|
ECORE_X_ATOM_XDND_TYPE_LIST,
|
|
ECORE_X_ATOM_ATOM,
|
|
32, data, num - 1);
|
|
}
|
|
|
|
free(oldset);
|
|
free(newset);
|
|
}
|
|
|
|
/* FIXME: round trips, but I don't think we can do much, here */
|
|
|
|
/**
|
|
* Set the types.
|
|
* @param window Unused.
|
|
* @param types The types to set
|
|
* @param num_types The number of types
|
|
*
|
|
* Set the types.
|
|
*
|
|
* To use this function, you must call before, and in order,
|
|
* ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request,
|
|
* then ecore_x_dnd_type_get_fetch(), which gets the reply.
|
|
*/
|
|
EAPI void
|
|
ecore_x_dnd_types_set(Ecore_X_Window window,
|
|
const char **types,
|
|
unsigned int num_types)
|
|
{
|
|
Ecore_X_Atom *newset = NULL;
|
|
void *data = NULL;
|
|
uint32_t i;
|
|
|
|
if (!num_types)
|
|
{
|
|
ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_TYPE_LIST);
|
|
}
|
|
else
|
|
{
|
|
xcb_intern_atom_cookie_t *cookies;
|
|
xcb_intern_atom_reply_t *reply;
|
|
|
|
cookies = (xcb_intern_atom_cookie_t *)malloc(sizeof(xcb_intern_atom_cookie_t));
|
|
if (!cookies) return;
|
|
for (i = 0; i < num_types; i++)
|
|
cookies[i] = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
|
|
strlen(types[i]), types[i]);
|
|
data = calloc(num_types, sizeof(Ecore_X_Atom));
|
|
if (!data)
|
|
{
|
|
for (i = 0; i < num_types; i++)
|
|
{
|
|
reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL);
|
|
if (reply) free(reply);
|
|
}
|
|
free(cookies);
|
|
return;
|
|
}
|
|
newset = data;
|
|
for (i = 0; i < num_types; i++)
|
|
{
|
|
reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL);
|
|
if (reply)
|
|
{
|
|
newset[i] = reply->atom;
|
|
free(reply);
|
|
}
|
|
else
|
|
newset[i] = XCB_NONE;
|
|
}
|
|
free(cookies);
|
|
ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_TYPE_LIST,
|
|
ECORE_X_ATOM_ATOM, 32, data, num_types);
|
|
free(data);
|
|
}
|
|
}
|
|
|
|
Ecore_X_DND_Source *
|
|
_ecore_x_dnd_source_get(void)
|
|
{
|
|
return _source;
|
|
}
|
|
|
|
Ecore_X_DND_Target *
|
|
_ecore_x_dnd_target_get(void)
|
|
{
|
|
return _target;
|
|
}
|
|
|
|
/**
|
|
* Sends the GetProperty request.
|
|
* @param source Window whose properties are requested.
|
|
*/
|
|
EAPI void
|
|
ecore_x_dnd_begin_prefetch(Ecore_X_Window source)
|
|
{
|
|
xcb_get_property_cookie_t cookie;
|
|
|
|
cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0,
|
|
source ? source : ((xcb_screen_t *)_ecore_xcb_screen)->root,
|
|
ECORE_X_ATOM_XDND_AWARE,
|
|
ECORE_X_ATOM_ATOM,
|
|
0, LONG_MAX);
|
|
_ecore_xcb_cookie_cache(cookie.sequence);
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the reply of the GetProperty request sent by ecore_x_dnd_begin_prefetch().
|
|
*/
|
|
EAPI void
|
|
ecore_x_dnd_begin_fetch(void)
|
|
{
|
|
xcb_get_property_cookie_t cookie;
|
|
xcb_get_property_reply_t *reply;
|
|
|
|
cookie.sequence = _ecore_xcb_cookie_get();
|
|
reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
|
|
_ecore_xcb_reply_cache(reply);
|
|
}
|
|
|
|
/* FIXME: round trip */
|
|
|
|
/**
|
|
* Begins the DnD.
|
|
* @param source Unused.
|
|
* @param data The data.
|
|
* @param size The size of the data.
|
|
* @return 0 on failure, 1 otherwise.
|
|
*
|
|
* Begins the DnD. Returns 0 on failure, 1 otherwise.
|
|
*
|
|
* To use this function, you must call before, and in order,
|
|
* ecore_x_dnd_begin_prefetch(), which sends the GetProperty request,
|
|
* then ecore_x_dnd_begin_fetch(), which gets the reply.
|
|
*/
|
|
EAPI int
|
|
ecore_x_dnd_begin(Ecore_X_Window source,
|
|
unsigned char *data,
|
|
int size)
|
|
{
|
|
ecore_x_selection_xdnd_prefetch();
|
|
if (!ecore_x_dnd_version_get(source))
|
|
{
|
|
ecore_x_selection_xdnd_fetch();
|
|
return 0;
|
|
}
|
|
|
|
/* Take ownership of XdndSelection */
|
|
ecore_x_selection_xdnd_prefetch();
|
|
ecore_x_selection_xdnd_fetch();
|
|
if (!ecore_x_selection_xdnd_set(source, data, size))
|
|
return 0;
|
|
|
|
_source->win = source;
|
|
ecore_x_window_ignore_set(_source->win, 1);
|
|
_source->state = ECORE_X_DND_SOURCE_DRAGGING;
|
|
_source->time = _ecore_xcb_event_last_time;
|
|
_source->prev.window = 0;
|
|
|
|
/* Default Accepted Action: ask */
|
|
_source->action = ECORE_X_ATOM_XDND_ACTION_COPY;
|
|
_source->accepted_action = XCB_NONE;
|
|
return 1;
|
|
}
|
|
|
|
EAPI int
|
|
ecore_x_dnd_drop(void)
|
|
{
|
|
uint8_t status = 0;
|
|
|
|
if (_source->dest)
|
|
{
|
|
xcb_client_message_event_t ev;
|
|
|
|
ev.response_type = XCB_CLIENT_MESSAGE;
|
|
ev.format = 32;
|
|
ev.window = _source->dest;
|
|
|
|
if (_source->will_accept)
|
|
{
|
|
ev.type = ECORE_X_ATOM_XDND_DROP;
|
|
ev.data.data32[0] = _source->win;
|
|
ev.data.data32[1] = 0;
|
|
ev.data.data32[2] = _source->time;
|
|
xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
|
|
_source->state = ECORE_X_DND_SOURCE_DROPPED;
|
|
status = 1;
|
|
}
|
|
else
|
|
{
|
|
ev.type = ECORE_X_ATOM_XDND_LEAVE;
|
|
ev.data.data32[0] = _source->win;
|
|
ev.data.data32[1] = 0;
|
|
xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
|
|
_source->state = ECORE_X_DND_SOURCE_IDLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Dropping on nothing */
|
|
ecore_x_selection_xdnd_clear();
|
|
_source->state = ECORE_X_DND_SOURCE_IDLE;
|
|
}
|
|
ecore_x_window_ignore_set(_source->win, 0);
|
|
|
|
_source->prev.window = 0;
|
|
_source->dest = XCB_NONE;
|
|
|
|
return status;
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_dnd_send_status(int will_accept,
|
|
int suppress,
|
|
Ecore_X_Rectangle rectangle,
|
|
Ecore_X_Atom action)
|
|
{
|
|
xcb_client_message_event_t ev;
|
|
|
|
if (_target->state == ECORE_X_DND_TARGET_IDLE)
|
|
return;
|
|
|
|
_target->will_accept = will_accept;
|
|
|
|
ev.response_type = XCB_CLIENT_MESSAGE;
|
|
ev.format = 32;
|
|
ev.window = _target->source;
|
|
ev.type = ECORE_X_ATOM_XDND_STATUS;
|
|
|
|
ev.data.data32[0] = _target->win;
|
|
ev.data.data32[1] = 0;
|
|
if (will_accept)
|
|
ev.data.data32[1] |= 0x1UL;
|
|
if (!suppress)
|
|
ev.data.data32[1] |= 0x2UL;
|
|
|
|
/* Set rectangle information */
|
|
ev.data.data32[2] = rectangle.x;
|
|
ev.data.data32[2] <<= 16;
|
|
ev.data.data32[2] |= rectangle.y;
|
|
ev.data.data32[3] = rectangle.width;
|
|
ev.data.data32[3] <<= 16;
|
|
ev.data.data32[3] |= rectangle.height;
|
|
|
|
if (will_accept)
|
|
{
|
|
ev.data.data32[4] = action;
|
|
_target->accepted_action = action;
|
|
}
|
|
else
|
|
{
|
|
ev.data.data32[4] = XCB_NONE;
|
|
_target->accepted_action = action;
|
|
}
|
|
|
|
xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev);
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_dnd_send_finished(void)
|
|
{
|
|
xcb_client_message_event_t ev;
|
|
|
|
if (_target->state == ECORE_X_DND_TARGET_IDLE)
|
|
return;
|
|
|
|
ev.response_type = XCB_CLIENT_MESSAGE;
|
|
ev.format = 32;
|
|
ev.window = _target->source;
|
|
ev.type = ECORE_X_ATOM_XDND_FINISHED;
|
|
|
|
ev.data.data32[0] = _target->win;
|
|
ev.data.data32[1] = 0;
|
|
ev.data.data32[2] = 0;
|
|
if (_target->will_accept)
|
|
{
|
|
ev.data.data32[1] |= 0x1UL;
|
|
ev.data.data32[2] = _target->accepted_action;
|
|
}
|
|
xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev);
|
|
|
|
_target->state = ECORE_X_DND_TARGET_IDLE;
|
|
}
|
|
|
|
void
|
|
ecore_x_dnd_source_action_set(Ecore_X_Atom action)
|
|
{
|
|
_source->action = action;
|
|
if (_source->prev.window)
|
|
_ecore_x_dnd_drag(_source->prev.window, _source->prev.x, _source->prev.y);
|
|
}
|
|
|
|
Ecore_X_Atom
|
|
ecore_x_dnd_source_action_get(void)
|
|
{
|
|
return _source->action;
|
|
}
|
|
|
|
void
|
|
_ecore_x_dnd_drag(Ecore_X_Window root,
|
|
int x,
|
|
int y)
|
|
{
|
|
xcb_client_message_event_t ev;
|
|
Ecore_X_Window win;
|
|
Ecore_X_Window *skip;
|
|
int num;
|
|
|
|
if (_source->state != ECORE_X_DND_SOURCE_DRAGGING)
|
|
return;
|
|
|
|
ev.response_type = XCB_CLIENT_MESSAGE;
|
|
ev.format = 32;
|
|
|
|
/* Attempt to find a DND-capable window under the cursor */
|
|
skip = ecore_x_window_ignore_list(&num);
|
|
// win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num);
|
|
win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
|
|
while (win)
|
|
{
|
|
xcb_query_tree_cookie_t cookie_tree;
|
|
xcb_query_tree_reply_t *reply_tree;
|
|
|
|
ecore_x_dnd_version_get_prefetch(win);
|
|
cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, win);
|
|
|
|
ecore_x_dnd_version_get_fetch();
|
|
/* We found the correct window ? */
|
|
if (ecore_x_dnd_version_get(win))
|
|
{
|
|
reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
|
|
if (reply_tree) free(reply_tree);
|
|
break;
|
|
}
|
|
reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
|
|
if (reply_tree)
|
|
{
|
|
win = reply_tree->parent;
|
|
free(reply_tree);
|
|
}
|
|
}
|
|
|
|
/* Send XdndLeave to current destination window if we have left it */
|
|
if ((_source->dest) && (win != _source->dest))
|
|
{
|
|
ev.window = _source->dest;
|
|
ev.type = ECORE_X_ATOM_XDND_LEAVE;
|
|
ev.data.data32[0] = _source->win;
|
|
ev.data.data32[1] = 0;
|
|
|
|
xcb_send_event(_ecore_xcb_conn, 0, _source->dest, 0, (const char *)&ev);
|
|
_source->suppress = 0;
|
|
}
|
|
|
|
if (win)
|
|
{
|
|
int16_t x1;
|
|
int16_t x2;
|
|
int16_t y1;
|
|
int16_t y2;
|
|
|
|
ecore_x_dnd_version_get_prefetch(win);
|
|
ecore_x_dnd_type_get_prefetch(_source->win);
|
|
|
|
ecore_x_dnd_version_get_fetch();
|
|
if (!ecore_x_dnd_version_get(win))
|
|
{
|
|
ecore_x_dnd_type_get_fetch();
|
|
return;
|
|
}
|
|
|
|
_source->version = MIN(ECORE_X_DND_VERSION,
|
|
ecore_x_dnd_version_get(win));
|
|
if (win != _source->dest)
|
|
{
|
|
unsigned char *data;
|
|
Ecore_X_Atom *types;
|
|
int num;
|
|
int i;
|
|
|
|
ecore_x_dnd_type_get_fetch();
|
|
if (!ecore_x_window_prop_property_get(_source->win,
|
|
ECORE_X_ATOM_XDND_TYPE_LIST,
|
|
ECORE_X_ATOM_ATOM,
|
|
32, &data, &num))
|
|
return;
|
|
|
|
types = (Ecore_X_Atom *)data;
|
|
|
|
/* Entered new window, send XdndEnter */
|
|
ev.window = win;
|
|
ev.type = ECORE_X_ATOM_XDND_ENTER;
|
|
ev.data.data32[0] = _source->win;
|
|
ev.data.data32[1] = 0;
|
|
if (num > 3)
|
|
ev.data.data32[1] |= 0x1UL;
|
|
else
|
|
ev.data.data32[1] &= 0xfffffffeUL;
|
|
ev.data.data32[1] |= ((unsigned long) _source->version) << 24;
|
|
|
|
for (i = 2; i < 5; i++)
|
|
ev.data.data32[i] = 0;
|
|
for (i = 0; i < MIN(num, 3); ++i)
|
|
ev.data.data32[i + 2] = types[i];
|
|
free(data);
|
|
xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev);
|
|
_source->await_status = 0;
|
|
_source->will_accept = 0;
|
|
}
|
|
else
|
|
ecore_x_dnd_type_get_fetch();
|
|
|
|
/* Determine if we're still in the rectangle from the last status */
|
|
x1 = _source->rectangle.x;
|
|
x2 = _source->rectangle.x + _source->rectangle.width;
|
|
y1 = _source->rectangle.y;
|
|
y2 = _source->rectangle.y + _source->rectangle.height;
|
|
|
|
if ((!_source->await_status) ||
|
|
(!_source->suppress) ||
|
|
((x < x1) || (x > x2) || (y < y1) || (y > y2)))
|
|
{
|
|
ev.window = win;
|
|
ev.type = ECORE_X_ATOM_XDND_POSITION;
|
|
ev.data.data32[0] = _source->win;
|
|
ev.data.data32[1] = 0; /* Reserved */
|
|
ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
|
|
ev.data.data32[3] = _source->time; /* Version 1 */
|
|
ev.data.data32[4] = _source->action; /* Version 2, Needs to be pre-set */
|
|
xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev);
|
|
|
|
_source->await_status = 1;
|
|
}
|
|
}
|
|
|
|
_source->prev.x = x;
|
|
_source->prev.y = y;
|
|
_source->prev.window = root;
|
|
_source->dest = win;
|
|
}
|