From dd7595a3475407a7fa96a97393bae8c5220e8762 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Wed, 4 Jan 2012 18:41:13 +1000 Subject: Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje. Note that embryo wont be used, but I'm not sure yet if you can build edje without it. --- .../ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c | 689 +++++++++++++++++++++ 1 file changed, 689 insertions(+) create mode 100644 libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c (limited to 'libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c') diff --git a/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c b/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c new file mode 100644 index 0000000..677de38 --- /dev/null +++ b/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c @@ -0,0 +1,689 @@ +#include "ecore_xcb_private.h" + +#ifndef MIN +# define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/* local structures */ +typedef struct _Version_Cache_Item +{ + Ecore_X_Window win; + int ver; +} Version_Cache_Item; + +/* local function prototypes */ +static Eina_Bool _ecore_xcb_dnd_converter_copy(char *target __UNUSED__, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *tprop __UNUSED__, + int *count __UNUSED__); + +/* local variables */ +static int _ecore_xcb_dnd_init_count = 0; +static Ecore_X_DND_Source *_source = NULL; +static Ecore_X_DND_Target *_target = NULL; +static Version_Cache_Item *_version_cache = NULL; +static int _version_cache_num = 0, _version_cache_alloc = 0; +static void (*_posupdatecb)(void *, + Ecore_X_Xdnd_Position *); +static void *_posupdatedata; + +/* external variables */ +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; + +void +_ecore_xcb_dnd_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!_ecore_xcb_dnd_init_count) + { + _source = calloc(1, sizeof(Ecore_X_DND_Source)); + if (!_source) return; + _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)); + if (!_target) + { + free(_source); + _source = NULL; + return; + } + _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_xcb_dnd_init_count++; +} + +void +_ecore_xcb_dnd_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_dnd_init_count--; + if (_ecore_xcb_dnd_init_count > 0) return; + if (_source) free(_source); + _source = NULL; + if (_target) free(_target); + _target = NULL; + _ecore_xcb_dnd_init_count = 0; +} + +EAPI void +ecore_x_dnd_send_status(Eina_Bool will_accept, + Eina_Bool suppress, + Ecore_X_Rectangle rect, + Ecore_X_Atom action) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (_target->state == ECORE_X_DND_TARGET_IDLE) return; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + _target->will_accept = will_accept; + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.type = ECORE_X_ATOM_XDND_STATUS; + ev.format = 32; + ev.window = _target->source; + 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; + + ev.data.data32[2] = rect.x; + ev.data.data32[2] <<= 16; + ev.data.data32[2] |= rect.y; + ev.data.data32[3] = rect.width; + ev.data.data32[3] <<= 16; + ev.data.data32[3] |= rect.height; + + if (will_accept) + ev.data.data32[4] = action; + else + ev.data.data32[4] = XCB_NONE; + _target->accepted_action = action; + + xcb_send_event(_ecore_xcb_conn, 0, _target->source, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI Eina_Bool +ecore_x_dnd_drop(void) +{ + xcb_client_message_event_t ev; + Eina_Bool status = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + if (_source->dest) + { + 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, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->state = ECORE_X_DND_SOURCE_DROPPED; + status = EINA_TRUE; + } + 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, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->state = ECORE_X_DND_SOURCE_IDLE; + } + } + else + { + ecore_x_selection_xdnd_clear(); + _source->state = ECORE_X_DND_SOURCE_IDLE; + } + + ecore_x_window_ignore_set(_source->win, 0); + _source->prev.window = 0; + + return status; +} + +EAPI void +ecore_x_dnd_aware_set(Ecore_X_Window win, + Eina_Bool on) +{ + Ecore_X_Atom prop_data = ECORE_X_DND_VERSION; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (on) + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE, + ECORE_X_ATOM_ATOM, 32, &prop_data, 1); + else + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE); +} + +EAPI int +ecore_x_dnd_version_get(Ecore_X_Window win) +{ + unsigned char *data; + int num = 0; + Version_Cache_Item *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + if (_version_cache) + { + int i = 0; + + for (i = 0; i < _version_cache_num; i++) + { + if (_version_cache[i].win == win) + return _version_cache[i].ver; + } + } + } + + if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE, + ECORE_X_ATOM_ATOM, 32, &data, &num)) + { + int version = 0; + + version = (int)*data; + free(data); + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + _version_cache_num++; + if (_version_cache_num > _version_cache_alloc) + _version_cache_alloc += 16; + t = realloc(_version_cache, + _version_cache_alloc * sizeof(Version_Cache_Item)); + if (!t) return 0; + _version_cache = t; + _version_cache[_version_cache_num - 1].win = win; + _version_cache[_version_cache_num - 1].ver = version; + } + return version; + } + + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + _version_cache_num++; + if (_version_cache_num > _version_cache_alloc) + _version_cache_alloc += 16; + t = realloc(_version_cache, + _version_cache_alloc * sizeof(Version_Cache_Item)); + if (!t) return 0; + _version_cache = t; + _version_cache[_version_cache_num - 1].win = win; + _version_cache[_version_cache_num - 1].ver = 0; + } + + return 0; +} + +EAPI Eina_Bool +ecore_x_dnd_type_isset(Ecore_X_Window win, + const char *type) +{ + int num = 0, i = 0; + Eina_Bool ret = EINA_FALSE; + unsigned char *data; + Ecore_X_Atom *atoms, atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, &data, &num)) + return ret; + + atom = ecore_x_atom_get(type); + atoms = (Ecore_X_Atom *)data; + for (i = 0; i < num; ++i) + { + if (atom == atoms[i]) + { + ret = EINA_TRUE; + break; + } + } + + free(data); + return ret; +} + +EAPI void +ecore_x_dnd_type_set(Ecore_X_Window win, + const char *type, + Eina_Bool on) +{ + Ecore_X_Atom atom, *oldset = NULL, *newset = NULL; + int i = 0, j = 0, num = 0; + unsigned char *data = NULL, *old_data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + atom = ecore_x_atom_get(type); + ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, &old_data, &num); + oldset = (Ecore_X_Atom *)old_data; + if (on) + { + if (ecore_x_dnd_type_isset(win, type)) + { + free(old_data); + return; + } + newset = calloc(num + 1, sizeof(Ecore_X_Atom)); + if (!newset) return; + data = (unsigned char *)newset; + for (i = 0; i < num; i++) + newset[i + 1] = oldset[i]; + newset[0] = atom; + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, data, num + 1); + } + else + { + if (!ecore_x_dnd_type_isset(win, 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(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, data, num - 1); + } + free(oldset); + free(newset); +} + +EAPI void +ecore_x_dnd_types_set(Ecore_X_Window win, + const char **types, + unsigned int num_types) +{ + Ecore_X_Atom *newset = NULL; + unsigned int i; + unsigned char *data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!num_types) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST); + else + { + newset = calloc(num_types, sizeof(Ecore_X_Atom)); + if (!newset) return; + + data = (unsigned char *)newset; + for (i = 0; i < num_types; i++) + { + newset[i] = ecore_x_atom_get(types[i]); + ecore_x_selection_converter_atom_add(newset[i], + _ecore_xcb_dnd_converter_copy); + } + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, data, + num_types); + free(newset); + } +} + +EAPI void +ecore_x_dnd_actions_set(Ecore_X_Window win, + Ecore_X_Atom *actions, + unsigned int num_actions) +{ + unsigned int i; + unsigned char *data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!num_actions) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST); + else + { + data = (unsigned char *)actions; + for (i = 0; i < num_actions; i++) + ecore_x_selection_converter_atom_add(actions[i], + _ecore_xcb_dnd_converter_copy); + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST, + ECORE_X_ATOM_ATOM, 32, data, + num_actions); + } +} + +/** + * The DND position update cb is called Ecore_X sends a DND position to a + * client. + * + * It essentially mirrors some of the data sent in the position message. + * Generally this cb should be set just before position update is called. + * Please note well you need to look after your own data pointer if someone + * trashes you position update cb set. + * + * It is considered good form to clear this when the dnd event finishes. + * + * @param cb Callback to updated each time ecore_x sends a position update. + * @param data User data. + */ +EAPI void +ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, + Ecore_X_Xdnd_Position *data), + const void *data) +{ + _posupdatecb = cb; + _posupdatedata = (void *)data; +} + +EAPI Eina_Bool +ecore_x_dnd_begin(Ecore_X_Window source, + unsigned char *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_dnd_version_get(source)) return EINA_FALSE; + + /* Take ownership of XdndSelection */ + if (!ecore_x_selection_xdnd_set(source, data, size)) return EINA_FALSE; + + if (_version_cache) + { + free(_version_cache); + _version_cache = NULL; + _version_cache_num = 0; + _version_cache_alloc = 0; + } + + ecore_x_window_shadow_tree_flush(); + + _source->win = source; + ecore_x_window_ignore_set(_source->win, 1); + _source->state = ECORE_X_DND_SOURCE_DRAGGING; + _source->time = _ecore_xcb_events_last_time_get(); + _source->prev.window = 0; + + /* Default Accepted Action: move */ + _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE; + _source->accepted_action = XCB_NONE; + _source->dest = XCB_NONE; + + return EINA_TRUE; +} + +EAPI void +ecore_x_dnd_send_finished(void) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (_target->state == ECORE_X_DND_TARGET_IDLE) return; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.type = ECORE_X_ATOM_XDND_FINISHED; + ev.window = _target->source; + 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, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _target->state = ECORE_X_DND_TARGET_IDLE; +} + +EAPI void +ecore_x_dnd_source_action_set(Ecore_X_Atom action) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _source->action = action; + if (_source->prev.window) + _ecore_xcb_dnd_drag(_source->prev.window, + _source->prev.x, _source->prev.y); +} + +Ecore_X_DND_Source * +_ecore_xcb_dnd_source_get(void) +{ + return _source; +} + +Ecore_X_DND_Target * +_ecore_xcb_dnd_target_get(void) +{ + return _target; +} + +void +_ecore_xcb_dnd_drag(Ecore_X_Window root, + int x, + int y) +{ + xcb_client_message_event_t ev; + Ecore_X_Window win, *skip; + Ecore_X_Xdnd_Position pos; + int num = 0; + + if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + + skip = ecore_x_window_ignore_list(&num); + win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num); + while ((win) && !(ecore_x_dnd_version_get(win))) + win = ecore_x_window_shadow_parent_get(root, win); + + 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, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->suppress = 0; + } + + if (win) + { + int x1, x2, y1, y2; + + _source->version = MIN(ECORE_X_DND_VERSION, + ecore_x_dnd_version_get(win)); + if (win != _source->dest) + { + int i = 0; + unsigned char *data; + Ecore_X_Atom *types; + + ecore_x_window_prop_property_get(_source->win, + ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, + &data, &num); + types = (Ecore_X_Atom *)data; + 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, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->await_status = 0; + _source->will_accept = 0; + } + + 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; + ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff); + ev.data.data32[3] = _source->time; + ev.data.data32[4] = _source->action; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->await_status = 1; + } + } + + if (_posupdatecb) + { + pos.position.x = x; + pos.position.y = y; + pos.win = win; + pos.prev = _source->dest; + _posupdatecb(_posupdatedata, &pos); + } + + _source->prev.x = x; + _source->prev.y = y; + _source->prev.window = root; + _source->dest = win; +} + +EAPI Ecore_X_Atom +ecore_x_dnd_source_action_get(void) +{ + return _source->action; +} + +/* local functions */ +static Eina_Bool +_ecore_xcb_dnd_converter_copy(char *target __UNUSED__, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *tprop __UNUSED__, + int *count __UNUSED__) +{ + Ecore_Xcb_Textproperty text_prop; + Ecore_Xcb_Encoding_Style style = XcbTextStyle; + char *mystr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!data) || (!size)) return EINA_FALSE; + + mystr = calloc(1, size + 1); + if (!mystr) return EINA_FALSE; + + memcpy(mystr, data, size); + if (_ecore_xcb_mb_textlist_to_textproperty(&mystr, 1, style, &text_prop)) + { + int len; + + len = strlen((char *)text_prop.value) + 1; + if (!(*data_ret = malloc(len))) + { + free(mystr); + return EINA_FALSE; + } + memcpy(*data_ret, text_prop.value, len); + *size_ret = len; + free(text_prop.value); + free(mystr); + return EINA_TRUE; + } + else + { + free(mystr); + return EINA_FALSE; + } +} + -- cgit v1.1