DnD: multi-callbacks support

This features permits execution of more than one set of functions during
DnD.
Delete function API has been modified to give the developer the
possibility to remove a specific set of functions.
This commit is contained in:
Daniel Zaoui 2013-11-04 15:08:53 +02:00
parent 579d309cc5
commit b66233d128
6 changed files with 210 additions and 104 deletions

View File

@ -919,6 +919,11 @@ static Eina_Bool _drop_box_button_new_cb(void *data, Evas_Object *obj, Elm_Selec
return EINA_TRUE;
}
void _enter_but_cb(void *data, Evas_Object *obj)
{
printf("Entered %s - drop it here and I will never print this line anymore.\n", __FUNCTION__);
}
static Eina_Bool _drop_but_icon_change_cb(void *data, Evas_Object *obj, Elm_Selection_Data *ev)
{
Evas_Object *win = data;
@ -935,6 +940,14 @@ static Eina_Bool _drop_but_icon_change_cb(void *data, Evas_Object *obj, Elm_Sele
return EINA_TRUE;
}
/* Callback used to test multi-callbacks feature */
static Eina_Bool _drop_but_cb_remove_cb(void *data, Evas_Object *obj, Elm_Selection_Data *ev)
{
printf("Second callback called - removing it\n");
elm_drop_target_del(obj, ELM_SEL_FORMAT_TARGETS, _enter_but_cb, NULL, NULL, NULL, NULL, NULL, _drop_but_cb_remove_cb, NULL);
return EINA_TRUE;
}
static Eina_Bool _drop_bg_change_cb(void *data EINA_UNUSED, Evas_Object *obj, Elm_Selection_Data *ev)
{
char *p = strchr(ev->data, '#');
@ -1012,6 +1025,7 @@ test_dnd_overlapping(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void
bt = elm_button_add(win);
elm_object_text_set(bt, "Drop into me to change my icon");
elm_drop_target_add(bt, ELM_SEL_FORMAT_TARGETS, NULL, NULL, NULL, NULL, NULL, NULL, _drop_but_icon_change_cb, win);
elm_drop_target_add(bt, ELM_SEL_FORMAT_TARGETS, _enter_but_cb, NULL, NULL, NULL, NULL, NULL, _drop_but_cb_remove_cb, NULL);
elm_object_part_content_set(bt, "icon", ic);
elm_box_pack_end(vert_box, bt);
evas_object_show(bt);
@ -1024,7 +1038,6 @@ test_dnd_overlapping(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void
bt = elm_button_add(win);
elm_object_text_set(bt, "No action on drop");
elm_object_part_content_set(bt, "icon", ic);
elm_object_disabled_set(bt, EINA_TRUE);
elm_box_pack_end(vert_box, bt);
evas_object_show(bt);
evas_object_show(ic);

View File

@ -49,6 +49,7 @@ typedef struct _Tmp_Info Tmp_Info;
typedef struct _Saved_Type Saved_Type;
typedef struct _Cnp_Escape Cnp_Escape;
typedef struct _Dropable Dropable;
typedef struct _Dropable_Cbs Dropable_Cbs;
static Eina_Bool doaccept = EINA_FALSE;
struct _Tmp_Info
@ -74,10 +75,9 @@ struct _Cnp_Escape
const char *value;
};
struct _Dropable
struct _Dropable_Cbs
{
Evas_Object *obj;
/* FIXME: Cache window */
EINA_INLIST;
Elm_Sel_Format types;
Elm_Drag_State entercb;
Elm_Drag_State leavecb;
@ -87,6 +87,13 @@ struct _Dropable
void *leavedata;
void *posdata;
void *dropdata;
};
struct _Dropable
{
Evas_Object *obj;
/* FIXME: Cache window */
Eina_Inlist *cbs_list; /* List of Dropable_Cbs * */
struct {
Evas_Coord x, y;
Eina_Bool in : 1;
@ -281,7 +288,12 @@ static Eina_Bool _x11_elm_drop_target_add (Evas_Object *obj, Elm_
Elm_Drag_State leavecb, void *leavedata,
Elm_Drag_Pos poscb, void *posdata,
Elm_Drop_Cb dropcb, void *dropdata);
static Eina_Bool _x11_elm_drop_target_del (Evas_Object *obj);
static Eina_Bool _x11_elm_drop_target_del (Evas_Object *obj, Elm_Sel_Format format,
Elm_Drag_State entercb, void *enterdata,
Elm_Drag_State leavecb, void *leavedata,
Elm_Drag_Pos poscb, void *posdata,
Elm_Drop_Cb dropcb, void *dropdata);
static void _all_drop_targets_cbs_del(void *data, Evas *e, Evas_Object *obj, void *info);
static Eina_Bool _x11_elm_selection_selection_has_owner (Evas_Object *obj __UNUSED__);
static X11_Cnp_Atom _x11_atoms[CNP_N_ATOMS] = {
@ -778,13 +790,16 @@ _x11_notify_handler_text(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify
}
if (dropable)
{
Dropable_Cbs *cbs;
ddata.x = savedtypes.x;
ddata.y = savedtypes.y;
ddata.format = ELM_SEL_FORMAT_TEXT;
ddata.data = data->data;
ddata.len = data->length;
ddata.action = sel->action;
dropable->dropcb(dropable->dropdata, dropable->obj, &ddata);
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->dropcb)
cbs->dropcb(cbs->dropdata, dropable->obj, &ddata);
goto end;
}
}
@ -931,6 +946,7 @@ _x11_vcard_receive(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
cnp_debug("vcard receive\n");
if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
{
Dropable_Cbs *cbs;
Elm_Selection_Data ddata;
cnp_debug("drag & drop\n");
@ -952,7 +968,9 @@ _x11_vcard_receive(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
ddata.data = data->data;
ddata.len = data->length;
ddata.action = sel->action;
dropable->dropcb(dropable->dropdata, dropable->obj, &ddata);
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->dropcb)
cbs->dropcb(cbs->dropdata, dropable->obj, &ddata);
ecore_x_dnd_send_finished();
}
else if (sel->datacb)
@ -1260,6 +1278,7 @@ static void
_x11_dnd_dropable_handle(Dropable *dropable, Evas_Coord x, Evas_Coord y, Eina_Bool have_obj, Elm_Xdnd_Action action)
{
Dropable *dropable_last = NULL;
Dropable_Cbs *cbs;
if (dropable->last.in)
dropable_last = _x11_dropable_geom_find
@ -1268,33 +1287,39 @@ _x11_dnd_dropable_handle(Dropable *dropable, Evas_Coord x, Evas_Coord y, Eina_Bo
if ((have_obj) && (dropable_last == dropable)) // same
{
cnp_debug("same obj dropable %p\n", dropable);
if (dropable->poscb)
dropable->poscb(dropable->posdata, dropable->obj, x, y, action);
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->poscb)
cbs->poscb(cbs->posdata, dropable->obj, x, y, action);
}
else if ((have_obj) && (!dropable_last)) // enter new obj
{
cnp_debug("enter %p\n", dropable->obj);
if (dropable->entercb)
dropable->entercb(dropable->enterdata, dropable->obj);
if (dropable->poscb)
dropable->poscb(dropable->posdata, dropable->obj, x, y, action);
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->entercb)
cbs->entercb(cbs->enterdata, dropable->obj);
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->poscb)
cbs->poscb(cbs->posdata, dropable->obj, x, y, action);
}
else if ((!have_obj) && (dropable_last)) // leave last obj
{
cnp_debug("leave %p\n", dropable_last->obj);
if (dropable->leavecb)
dropable->leavecb(dropable->leavedata, dropable->obj);
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->leavecb)
cbs->leavecb(cbs->leavedata, dropable->obj);
}
else if (have_obj) // leave last obj and enter new one
{
cnp_debug("enter %p\n", dropable->obj);
if (dropable->entercb)
dropable->entercb(dropable->enterdata, dropable->obj);
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->entercb)
cbs->entercb(cbs->enterdata, dropable->obj);
if (dropable_last)
{
dropable = dropable_last;
if (dropable->leavecb)
dropable->leavecb(dropable->leavedata, dropable->obj);
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->leavecb)
cbs->leavecb(cbs->leavedata, dropable->obj);
cnp_debug("leave %p\n", dropable->obj);
}
}
@ -1478,41 +1503,38 @@ found:
ddata.y = savedtypes.y;
ddata.action = act;
/* If it's markup that also supports images */
if ((dropable->types & ELM_SEL_FORMAT_MARKUP) &&
(dropable->types & ELM_SEL_FORMAT_IMAGE))
Dropable_Cbs *cbs;
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
{
int len;
ddata.format = ELM_SEL_FORMAT_MARKUP;
/* If it's markup that also supports images */
if ((cbs->types & ELM_SEL_FORMAT_MARKUP) &&
(cbs->types & ELM_SEL_FORMAT_IMAGE))
{
int len;
ddata.format = ELM_SEL_FORMAT_MARKUP;
len = strlen(tagstring) + strlen(savedtypes.imgfile);
entrytag = alloca(len + 1);
snprintf(entrytag, len + 1, tagstring, savedtypes.imgfile);
ddata.data = entrytag;
cnp_debug("Insert %s\n", (char *)ddata.data);
if (dropable->dropcb) dropable->dropcb(dropable->dropdata, dropable->obj, &ddata);
ecore_x_dnd_send_finished();
if (savedtypes.imgfile) free(savedtypes.imgfile);
savedtypes.imgfile = NULL;
return EINA_TRUE;
}
else if (dropable->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;
dropable->dropcb(dropable->dropdata, dropable->obj, &ddata);
ecore_x_dnd_send_finished();
ELM_SAFE_FREE(savedtypes.imgfile, free);
return EINA_TRUE;
}
else
{
cnp_debug("Item doesn't support images... passing\n");
return EINA_TRUE;
len = strlen(tagstring) + strlen(savedtypes.imgfile);
entrytag = alloca(len + 1);
snprintf(entrytag, len + 1, tagstring, savedtypes.imgfile);
ddata.data = entrytag;
cnp_debug("Insert %s\n", (char *)ddata.data);
if (cbs->dropcb) cbs->dropcb(cbs->dropdata, dropable->obj, &ddata);
}
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;
if (cbs->dropcb) cbs->dropcb(cbs->dropdata, dropable->obj, &ddata);
}
else
{
cnp_debug("Item doesn't support images... passing\n");
}
}
ecore_x_dnd_send_finished();
ELM_SAFE_FREE(savedtypes.imgfile, free);
return EINA_TRUE;
}
else if (savedtypes.textreq)
{
@ -1805,9 +1827,10 @@ _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
Elm_Drag_Pos poscb, void *posdata,
Elm_Drop_Cb dropcb, void *dropdata)
{
Dropable *dropable;
Dropable *dropable = NULL;
Dropable_Cbs *cbs = NULL;
Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
Eina_List *item, *l;
Eina_List *l;
Eina_Bool first = !drops;
Eina_Bool have_drops = EINA_FALSE;
@ -1824,45 +1847,36 @@ _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
break;
}
}
dropable = NULL; // In case of error, we don't want to free it
cbs = calloc(1, sizeof(*cbs));
if (!cbs) return EINA_FALSE;
cbs->entercb = entercb;
cbs->enterdata = enterdata;
cbs->leavecb = leavecb;
cbs->leavedata = leavedata;
cbs->poscb = poscb;
cbs->posdata = posdata;
cbs->dropcb = dropcb;
cbs->dropdata = dropdata;
cbs->types = format;
eo_do(obj, eo_base_data_get("__elm_dropable", (void **)&dropable));
if (dropable)
if (!dropable)
{
/* Update: Not a new one */
dropable->dropcb = dropcb;
dropable->dropdata = dropdata;
dropable->types = format;
return EINA_TRUE;
/* Create new drop */
dropable = calloc(1, sizeof(Dropable));
if (!dropable) goto error;
drops = eina_list_append(drops, dropable);
if (!drops) goto error;
dropable->obj = obj;
eo_do(obj, eo_base_data_set("__elm_dropable", dropable, NULL));
}
dropable->cbs_list = eina_inlist_append(dropable->cbs_list, EINA_INLIST_GET(cbs));
/* Create new drop */
dropable = calloc(1, sizeof(Dropable));
if (!dropable) return EINA_FALSE;
/* FIXME: Check for eina's deranged error method */
drops = eina_list_append(drops, dropable);
if (!drops/* || or other error */)
{
free(dropable);
return EINA_FALSE;
}
dropable->entercb = entercb;
dropable->enterdata = enterdata;
dropable->leavecb = leavecb;
dropable->leavedata = leavedata;
dropable->poscb = poscb;
dropable->posdata = posdata;
dropable->dropcb = dropcb;
dropable->dropdata = dropdata;
dropable->types = format;
dropable->obj = obj;
eo_do(obj, eo_base_data_set("__elm_dropable", dropable, NULL));
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
/* I love C and varargs */
(Evas_Object_Event_Cb)elm_drop_target_del,
obj);
_all_drop_targets_cbs_del, obj);
if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_TRUE);
/* TODO BUG: should handle dnd-aware per window, not just the first
@ -1870,7 +1884,6 @@ _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
/* If not the first: We're done */
if (!first) return EINA_TRUE;
cnp_debug("Adding drop target calls xwin=%#llx\n", (unsigned long long)xwin);
handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
_x11_dnd_enter, NULL);
@ -1881,10 +1894,18 @@ _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
_x11_dnd_drop, NULL);
return EINA_TRUE;
error:
free(cbs);
free(dropable);
return EINA_FALSE;
}
static Eina_Bool
_x11_elm_drop_target_del(Evas_Object *obj)
_x11_elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format,
Elm_Drag_State entercb, void *enterdata,
Elm_Drag_State leavecb, void *leavedata,
Elm_Drag_Pos poscb, void *posdata,
Elm_Drop_Cb dropcb, void *dropdata)
{
Dropable *dropable;
Eina_List *l;
@ -1896,16 +1917,34 @@ _x11_elm_drop_target_del(Evas_Object *obj)
eo_do(obj, eo_base_data_get("__elm_dropable", (void **)&dropable));
if (dropable)
{
drops = eina_list_remove(drops, dropable);
eo_do(obj, eo_base_data_del("__elm_dropable"));
free(dropable);
dropable = NULL;
Eina_Inlist *itr;
Dropable_Cbs *cbs_info;
/* Look for the callback in the list */
EINA_INLIST_FOREACH_SAFE(dropable->cbs_list, itr, cbs_info)
if (cbs_info->entercb == entercb && cbs_info->enterdata == enterdata &&
cbs_info->leavecb == leavecb && cbs_info->leavedata == leavedata &&
cbs_info->poscb == poscb && cbs_info->posdata == posdata &&
cbs_info->dropcb == dropcb && cbs_info->dropdata == dropdata &&
cbs_info->types == format)
{
dropable->cbs_list = eina_inlist_remove(dropable->cbs_list,
EINA_INLIST_GET(cbs_info));
free(cbs_info);
}
/* In case no more callbacks are listed for the object */
if (!dropable->cbs_list)
{
drops = eina_list_remove(drops, dropable);
eo_do(obj, eo_base_data_del("__elm_dropable"));
free(dropable);
dropable = NULL;
evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL,
_all_drop_targets_cbs_del);
}
}
else return EINA_FALSE;
evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
(Evas_Object_Event_Cb)elm_drop_target_del);
/* TODO BUG: we should handle dnd-aware per window, not just the last that reelased it */
/* If still drops there: All fine.. continue */
@ -1936,6 +1975,24 @@ _x11_elm_drop_target_del(Evas_Object *obj)
return EINA_TRUE;
}
static void
_all_drop_targets_cbs_del(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *info __UNUSED__)
{
Dropable *dropable = NULL;
eo_do(obj, eo_base_data_get("__elm_dropable", (void **)&dropable));
if (dropable)
{
Eina_Inlist *itr;
Dropable_Cbs *cbs;
EINA_INLIST_FOREACH_SAFE(dropable->cbs_list, itr, cbs)
{
elm_drop_target_del(obj, cbs->types,
cbs->entercb, cbs->enterdata, cbs->leavecb, cbs->leavedata,
cbs->poscb, cbs->posdata, cbs->dropcb, cbs->dropdata);
}
}
}
static void
_x11_drag_target_del(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *info __UNUSED__)
{
@ -2964,7 +3021,7 @@ _wl_elm_widget_window_get(Evas_Object *obj)
win = ecore_evas_wayland_window_get(ee);
}
if (win) return ecore_wl_window_id_get(win);
if (win) return win->id;
return 0;
}
@ -3399,12 +3456,17 @@ elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
}
EAPI Eina_Bool
elm_drop_target_del(Evas_Object *obj)
elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format,
Elm_Drag_State entercb, void *enterdata,
Elm_Drag_State leavecb, void *leavedata,
Elm_Drag_Pos poscb, void *posdata,
Elm_Drop_Cb dropcb, void *dropdata)
{
if (!_elm_cnp_init_count) _elm_cnp_init();
#ifdef HAVE_ELEMENTARY_X
if (_x11_elm_widget_xwin_get(obj))
return _x11_elm_drop_target_del(obj);
return _x11_elm_drop_target_del(obj, format, entercb, enterdata,
leavecb, leavedata, poscb, posdata, dropcb, dropdata);
#endif
#ifdef HAVE_ELEMENTARY_WAYLAND
return _wl_elm_drop_target_del(obj);
@ -3536,7 +3598,8 @@ elm_drop_item_container_del_internal(Evas_Object *obj, Eina_Bool full)
if (st)
{
elm_drop_target_del(obj);
// temp until st is stored inside data of obj.
_all_drop_targets_cbs_del(NULL, NULL, obj, NULL);
st->itemgetcb= NULL;
st->poscb = NULL;
st->dropcb = NULL;

View File

@ -308,13 +308,26 @@ EAPI Eina_Bool elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
* @brief Deletes the drop target status of an object
*
* @param obj The target object
* @param format The formats supported for dropping
* @param entercb The function to call when the object is entered with a drag
* @param enterdata The application data to pass to enterdata
* @param leavecb The function to call when the object is left with a drag
* @param leavedata The application data to pass to leavedata
* @param poscb The function to call when the object has a drag over it
* @param posdata The application data to pass to posdata
* @param dropcb The function to call when a drop has occurred
* @param dropdata The application data to pass to dropcb
* @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
*
* @ingroup CopyPaste
*
* @since 1.8
*/
EAPI Eina_Bool elm_drop_target_del(Evas_Object *obj);
EAPI Eina_Bool elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format,
Elm_Drag_State entercb, void *enterdata,
Elm_Drag_State leavecb, void *leavedata,
Elm_Drag_Pos poscb, void *posdata,
Elm_Drop_Cb dropcb, void *dropdata);
/**
* @brief Begins a drag given a source object

View File

@ -3411,7 +3411,11 @@ _password_set(Eo *obj, void *_pd, va_list *list)
{
sd->single_line = EINA_TRUE;
sd->line_wrap = ELM_WRAP_NONE;
elm_drop_target_del(obj);
elm_drop_target_del(obj, ELM_SEL_FORMAT_MARKUP,
NULL, NULL,
NULL, NULL,
NULL, NULL,
_drag_drop_cb, NULL);
_entry_selection_callbacks_unregister(obj);
}
else
@ -3683,7 +3687,11 @@ _editable_set(Eo *obj, void *_pd, va_list *list)
_drag_drop_cb, NULL);
else
#endif
elm_drop_target_del(obj);
elm_drop_target_del(obj, ELM_SEL_FORMAT_MARKUP,
NULL, NULL,
NULL, NULL,
NULL, NULL,
_drag_drop_cb, NULL);
}
EAPI Eina_Bool

View File

@ -1493,7 +1493,12 @@ _elm_image_smart_editable_set(Eo *obj, void *_pd, va_list *list)
NULL, NULL,
_elm_image_drag_n_drop_cb, parent);
else
elm_drop_target_del(obj);
elm_drop_target_del
(obj, ELM_SEL_FORMAT_IMAGE,
NULL, NULL,
NULL, NULL,
NULL, NULL,
_elm_image_drag_n_drop_cb, parent);
}
EAPI Eina_Bool

View File

@ -1137,7 +1137,11 @@ _editable_set(Eo *obj, void *_pd, va_list *list)
NULL, NULL,
_elm_thumb_dnd_cb, obj);
else
elm_drop_target_del(obj);
elm_drop_target_del(obj, ELM_SEL_FORMAT_IMAGE,
NULL, NULL,
NULL, NULL,
NULL, NULL,
_elm_thumb_dnd_cb, obj);
}
EAPI Eina_Bool