diff options
author | Daniel Zaoui <daniel.zaoui@samsung.com> | 2015-06-18 10:15:58 +0300 |
---|---|---|
committer | Daniel Zaoui <daniel.zaoui@yahoo.com> | 2015-06-20 22:23:06 +0300 |
commit | 5a5785d26c7626bdd9175bd1b6196683697c0ede (patch) | |
tree | 29bfe20c6f3608821ce7faa86a2469162f5fe0cc | |
parent | 475bc14beddf4229b030acf0ae127e436ef63d2b (diff) | |
download | elementary-devs/jackdanielz/DnD.tar.gz |
-rw-r--r-- | src/lib/elm_cnp.c | 299 |
1 files changed, 188 insertions, 111 deletions
diff --git a/src/lib/elm_cnp.c b/src/lib/elm_cnp.c index 0aceecd70..b5e8b7e83 100644 --- a/src/lib/elm_cnp.c +++ b/src/lib/elm_cnp.c @@ -66,10 +66,8 @@ struct _Tmp_Info struct _Saved_Type { const char **types; - char *imgfile; int ntypes; int x, y; - Eina_Bool textreq: 1; }; struct _Cnp_Escape @@ -157,7 +155,20 @@ static const char *text_uri; static Eina_Hash *_types_hash = NULL; /* Data for DND in progress */ -static Saved_Type savedtypes = { NULL, NULL, 0, 0, 0, EINA_FALSE }; +static Saved_Type savedtypes = { NULL, 0, 0, 0 }; + +/* Stores the data that has been requested before drop. + * It could be useful to preview images/data during DnD. + */ +typedef struct +{ + Elm_Selection_Data ddata; + Tmp_Info *tmp_info; + Eina_Bool requested:1; +} Request_Data; +static Request_Data **_requested_data = NULL; + +static Eina_Bool _drop_request = EINA_FALSE; /* Drag & Drop functions */ /* FIXME: Way too many globals */ @@ -431,6 +442,19 @@ _all_drop_targets_cbs_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Obje } } +static void +_request_data_all_free(void) +{ + int i; + /* Free previous requested data */ + for (i = 0; i < CNP_N_ATOMS; i++) + { + ELM_SAFE_FREE(_requested_data[i]->ddata.data, free); + ELM_SAFE_FREE(_requested_data[i]->tmp_info, _tmpinfo_free); + memset(_requested_data[i], 0, sizeof(Request_Data)); + } +} + static Cnp_Atom _atoms[CNP_N_ATOMS] = { ARRAYINIT(CNP_ATOM_TARGETS) { .name = "TARGETS", @@ -617,6 +641,14 @@ static Cnp_Atom _atoms[CNP_N_ATOMS] = { }, }; +static int +_get_atom_id_by_mime_type(const char *type) +{ + Cnp_Atom *atom = eina_hash_find(_types_hash, type); + if (atom) return atom - _atoms; + else return -1; +} + // x11 specific stuff //////////////////////////////////////////////////////////////////////////// #ifdef HAVE_ELEMENTARY_X @@ -732,7 +764,7 @@ _x11_selection_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event { Ecore_X_Event_Selection_Notify *ev = event; X11_Cnp_Selection *sel; - int i; + int atom_idx; cnp_debug("selection notify callback: %d\n",ev->selection); switch (ev->selection) @@ -760,57 +792,63 @@ _x11_selection_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event _x11_notify_handler_targets(sel, ev); return ECORE_CALLBACK_PASS_ON; } - for (i = 0; i < CNP_N_ATOMS; i++) + atom_idx = _get_atom_id_by_mime_type(ev->target); + if (_atoms[atom_idx].x_data_preparer) { - if (!strcmp(ev->target, _atoms[i].name)) + Elm_Selection_Data *ddata = &_requested_data[atom_idx]->ddata; + Eina_Bool success; + cnp_debug("Found something: %s\n", _atoms[atom_idx].name); + ELM_SAFE_FREE(_requested_data[atom_idx]->ddata.data, free); + ELM_SAFE_FREE(_requested_data[atom_idx]->tmp_info, _tmpinfo_free); + success = _atoms[atom_idx].x_data_preparer(ev, ddata, &(_requested_data[atom_idx]->tmp_info)); + if (ev->selection == ECORE_X_SELECTION_XDND) { - if (_atoms[i].x_data_preparer) + if (success) { - Elm_Selection_Data ddata; - Tmp_Info *tmp_info = NULL; - Eina_Bool success; - ddata.data = NULL; - cnp_debug("Found something: %s\n", _atoms[i].name); - success = _atoms[i].x_data_preparer(ev, &ddata, &tmp_info); - if (_atoms[i].formats == ELM_SEL_FORMAT_IMAGE && savedtypes.imgfile) break; - if (ev->selection == ECORE_X_SELECTION_XDND) + if (_drop_request) { - if (success) + Dropable *dropable; + Eina_List *l; + cnp_debug("drag & drop\n"); + EINA_LIST_FOREACH(drops, l, dropable) { - Dropable *dropable; - Eina_List *l; - cnp_debug("drag & drop\n"); - EINA_LIST_FOREACH(drops, l, dropable) - { - if (dropable->obj == sel->requestwidget) break; - dropable = NULL; - } - if (dropable) - { - Dropable_Cbs *cbs; - Eina_Inlist *itr; - ddata.x = savedtypes.x; - ddata.y = savedtypes.y; - EINA_INLIST_FOREACH_SAFE(dropable->cbs_list, itr, cbs) - if ((cbs->types & dropable->last.format) && cbs->dropcb) - cbs->dropcb(cbs->dropdata, dropable->obj, &ddata); - } + if (dropable->obj == sel->requestwidget) break; + dropable = NULL; + } + if (dropable) + { + Dropable_Cbs *cbs; + Eina_Inlist *itr; + ddata->x = savedtypes.x; + ddata->y = savedtypes.y; + EINA_INLIST_FOREACH_SAFE(dropable->cbs_list, itr, cbs) + if ((cbs->types & dropable->last.format) && cbs->dropcb) + cbs->dropcb(cbs->dropdata, dropable->obj, ddata); } - /* We have to finish DnD, no matter what */ - ecore_x_dnd_send_finished(); + _drop_request = EINA_FALSE; + _request_data_all_free(); } - else if (sel->datacb && success) + else { - ddata.x = ddata.y = 0; - sel->datacb(sel->udata, sel->requestwidget, &ddata); + cnp_debug("Caching data\n"); + _requested_data[atom_idx]->requested = EINA_FALSE; + /* DnD is not finished yet. The data has just been requested during DnD and needs to be cached. + * The process will be finished on drop. + */ + return ECORE_CALLBACK_PASS_ON; } - free(ddata.data); - if (tmp_info) _tmpinfo_free(tmp_info); } - else cnp_debug("Ignored: No handler!\n"); - break; + /* We have to finish DnD, no matter what */ + ecore_x_dnd_send_finished(); + } + else if (sel->datacb && success) + { + ddata->x = ddata->y = 0; + sel->datacb(sel->udata, sel->requestwidget, ddata); + _request_data_all_free(); } } + else cnp_debug("Ignored: No handler!\n"); return ECORE_CALLBACK_PASS_ON; } @@ -1052,19 +1090,9 @@ _x11_data_preparer_uri(Ecore_X_Event_Selection_Notify *notify, cnp_debug("Couldn't find a file\n"); return EINA_FALSE; } - free(savedtypes.imgfile); - if (savedtypes.textreq) - { - savedtypes.textreq = 0; - savedtypes.imgfile = stripstr; - } - else - { - ddata->format = ELM_SEL_FORMAT_IMAGE; - ddata->data = stripstr; - ddata->len = strlen(stripstr); - savedtypes.imgfile = NULL; - } + ddata->format = ELM_SEL_FORMAT_IMAGE; + ddata->data = stripstr; + ddata->len = strlen(stripstr); return EINA_TRUE; } @@ -1256,17 +1284,11 @@ _x11_evas_get_from_xwin(Ecore_X_Window win) static Eina_Bool _x11_dnd_enter(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) { - Ecore_X_Event_Xdnd_Enter *enter = ev; int i; - Dropable *dropable; + Ecore_X_Event_Xdnd_Enter *enter = ev; if (!enter) return EINA_TRUE; - dropable = _x11_dropable_find(enter->win); - if (dropable) - { - cnp_debug("Enter %x\n", enter->win); - } - /* Skip it */ + cnp_debug("enter types=%p (%d)\n", enter->types, enter->num_types); if ((!enter->num_types) || (!enter->types)) return EINA_TRUE; @@ -1276,6 +1298,9 @@ _x11_dnd_enter(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) savedtypes.types = malloc(sizeof(char *) * enter->num_types); if (!savedtypes.types) return EINA_FALSE; + _request_data_all_free(); + _x11_selections[ELM_SEL_TYPE_XDND].xwin = enter->win; + for (i = 0; i < enter->num_types; i++) { savedtypes.types[i] = eina_stringshare_add(enter->types[i]); @@ -1284,9 +1309,9 @@ _x11_dnd_enter(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) if (savedtypes.types[i] == text_uri) { /* Request it, so we know what it is */ - cnp_debug("Sending uri request\n"); - savedtypes.textreq = 1; - ELM_SAFE_FREE(savedtypes.imgfile, free); + cnp_debug("Sending text/uri-list request\n"); + _requested_data[CNP_ATOM_text_urilist]->requested = EINA_TRUE; + ELM_SAFE_FREE(_requested_data[CNP_ATOM_text_urilist]->ddata.data, free); ecore_x_selection_xdnd_request(enter->win, text_uri); } } @@ -1506,8 +1531,21 @@ _x11_dnd_position(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action); cnp_debug("dnd position %i %i %p\n", x - ox, y - oy, dropable); _x11_dnd_dropable_handle(dropable, x - ox, y - oy, act); - // CCCCCCC: call dnd exit on last obj if obj != last - // CCCCCCC: call drop position on obj + // FIXME check if the object needs the request before the drop + /* Request data before drop */ + { + Cnp_Atom *atom = eina_hash_find(_types_hash, dropable->last.type); + int atom_idx = (atom - _atoms); + if (!_requested_data[atom_idx]->requested && !_requested_data[atom_idx]->ddata.data) + { + ecore_x_selection_xdnd_request(pos->win, dropable->last.type); + _requested_data[atom_idx]->requested = EINA_TRUE; + } + else + { + // FIXME invoke the target cbs with the cached data + } + } } else { @@ -1515,7 +1553,6 @@ _x11_dnd_position(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, pos->action); cnp_debug("dnd position (%d, %d) not in obj\n", x, y); _x11_dnd_dropable_handle(NULL, 0, 0, act); - // CCCCCCC: call dnd exit on last obj } eina_list_free(dropable_list); } @@ -1536,28 +1573,34 @@ _x11_dnd_position(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) static Eina_Bool _x11_dnd_leave(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) { + Ecore_X_Event_Xdnd_Leave *leave = (Ecore_X_Event_Xdnd_Leave *)ev; #ifdef DEBUGON - cnp_debug("Leave %x\n", ((Ecore_X_Event_Xdnd_Leave *)ev)->win); + cnp_debug("Leave %x\n", leave->win); #else (void)ev; #endif _x11_dnd_dropable_handle(NULL, 0, 0, ELM_XDND_ACTION_UNKNOWN); + + /* If the current xwin is different, we don't free the temp data. + * It could happen if enter event into another xwin occurs before leave event of the first window */ + if (leave->win == _x11_selections[ELM_SEL_TYPE_XDND].xwin) _request_data_all_free(); + // CCCCCCC: call dnd exit on last obj if there was one // leave->win leave->source return EINA_TRUE; } static Eina_Bool -_x11_dnd_drop(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) +_x11_dnd_drop(void *_data EINA_UNUSED, int etype EINA_UNUSED, void *ev) { Ecore_X_Event_Xdnd_Drop *drop; Dropable *dropable = NULL; - Elm_Selection_Data ddata; Evas_Coord x = 0, y = 0; Elm_Xdnd_Action act = ELM_XDND_ACTION_UNKNOWN; Eina_List *l; Dropable_Cbs *cbs; Eina_Inlist *itr; + int atom_idx; drop = ev; @@ -1588,25 +1631,29 @@ _x11_dnd_drop(void *data EINA_UNUSED, int etype EINA_UNUSED, void *ev) return EINA_TRUE; found: + atom_idx = _get_atom_id_by_mime_type(dropable->last.type); cnp_debug("0x%x\n", drop->win); act = _x11_dnd_action_map(drop->action); dropable->last.in = EINA_FALSE; cnp_debug("Last type: %s - Last format: %X\n", dropable->last.type, dropable->last.format); - if ((!strcmp(dropable->last.type, text_uri))) + /* Check if the data has already been cached. */ + if (_requested_data[atom_idx]->ddata.data) { - cnp_debug("We found a URI... (%scached) %s\n", - savedtypes.imgfile ? "" : "not ", - savedtypes.imgfile); - if (savedtypes.imgfile) + /* We just need to call drop callbacks as we already have the data */ + Elm_Selection_Data *ddata = &_requested_data[atom_idx]->ddata; + cnp_debug("We found a cached data (%s)\n", dropable->last.type); + ddata->x = savedtypes.x; + ddata->y = savedtypes.y; + ddata->action = act; + /* FIXME Special case that needs to be removed */ + if ((!strcmp(dropable->last.type, text_uri))) { + char *data = ddata->data; char *entrytag; static const char *tagstring = "<item absize=240x180 href=file://%s></item>"; - ddata.x = savedtypes.x; - ddata.y = savedtypes.y; - ddata.action = act; EINA_INLIST_FOREACH_SAFE(dropable->cbs_list, itr, cbs) { @@ -1615,50 +1662,67 @@ found: (cbs->types & ELM_SEL_FORMAT_IMAGE)) { int len; - ddata.format = ELM_SEL_FORMAT_MARKUP; + ddata->format = ELM_SEL_FORMAT_MARKUP; - len = strlen(tagstring) + strlen(savedtypes.imgfile); + len = strlen(tagstring) + strlen(data); entrytag = alloca(len + 1); - snprintf(entrytag, len + 1, tagstring, savedtypes.imgfile); - ddata.data = entrytag; - cnp_debug("Insert %s\n", (char *)ddata.data); + snprintf(entrytag, len + 1, tagstring, data); + ddata->data = entrytag; + cnp_debug("Insert %s\n", data); if ((cbs->types & dropable->last.format) && cbs->dropcb) - cbs->dropcb(cbs->dropdata, dropable->obj, &ddata); + cbs->dropcb(cbs->dropdata, dropable->obj, ddata); + free(ddata->data); } else if (cbs->types & ELM_SEL_FORMAT_IMAGE) { - cnp_debug("Doing image insert (%s)\n", savedtypes.imgfile); - ddata.format = ELM_SEL_FORMAT_IMAGE; - ddata.data = (char *)savedtypes.imgfile; + cnp_debug("Doing image insert (%s)\n", data); + ddata->format = ELM_SEL_FORMAT_IMAGE; + ddata->data = data; if ((cbs->types & dropable->last.format) && cbs->dropcb) - cbs->dropcb(cbs->dropdata, dropable->obj, &ddata); + cbs->dropcb(cbs->dropdata, dropable->obj, ddata); } else { cnp_debug("Item doesn't support images... passing\n"); } + ddata->data = NULL; } - ecore_x_dnd_send_finished(); - ELM_SAFE_FREE(savedtypes.imgfile, free); - return EINA_TRUE; + ddata->data = data; } - else if (savedtypes.textreq) + else { - /* Already asked: Pretend we asked now, and paste immediately when - * it comes in */ - savedtypes.textreq = 0; - ecore_x_dnd_send_finished(); - return EINA_TRUE; + EINA_INLIST_FOREACH_SAFE(dropable->cbs_list, itr, cbs) + if ((cbs->types & dropable->last.format) && cbs->dropcb) + cbs->dropcb(cbs->dropdata, dropable->obj, ddata); } + _request_data_all_free(); + ecore_x_dnd_send_finished(); + } + else if (_requested_data[atom_idx]->requested) + { + cnp_debug("Data already requested for %s\n", dropable->last.type); + /* The data has been requested but has not been received yet. + * Drop callbacks will be invoked when the data arrives + * (selection notify event). + * DnD finish will be done there. + */ + _drop_request = EINA_TRUE; + } + else + { + /* We need to request the data. Drop callbacks will be invoked + * when the data arrives (selection notify event). + * DnD finish will be done there. + */ + cnp_debug("doing a request then: %s\n", dropable->last.type); + _x11_selections[ELM_SEL_TYPE_XDND].xwin = drop->win; + _x11_selections[ELM_SEL_TYPE_XDND].requestwidget = dropable->obj; + _x11_selections[ELM_SEL_TYPE_XDND].requestformat = dropable->last.format; + _x11_selections[ELM_SEL_TYPE_XDND].active = EINA_TRUE; + _x11_selections[ELM_SEL_TYPE_XDND].action = act; + _drop_request = EINA_TRUE; + ecore_x_selection_xdnd_request(drop->win, dropable->last.type); } - - cnp_debug("doing a request then: %s\n", dropable->last.type); - _x11_selections[ELM_SEL_TYPE_XDND].xwin = drop->win; - _x11_selections[ELM_SEL_TYPE_XDND].requestwidget = dropable->obj; - _x11_selections[ELM_SEL_TYPE_XDND].requestformat = dropable->last.format; - _x11_selections[ELM_SEL_TYPE_XDND].active = EINA_TRUE; - _x11_selections[ELM_SEL_TYPE_XDND].action = act; - ecore_x_selection_xdnd_request(drop->win, dropable->last.type); return EINA_TRUE; } @@ -2091,8 +2155,6 @@ _x11_elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, ELM_SAFE_FREE(handler_leave, ecore_event_handler_del); } - ELM_SAFE_FREE(savedtypes.imgfile, free); - return EINA_TRUE; } @@ -2955,6 +3017,7 @@ _wl_dnd_enter(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) savedtypes.types = malloc(sizeof(char *) * ev->num_types); if (!savedtypes.types) return EINA_FALSE; +#if 0 for (i = 0; i < ev->num_types; i++) { savedtypes.types[i] = eina_stringshare_add(ev->types[i]); @@ -2964,6 +3027,7 @@ _wl_dnd_enter(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) ELM_SAFE_FREE(savedtypes.imgfile, free); } } +#endif doaccept = EINA_FALSE; for (i = 0; i < ev->num_types; i++) @@ -3233,11 +3297,13 @@ _wl_dropable_data_handle(Wl_Cnp_Selection *sel, char *data) memcpy(s, data, len); s[len] = 0; +#if 0 if (savedtypes.textreq) { savedtypes.textreq = 0; savedtypes.imgfile = s; } +#endif sdata.len = len; sdata.x = savedtypes.x; @@ -3253,6 +3319,7 @@ _wl_dropable_data_handle(Wl_Cnp_Selection *sel, char *data) if (cbs->types && drop->last.format) { /* If it's markup that also supports images */ +#if 0 if (cbs->types & (ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE)) { sdata.format = ELM_SEL_FORMAT_MARKUP; @@ -3264,6 +3331,7 @@ _wl_dropable_data_handle(Wl_Cnp_Selection *sel, char *data) sdata.data = (char *)savedtypes.imgfile; } else +#endif { sdata.format = drop->last.format; sdata.data = s; @@ -3273,7 +3341,6 @@ _wl_dropable_data_handle(Wl_Cnp_Selection *sel, char *data) } } ecore_wl_dnd_drag_end(ecore_wl_input_get()); - ELM_SAFE_FREE(savedtypes.imgfile, free); } static Dropable * @@ -3631,6 +3698,9 @@ _local_elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, drops = eina_list_remove(drops, dropable); eo_do(obj, eo_key_data_del("__elm_dropable")); free(dropable); + /* In case temp data remains allocated */ +// ELM_SAFE_FREE(dropable->requested_data, free); +// ELM_SAFE_FREE(dropable->requested_); dropable = NULL; evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _all_drop_targets_cbs_del); @@ -3692,9 +3762,11 @@ _elm_cnp_init(void) _elm_cnp_init_count++; text_uri = eina_stringshare_add("text/uri-list"); _types_hash = eina_hash_string_small_new(NULL); + _requested_data = calloc(CNP_N_ATOMS, sizeof(Request_Data *)); for (i = 0; i < CNP_N_ATOMS; i++) { eina_hash_add(_types_hash, _atoms[i].name, &_atoms[i]); + _requested_data[i] = calloc(1, sizeof(Request_Data)); } return EINA_TRUE; } @@ -3702,12 +3774,17 @@ _elm_cnp_init(void) static Eina_Bool _elm_cnp_shutdown(void) { + int i; if (!_elm_cnp_init_count) return EINA_TRUE; if (--_elm_cnp_init_count > 0) return EINA_TRUE; eina_stringshare_del(text_uri); text_uri = NULL; eina_hash_free(_types_hash); _types_hash = NULL; + _request_data_all_free(); + for (i = 0; i < CNP_N_ATOMS; i++) free(_requested_data[i]); + free(_requested_data); + _requested_data = NULL; return EINA_TRUE; } |