diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h index c010581c74..1020d9e6d1 100644 --- a/src/lib/elementary/Efl_Ui.h +++ b/src/lib/elementary/Efl_Ui.h @@ -119,8 +119,6 @@ extern EAPI Eina_Error EFL_UI_THEME_APPLY_ERROR_NONE; // EO types. Defined for legacy-only builds as legacy uses typedef of EO types. #include "efl_ui.eot.h" -#include "efl_ui_selection_types.eot.h" -#include "efl_ui_dnd_types.eot.h" //define focus manager earlier since focus object and manager is circular typedef Eo Efl_Ui_Focus_Manager; @@ -323,7 +321,6 @@ typedef Eo Efl_Ui_Spotlight_Indicator; # include # include # include -# include # include # include diff --git a/src/lib/elementary/efl_ui_dnd.c b/src/lib/elementary/efl_ui_dnd.c index df79eb9762..7d9ef2e1d1 100644 --- a/src/lib/elementary/efl_ui_dnd.c +++ b/src/lib/elementary/efl_ui_dnd.c @@ -12,838 +12,137 @@ #include #include "elm_priv.h" -typedef struct _Efl_Ui_Dnd_Container_Data Efl_Ui_Dnd_Container_Data; -struct _Efl_Ui_Dnd_Container_Data -{ - unsigned int drag_delay_time; -}; +typedef struct { + Ecore_Evas *ee; + Eina_Bool registered; +} Efl_Ui_Dnd_Data; -extern int _wl_default_seat_id_get(Evas_Object *obj); -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -#endif - -Eo* -_efl_ui_selection_manager_get(Eo *obj) -{ - if (!efl_isa(obj, EFL_UI_WIDGET_CLASS)) return NULL; - Eo *app = efl_app_main_get(); - Eo *sel_man = efl_key_data_get(app, "__selection_manager"); - if (!sel_man) - { - sel_man = efl_add(EFL_UI_SELECTION_MANAGER_CLASS, app); - efl_key_data_set(app, "__selection_manager", sel_man); - } - return sel_man; -} - -void -_efl_ui_dnd_shutdown(void) -{ - Eo *app = efl_app_main_get(); - Eo *sel_man = efl_key_data_get(app, "__selection_manager"); - - efl_del(sel_man); -} - -EOLIAN static void -_efl_ui_dnd_drag_start(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, Eina_Slice data, - Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_start(sel_man, obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - seat); -} - -EOLIAN static void -_efl_ui_dnd_drag_cancel(Eo *obj, void *pd EINA_UNUSED, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_cancel(sel_man, obj, seat); -} - -EOLIAN static void -_efl_ui_dnd_drag_action_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Action action, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_action_set(sel_man, obj, action, seat); -} - - -EOLIAN static void -_efl_ui_dnd_drop_target_add(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drop_target_add(sel_man, obj, format, seat); -} - -EOLIAN static void -_efl_ui_dnd_drop_target_del(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drop_target_del(sel_man, obj, format, seat); -} - -EOLIAN static double -_efl_ui_dnd_container_drag_delay_time_get(const Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd) -{ - return pd->drag_delay_time; -} - -EOLIAN static void -_efl_ui_dnd_container_drag_delay_time_set(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd, double drag_delay_time) -{ - pd->drag_delay_time = drag_delay_time; -} - -EOLIAN static void -_efl_ui_dnd_container_drag_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd, - void *data_func_data, Efl_Dnd_Drag_Data_Get data_func, Eina_Free_Cb data_func_free_cb, - void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - void *icon_list_func_data, Efl_Dnd_Drag_Icon_List_Create icon_list_func, Eina_Free_Cb icon_list_func_free_cb, - unsigned int seat) -{ - double drag_delay_time = pd->drag_delay_time; - double anim_time = elm_config_drag_anim_duration_get(); - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drag_item_add(sel_man, obj, drag_delay_time, anim_time, - data_func_data, data_func, data_func_free_cb, - item_func_data, item_func, item_func_free_cb, - icon_func_data, icon_func, icon_func_free_cb, - icon_list_func_data, icon_list_func, icon_list_func_free_cb, - seat); -} +typedef struct { + Eo *win; + Efl_Ui_Dnd *obj; +} Efl_Ui_Drag_Start; static void -_efl_ui_dnd_container_drag_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat) +_ecore_evas_drag_terminated(Ecore_Evas *ee EINA_UNUSED, void *data, Eina_Bool accepted) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seat); + Efl_Ui_Drag_Start *start = data; + efl_event_callback_call(start->obj, EFL_UI_DND_EVENT_DRAG_FINISHED, &accepted); + efl_del(start->win); + free(start); } -EOLIAN static void -_efl_ui_dnd_container_drop_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, - Efl_Ui_Selection_Format format, - void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb, - unsigned int seat) + +EOLIAN static Efl_Content* +_efl_ui_dnd_drag_start(Eo *obj, Efl_Ui_Dnd_Data *pd, Eina_Content *content, const char* action, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drop_item_add(sel_man, obj, format, item_func_data, item_func, item_func_free_cb, seat); + Eo *drag_win; + Efl_Ui_Drag_Start *start; + Ecore_Evas *drag_ee; + EINA_SAFETY_ON_NULL_RETURN_VAL(pd->ee, NULL); + + start = calloc(1, sizeof(Efl_Ui_Drag_Start)); + start->obj = obj; + start->win = drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); + elm_win_alpha_set(drag_win, EINA_TRUE); + elm_win_override_set(drag_win, EINA_TRUE); + drag_ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_win)); + + ecore_evas_drag_start(pd->ee, seat, content, drag_ee, action, _ecore_evas_drag_terminated, start); + + evas_object_show(drag_win); + + efl_event_callback_call(obj, EFL_UI_DND_EVENT_DRAG_START, NULL); + + return drag_win; } EOLIAN static void -_efl_ui_dnd_container_drop_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat) +_efl_ui_dnd_drag_cancel(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seat); + ecore_evas_drag_cancel(pd->ee, seat); } - -/////////// -typedef struct _Dnd_Icon_Create Dnd_Icon_Create; -typedef struct _Dnd_Drag_Pos Dnd_Drag_Pos; -typedef struct _Dnd_Drag_Accept Dnd_Drag_Accept; -typedef struct _Dnd_Drag_Done Dnd_Drag_Done; -typedef struct _Dnd_Drag_State Dnd_Drag_State; -typedef struct _Dnd_Drop Dnd_Drop; -typedef struct _Dnd_Cont_Drag_Pos Dnd_Cont_Drag_Pos; -typedef struct _Dnd_Cont_Drop Dnd_Cont_Drop; -typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info; - -struct _Dnd_Icon_Create +EOLIAN static Eina_Future* +_efl_ui_dnd_drop_data_get(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat, Eina_Iterator *acceptable_types) { - void *icon_data; - Elm_Drag_Icon_Create_Cb icon_cb; -}; - -struct _Dnd_Drag_Pos -{ - void *pos_data; - Elm_Drag_Pos pos_cb; -}; - -struct _Dnd_Drag_Accept -{ - void *accept_data; - Elm_Drag_Accept accept_cb; -}; - -struct _Dnd_Drag_Done -{ - void *done_data; - Elm_Drag_State done_cb; - - //for deleting - Dnd_Drag_Pos *pos; - Dnd_Drag_Accept *accept; -}; - -struct _Dnd_Drag_State -{ - void *state_data; - Elm_Drag_State state_cb; -}; - -struct _Dnd_Drop -{ - Efl_Object *obj; - Elm_Sel_Format format; - void *drop_data; - Elm_Drop_Cb drop_cb; - - //for deleting - Dnd_Drag_State *enter; - Dnd_Drag_State *leave; - Dnd_Drag_Pos *pos; -}; - -struct _Dnd_Cont_Drag_Pos -{ - void *pos_data; - Elm_Drag_Item_Container_Pos pos_cb; - Elm_Xy_Item_Get_Cb item_get_cb; -}; - -struct _Dnd_Cont_Drop -{ - Efl_Object *obj; - Elm_Sel_Format format; - void *drop_data; - Elm_Drop_Item_Container_Cb drop_cb; - Elm_Xy_Item_Get_Cb item_get_cb; - - //for deleting - Dnd_Drag_State *enter; - Dnd_Drag_State *leave; - Dnd_Cont_Drag_Pos *pos; -}; - -struct _Item_Container_Drag_Info -{ - Elm_Drag_User_Info user_info; - Elm_Object_Item *it; - Elm_Item_Container_Data_Get_Cb data_get_cb; - Elm_Xy_Item_Get_Cb item_get_cb; -}; - -static Efl_Object * -_dnd_icon_create_cb(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret) -{ - Dnd_Icon_Create *ic = data; - Efl_Object *ret = ic->icon_cb(ic->icon_data, win, &pos_ret->x, &pos_ret->y); - - free(ic); - return ret; + return ecore_evas_selection_get(pd->ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, acceptable_types); } -static void -_dnd_drag_pos_cb(void *data, const Efl_Event *event) +EOLIAN static Efl_Object * +_efl_ui_dnd_efl_object_constructor(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Drag_Pos *pos = data; - Efl_Dnd_Drag_Pos *ddata = event->info; + if (!efl_constructor(efl_super(obj, EFL_UI_DND_MIXIN))) + return NULL; - if (pos->pos_cb) - pos->pos_cb(pos->pos_data, event->object, ddata->pos.x, ddata->pos.y, - (Elm_Xdnd_Action)ddata->action); -} - -static void -_dnd_drag_accept_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_Accept *accept = data; - - if (accept->accept_cb) - accept->accept_cb(accept->accept_data, event->object, *(Eina_Bool *)event->info); -} - -static void -_dnd_drag_done_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_Done *done = data; - - if (done->done_cb) - done->done_cb(done->done_data, event->object); - - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, done->pos); - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_ACCEPT, - _dnd_drag_accept_cb, done->accept); - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_DONE, - _dnd_drag_done_cb, done); - free(done->pos); - free(done->accept); - free(done); -} - -static void -_dnd_drag_enter_leave_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_State *state = data; - - if (state->state_cb) - state->state_cb(state->state_data, event->object); -} - -static void -_dnd_drop_cb(void *data, const Efl_Event *event) -{ - Dnd_Drop *drop = data; - Efl_Ui_Selection_Data *org_ddata = event->info; - Elm_Selection_Data ddata; - - ddata.x = org_ddata->pos.x; - ddata.y = org_ddata->pos.y; - ddata.format = (Elm_Sel_Format)org_ddata->format; - ddata.action = (Elm_Xdnd_Action)org_ddata->action; - ddata.data = calloc(1, org_ddata->content.len); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len); - ddata.len = org_ddata->content.len; - if (drop->drop_cb) - drop->drop_cb(drop->drop_data, event->object, &ddata); - free(ddata.data); -} - -EAPI Eina_Bool -elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, - Elm_Xdnd_Action action, - Elm_Drag_Icon_Create_Cb icon_create_cb, void *icon_create_data, - Elm_Drag_Pos drag_pos_cb, void *drag_pos_data, - Elm_Drag_Accept drag_accept_cb, void *drag_accept_data, - Elm_Drag_State drag_done_cb, void *drag_done_data) -{ - if (!data) return EINA_FALSE; - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Eina_Slice sl; - Dnd_Drag_Pos *pos = calloc(1, sizeof(Dnd_Drag_Pos)); - Dnd_Drag_Accept *accept = calloc(1, sizeof(Dnd_Drag_Accept)); - Dnd_Drag_Done *done = calloc(1, sizeof(Dnd_Drag_Done)); - Dnd_Icon_Create *ic = calloc(1, sizeof(Dnd_Icon_Create)); - if (!pos || !accept || !done || !ic) goto on_error; - - pos->pos_data = drag_pos_data; - pos->pos_cb = drag_pos_cb; - - accept->accept_data = drag_accept_data; - accept->accept_cb = drag_accept_cb; - - done->done_data = drag_done_data; - done->done_cb = drag_done_cb; - done->pos = pos; - done->accept = accept; - - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, _dnd_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, _dnd_drag_accept_cb, accept); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DONE, _dnd_drag_done_cb, done); - sl.mem = data; - sl.len = strlen(data); -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - ic->icon_data = icon_create_data; - ic->icon_cb = icon_create_cb; - efl_ui_selection_manager_drag_start(sel_man, obj, (Efl_Ui_Selection_Format)format, sl, - (Efl_Ui_Selection_Action)action, - ic, _dnd_icon_create_cb, NULL, seatid); - - return EINA_TRUE; - -on_error: - if (pos) free(pos); - if (accept) free(accept); - if (done) free(done); - if (ic) free(ic); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - efl_ui_selection_manager_drag_action_set(sel_man, obj, (Efl_Ui_Selection_Action)action, seatid); - - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_drag_cancel(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - efl_ui_selection_manager_drag_cancel(sel_man, obj, seatid); - - return EINA_TRUE; -} - -static void -_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Eina_List *drop_list; - Dnd_Drop *drop; - - drop_list = efl_key_data_get(obj, "__drop_list"); - EINA_LIST_FREE(drop_list, drop) - { - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - free(drop); - } - efl_key_data_set(obj, "__drop_list", NULL); -} - -EAPI Eina_Bool -elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Pos pos_cb, void *pos_data, - Elm_Drop_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Dnd_Drag_State *enter, *leave; - Dnd_Drag_Pos *pos; - Dnd_Drop *drop; - Eina_List *drop_list; - - enter = calloc(1, sizeof(Dnd_Drag_State)); - leave = calloc(1, sizeof(Dnd_Drag_State)); - pos = calloc(1, sizeof(Dnd_Drag_Pos)); - drop = calloc(1, sizeof(Dnd_Drop)); - if (!enter || !leave || !pos || !drop) goto on_error; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - enter->state_cb = enter_cb; - enter->state_data = enter_data; - leave->state_cb = leave_cb; - leave->state_data = leave_data; - pos->pos_cb = pos_cb; - pos->pos_data = pos_data; - drop->obj = obj; - drop->format = format; - drop->drop_cb = drop_cb; - drop->drop_data = drop_data; - drop->enter = enter; - drop->leave = leave; - drop->pos = pos; - - drop_list = efl_key_data_get(obj, "__drop_list"); - drop_list = eina_list_append(drop_list, drop); - efl_key_data_set(obj, "__drop_list", drop_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, - _drop_obj_del_cb, NULL); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, enter); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, leave); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - efl_ui_selection_manager_drop_target_add(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid); - - return EINA_TRUE; - -on_error: - if (enter) free(enter); - if (leave) free(leave); - if (pos) free(pos); - if (drop) free(drop); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Pos pos_cb, void *pos_data, - Elm_Drop_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - //Eina_List *l, *l2; - Eina_List *drop_list; - Dnd_Drop *drop; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - drop_list = efl_key_data_get(obj, "__drop_list"); - drop = eina_list_data_get(drop_list); - if (drop && - (drop->format == format) && - (drop->enter->state_cb == enter_cb) && - (drop->enter->state_data == enter_data) && - (drop->leave->state_cb == leave_cb) && - (drop->leave->state_data == leave_data) && - (drop->pos->pos_cb == pos_cb) && - (drop->pos->pos_data == pos_data) && - (drop->drop_cb == drop_cb) && - (drop->drop_data == drop_data)) - { - drop_list = eina_list_remove(drop_list, drop); - efl_key_data_set(obj, "__drop_list", drop_list); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _drop_obj_del_cb); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - free(drop); - } - efl_ui_selection_manager_drop_target_del(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid); - - return EINA_TRUE; -} - -static Efl_Object * -_dnd_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret) -{ - Elm_Xy_Item_Get_Cb item_get_cb = data; - Evas_Coord x, y; - Efl_Object *obj = NULL; - - x = y = 0; - if (item_get_cb) - obj = item_get_cb(item, pos.x, pos.y, &x, &y); - if (pos_ret) - { - pos_ret->x = x; - pos_ret->y = y; - } + pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); return obj; } -static void -_dnd_cont_drag_pos_cb(void *data, const Efl_Event *event) +EOLIAN static void +_efl_ui_dnd_efl_object_invalidate(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Cont_Drag_Pos *pos = data; - Efl_Dnd_Drag_Pos *ddata = event->info; - Evas_Coord xret = 0, yret = 0; - - if (pos->item_get_cb) + if (pd->registered) { - Evas_Coord x, y; - evas_object_geometry_get(event->object, &x, &y, NULL, NULL); - pos->item_get_cb(event->object, ddata->pos.x + x, ddata->pos.y + y, - &xret, &yret); + _drop_event_unregister(obj); } - if (pos->pos_cb) - pos->pos_cb(pos->pos_data, event->object, ddata->item, ddata->pos.x, ddata->pos.y, - xret, yret, (Elm_Xdnd_Action)ddata->action); + efl_invalidate(efl_super(obj, EFL_UI_DND_MIXIN)); + } -static void -_dnd_cont_drop_cb(void *data, const Efl_Event *event) +#define IS_DROP_EVENT(D) ( \ +(D == EFL_UI_DND_EVENT_DROP_POS) || \ +(D == EFL_UI_DND_EVENT_DROP_DROP) || \ +(D == EFL_UI_DND_EVENT_DROP_LEAVE) || \ +(D == EFL_UI_DND_EVENT_DROP_ENTER) \ +) + +EOLIAN static Efl_Object* +_efl_ui_dnd_efl_object_finalize(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Cont_Drop *drop = data; - Efl_Ui_Selection_Data *org_ddata = event->info; - Elm_Selection_Data ddata; - Evas_Coord xret = 0, yret = 0; + if (pd->registered) + _drop_event_register(obj); - ddata.x = org_ddata->pos.x; - ddata.y = org_ddata->pos.y; - ddata.format = (Elm_Sel_Format)org_ddata->format; - ddata.action = (Elm_Xdnd_Action)org_ddata->action; - ddata.data = calloc(1, org_ddata->content.len); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len); - ddata.len = org_ddata->content.len; + return efl_finalize(efl_super(obj, EFL_UI_DND_MIXIN)); +} - if (drop->item_get_cb) + +EOLIAN static Eina_Bool +_efl_ui_dnd_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd, + const Efl_Event_Description *desc, + Efl_Callback_Priority priority, + Efl_Event_Cb func, + const void *user_data) +{ + if (IS_DROP_EVENT(desc) && !pd->registered) + { + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _drop_event_register(obj); + } + + return efl_event_callback_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), desc, priority, func, user_data); +} + +EOLIAN static Eina_Bool +_efl_ui_dnd_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd, + const Efl_Callback_Array_Item *array, + Efl_Callback_Priority priority, + const void *user_data) +{ + for (int i = 0; array[i].desc; ++i) { - Evas_Coord x, y; - evas_object_geometry_get(event->object, &x, &y, NULL, NULL); - drop->item_get_cb(event->object, ddata.x + x, ddata.y + y, - &xret, &yret); - } - - if (drop->drop_cb) - drop->drop_cb(drop->drop_data, event->object, org_ddata->item, - &ddata, xret, yret); - free(ddata.data); -} - -static void -_cont_drop_free_data(Evas_Object *obj) -{ - Eina_List *cont_drop_list; - Dnd_Cont_Drop *drop; - - cont_drop_list = efl_key_data_get(obj, "__cont_drop_item"); - drop = eina_list_data_get(cont_drop_list); - if (drop) - { - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_cont_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_cont_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - cont_drop_list = eina_list_remove(cont_drop_list, drop); - efl_key_data_set(obj, "__cont_drop_item", cont_drop_list); - free(drop); - } -} - -static void -_cont_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - _cont_drop_free_data(obj); -} - -EAPI Eina_Bool -elm_drop_item_container_add(Evas_Object *obj, - Elm_Sel_Format format, - Elm_Xy_Item_Get_Cb item_get_cb, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Item_Container_Pos pos_cb, void *pos_data, - Elm_Drop_Item_Container_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Dnd_Drag_State *enter = NULL, *leave = NULL; - Dnd_Cont_Drag_Pos *pos = NULL; - Dnd_Cont_Drop *drop = NULL; - Eina_List *cont_drop_list; - - enter = calloc(1, sizeof(Dnd_Drag_State)); - leave = calloc(1, sizeof(Dnd_Drag_State)); - pos = calloc(1, sizeof(Dnd_Cont_Drag_Pos)); - drop = calloc(1, sizeof(Dnd_Cont_Drop)); - if (!enter || !leave || !pos || !drop) goto on_error; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - enter->state_cb = enter_cb; - enter->state_data = enter_data; - leave->state_cb = leave_cb; - leave->state_data = leave_data; - pos->pos_cb = pos_cb; - pos->pos_data = pos_data; - pos->item_get_cb = item_get_cb; - drop->obj = obj; - drop->format = format; - drop->drop_cb = drop_cb; - drop->drop_data = drop_data; - drop->enter = enter; - drop->leave = leave; - drop->pos = pos; - - cont_drop_list = efl_key_data_get(obj, "__cont_drop_item"); - cont_drop_list = eina_list_append(cont_drop_list, drop); - efl_key_data_set(obj, "__cont_drop_item", cont_drop_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, - _cont_drop_obj_del_cb, NULL); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, enter); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, leave); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_cont_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_cont_drop_cb, drop); - efl_ui_selection_manager_container_drop_item_add(sel_man, obj, (Efl_Ui_Selection_Format)format, - item_get_cb, _dnd_item_func, NULL, - seatid); - - return EINA_TRUE; - -on_error: - if (enter) free(enter); - if (leave) free(leave); - if (pos) free(pos); - if (drop) free(drop); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drop_item_container_del(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - _cont_drop_free_data(obj); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drop_obj_del_cb); - efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seatid); - - return EINA_TRUE; -} - -static void -_cont_drag_data_func(void *data, Efl_Object *obj, Efl_Ui_Selection_Format *format, - Eina_Rw_Slice *drag_data, Efl_Ui_Selection_Action *action) -{ - Item_Container_Drag_Info *di; - - di = data; - if (!di) return; - di->data_get_cb(obj, di->it, &di->user_info); - if (format) *format = (Efl_Ui_Selection_Format)di->user_info.format; - if (drag_data) - { - if (di->user_info.data) + if (IS_DROP_EVENT(array[i].desc) && !pd->registered) { - drag_data->mem = (void *)di->user_info.data; - drag_data->len = strlen(di->user_info.data); + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _drop_event_register(obj); } } - if (action) *action = (Efl_Ui_Selection_Action)di->user_info.action; + return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), array, priority, user_data); } -static Eina_List * -_cont_drag_icon_list_create(void *data, Efl_Object *obj EINA_UNUSED) -{ - Item_Container_Drag_Info *di; - - di = data; - return di->user_info.icons; -} - -static Efl_Object * -_cont_drag_icon_create(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret) -{ - Item_Container_Drag_Info *di; - Elm_Object_Item *it = NULL; - - di = data; - if (!di) return NULL; - if (!di->user_info.createicon) return NULL; - it = di->user_info.createicon(di->user_info.createdata, win, &pos_ret->x, &pos_ret->y); - di->it = it; - return it; -} - -static Efl_Object * -_cont_drag_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret) -{ - Item_Container_Drag_Info *di = data; - Evas_Coord x, y; - Efl_Object *obj = NULL; - - x = y = 0; - if (di->item_get_cb) - obj = di->item_get_cb(item, pos.x, pos.y, &x, &y); - if (pos_ret) - { - pos_ret->x = x; - pos_ret->y = y; - } - di->it = obj; - - return obj; -} - -static void -_cont_drag_free_data(Evas_Object *obj) -{ - Eina_List *di_list; - Item_Container_Drag_Info *di; - - di_list = efl_key_data_get(obj, "__cont_drag_item"); - di = eina_list_data_get(di_list); - di_list = eina_list_remove(di_list, di); - efl_key_data_set(obj, "__cont_drag_item", di_list); - free(di); -} - -static void -_cont_drag_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) -{ - _cont_drag_free_data(obj); -} - -EAPI Eina_Bool -elm_drag_item_container_add(Evas_Object *obj, double anim_tm, double tm_to_drag, - Elm_Xy_Item_Get_Cb item_get_cb, Elm_Item_Container_Data_Get_Cb data_get_cb) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Eina_List *di_list; - Item_Container_Drag_Info *di; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - di = calloc(1, sizeof(Item_Container_Drag_Info)); - if (!di) return EINA_FALSE; - di->data_get_cb = data_get_cb; - di->item_get_cb = item_get_cb; - di_list = efl_key_data_get(obj, "__cont_drag_item"); - di_list = eina_list_append(di_list, di); - efl_key_data_set(obj, "__cont_drag_item", di_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb, NULL); - efl_ui_selection_manager_container_drag_item_add(sel_man, obj, tm_to_drag, anim_tm, - di, _cont_drag_data_func, NULL, - di, _cont_drag_item_func, NULL, - di, _cont_drag_icon_create, NULL, - di, _cont_drag_icon_list_create, NULL, - seatid); - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_drag_item_container_del(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - _cont_drag_free_data(obj); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb); - efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seatid); - - return EINA_TRUE; -} +#define EFL_UI_DND_EXTRA_OPS \ + EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_dnd_efl_object_event_callback_priority_add), \ + EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_dnd_efl_object_event_callback_array_priority_add), \ #include "efl_ui_dnd.eo.c" -#include "efl_ui_dnd_container.eo.c" diff --git a/src/lib/elementary/efl_ui_dnd.eo b/src/lib/elementary/efl_ui_dnd.eo index 08f668856b..7fe2e8103c 100644 --- a/src/lib/elementary/efl_ui_dnd.eo +++ b/src/lib/elementary/efl_ui_dnd.eo @@ -1,29 +1,31 @@ -import efl_ui_dnd_types; +import eina_types; -mixin @beta Efl.Ui.Dnd { - data: null; +struct @beta Efl.Ui.Dnd_Event { + [[Event struct that contains information about what is avaiable at which position, in which seat]] + position : Eina.Position2D; [[The position of the Drop event]] + seat : uint; [[In which seat it is happening]] + available_types : accessor; [[which types are avaiable, you should use one of these for a call to @Efl.Ui.Dnd.drop_data_get ]] +} + +struct @beta Efl.Ui.Dnd_Drop_Event { + dnd : Efl.Ui.Dnd_Event; [[The overall information]] + action : string; [[The action the client should take]] +} + +mixin @beta Efl.Ui.Dnd requires Efl.Object { methods { drag_start { - [[Start a drag and drop process at the drag side. - During dragging, there are three events emitted as belows: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE + [[Start a drag from this client. + + @[Efl.Ui.Dnd.drag,start] will be emitted each time a successfull drag will be started. + @[Efl.Ui.Dnd.drag,finished] will be emitted every time a drag is finished. ]] params { - @in format: Efl.Ui.Selection_Format; [[The data format]] - @in data: Eina.Slice; [[The drag data]] - @in action: Efl.Ui.Selection_Action; [[Action when data is transferred]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_action_set { - [[Set the action for the drag]] - params { - @in action: Efl.Ui.Selection_Action; [[Drag action]] + content : Eina.Content @by_ref; [[The content you want to provide via dnd]] + @in action: string; [[Action when data is transferred]] @in seat: uint; [[Specified seat for multiple seats case.]] } + return : Efl.Content; [[A UI element where you can just set your visual representation into]] } drag_cancel { [[Cancel the on-going drag]] @@ -31,33 +33,26 @@ mixin @beta Efl.Ui.Dnd { @in seat: uint; [[Specified seat for multiple seats case.]] } } - drop_target_add { - [[Make the current object as drop target. - There are four events emitted: - - EFL_UI_DND_EVENT_DRAG_ENTER - - EFL_UI_DND_EVENT_DRAG_LEAVE - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_DROP.]] + drop_data_get { + [[Get the data from the object that has selection]] params { - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_target_del { - [[Delete the dropable status from object]] - params { - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] + seat : uint; [[Specified seat for multiple seats case.]] + acceptable_types : iterator; [[The types that are acceptable for you]] } + return : future @move; [[fullfilled when the content is transmitted, and ready to use]] } } events { - /* FIXME: This is not very future-proof. Better return a struct. */ - drag,accept: ptr(bool); [[accept drag data]] - drag,done: void; [[drag is done (mouse up)]] - drag,enter: void; [[called when the drag object enters this object]] - drag,leave: void; [[called when the drag object leaves this object]] - drag,pos: Efl.Dnd.Drag_Pos; [[called when the drag object changes drag position]] - drag,drop: Efl.Ui.Selection_Data; [[called when the drag object dropped on this object]] + drop,enter : Efl.Ui.Dnd_Event; + drop,leave : Efl.Ui.Dnd_Event; + drop,pos : Efl.Ui.Dnd_Event; + drop,drop : Efl.Ui.Dnd_Drop_Event; + drag,start : void; + drag,finished : bool; + } + implements { + Efl.Object.constructor; + Efl.Object.invalidate; + Efl.Object.finalize; } } diff --git a/src/lib/elementary/efl_ui_dnd_container.eo b/src/lib/elementary/efl_ui_dnd_container.eo deleted file mode 100644 index 0cc1f3f945..0000000000 --- a/src/lib/elementary/efl_ui_dnd_container.eo +++ /dev/null @@ -1,46 +0,0 @@ -import efl_ui_dnd_types; - -mixin @beta Efl.Ui.Dnd_Container { - methods { - @property drag_delay_time { - [[The time since mouse down happens to drag starts.]] - set { - } - get { - } - values { - time: double; [[The drag delay time]] - } - } - drag_item_add { - [[This registers a drag for items in a container. Many items can be - dragged at a time. During dragging, there are three events emitted: - EFL_DND_EVENT_DRAG_POS, EFL_DND_EVENT_DRAG_ACCEPT, EFL_DND_EVENT_DRAG_DONE.]] - params { - @in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]] - @in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]] - @in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations CHECKING ]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_item_del { - [[Remove drag function of items in the container object.]] - params { - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_item_add { - params { - @in format: Efl.Ui.Selection_Format; [[Accepted data formats]] - @in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_item_del { - params { - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - } -} diff --git a/src/lib/elementary/efl_ui_dnd_types.eot b/src/lib/elementary/efl_ui_dnd_types.eot deleted file mode 100644 index ace1c8de7b..0000000000 --- a/src/lib/elementary/efl_ui_dnd_types.eot +++ /dev/null @@ -1,60 +0,0 @@ -import efl_ui_selection_types; - -function @beta Efl.Dnd.Drag_Icon_Create { - [[Function pointer for creating icon at the drag side.]] - params { - @in win: Efl.Canvas.Object; [[The window to create the objects relative to]] - @in drag_obj: Efl.Canvas.Object; [[The drag object]] - @out off: Eina.Position2D; [[Offset from the icon position to the cursor]] - } - return: Efl.Canvas.Object; [[The drag icon object]] -}; - -function @beta Efl.Dnd.Drag_Data_Get { - [[Function pointer for getting data and format at the drag side.]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - @out format: Efl.Ui.Selection_Format; [[Data format]] - @out drag_data: Eina.Rw_Slice; [[Data]] - @out action: Efl.Ui.Selection_Action; [[The drag action]] - } -}; - -function @beta Efl.Dnd.Item_Get { - [[Function pointer to find out which item is under position (x, y)]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - @in pos: Eina.Position2D; [[The coordinates to get item]] - @out posret: Eina.Position2D; [[position relative to item (left (-1), middle (0), right (1)]] - } - return: Efl.Object; [[Object under x,y coordinates or NULL if not found]] -}; - -function @beta Efl.Dnd.Drag_Icon_List_Create { - [[Function pointer to create list of icons at the drag side. - These icons are used for animation on combining selection icons - to one icon.]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - } - return: list; -}; - -struct @beta Efl.Dnd.Drag_Accept { - accepted: bool; -} - -struct @beta Efl.Dnd.Drag_Pos { - [[Dragging position information.]] - pos: Eina.Position2D; [[Evas Coordinate]] - action: Efl.Ui.Selection_Action; [[The drag action]] - format: Efl.Ui.Selection_Format; [[The drag format]] - item: Efl.Canvas.Object; [[The item object. It is only available for container object.]] -} - -struct @beta Efl.Dnd.Drag_Item_Container_Drop { - [[Drop information for a drag&drop operation.]] - item: Efl.Canvas.Object; [[The item object]] - data: Efl.Ui.Selection_Data; [[The selection data]] - pos: Eina.Position2D; [[Position relative to item (left (-1), middle (0), right (1)]] -} diff --git a/src/lib/elementary/efl_ui_selection.c b/src/lib/elementary/efl_ui_selection.c index 675eb0cf99..d67d1f3fef 100644 --- a/src/lib/elementary/efl_ui_selection.c +++ b/src/lib/elementary/efl_ui_selection.c @@ -9,278 +9,115 @@ #define MY_CLASS EFL_UI_SELECTION_MIXIN #define MY_CLASS_NAME "Efl.Ui.Selection" -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -#endif +typedef struct { + Ecore_Evas *ee; + Eina_Bool registered : 1; +} Efl_Ui_Selection_Data; -EOLIAN static void -_efl_ui_selection_selection_get(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, unsigned int seat) +static inline Ecore_Evas_Selection_Buffer +_ee_buffer_get(Efl_Ui_Cnp_Buffer buffer) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_selection_get(sel_man, obj, type, format, - data_func_data, data_func, - data_func_free_cb, seat); + if (buffer == EFL_UI_CNP_BUFFER_SELECTION) + return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER; + else + return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER; } -EOLIAN static Eina_Future * -_efl_ui_selection_selection_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data, unsigned int seat) +EOLIAN static Eina_Future* +_efl_ui_selection_selection_get(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat, Eina_Iterator *acceptable_types) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - return efl_ui_selection_manager_selection_set(sel_man, obj, type, format, data, seat); + return ecore_evas_selection_get(pd->ee, seat, _ee_buffer_get(buffer), acceptable_types); } EOLIAN static void -_efl_ui_selection_selection_clear(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat) +_efl_ui_selection_selection_set(Eo *obj, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, Eina_Content *content, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_selection_clear(sel_man, obj, type, seat); + _register_selection_changed(obj); + ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), content); +} + +EOLIAN static void +_efl_ui_selection_selection_clear(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat) +{ + ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), NULL); } EOLIAN static Eina_Bool -_efl_ui_selection_has_owner(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat) +_efl_ui_selection_has_selection(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, type, seat); + return ecore_evas_selection_exists(pd->ee, seat, _ee_buffer_get(buffer)); } - -////////// Support legacy APIs - -//TODO: Clear this list (when sel_man is deleted) -Eina_List *lost_cb_list = NULL; - -#ifdef HAVE_ELEMENTARY_WL2 -static Ecore_Evas * -_wl_is_wl(const Evas_Object *obj) +EOLIAN static Efl_Object* +_efl_ui_selection_efl_object_constructor(Eo *obj, Efl_Ui_Selection_Data *pd) { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; + if (!efl_constructor(efl_super(obj, EFL_UI_SELECTION_MIXIN))) + return NULL; - if (!(evas = evas_object_evas_get(obj))) - return NULL; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return NULL; + pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) + return obj; +} + +EOLIAN static void +_efl_ui_selection_efl_object_invalidate(Eo *obj, Efl_Ui_Selection_Data *pd) +{ + if (pd->registered) { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - engine_name = ecore_evas_engine_name_get(ee); + _selection_changed_event_unregister(obj); } - if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1)) - return ee; - return NULL; + efl_invalidate(efl_super(obj, EFL_UI_SELECTION_MIXIN)); } -int -_wl_default_seat_id_get(Evas_Object *obj) +EOLIAN static Eina_Bool +_efl_ui_selection_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd, + const Efl_Event_Description *desc, + Efl_Callback_Priority priority, + Efl_Event_Cb func, + const void *user_data) { - Ecore_Wl2_Window *win = _wl_window_get(obj); - Eo *seat, *parent2, *ewin; - Eina_Bool is_wl = EINA_FALSE; + if (desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered) + { - if (obj) + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _selection_changed_event_register(obj); + } + + return efl_event_callback_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), desc, priority, func, user_data); +} + +EOLIAN static Eina_Bool +_efl_ui_selection_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd, + const Efl_Callback_Array_Item *array, + Efl_Callback_Priority priority, + const void *user_data) +{ + for (int i = 0; array[i].desc; ++i) { - if (_wl_is_wl(obj)) is_wl = EINA_TRUE; - if (efl_isa(obj, EFL_UI_WIDGET_CLASS)) + if (array[i].desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered) { - Eo *top = elm_widget_top_get(obj); - if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS)) - { - parent2 = efl_ui_win_inlined_parent_get(top); - if (parent2) obj = elm_widget_top_get(parent2) ?: parent2; - } - /* fake win means canvas seat id will not match protocol seat id */ - ewin = elm_win_get(obj); - if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL; + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _selection_changed_event_register(obj); } } - - if (!obj) - { - if (is_wl) - { - Ecore_Wl2_Input *input; - Eina_Iterator *it; - - it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win)); - EINA_ITERATOR_FOREACH(it, input) break; - eina_iterator_free(it); - if (input) - return ecore_wl2_input_seat_id_get(input); - } - } - - seat = evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, 1); - return evas_device_seat_id_get(seat); -} -#endif - -typedef struct _Cnp_Data_Cb_Wrapper Cnp_Data_Cb_Wrapper; -struct _Cnp_Data_Cb_Wrapper -{ - void *udata; - Elm_Drop_Cb datacb; -}; - -static void -_selection_data_ready_cb(void *data, Efl_Object *obj, Efl_Ui_Selection_Data *seldata) -{ - Cnp_Data_Cb_Wrapper *wdata = data; - if (!wdata) return; - Elm_Selection_Data ddata; - - ddata.data = calloc(1, seldata->content.len + 1); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, seldata->content.mem, seldata->content.len); - ddata.len = seldata->content.len; - ddata.x = seldata->pos.x; - ddata.y = seldata->pos.y; - ddata.format = (Elm_Sel_Format)seldata->format; - ddata.action = (Elm_Xdnd_Action)seldata->action; - wdata->datacb(wdata->udata, obj, &ddata); - free(ddata.data); + return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), array, priority, user_data); } -typedef struct _Sel_Lost_Data Sel_Lost_Data; -struct _Sel_Lost_Data + +EOLIAN static Efl_Object* +_efl_ui_selection_efl_object_finalize(Eo *obj, Efl_Ui_Selection_Data *pd) { - const Evas_Object *obj; - Elm_Sel_Type type; - void *udata; - Elm_Selection_Loss_Cb loss_cb; -}; + if (pd->registered) + _selection_changed_event_register(obj); -static Eina_Value -_selection_lost_cb(void *data, const Eina_Value value) -{ - Eina_List *l, *l2; - Sel_Lost_Data *ldata, *ldata2; - - ldata = data; - EINA_LIST_FOREACH_SAFE(lost_cb_list, l, l2, ldata2) - { - if ((ldata->obj == ldata2->obj) && - (ldata->type == ldata2->type)) - { - ldata2->loss_cb(ldata2->udata, ldata2->type); - lost_cb_list = eina_list_remove(lost_cb_list, ldata2); - } - } - free(ldata); - - return value; + return efl_finalize(efl_super(obj, MY_CLASS)); } -EAPI Eina_Bool -elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type type, - Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - Cnp_Data_Cb_Wrapper *wdata = calloc(1, sizeof(Cnp_Data_Cb_Wrapper)); - if (!wdata) return EINA_FALSE; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get((Evas_Object *)obj); -#endif - wdata->udata = udata; - wdata->datacb = datacb; - efl_ui_selection_manager_selection_get(sel_man, (Evas_Object *)obj, (Efl_Ui_Selection_Type)type, - (Efl_Ui_Selection_Format)format, - wdata, _selection_data_ready_cb, NULL, seatid); - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type type, - Elm_Sel_Format format, const void *selbuf, size_t buflen) -{ - int seatid = 1; - Eina_Future *f; - Sel_Lost_Data *ldata; - Eo *sel_man = _efl_ui_selection_manager_get(obj); - Eina_Slice data; - - ldata = calloc(1, sizeof(Sel_Lost_Data)); - if (!ldata) return EINA_FALSE; - data.mem = selbuf; - data.len = buflen; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - f = efl_ui_selection_manager_selection_set(sel_man, obj, (Efl_Ui_Selection_Type)type, - (Efl_Ui_Selection_Format)format, data, seatid); - - ldata->obj = obj; - ldata->type = type; - eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata); - - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type type) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - efl_ui_selection_manager_selection_clear(sel_man, obj, (Efl_Ui_Selection_Type)type, seatid); - - return EINA_TRUE; -} - -EAPI void -elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, - Elm_Selection_Loss_Cb func, const void *data) -{ - Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data)); -#if HAVE_ELEMENTARY_COCOA - // Currently, we have no way to track changes in Cocoa pasteboard. - // Therefore, don't track this... - return; -#endif - if (!ldata) return; - ldata->obj = obj; - ldata->type = type; - ldata->udata = (void *)data; - ldata->loss_cb = func; - lost_cb_list = eina_list_append(lost_cb_list, ldata); -} - -EAPI Eina_Bool -elm_selection_selection_has_owner(Evas_Object *obj) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, - EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid); -} - -EAPI Eina_Bool -elm_cnp_clipboard_selection_has_owner(Evas_Object *obj) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, - EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid); -} +#define EFL_UI_SELECTION_EXTRA_OPS \ + EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_selection_efl_object_event_callback_priority_add), \ + EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_selection_efl_object_event_callback_array_priority_add), \ #include "efl_ui_selection.eo.c" diff --git a/src/lib/elementary/efl_ui_selection.eo b/src/lib/elementary/efl_ui_selection.eo index 20e42261d0..492e60e117 100644 --- a/src/lib/elementary/efl_ui_selection.eo +++ b/src/lib/elementary/efl_ui_selection.eo @@ -1,45 +1,57 @@ -import efl_ui_selection_types; +import eina_types; -mixin @beta Efl.Ui.Selection { - [[Efl Ui Selection class]] - data: null; - methods { - selection_set { - [[Set the selection data to the object]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data: Eina.Slice; [[Selection data]] - @in seat: uint;[[Specified seat for multiple seats case.]] - } - return: future; [[Future for tracking when the selection is lost]] - } - selection_get { - [[Get the data from the object that has selection]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]] - @in seat: uint;[[Specified seat for multiple seats case.]] - } - } - selection_clear { - [[Clear the selection data from the object]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - has_owner { - [[Determine whether the selection data has owner]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - return: bool; [[EINA_TRUE if there is object owns selection, otherwise EINA_FALSE]] - } - } - events { - wm_selection,changed: Efl.Ui.Selection_Changed; [[Called when display server's selection has changed]] - } +enum @beta Efl.Ui.Cnp_Buffer{ + selection = 0, + copy_and_paste = 1, +} + +struct @beta Efl.Ui.Wm_Selection_Changed { + buffer : Efl.Ui.Cnp_Buffer; + caused_by : Efl.Ui.Selection; + seat : uint; +} + +mixin @beta Efl.Ui.Selection requires Efl.Object { + methods { + selection_set { + [[Set the selection data to the object]] + params { + buffer : Efl.Ui.Cnp_Buffer; + content : Eina.Content @by_ref; + seat : uint; + } + } + selection_clear { + [[Clear the selection data from the object]] + params { + buffer : Efl.Ui.Cnp_Buffer; + seat : uint; + } + } + selection_get { + [[Get the data from the object that has selection]] + params { + buffer : Efl.Ui.Cnp_Buffer; + seat : uint; + acceptable_types : iterator; + } + return : future @move; + } + has_selection { + [[Determine whether the selection data has owner]] + params { + buffer : Efl.Ui.Cnp_Buffer; + seat : uint; + } + return : bool; [[$true if there is a available selection, $false if not]] + } + } + implements { + Efl.Object.constructor; + Efl.Object.invalidate; + Efl.Object.finalize; + } + events { + wm_selection,changed : Efl.Ui.Wm_Selection_Changed; + } } diff --git a/src/lib/elementary/efl_ui_selection_manager.c b/src/lib/elementary/efl_ui_selection_manager.c deleted file mode 100644 index 3a5db9713c..0000000000 --- a/src/lib/elementary/efl_ui_selection_manager.c +++ /dev/null @@ -1,5678 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "elementary_config.h" -#endif - -#include -#include "elm_priv.h" - -#ifdef _WIN32 -# include /* mmap */ -#else -# include -#endif - -#include "efl_ui_selection_manager_private.h" - -#define MY_CLASS EFL_UI_SELECTION_MANAGER_CLASS - -//#define DEBUGON 1 -#ifdef DEBUGON -# define sel_debug(fmt, args...) fprintf(stderr, __FILE__":%s:%d : " fmt "\n", __FUNCTION__, __LINE__, ##args) -#else -# define sel_debug(x...) do { } while (0) -#endif - -static void _anim_data_free(Sel_Manager_Drag_Container *dc); -static void _cont_obj_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); -static void _cont_obj_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); -static void _item_container_del_internal(Sel_Manager_Drag_Container *dc, Eina_Bool full); - -void efl_ui_selection_manager_drop_target_del(Eo *obj, Efl_Object *target_obj, Efl_Ui_Selection_Format format, unsigned int seat); -void efl_ui_selection_manager_selection_clear(Eo *obj, Efl_Object *owner, Efl_Ui_Selection_Type type, unsigned int seat); -void efl_ui_selection_manager_drag_start(Eo *obj, Efl_Object *drag_obj, Efl_Ui_Selection_Format format, Eina_Slice data, Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, unsigned int seat); - -static Eina_List *managers; - -#ifdef HAVE_ELEMENTARY_X -static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel); -static Ecore_X_Atom _x11_dnd_action_rev_map(Efl_Ui_Selection_Action action); -static Ecore_X_Window _x11_xwin_get(const Evas_Object *obj); -#endif - -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -static Ecore_Wl2_Input *_wl_seat_get(Ecore_Wl2_Window *win, Evas_Object *obj, unsigned int seat_id); -#endif - -#ifdef HAVE_ELEMENTARY_WIN32 -static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel); -#endif - -EAPI int ELM_CNP_EVENT_SELECTION_CHANGED = -1; - -static Sel_Manager_Seat_Selection * -_sel_manager_seat_selection_get(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Eina_List *l = NULL; - Sel_Manager_Seat_Selection *seat_sel = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if (seat_sel->seat == seat) - break; - } - if (!seat_sel) - ERR("Could not find request seat"); - - return seat_sel; -} - -static inline void -_owner_change_check(Efl_Ui_Selection_Manager *manager, Efl_Object *owner, - Sel_Manager_Seat_Selection *seat_sel, - Sel_Manager_Selection *sel, - Efl_Ui_Selection_Type type, Eina_Bool same_win) -{ - if (!same_win) - { - Eina_List *l, *l_next; - Eo *man; - - EINA_LIST_FOREACH_SAFE(managers, l, l_next, man) - { - if (man != manager) - { - Eina_List *l2, *l2_next, *l3, *l3_next; - Sel_Manager_Selection_Lost *sel_lost; - Sel_Manager_Seat_Selection *seat_sel2; - Efl_Ui_Selection_Manager_Data *pd = efl_data_scope_get(man, MY_CLASS); - - if (!pd) continue; - EINA_LIST_FOREACH_SAFE(pd->seat_list, l3, l3_next, seat_sel2) - { - EINA_LIST_FOREACH_SAFE(seat_sel2->sel_lost_list, l2, l2_next, sel_lost) - { - if ((sel_lost->request) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - seat_sel2->xwin = 0; -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WIN32) - if (seat_sel2->sel_list) - { - int i; - - for (i = 0; - i < (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) - ; i++) - { -#ifdef HAVE_ELEMENTARY_X - seat_sel2->sel_list[i].xwin = 0; -#elif defined (HAVE_ELEMENTARY_WIN32) - seat_sel2->sel_list[i].win = NULL; -#endif - seat_sel2->sel_list[i].active = EINA_FALSE; - } - } -#endif -#if defined(HAVE_ELEMENTARY_WL2) || defined(HAVE_ELEMENTARY_COCOA) - if (seat_sel2->sel) - { - seat_sel2->sel->win = 0; - seat_sel2->sel->active = EINA_FALSE; - } -#endif - } - } - } - } - if ((sel->owner != NULL) && - (sel->owner != owner) && same_win) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - } -} - -static Sel_Manager_Seat_Selection * -_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } -#ifdef HAVE_ELEMENTARY_X - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } -#endif - - return seat_sel; -} - -static void -_sel_manager_promise_cancel(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED) -{ - Sel_Manager_Selection_Lost *sel_lost = data; - sel_lost->seat_sel->sel_lost_list = eina_list_remove(sel_lost->seat_sel->sel_lost_list, sel_lost); - free(sel_lost); -} - -static inline Eina_Future * -_update_sel_lost_list(Efl_Object *obj, Efl_Ui_Selection_Type type, - Sel_Manager_Seat_Selection *seat_sel) -{ - Eina_Promise *p; - Sel_Manager_Selection_Lost *sel_lost; - - sel_lost = calloc(1, sizeof(Sel_Manager_Selection_Lost)); - if (!sel_lost) - return NULL; - sel_lost->request = obj; - sel_lost->type = type; - sel_lost->seat_sel = seat_sel; - seat_sel->sel_lost_list = eina_list_append(seat_sel->sel_lost_list, sel_lost); - - p = efl_loop_promise_new(obj); - if (!p) return NULL; - sel_lost->promise = p; - - return efl_future_then(obj, eina_future_new(p), - .data = sel_lost, - .free = _sel_manager_promise_cancel); -} - -/* TODO: this should not be an actual tempfile, but rather encode the object - * as http://dataurl.net/ if it's an image or similar. Evas should support - * decoding it as memfile. */ -static Tmp_Info * -_tempfile_new(int size) -{ -#ifdef HAVE_MMAP - Tmp_Info *info; - const char *tmppath = NULL; - mode_t cur_umask; - int len; - - info = calloc(1, sizeof(Tmp_Info)); - if (!info) return NULL; -#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) - if (getuid() == geteuid()) -#endif - tmppath = getenv("TMP"); - if (!tmppath) tmppath = P_tmpdir; - len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-"); - if (len < 0) goto on_error; - len++; - info->filename = malloc(len); - if (!info->filename) goto on_error; - snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-"); - cur_umask = umask(S_IRWXO | S_IRWXG); - info->fd = mkstemp(info->filename); - umask(cur_umask); - if (info->fd < 0) goto on_error; -# ifdef __linux__ - { - char *tmp; - /* And before someone says anything see POSIX 1003.1-2008 page 400 */ - long pid; - - pid = (long)getpid(); - /* Use pid instead of /proc/self: That way if can be passed around */ - len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd); - len++; - tmp = malloc(len); - if (tmp) - { - snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd); - unlink(info->filename); - free(info->filename); - info->filename = tmp; - } - } -# endif - sel_debug("filename is %s\n", info->filename); - if (size < 1) goto on_error; - /* Map it in */ - if (ftruncate(info->fd, size)) - { - perror("ftruncate"); - goto on_error; - } - eina_mmap_safety_enabled_set(EINA_TRUE); - info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0); - if (info->map == MAP_FAILED) - { - perror("mmap"); - goto on_error; - } - return info; - - on_error: - if (info->fd >= 0) close(info->fd); - info->fd = -1; - /* Set map to NULL and return */ - info->map = NULL; - info->len = 0; - free(info->filename); - free(info); - return NULL; -#else - (void) size; - return NULL; -#endif -} - -static int -_tmpinfo_free(Tmp_Info *info) -{ - if (!info) return 0; - free(info->filename); - free(info); - return 0; -} - -static inline void -_drop_target_cbs_del(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Efl_Object *obj) -{ - if (dropable) - { - Drop_Format *df; - while (dropable->format_list) - { - df = EINA_INLIST_CONTAINER_GET(dropable->format_list, Drop_Format); - efl_ui_selection_manager_drop_target_del(pd->sel_man, obj, - df->format, dropable->seat); - // If drop_target_del() happened to delete dropabale, then - // re-fetch it each loop to make sure it didn't - dropable = efl_key_data_get(obj, "__elm_dropable"); - if (!dropable) break; - } - } -} - -static void -_all_drop_targets_cbs_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Sel_Manager_Dropable *dropable = NULL; - - if (!pd) return; - dropable = efl_key_data_get(obj, "__elm_dropable"); - _drop_target_cbs_del(pd, dropable, obj); -} - -static void -_dropable_coords_adjust(Sel_Manager_Dropable *dropable, Eina_Position2D *pos) -{ - Ecore_Evas *ee; - Evas *evas = evas_object_evas_get(dropable->obj); - int ex = 0, ey = 0, ew = 0, eh = 0; - Evas_Object *win; - - ee = ecore_evas_ecore_evas_get(evas); - ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh); - pos->x = pos->x - ex; - pos->y = pos->y - ey; - - /* For Wayland, frame coords have to be subtracted. */ - Evas_Coord fx, fy; - evas_output_framespace_get(evas, &fx, &fy, NULL, NULL); - if (fx || fy) sel_debug("evas frame fx %d fy %d\n", fx, fy); - pos->x = pos->x - fx; - pos->y = pos->y - fy; - - if (elm_widget_is(dropable->obj)) - { - win = elm_widget_top_get(dropable->obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - { - Evas_Coord x2, y2; - int rot = elm_win_rotation_get(win); - switch (rot) - { - case 90: - x2 = ew - pos->y; - y2 = pos->x; - break; - case 180: - x2 = ew - pos->x; - y2 = eh - pos->y; - break; - case 270: - x2 = pos->y; - y2 = eh - pos->x; - break; - default: - x2 = pos->x; - y2 = pos->y; - break; - } - sel_debug("rotation %d, w %d, h %d - x:%d->%d, y:%d->%d\n", - rot, ew, eh, pos->x, x2, pos->y, y2); - pos->x = x2; - pos->y = y2; - } - } -} - -static Eina_Bool -_drag_cancel_animate(void *data, double pos) -{ /* Animation to "move back" drag-window */ - Sel_Manager_Seat_Selection *seat_sel = data; - sel_debug("in, pos: %f", pos); - if (pos >= 0.99) - { -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 0); -#endif - sel_debug("Delete drag_win"); - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - return ECORE_CALLBACK_CANCEL; - } - else - { - int x, y; - x = seat_sel->drag_win_end.x - (pos * (seat_sel->drag_win_end.x - seat_sel->drag_win_start.x)); - y = seat_sel->drag_win_end.y - (pos * (seat_sel->drag_win_end.y - seat_sel->drag_win_start.y)); - evas_object_move(seat_sel->drag_win, x, y); - } - - return ECORE_CALLBACK_RENEW; -} - -static Efl_Ui_Selection_Format -_dnd_types_to_format(Efl_Ui_Selection_Manager_Data *pd, const char **types, int ntypes) -{ - Efl_Ui_Selection_Format ret_type = 0; - int i; - for (i = 0; i < ntypes; i++) - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, types[i]); - if (atom) ret_type |= atom->format; - } - return ret_type; -} - -static Eina_List * -_dropable_list_geom_find(Efl_Ui_Selection_Manager_Data *pd, Evas *evas, Evas_Coord px, Evas_Coord py) -{ - Eina_List *itr, *top_objects_list = NULL, *dropable_list = NULL; - Evas_Object *top_obj; - Sel_Manager_Dropable *dropable = NULL; - - if (!pd->drop_list) return NULL; - - /* We retrieve the (non-smart) objects pointed by (px, py) */ - top_objects_list = evas_tree_objects_at_xy_get(evas, NULL, px, py); - /* We walk on this list from the last because if the list contains more than one - * element, all but the last will repeat events. The last one can repeat events - * or not. Anyway, this last one is the first that has to be taken into account - * for the determination of the drop target. - */ - EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj) - { - Evas_Object *object = top_obj; - /* We search for the dropable data into the object. If not found, we search into its parent. - * For example, if a button is a drop target, the first object will be an (internal) image. - * The drop target is attached to the button, i.e to image's parent. That's why we need to - * walk on the parents until NULL. - * If we find this dropable data, we found our drop target. - */ - while (object) - { - dropable = efl_key_data_get(object, "__elm_dropable"); - if (dropable) - { - Eina_Bool exist = EINA_FALSE; - Eina_List *l; - Sel_Manager_Dropable *d = NULL; - EINA_LIST_FOREACH(dropable_list, l, d) - { - if (d == dropable) - { - exist = EINA_TRUE; - break; - } - } - if (!exist) - dropable_list = eina_list_append(dropable_list, dropable); - object = evas_object_smart_parent_get(object); - if (dropable) - sel_debug("Drop target %p of type %s found\n", - dropable->obj, efl_class_name_get(efl_class_get(dropable->obj))); - } - else - object = evas_object_smart_parent_get(object); - } - } - eina_list_free(top_objects_list); - return dropable_list; -} - -#ifdef HAVE_ELEMENTARY_X -static Ecore_X_Window -_x11_xwin_get(const Efl_Object *obj) -{ - if (!obj) return 0; - - Ecore_X_Window xwin = 0; - //get top - const Evas_Object *top = obj; - const Evas_Object *parent = obj; - while(parent) - { - top = parent; - parent = efl_parent_get(parent); - } - if (efl_isa(top, EFL_UI_WIN_CLASS)) - { - xwin = elm_win_xwindow_get(top); - } - if (!xwin) - { - Ecore_Evas *ee; - Evas *evas = evas_object_evas_get(obj); - if (!evas) return 0; - ee = ecore_evas_ecore_evas_get(evas); - if (!ee) return 0; - - while(!xwin) - { - const char *engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return 0; - xwin = _elm_ee_xwin_get(ee); - } - else - { - xwin = _elm_ee_xwin_get(ee); - if (!xwin) return 0; - } - } - } - - return xwin; -} - -static Eina_Bool -_x11_is_uri_type_data(Sel_Manager_Selection *sel EINA_UNUSED, Ecore_X_Event_Selection_Notify *notify) -{ - Ecore_X_Selection_Data *data; - char *p; - - data = notify->data; - sel_debug("data->format is %d %p %p", data->format, notify, data); - if (data->content == ECORE_X_SELECTION_CONTENT_FILES) return EINA_TRUE; - p = (char *)data->data; - if (!p) return EINA_TRUE; - sel_debug("Got %s", p); - if (strncmp(p, "file:/", 6)) - { - if (*p != '/') return EINA_FALSE; - } - return EINA_TRUE; -} - -static Sel_Manager_Seat_Selection * -_x11_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel_list) - { - //TODO: reduce memory (may be just need one common sel_list) - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } - - return seat_sel; -} - -static Eina_Bool -_x11_data_preparer_text(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("text data preparer"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -static Eina_Bool -_x11_data_preparer_markup(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("markup data preparer"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_MARKUP; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -/** - * So someone is pasting an image into my entry or widget... - */ -static Eina_Bool -_x11_data_preparer_uri(Sel_Manager_Seat_Selection *seat_sel, Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("uri data preparer"); - Ecore_X_Selection_Data *data; - Ecore_X_Selection_Data_Files *files; - char *p, *stripstr = NULL; - - data = notify->data; - sel_debug("data->format is %d %p %p\n", data->format, notify, data); - if (data->content == ECORE_X_SELECTION_CONTENT_FILES) - { - Efreet_Uri *uri; - Eina_Strbuf *strbuf; - int i; - - sel_debug("got a files list\n"); - files = notify->data; - /* - if (files->num_files > 1) - { - // Don't handle many items <- this makes mr bigglesworth sad :( - sel_debug("more then one file: Bailing\n"); - return EINA_FALSE; - } - stripstr = p = strdup(files->files[0]); - */ - - strbuf = eina_strbuf_new(); - if (!strbuf) - return EINA_FALSE; - - for (i = 0; i < files->num_files ; i++) - { - uri = efreet_uri_decode(files->files[i]); - if (uri) - { - eina_strbuf_append(strbuf, uri->path); - efreet_uri_free(uri); - } - else - { - eina_strbuf_append(strbuf, files->files[i]); - } - if (i < (files->num_files - 1)) - eina_strbuf_append(strbuf, "\n"); - } - stripstr = eina_strbuf_string_steal(strbuf); - eina_strbuf_free(strbuf); - } - else - { - Efreet_Uri *uri; - - p = (char *)eina_memdup((unsigned char *)data->data, data->length, EINA_TRUE); - if (!p) return EINA_FALSE; - uri = efreet_uri_decode(p); - if (!uri) - { - /* Is there any reason why we care of URI without scheme? */ - if (p[0] == '/') stripstr = p; - else free(p); - } - else - { - free(p); - stripstr = strdup(uri->path); - efreet_uri_free(uri); - } - } - - if (!stripstr) - { - sel_debug("Couldn't find a file\n"); - return EINA_FALSE; - } - free(seat_sel->saved_types->imgfile); -#if 0 // this seems to be broken - we should be handling uri lists as text - if (seat_sel->saved_types->textreq) - { - seat_sel->saved_types->textreq = 0; - seat_sel->saved_types->imgfile = stripstr; - } - else -#endif - { - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = stripstr; - ddata->content.len = strlen(stripstr); - seat_sel->saved_types->imgfile = NULL; - } - return EINA_TRUE; -} - -/** - * Just received an vcard, either through cut and paste, or dnd. - */ -static Eina_Bool -_x11_data_preparer_vcard(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("vcard receive\n"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_VCARD; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -static Eina_Bool -_x11_data_preparer_image(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info) -{ - Ecore_X_Selection_Data *data = notify->data; - sel_debug("got a image file!\n"); - sel_debug("Size if %d\n", data->length); - - ddata->format = EFL_UI_SELECTION_FORMAT_IMAGE; - data = notify->data; - - Tmp_Info *tmp = _tempfile_new(data->length); - if (!tmp) return EINA_FALSE; - memcpy(tmp->map, data->data, data->length); - munmap(tmp->map, data->length); - ddata->content.mem = strdup(tmp->filename); - ddata->content.len = strlen(tmp->filename); - *tmp_info = tmp; - return EINA_TRUE; -} - -static Eina_Bool -_x11_win_filter(Eo *manager EINA_UNUSED, Ecore_X_Window xwin) -{ - Eo *win; - const Eina_List *l; - - EINA_LIST_FOREACH(_elm_win_list, l, win) - { - if (elm_win_window_id_get(win) == xwin) return EINA_FALSE; - } - return EINA_TRUE; -} - -/* - * Callback to handle a targets response on a selection request: - * So pick the format we'd like; and then request it. - */ -static Eina_Bool -_x11_notify_handler_targets(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Selection *sel, Ecore_X_Event_Selection_Notify *notify) -{ - sel_debug("notify handler targets"); - Ecore_X_Selection_Data_Targets *targets; - Ecore_X_Atom *atom_list; - int i, j; - - targets = notify->data; - atom_list = (Ecore_X_Atom *)(targets->data.data); - for (j = (SELECTION_ATOM_LISTING_ATOMS + 1); j < SELECTION_N_ATOMS; j++) - { - sel_debug("\t%s %d", pd->atom_list[j].name, pd->atom_list[j].x_atom); - if (!(pd->atom_list[j].format & sel->request_format)) continue; - for (i = 0; i < targets->data.length; i++) - { - if ((pd->atom_list[j].x_atom == atom_list[i]) && (pd->atom_list[j].x_data_preparer)) - { - if (j == SELECTION_ATOM_TEXT_URILIST) - { - if (!_x11_is_uri_type_data(sel, notify)) continue; - } - sel_debug("Atom %s matches", pd->atom_list[j].name); - goto done; - } - } - } - sel_debug("Couldn't find anything that matches"); - return ECORE_CALLBACK_PASS_ON; -done: - sel_debug("Sending request for %s, xwin=%#llx", - pd->atom_list[j].name, (unsigned long long)sel->xwin); - sel->request(sel->xwin, pd->atom_list[j].name); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_fixes_selection_notify(void *data, int t EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Efl_Ui_Selection_Changed e; - Elm_Cnp_Event_Selection_Changed *_e; - Ecore_X_Event_Fixes_Selection_Notify *ev = event; - Sel_Manager_Seat_Selection *seat_sel; - Efl_Ui_Selection_Type type; - Sel_Manager_Selection *sel; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - switch (ev->selection) - { - case ECORE_X_SELECTION_CLIPBOARD: - type = EFL_UI_SELECTION_TYPE_CLIPBOARD; - break; - case ECORE_X_SELECTION_PRIMARY: - type = EFL_UI_SELECTION_TYPE_PRIMARY; - break; - default: return ECORE_CALLBACK_RENEW; - } - seat_sel = _x11_sel_manager_seat_selection_init(pd, 1); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel_list + type; - if (sel->active && (sel->xwin != ev->owner)) - efl_ui_selection_manager_selection_clear(pd->sel_man, sel->owner, type, seat_sel->seat); - e.type = type; - e.seat = 1; /* under x11 this is always the default seat */ - e.exist = !!ev->owner; - - _e = calloc(1, sizeof(Elm_Cnp_Event_Selection_Changed)); - EINA_SAFETY_ON_NULL_RETURN_VAL(_e, ECORE_CALLBACK_RENEW); - _e->type = type; - _e->seat_id = 1; - _e->exists = e.exist; - - ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, _e, NULL, NULL); - efl_event_callback_call(sel->owner, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &e); - - return ECORE_CALLBACK_RENEW; -} - -/* - * Response to a selection notify: - * - So we have asked for the selection list. - * - If it's the targets list, parse it, and fire of what we want, - * else it's the data we want. - */ -//NB: x11 does not have seat, use 1 as default -static Eina_Bool -_efl_sel_manager_x11_selection_notify(void *udata, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = udata; - Ecore_X_Event_Selection_Notify *ev = event; - Sel_Manager_Selection *sel; - Sel_Manager_Seat_Selection *seat_sel = NULL; - int i; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - seat_sel = _sel_manager_seat_selection_get(pd, 1); - if (!seat_sel) - return EINA_FALSE; - - sel_debug("selection notify callback: %d", ev->selection); - switch (ev->selection) - { - case ECORE_X_SELECTION_PRIMARY: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_PRIMARY; - break; - case ECORE_X_SELECTION_SECONDARY: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_SECONDARY; - break; - case ECORE_X_SELECTION_XDND: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_DND; - break; - case ECORE_X_SELECTION_CLIPBOARD: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_CLIPBOARD; - break; - default: - return ECORE_CALLBACK_PASS_ON; - } - sel_debug("Target is %s", ev->target); - if (!sel->asked) return ECORE_CALLBACK_PASS_ON; - sel->asked--; - - if (ev->selection != ECORE_X_SELECTION_XDND && - (!strcmp(ev->target, "TARGETS") || !strcmp(ev->target, "ATOMS"))) - { - _x11_notify_handler_targets(pd, sel, ev); - return ECORE_CALLBACK_PASS_ON; - } - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (!strcmp(ev->target, pd->atom_list[i].name)) - { - if (pd->atom_list[i].x_data_preparer) - { - Efl_Ui_Selection_Data ddata = { 0 }; - Tmp_Info *tmp_info = NULL; - Eina_Bool success; - sel_debug("Found something: %s", pd->atom_list[i].name); - - success = pd->atom_list[i].x_data_preparer(seat_sel, ev, &ddata, &tmp_info); - sel_debug("ddata: %s (%zd)", (const char *)ddata.content.mem, ddata.content.len); - if ((pd->atom_list[i].format == EFL_UI_SELECTION_FORMAT_IMAGE) && - (seat_sel->saved_types->imgfile)) - break; - if (ev->selection == ECORE_X_SELECTION_XDND) - { - if (success) - { - Sel_Manager_Dropable *dropable; - Eina_List *l; - sel_debug("drag & drop\n"); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->obj == sel->request_obj) break; - dropable = NULL; - } - if (dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - ddata.action = sel->action; - if (!dropable->is_container) - { - sel_debug("normal dnd, not container"); - ddata.pos = seat_sel->saved_types->pos; - } - else - { - sel_debug("Drop on container"); - Eina_Position2D pos, posret = {0, 0}; - evas_object_geometry_get(dropable->obj, &pos.x, &pos.y, NULL, NULL); - //get item - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + pos.x, - seat_sel->saved_types->pos.y + pos.y); - Efl_Object *it = NULL; - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, - dropable->obj, pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - sel_debug("calling Drop event on: %p", dropable->obj); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - } - } - else - { - sel_debug("dnd: has NO dropable"); - } - } - /* We have to finish DnD, no matter what */ - ecore_x_dnd_send_finished(); - } - else if (sel->data_func && success) - { - ddata.pos.x = ddata.pos.y = 0; - sel->data_func(sel->data_func_data, sel->request_obj, &ddata); - } - free((void *)ddata.content.mem); - if (tmp_info) _tmpinfo_free(tmp_info); - } - else sel_debug("Ignored: No handler!"); - break; - } - } - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_selection_clear(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Ecore_X_Event_Selection_Clear *ev = event; - Sel_Manager_Selection *sel; - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - unsigned int i; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - seat_sel = _sel_manager_seat_selection_get(pd, 1); - if (!seat_sel) - return EINA_FALSE; - - for (i = EFL_UI_SELECTION_TYPE_PRIMARY; i <= EFL_UI_SELECTION_TYPE_CLIPBOARD; i++) - { - if (seat_sel->sel_list[i].ecore_sel == ev->selection) break; - } - sel_debug("selection %d clear", i); - /* Not me... Don't care */ - if (i > EFL_UI_SELECTION_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON; - - sel = seat_sel->sel_list + i; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == i)) - { - sel_debug("resolve the promise: %p", sel_lost->promise); - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - sel->active = EINA_FALSE; - sel->owner = NULL; - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_general_converter(char *target EINA_UNUSED, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - sel_debug("general converter"); - Sel_Manager_Selection *sel = *(Sel_Manager_Selection **)data; - if (sel->format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(sel->data.len * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, sel->data.mem, sel->data.len); - ((char**)(data_ret))[0][sel->data.len] = 0; - } - if (size_ret) *size_ret = sel->data.len; - } - else - { - if (sel->data.mem) - { - if (data_ret) - *data_ret = eina_memdup(sel->data.mem, sel->data.len, 1); - if (size_ret) *size_ret = sel->data.len; - } - else - { - if (data_ret) *data_ret = NULL; - if (size_ret) *size_ret = 0; - } - } - return EINA_TRUE; -} - -static Eina_Bool -_x11_targets_converter(char *target EINA_UNUSED, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize) -{ - int i, count; - Ecore_X_Atom *aret; - Sel_Manager_Selection *sel; - Efl_Ui_Selection_Format seltype; - - sel_debug("target converter"); - if (!data_ret) return EINA_FALSE; - - sel = *(Sel_Manager_Selection **)data; - seltype = sel->format; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++) - { - if (seltype & pd->atom_list[i].format) count++; - } - aret = malloc(sizeof(Ecore_X_Atom) * count); - if (!aret) return EINA_FALSE; - for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++) - { - if (seltype & pd->atom_list[i].format) - aret[count ++] = pd->atom_list[i].x_atom; - } - - *data_ret = aret; - if (typesize) *typesize = 32 /* urk */; - if (ttype) *ttype = ECORE_X_ATOM_ATOM; - if (size_ret) *size_ret = count; - return EINA_TRUE; -} - -static Eina_Bool -_x11_image_converter(char *target EINA_UNUSED, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret EINA_UNUSED, int *size_ret EINA_UNUSED, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - sel_debug("Image converter called"); - return EINA_TRUE; -} - -static Eina_Bool -_x11_vcard_send(char *target EINA_UNUSED, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - Sel_Manager_Selection *sel; - - sel_debug("Vcard send called"); - sel = *(Sel_Manager_Selection **)data; - if (data_ret) - { - char *s; - - s = malloc(sel->data.len + 1); - if (!s) return EINA_FALSE; - memcpy(s, sel->data.mem, sel->data.len); - s[sel->data.len] = 0; - *data_ret = s; - } - - if (size_ret) *size_ret = sel->data.len; - return EINA_TRUE; -} - -static Eina_Bool -_x11_text_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize) -{ - Sel_Manager_Selection *sel; - - sel = *(Sel_Manager_Selection **)data; - if (!sel) return EINA_FALSE; - - sel_debug("text converter"); - if (sel->format == EFL_UI_SELECTION_FORMAT_NONE) - { - sel_debug("none"); - if (data_ret) - { - *data_ret = malloc(sel->data.len * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, sel->data.len); - ((char**)(data_ret))[0][sel->data.len] = 0; - } - if (size_ret) *size_ret = sel->data.len; - return EINA_TRUE; - } - - if (!sel->active) return EINA_TRUE; - - if ((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *tmp = malloc(sel->data.len + 1); - if (tmp) - { - strncpy(tmp, sel->data.mem, sel->data.len); - tmp[sel->data.len] = 0; - *data_ret = _elm_util_mkup_to_text(tmp); - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - free(tmp); - sel_debug("markup or html: %s", (const char *)*data_ret); - } - else return EINA_FALSE; - } - else if (sel->format & EFL_UI_SELECTION_FORMAT_TEXT) - { - ecore_x_selection_converter_text(target, sel->data.mem, - sel->data.len, - data_ret, size_ret, - ttype, typesize); - sel_debug("text"); - } - else if (sel->format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - efl_file_simple_get(sel->request_obj, (const char **)data_ret, NULL); - if (!*data_ret) *data_ret = strdup("No file"); - else *data_ret = strdup(*data_ret); - - if (!*data_ret) - { - ERR("Failed to allocate memory!"); - *size_ret = 0; - return EINA_FALSE; - } - - *size_ret = strlen(*data_ret); - } - return EINA_TRUE; -} - -static Eina_Future * -_x11_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *owner, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data, - Ecore_X_Window xwin, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Eina_Bool same_win = EINA_FALSE; - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel_list + type; - //support 1 app with multiple window, 1 selection manager - if (seat_sel->xwin == xwin) - same_win = EINA_TRUE; - _owner_change_check(pd->sel_man, owner, seat_sel, sel, type, same_win); - seat_sel->xwin = xwin; - - sel->owner = owner; - free(sel->data.mem); - sel->xwin = xwin; - sel->data = eina_slice_dup(data); - sel->active = EINA_TRUE; - sel->format = format; - - sel->set(xwin, &sel, sizeof(Sel_Manager_Selection *)); - sel_debug("data: %p (%zu)", &sel, sizeof(Sel_Manager_Selection *)); - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_x11_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_X_Window xwin, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel;; - - sel_debug("request: %p, seat: %u, type: %d, format: %d", request, seat, type, format); - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel_list + type; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - sel->request_format = format; - sel->xwin = xwin; - - if (sel->active) - { - if (sel->data.mem && - ((format == sel->format) || (xwin == 0))) - { - sel_debug("use local data"); - Efl_Ui_Selection_Data seldata; - - seldata.content.mem = sel->data.mem; - seldata.content.len = sel->data.len; - seldata.pos.x = seldata.pos.y = 0; - seldata.format = sel->format; - sel->data_func(sel->data_func_data, sel->request_obj, &seldata); - return; - } - } - - sel->asked = 2; - sel->request(xwin, ECORE_X_SELECTION_TARGET_TARGETS); -} - -static void -_x11_win_rotation_changed_cb(void *data, const Efl_Event *event) -{ - Evas_Object *win = data; - int rot = elm_win_rotation_get(event->object); - elm_win_rotation_set(win, rot); -} - -static Eina_Bool -_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Window xwin = seat_sel->xwin; - Ecore_Event_Mouse_Button *ev = event; - - if ((ev->buttons == 1) && - (ev->event_window == xwin)) - { - Eina_Bool have_drop_list = EINA_FALSE; - Eina_List *l; - Sel_Manager_Dropable *dropable; - - ecore_x_pointer_ungrab(); - ELM_SAFE_FREE(seat_sel->mouse_up_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->dnd_status_handler, ecore_event_handler_del); - ecore_x_dnd_self_drop(); - - sel_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin); - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_FALSE); - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL); - if (seat_sel->drag_win) - { - if (seat_sel->drag_obj) - { - if (elm_widget_is(seat_sel->drag_obj)) - { - Evas_Object *win = elm_widget_top_get(seat_sel->drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - efl_event_callback_del(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - - if (!seat_sel->accept) - { /* Commit animation when drag cancelled */ - /* Record final position of dragwin, then do animation */ - ecore_evas_animator_timeline_add(seat_sel->drag_win, 0.3, - _drag_cancel_animate, seat_sel); - } - else - { /* No animation drop was committed */ - Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 0); - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - sel_debug("deleted drag_win"); - } - } - - seat_sel->drag_obj = NULL; - seat_sel->accept = EINA_FALSE; - } - return EINA_TRUE; -} - -static void -_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Dnd_Drag_Pos dp; - - evas_object_move(seat_sel->drag_win, - pos->position.x - seat_sel->drag_pos.x, - pos->position.y - seat_sel->drag_pos.y); - seat_sel->drag_win_end.x = pos->position.x - seat_sel->drag_pos.x; - seat_sel->drag_win_end.y = pos->position.y - seat_sel->drag_pos.y; - sel_debug("dragevas: %p -> %p\n", - seat_sel->drag_obj, - evas_object_evas_get(seat_sel->drag_obj)); - dp.pos.x = pos->position.x; - dp.pos.y = pos->position.y; - dp.action = seat_sel->drag_action; - //for drag side - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_POS, &dp); -} - -static void -_x11_drag_target_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Selection *sel = &seat_sel->sel_list[seat_sel->active_type]; - - if (seat_sel->drag_obj == obj) - { - sel->request_obj = NULL; - seat_sel->drag_obj = NULL; - } -} - -static Eina_Bool -_x11_dnd_status(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Ecore_X_Event_Xdnd_Status *status = ev; - - seat_sel->accept = EINA_FALSE; - - /* Only thing we care about: will accept */ - if ((status) && (status->will_accept)) - { - sel_debug("Will accept\n"); - seat_sel->accept = EINA_TRUE; - } - /* Won't accept */ - else - { - sel_debug("Won't accept accept\n"); - } - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept); - - return EINA_TRUE; -} - -static void -_x11_efl_sel_manager_drag_start(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Format format, - Eina_Slice data, Efl_Ui_Selection_Action action, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, - Eina_Free_Cb icon_func_free_cb EINA_UNUSED, - Ecore_X_Window xwin, unsigned int seat) -{ - Ecore_X_Window xdragwin; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Evas *ee; - int x, y, x2 = 0, y2 = 0, x3, y3; - Evas_Object *icon = NULL; - int w = 0, h = 0; - int ex, ey, ew, eh; - Ecore_X_Atom actx; - int i; - int xr, yr, rot; - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return; - seat_sel->active_type = EFL_UI_SELECTION_TYPE_DND; - - sel = &seat_sel->sel_list[seat_sel->active_type]; - ecore_x_dnd_types_set(xwin, NULL, 0); - for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++) - { - if (format == EFL_UI_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format)) - { - ecore_x_dnd_type_set(xwin, pd->atom_list[i].name, EINA_TRUE); - sel_debug("set dnd type: %s\n", pd->atom_list[i].name); - } - } - - sel->active = EINA_TRUE; - sel->request_obj = drag_obj; - sel->format = format; - if (sel->data.mem) free(sel->data.mem); - sel->data = eina_slice_dup(data); - sel->action = action; - seat_sel->drag_obj = drag_obj; - seat_sel->drag_action = action; - seat_sel->xwin = xwin; - - evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL, - _x11_drag_target_del, seat_sel); - /* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */ - ecore_x_dnd_aware_set(xwin, EINA_TRUE); - ecore_x_dnd_callback_pos_update_set(_x11_drag_move, seat_sel); - ecore_x_dnd_self_begin(xwin, (unsigned char *)sel, sizeof(Sel_Manager_Selection)); - actx = _x11_dnd_action_rev_map(seat_sel->drag_action); - ecore_x_dnd_source_action_set(actx); - ecore_x_pointer_grab(xwin); - seat_sel->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, - _x11_drag_mouse_up, seat_sel); - seat_sel->dnd_status_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS, - _x11_dnd_status, seat_sel); - seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); - elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE); - elm_win_override_set(seat_sel->drag_win, EINA_TRUE); - xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 1); - - /* dragwin has to be rotated as the main window is */ - if (elm_widget_is(drag_obj)) - { - Evas_Object *win = elm_widget_top_get(drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - { - elm_win_rotation_set(seat_sel->drag_win, elm_win_rotation_get(win)); - efl_event_callback_add(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - - if (icon_func) - { - Eina_Position2D off; - - icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off); - if (icon) - { - x2 = off.x; - y2 = off.y; - evas_object_geometry_get(icon, NULL, NULL, &w, &h); - } - } - else - { - icon = elm_icon_add(seat_sel->drag_win); - evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - // need to resize - } - elm_win_resize_object_add(seat_sel->drag_win, icon); - - /* Position subwindow appropriately */ - ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj)); - ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh); - evas_object_resize(seat_sel->drag_win, w, h); - - evas_object_show(icon); - evas_object_show(seat_sel->drag_win); - evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3); - - rot = ecore_evas_rotation_get(ee); - switch (rot) - { - case 90: - xr = y3; - yr = ew - x3; - seat_sel->drag_pos.x = y3 - y2; - seat_sel->drag_pos.y = x3 - x2; - break; - case 180: - xr = ew - x3; - yr = eh - y3; - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - break; - case 270: - xr = eh - y3; - yr = x3; - seat_sel->drag_pos.x = y3 - y2; - seat_sel->drag_pos.y = x3 - x2; - break; - default: - xr = x3; - yr = y3; - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - break; - } - x = ex + xr - seat_sel->drag_pos.x; - y = ey + yr - seat_sel->drag_pos.y; - evas_object_move(seat_sel->drag_win, x, y); - seat_sel->drag_win_start = EINA_POSITION2D(x, y); - seat_sel->drag_win_end = EINA_POSITION2D(x, y); -} - -static void -_x11_dnd_dropable_handle(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Eina_Position2D pos, Efl_Ui_Selection_Action action) -{ - Sel_Manager_Dropable *d, *last_dropable = NULL; - Eina_List *l; - Eina_Inlist *itr; - - EINA_LIST_FOREACH(pd->drop_list, l, d) - { - if (d->last.in) - { - last_dropable = d; - break; - } - } - if (last_dropable) - { - if (last_dropable == dropable) // same - { - Evas_Coord ox, oy; - Drop_Format *df; - - sel_debug("same obj dropable %p\n", dropable->obj); - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - Efl_Dnd_Drag_Pos pos_data; - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy); - pos_data.item = NULL; - } - else - { - Eina_Position2D posret = {0, 0}; - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - pos_data.pos = posret; - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - else - { - if (dropable) // leave last obj and enter new one - { - sel_debug("leave %p\n", last_dropable->obj); - sel_debug("enter %p\n", dropable->obj); - last_dropable->last.in = EINA_FALSE; - last_dropable->last.type = NULL; - dropable->last.in = EINA_TRUE; - - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format &dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - } - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - else // leave last obj - { - sel_debug("leave %p\n", last_dropable->obj); - last_dropable->last.in = EINA_FALSE; - last_dropable->last.type = NULL; - - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - } - } - else - { - if (dropable) // enter new obj - { - Evas_Coord ox, oy; - - sel_debug("enter %p\n", dropable->obj); - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - dropable->last.in = EINA_TRUE; - - Drop_Format *df; - Efl_Dnd_Drag_Pos pos_data; - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy); - pos_data.item = NULL; - } - else - { - Eina_Position2D posret = {0, 0}; - Efl_Object *it = NULL; - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - pos_data.pos = posret; - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - } - else - { - sel_debug("both dropable & last_dropable are null\n"); - } - } -} - -static Sel_Manager_Dropable * -_x11_dropable_find(Efl_Ui_Selection_Manager_Data *pd, Ecore_X_Window win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!pd->drop_list) return NULL; - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (_x11_xwin_get(dropable->obj) == win) return dropable; - } - return NULL; -} - -static Evas * -_x11_evas_get_from_xwin(Efl_Ui_Selection_Manager_Data *pd, Ecore_X_Window win) -{ - /* Find the Evas connected to the window */ - Sel_Manager_Dropable *dropable = _x11_dropable_find(pd, win); - return dropable ? evas_object_evas_get(dropable->obj) : NULL; -} - -static Efl_Ui_Selection_Action -_x11_dnd_action_map(Ecore_X_Atom action) -{ - Efl_Ui_Selection_Action act = EFL_UI_SELECTION_ACTION_UNKNOWN; - - if (action == ECORE_X_ATOM_XDND_ACTION_COPY) - act = EFL_UI_SELECTION_ACTION_COPY; - else if (action == ECORE_X_ATOM_XDND_ACTION_MOVE) - act = EFL_UI_SELECTION_ACTION_MOVE; - else if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE) - act = EFL_UI_SELECTION_ACTION_PRIVATE; - else if (action == ECORE_X_ATOM_XDND_ACTION_ASK) - act = EFL_UI_SELECTION_ACTION_ASK; - else if (action == ECORE_X_ATOM_XDND_ACTION_LIST) - act = EFL_UI_SELECTION_ACTION_LIST; - else if (action == ECORE_X_ATOM_XDND_ACTION_LINK) - act = EFL_UI_SELECTION_ACTION_LINK; - else if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION) - act = EFL_UI_SELECTION_ACTION_DESCRIPTION; - return act; -} - -static Ecore_X_Atom -_x11_dnd_action_rev_map(Efl_Ui_Selection_Action action) -{ - Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE; - - if (action == EFL_UI_SELECTION_ACTION_COPY) - act = ECORE_X_ATOM_XDND_ACTION_COPY; - else if (action == EFL_UI_SELECTION_ACTION_MOVE) - act = ECORE_X_ATOM_XDND_ACTION_MOVE; - else if (action == EFL_UI_SELECTION_ACTION_PRIVATE) - act = ECORE_X_ATOM_XDND_ACTION_PRIVATE; - else if (action == EFL_UI_SELECTION_ACTION_ASK) - act = ECORE_X_ATOM_XDND_ACTION_ASK; - else if (action == EFL_UI_SELECTION_ACTION_LIST) - act = ECORE_X_ATOM_XDND_ACTION_LIST; - else if (action == EFL_UI_SELECTION_ACTION_LINK) - act = ECORE_X_ATOM_XDND_ACTION_LINK; - else if (action == EFL_UI_SELECTION_ACTION_DESCRIPTION) - act = ECORE_X_ATOM_XDND_ACTION_DESCRIPTION; - return act; -} - -static Eina_Bool -_x11_dnd_enter(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Enter *enter = ev; - Sel_Manager_Dropable *dropable; - int i; - - sel_debug("In"); - if (!enter) return EINA_TRUE; - dropable = _x11_dropable_find(pd, enter->win); - if (dropable) - { - sel_debug("Enter %x\n", enter->win); - } - /* Skip it */ - sel_debug("enter types=%p (%d)\n", enter->types, enter->num_types); - if ((!enter->num_types) || (!enter->types)) return EINA_TRUE; - - sel_debug("Types\n"); - seat_sel->saved_types->ntypes = enter->num_types; - free(seat_sel->saved_types->types); - seat_sel->saved_types->types = malloc(sizeof(char *) * enter->num_types); - if (!seat_sel->saved_types->types) return EINA_FALSE; - - for (i = 0; i < enter->num_types; i++) - { - seat_sel->saved_types->types[i] = eina_stringshare_add(enter->types[i]); - sel_debug("Type is %s %p %p\n", enter->types[i], - seat_sel->saved_types->types[i], pd->text_uri); - if (seat_sel->saved_types->types[i] == pd->text_uri) - { - /* Request it, so we know what it is */ - sel_debug("Sending uri request\n"); - seat_sel->saved_types->textreq = 1; - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - ecore_x_selection_xdnd_request(enter->win, pd->text_uri); - } - } - - /* FIXME: Find an object and make it current */ - return EINA_TRUE; -} - -static Eina_Bool -_x11_dnd_position(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Position *xpos = ev; - Ecore_X_Rectangle rect = { 0, 0, 0, 0 }; - Sel_Manager_Dropable *dropable; - Efl_Ui_Selection_Action act; - - sel_debug("In"); - /* Need to send a status back */ - /* FIXME: Should check I can drop here */ - /* FIXME: Should highlight widget */ - dropable = _x11_dropable_find(pd, xpos->win); - if (dropable) - { - Evas_Coord ox = 0, oy = 0; - Eina_Position2D pos; - - act = _x11_dnd_action_map(xpos->action); - pos.x = xpos->position.x; - pos.y = xpos->position.y; - _dropable_coords_adjust(dropable, &pos); - Evas *evas = _x11_evas_get_from_xwin(pd, xpos->win); - Eina_List *dropable_list = evas ? _dropable_list_geom_find(pd, evas, pos.x, pos.y) : NULL; - /* check if there is dropable (obj) can accept this drop */ - if (dropable_list) - { - Efl_Ui_Selection_Format saved_format = _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes); - Eina_List *l; - Eina_Bool found = EINA_FALSE; - - EINA_LIST_FOREACH(dropable_list, l, dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - Efl_Ui_Selection_Format common_fmt = saved_format & df->format; - if (common_fmt) - { - //We found a target that can accept this type of data - int i, min_index = SELECTION_N_ATOMS; - //We have to find the first atom that corresponds to one - //of the supported data types. - for (i = 0; i < seat_sel->saved_types->ntypes; i++) - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, seat_sel->saved_types->types[i]); - if (atom && (atom->format & common_fmt)) - { - int atom_idx = (atom - pd->atom_list); - if (min_index > atom_idx) min_index = atom_idx; - } - } - if (min_index != SELECTION_N_ATOMS) - { - sel_debug("Found atom %s\n", pd->atom_list[min_index].name); - found = EINA_TRUE; - dropable->last.type = pd->atom_list[min_index].name; - dropable->last.format = common_fmt; - break; - } - } - } - if (found) break; - } - if (found) - { - Sel_Manager_Dropable *d = NULL; - Eina_Rectangle inter_rect = {0, 0, 0, 0}; - int idx = 0; - EINA_LIST_FOREACH(dropable_list, l, d) - { - if (idx == 0) - { - evas_object_geometry_get(d->obj, &inter_rect.x, &inter_rect.y, - &inter_rect.w, &inter_rect.h); - } - else - { - Eina_Rectangle cur_rect; - evas_object_geometry_get(d->obj, &cur_rect.x, &cur_rect.y, - &cur_rect.w, &cur_rect.h); - if (!eina_rectangle_intersection(&inter_rect, &cur_rect)) continue; - } - idx++; - } - rect.x = inter_rect.x; - rect.y = inter_rect.y; - rect.width = inter_rect.w; - rect.height = inter_rect.h; - ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position %i %i %p\n", pos.x - ox, pos.y - oy, dropable); - pos.x = pos.x - ox; - pos.y = pos.y - oy; - _x11_dnd_dropable_handle(pd, dropable, pos, act); - // CCCCCCC: call dnd exit on last obj if obj != last - // CCCCCCC: call drop position on obj - } - else - { - //if not: send false status - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position (%d, %d) not in obj\n", pos.x, pos.y); - _x11_dnd_dropable_handle(pd, NULL, EINA_POSITION2D(0, 0), act); - // CCCCCCC: call dnd exit on last obj - } - eina_list_free(dropable_list); - } - else - { - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position (%d, %d) has no drop\n", pos.x, pos.y); - _x11_dnd_dropable_handle(pd, NULL, EINA_POSITION2D(0, 0), act); - } - } - else - { - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - } - return EINA_TRUE; -} - -static Eina_Bool -_x11_dnd_leave(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Eina_Position2D pos = {0, 0}; -#ifdef DEBUGON - sel_debug("Leave %x\n", ((Ecore_X_Event_Xdnd_Leave *)ev)->win); -#else - (void)ev; -#endif - _x11_dnd_dropable_handle(seat_sel->pd, NULL, pos, EFL_UI_SELECTION_ACTION_UNKNOWN); - // 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, int etype EINA_UNUSED, void *ev) -{ - sel_debug("In"); - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Drop *drop; - Sel_Manager_Dropable *dropable = NULL; - Evas_Coord x = 0, y = 0; - Efl_Ui_Selection_Action act = EFL_UI_SELECTION_ACTION_UNKNOWN; - Eina_List *l; - Sel_Manager_Selection *sel; - - drop = ev; - sel_debug("drop_list %p (%d)\n", pd->drop_list, eina_list_count(pd->drop_list)); - if (!(dropable = _x11_dropable_find(pd, drop->win))) return EINA_TRUE; - - /* Calculate real (widget relative) position */ - // - window position - // - widget position - seat_sel->saved_types->pos = EINA_POSITION2D(drop->position.x, drop->position.y); - _dropable_coords_adjust(dropable, &seat_sel->saved_types->pos); - - sel_debug("Drop position is %d,%d\n", seat_sel->saved_types->pos.x, seat_sel->saved_types->pos.y); - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->last.in) - { - evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL); - seat_sel->saved_types->pos.x -= x; - seat_sel->saved_types->pos.y -= y; - goto found; - } - } - - sel_debug("Didn't find a target\n"); - return EINA_TRUE; - -found: - sel_debug("0x%x\n", drop->win); - - act = _x11_dnd_action_map(drop->action); - - dropable->last.in = EINA_FALSE; - sel_debug("Last type: %s - Last format: %X\n", dropable->last.type, dropable->last.format); -#if 0 // this seems to be broken and causes dnd to stop working e.g. to/from - // rage even though iut used to work fine. - Efl_Ui_Selection_Data ddata; - Eina_Inlist *itr; - if ((!strcmp(dropable->last.type, pd->text_uri))) - { - sel_debug("We found a URI... (%scached) %s\n", - seat_sel->saved_types->imgfile ? "" : "not ", - seat_sel->saved_types->imgfile); - if (seat_sel->saved_types->imgfile) - { - Drop_Format *df; - - if (!dropable->is_container) - { - ddata.pos = seat_sel->saved_types->pos; - ddata.item = NULL; - } - else - { - //for container - Efl_Object *it = NULL; - Evas_Coord x0 = 0, y0 = 0; - Eina_Position2D pos, posret = {0, 0}; - - evas_object_geometry_get(dropable->obj, &x0, &y0, NULL, NULL); - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + x0, - seat_sel->saved_types->pos.y + y0); - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - ddata.action = act; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - sel_debug("Doing image insert (%s)\n", seat_sel->saved_types->imgfile); - ddata.format = EFL_UI_SELECTION_FORMAT_IMAGE; - ddata.content.mem = (char *)seat_sel->saved_types->imgfile; - ddata.content.len = strlen(ddata.content.mem); - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - else - { - sel_debug("Item doesn't support images... passing\n"); - } - } - ecore_x_dnd_send_finished(); - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - return EINA_TRUE; - } - else if (seat_sel->saved_types->textreq) - { - /* Already asked: Pretend we asked now, and paste immediately when - * it comes in */ - seat_sel->saved_types->textreq = 0; - ecore_x_dnd_send_finished(); - return EINA_TRUE; - } - } -#endif - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_DND; - sel_debug("doing a request then: %s\n", dropable->last.type); - sel->xwin = drop->win; - sel->request_obj = dropable->obj; - sel->request_format = dropable->last.format; - sel->active = EINA_TRUE; - sel->action = act; - sel->asked++; - ecore_x_selection_xdnd_request(drop->win, dropable->last.type); - - return EINA_TRUE; -} - -static Eina_Bool -_x11_sel_manager_drop_target_add(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *target_obj, - Efl_Ui_Selection_Format format, Ecore_X_Window xwin, - unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Eina_List *l; - Eina_Bool have_drop_list = EINA_FALSE; - Sel_Manager_Seat_Selection *seat_sel = NULL; - - /* Is this the first? */ - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - dropable = NULL; // In case of error, we don't want to free it - - - Drop_Format *df = calloc(1, sizeof(Drop_Format)); - if (!df) return EINA_FALSE; - df->format = format; - - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (!dropable) - { - /* Create new drop */ - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) goto error; - dropable->last.in = EINA_FALSE; - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) goto error; - dropable->obj = target_obj; - efl_key_data_set(target_obj, "__elm_dropable", dropable); - } - dropable->format_list = eina_inlist_append(dropable->format_list, EINA_INLIST_GET(df)); - dropable->seat = seat; - - evas_object_event_callback_add(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del, pd); - if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_TRUE); - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - - if (seat_sel->enter_handler) return EINA_TRUE; - sel_debug("Adding drop target calls xwin=%#llx", (unsigned long long)xwin); - seat_sel->enter_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER, - _x11_dnd_enter, seat_sel); - seat_sel->leave_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE, - _x11_dnd_leave, seat_sel); - seat_sel->pos_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION, - _x11_dnd_position, seat_sel); - seat_sel->drop_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP, - _x11_dnd_drop, seat_sel); - return EINA_TRUE; -error: - free(df); - free(dropable); - return EINA_FALSE; -} - -#endif - -//Wayland -#ifdef HAVE_ELEMENTARY_WL2 -static Sel_Manager_Seat_Selection * -_wl_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } - - return seat_sel; -} - -static void -_wl_drag_source_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - if (seat_sel->drag_obj == obj) - seat_sel->drag_obj = NULL; -} - -static void -_wl_efl_sel_manager_drag_start(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, Efl_Object *drag_obj, - Efl_Ui_Selection_Format format, Eina_Slice data, - Efl_Ui_Selection_Action action, void *icon_func_data, - Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb EINA_UNUSED, - Ecore_Wl2_Window *win, unsigned int seat) -{ - Ecore_Evas *ee; - Evas_Object *icon = NULL; - int x, y, x2 = 0, y2 = 0, x3, y3, w = 0, h = 0; - const char *types[SELECTION_N_ATOMS + 1]; - int i, nb_types = 0; - Ecore_Wl2_Window *parent = NULL; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - sel_debug("In"); - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return; - seat_sel->active_type = EFL_UI_SELECTION_TYPE_DND; - sel = seat_sel->sel; - - sel_debug("checking drag_win: %p", seat_sel->drag_win); - /* if we already have a drag, get out */ - if (seat_sel->drag_win) return; - - for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++) - { - if (format == EFL_UI_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format)) - { - types[nb_types++] = pd->atom_list[i].name; - sel_debug("set dnd type: %s\n", pd->atom_list[i].name); - } - } - types[nb_types] = NULL; - - ecore_wl2_dnd_drag_types_set(_wl_seat_get(win, drag_obj, seat), types); - - /* set the drag data used when a drop occurs */ - free(sel->data.mem); - sel->data.len = 0; - sel->data = eina_slice_dup(data); - - /* setup callback to notify if this object gets deleted */ - evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL, - _wl_drag_source_del, sel); - - seat_sel->drag_obj = drag_obj; - seat_sel->drag_action = action; - - seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); - elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE); - elm_win_borderless_set(seat_sel->drag_win, EINA_TRUE); - elm_win_override_set(seat_sel->drag_win, EINA_TRUE); - - win = elm_win_wl_window_get(seat_sel->drag_win); - - if (icon_func) - { - Eina_Position2D off; - - icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off); - if (icon) - { - x2 = off.x; - y2 = off.y; - evas_object_geometry_get(icon, NULL, NULL, &w, &h); - } - } - else - { - icon = elm_icon_add(seat_sel->drag_win); - evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, - EVAS_HINT_EXPAND); - } - - elm_win_resize_object_add(seat_sel->drag_win, icon); - evas_object_show(icon); - - /* Position subwindow appropriately */ - ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj)); - ecore_evas_geometry_get(ee, &x, &y, NULL, NULL); - x += x2; - y += y2; - seat_sel->drag_win_start.x = seat_sel->drag_win_end.x = x; - seat_sel->drag_win_start.y = seat_sel->drag_win_end.y = y; - - evas_object_geometry_set(seat_sel->drag_win, x, y, w, h); - evas_object_show(seat_sel->drag_win); - - evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3); - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - - if (elm_widget_is(drag_obj)) - { - Evas_Object *top; - - top = elm_widget_top_get(drag_obj); - if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(drag_obj)); - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - parent = elm_win_wl_window_get(top); - } - if (!parent) - { - Evas *evas; - - if (!(evas = evas_object_evas_get(drag_obj))) - return; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return; - - parent = ecore_evas_wayland2_window_get(ee); - } - - sel->drag_serial = ecore_wl2_dnd_drag_start(_wl_seat_get(win, drag_obj, seat), parent, win); -} - -static Eina_Bool -_wl_is_uri_type_data(const char *data, int len) -{ - char *p; - if (len < 6) return EINA_FALSE; - - p = (char *)data; - if (!p) return EINA_FALSE; - if (strncmp(p, "file:/", 6)) - { - if (*p != '/') return EINA_FALSE; - } - return EINA_TRUE; -} - -static Efl_Ui_Selection_Action -_wl_to_elm(Ecore_Wl2_Drag_Action action) -{ - #define CONV(wl, elm) if (action == wl) return elm; - CONV(ECORE_WL2_DRAG_ACTION_COPY, EFL_UI_SELECTION_ACTION_COPY); - CONV(ECORE_WL2_DRAG_ACTION_MOVE, EFL_UI_SELECTION_ACTION_MOVE); - CONV(ECORE_WL2_DRAG_ACTION_ASK, EFL_UI_SELECTION_ACTION_ASK); - #undef CONV - return EFL_UI_SELECTION_ACTION_UNKNOWN; -} - -static Eina_Bool -_wl_targets_converter(char *target, Sel_Manager_Selection *sel, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret, int *size_ret) -{ - sel_debug("in\n"); - if (!data_ret) return EINA_FALSE; - - const char *sep = "\n"; - char *aret; - int len = 0; - int i = 0; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Eina_Bool is_uri = EINA_FALSE; - - if (sel->format) - { - format = sel->format; - is_uri = _wl_is_uri_type_data(sel->data.mem, sel->data.len); - } - else - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - } - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - len += strlen(pd->atom_list[i].name) + strlen(sep); - } - } - len++; //terminating null byte - aret = calloc(1, len * sizeof(char)); - if (!aret) return EINA_FALSE; - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - { - aret = strcat(aret, pd->atom_list[i].name); - aret = strcat(aret, sep); - } - } - } - *data_ret = aret; - if (size_ret) *size_ret = len; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_general_converter(char *target, Sel_Manager_Selection *sel, void *data, int size, void **data_ret, int *size_ret) -{ - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Sel_Manager_Atom *atom = NULL; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - sel_debug("in\n"); - - atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - if (format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(size * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, size); - ((char**)(data_ret))[0][size] = 0; - } - if (size_ret) *size_ret = size; - } - else - { - if ((data) && (size > 0)) - { - char *tmp = malloc(size); - if (tmp) - { - memcpy(tmp, data, size); - if (data_ret) *data_ret = tmp; - if (size_ret) *size_ret = size; - if (!data_ret) free(tmp); - } - } - else - { - if (data_ret) *data_ret = NULL; - if (size_ret) *size_ret = 0; - } - } - - return EINA_TRUE; -} - -static Eina_Bool -_wl_text_converter(char *target, Sel_Manager_Selection *sel, void *data, int size, void **data_ret, int *size_ret) -{ - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Sel_Manager_Atom *atom = NULL; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - sel_debug("in\n"); - - atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - if (format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(size * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, size); - ((char**)(data_ret))[0][size] = 0; - if (size_ret) *size_ret = size; - return EINA_TRUE; - } - } - else if ((format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *tmp = malloc(size + 1); - if (tmp) - { - strncpy(tmp, data, size); - tmp[size] = 0; - *data_ret = _elm_util_mkup_to_text(tmp); - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - free(tmp); - } - else return EINA_FALSE; - } - else if (format & EFL_UI_SELECTION_FORMAT_TEXT) - { - char *tmp = malloc(size + 1); - if (tmp) - { - strncpy(tmp, data, size); - tmp[size] = 0; - *data_ret = tmp; - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - } - else return EINA_FALSE; - } - else if (format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - sel_debug("Image %s\n", evas_object_type_get(sel->request_obj)); - efl_file_simple_get(sel->request_obj, (const char **)data_ret, NULL); - if (!*data_ret) *data_ret = strdup("No file"); - else *data_ret = strdup(*data_ret); - - if (!*data_ret) - { - ERR("Failed to allocate memory!"); - *size_ret = 0; - return EINA_FALSE; - } - - if (size_ret) *size_ret = strlen(*data_ret); - } - return EINA_TRUE; -} - -static void -_wl_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) - { - sel->owner = NULL; - } - //if (dragwidget == obj) dragwidget = NULL; -} - -static Eina_Future * -_wl_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Wl2_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - int i = 0, count = 0; - Eina_Bool is_uri = EINA_FALSE; - const char **types; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - - if (data.len <= 0) - return NULL; - - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel; - - if (sel->owner != owner) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - } - - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _wl_sel_obj_del, sel); - sel->active = EINA_TRUE; - sel->owner = owner; - sel->win = win; - /* sel->set(win, &selection, sizeof(Elm_Sel_Type)); */ - sel->format = format; - - evas_object_event_callback_add - (sel->owner, EVAS_CALLBACK_DEL, _wl_sel_obj_del, &sel); - - sel->data = eina_slice_dup(data); - if (!sel->data.mem) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - is_uri = _wl_is_uri_type_data(sel->data.mem, sel->data.len); - types = malloc(sizeof(char *)); - if (!types) return NULL; - for (i = 0, count = 1; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - { - const char **t = NULL; - - types[count - 1] = pd->atom_list[i].name; - count++; - t = realloc(types, sizeof(char *) * count); - if (!t) - { - free(types); - return NULL; - } - types = t; - } - } - } - types[count - 1] = 0; - - sel->selection_serial = ecore_wl2_dnd_selection_set(_wl_seat_get(win, owner, seat_sel->seat), types); - DBG("serial: %d", sel->selection_serial); - - free(types); - //return _local_elm_cnp_selection_set(obj, selection, format, buf, buflen); - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_wl_selection_changed_free(void *data, void *ev) -{ - ecore_wl2_display_disconnect(data); - - free(ev); -} - -static Eina_Bool -_wl_selection_changed(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Elm_Cnp_Event_Selection_Changed *_e; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Efl_Ui_Selection_Changed e; - Ecore_Wl2_Event_Seat_Selection *ev = event; - Ecore_Wl2_Input *seat; - - seat_sel = _wl_sel_manager_seat_selection_init(pd, ev->seat); - sel_debug("seat: %d", ev->seat); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel; - - seat = ecore_wl2_display_input_find(ev->display, ev->seat); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, ECORE_CALLBACK_RENEW); - e.type = EFL_UI_SELECTION_TYPE_CLIPBOARD; - e.seat = ev->seat; - /* connect again to add ref */ - e.display = ecore_wl2_display_connect(ecore_wl2_display_name_get(ev->display)); - e.exist = !!ecore_wl2_dnd_selection_get(seat); - - _e = calloc(1, sizeof(Elm_Cnp_Event_Selection_Changed)); - EINA_SAFETY_ON_NULL_RETURN_VAL(_e, ECORE_CALLBACK_RENEW); - _e->type = e.type; - _e->seat_id = e.seat; - _e->display = e.display; - _e->exists = e.exist; - - ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, _e, _wl_selection_changed_free, ev->display); - efl_event_callback_call(sel->request_obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &e); - - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_wl_selection_send(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - char *buf; - int ret, len_remained; - int len_written = 0; - Ecore_Wl2_Event_Data_Source_Send *ev; - int seat; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - void *data_ret = NULL; - int len_ret = 0; - int i = 0; - - ev = event; - seat = ev->seat; - sel_debug("seat: %d, type: %d", seat, type); - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel; - - if ((ev->serial != sel->selection_serial) && - (ev->serial != sel->drag_serial)) - return ECORE_CALLBACK_RENEW; - - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (!strcmp(pd->atom_list[i].name, ev->type)) - { - sel_debug("Found a type: %s\n", pd->atom_list[i].name); - Sel_Manager_Dropable *drop; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) - drop->last.type = pd->atom_list[i].name; - if (pd->atom_list[i].wl_converter) - { - pd->atom_list[i].wl_converter(ev->type, sel, sel->data.mem, - sel->data.len, &data_ret, &len_ret); - } - else - { - data_ret = eina_memdup(sel->data.mem, sel->data.len, 0); - len_ret = sel->data.len; - } - break; - } - } - - len_remained = len_ret; - buf = data_ret; - - while (len_written < len_ret) - { - ret = write(ev->fd, buf, len_remained); - if (ret == -1) break; - buf += ret; - len_written += ret; - len_remained -= ret; - } - free(data_ret); - - close(ev->fd); - ecore_wl2_display_flush(ev->display); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_end(void *data, int type EINA_UNUSED, void *event) -{ - sel_debug("In"); - Efl_Ui_Selection_Manager_Data *pd = data; - Ecore_Wl2_Event_Data_Source_End *ev; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - ev = event; - seat_sel = _wl_sel_manager_seat_selection_init(pd, ev->seat); - sel = seat_sel->sel; - if (ev->serial != sel->drag_serial) - return ECORE_CALLBACK_RENEW; - - if (seat_sel->active_type != EFL_UI_SELECTION_TYPE_DND) - return ECORE_CALLBACK_RENEW; - - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL); - if (seat_sel->drag_win) - { - if (!seat_sel->accept) - { - /* Commit animation when drag cancelled */ - /* Record final position of dragwin, then do animation */ - ecore_evas_animator_timeline_add(seat_sel->drag_win, 0.3, _drag_cancel_animate, seat_sel); - } - else - { - /* No animation drop was committed */ - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - } - } - - seat_sel->accept = EINA_FALSE; - - ecore_wl2_display_flush(ev->display); - return ECORE_CALLBACK_PASS_ON; -} - -static Ecore_Wl2_Input * -_wl_seat_get(Ecore_Wl2_Window *win, Evas_Object *obj, unsigned int seat_id) -{ - Eo *seat, *parent2, *ewin; - Ecore_Wl2_Input *input = NULL; - - input = ecore_wl2_display_input_find(ecore_wl2_window_display_get(win), seat_id); - if (input) return input; - - if (obj) - { - // FIXME (there might be a better solution): - // In case of inwin, we want to use the main wl2 window for cnp, but obj - // obj belongs to the buffer canvas, so the default seat for obj does not - // match the window win. - Eo *top = elm_widget_top_get(obj); - if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS)) - { - parent2 = efl_ui_win_inlined_parent_get(top); - if (parent2) obj = elm_widget_top_get(parent2) ?: parent2; - } - /* fake win means canvas seat id will not match protocol seat id */ - ewin = elm_win_get(obj); - if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL; - } - - if (!obj) - { - Eina_Iterator *it; - it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win)); - EINA_ITERATOR_FOREACH(it, input) break; - eina_iterator_free(it); - return input; - } - - seat = evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, NULL); - return ecore_wl2_display_input_find(ecore_wl2_window_display_get(win), - evas_device_seat_id_get(seat)); -} - -Ecore_Wl2_Window * -_wl_window_get(const Evas_Object *obj) -{ - Evas_Object *top; - Ecore_Wl2_Window *win = NULL; - - if (elm_widget_is(obj)) - { - top = elm_widget_top_get(obj); - if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj)); - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - win = elm_win_wl_window_get(top); - } - if (!win) - { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; - - if (!(evas = evas_object_evas_get(obj))) - return NULL; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return NULL; - - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - engine_name = ecore_evas_engine_name_get(ee); - } - if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1)) - { - /* In case the engine is not a buffer, we want to check once. */ - win = ecore_evas_wayland2_window_get(ee); - if (!win) return NULL; - } - } - - return win; -} - -static void -_wl_selection_receive_timeout(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - - if (sel->request_obj != obj) return; - - ecore_event_handler_del(sel->offer_handler); -} - -static Eina_Bool -_wl_selection_receive(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Offer_Data_Ready *ev = event; - Sel_Manager_Selection *sel = data; - - if (sel->sel_offer != ev->offer) return ECORE_CALLBACK_PASS_ON; - - if (sel->data_func) - { - Efl_Ui_Selection_Data sel_data; - - sel_data.pos.x = sel_data.pos.y = 0; - if (((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) && - (sel->want_format == EFL_UI_SELECTION_FORMAT_TEXT)) - { - char *tmp = malloc(ev->len + 1); - sel_data.format = sel->format; - sel_data.content.mem = NULL; - sel_data.content.len = 0; - if (tmp) - { - sel_data.format = sel->want_format; - strncpy(tmp, ev->data, ev->len); - tmp[ev->len] = 0; - sel_data.content.mem = _elm_util_mkup_to_text(tmp); - if (sel_data.content.mem) - sel_data.content.len = strlen(sel_data.content.mem); - free(tmp); - } - } - else - { - sel_data.format = sel->format; - sel_data.content.mem = ev->data; - sel_data.content.len = ev->len; - } - sel_data.action = _wl_to_elm(ecore_wl2_offer_action_get(sel->sel_offer)); - sel->data_func(sel->data_func_data, - sel->request_obj, - &sel_data); - } - else - { - char *stripstr, *mkupstr; - - stripstr = malloc(ev->len + 1); - if (!stripstr) return ECORE_CALLBACK_CANCEL; - strncpy(stripstr, (char *)ev->data, ev->len); - stripstr[ev->len] = '\0'; - mkupstr = _elm_util_text_to_mkup((const char *)stripstr); - /* TODO BUG: should never NEVER assume it's an elm_entry! */ - _elm_entry_entry_paste(sel->request_obj, mkupstr); - free(stripstr); - free(mkupstr); - } - - evas_object_event_callback_del_full(sel->request_obj, - EVAS_CALLBACK_DEL, - _wl_selection_receive_timeout, sel); - - ecore_event_handler_del(sel->offer_handler); - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_wl_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_Wl2_Window *win, unsigned int seat) -{ - sel_debug("In, format: %d", format); - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Wl2_Input *input; - Ecore_Wl2_Offer *offer; - int i = 0; - - if (type == EFL_UI_SELECTION_TYPE_DND) return EINA_FALSE; - - //if (sel->active) - //return _local_elm_cnp_selection_get(obj, selection, format, datacb, udata); - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - - input = _wl_seat_get(win, (Efl_Object *)request, seat_sel->seat); - offer = ecore_wl2_dnd_selection_get(input); - - //there can be no selection available - if (!offer) return EINA_FALSE; - - for (i = 0; sm_wl_convertion[i].translates; i++) - { - int j = 0; -// if (!(format & sm_wl_convertion[i].format)) continue; - - for (j = 0; sm_wl_convertion[i].translates[j]; j++) - { - if (!ecore_wl2_offer_supports_mime(offer, sm_wl_convertion[i].translates[j])) continue; - - //we have found matching mimetypes - sel->sel_offer = offer; - sel->format = sm_wl_convertion[i].format; - sel->want_format = format; - - sel_debug("request type: %s", (char *)sm_wl_convertion[i].translates[j]); - evas_object_event_callback_add(sel->request_obj, EVAS_CALLBACK_DEL, - _wl_selection_receive_timeout, sel); - sel->offer_handler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, - _wl_selection_receive, sel); - - ecore_wl2_offer_receive(offer, (char*)sm_wl_convertion[i].translates[j]); - ecore_wl2_display_flush(ecore_wl2_input_display_get(input)); - return EINA_TRUE; - } - } - - sel_debug("no type match"); - return EINA_FALSE; -} - -static void -_wl_sel_obj_del2(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static Sel_Manager_Dropable * -_wl_dropable_find(Efl_Ui_Selection_Manager_Data *pd, Ecore_Wl2_Window *win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!pd->drop_list) return NULL; - - if (!win) return NULL; - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - if (_wl_window_get(dropable->obj) == win) - return dropable; - - return NULL; -} - -static Evas * -_wl_evas_get_from_win(Efl_Ui_Selection_Manager_Data *pd, Ecore_Wl2_Window *win) -{ - Sel_Manager_Dropable *dropable = _wl_dropable_find(pd, win); - return dropable ? evas_object_evas_get(dropable->obj) : NULL; -} - -static Eina_Bool -_wl_drops_accept(Sel_Manager_Seat_Selection *seat_sel, const char *type) -{ - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Selection *sel; - Eina_List *l; - Sel_Manager_Dropable *drop; - Eina_Bool will_accept = EINA_FALSE; - - if (!type) return EINA_FALSE; - - pd = seat_sel->pd; - sel = seat_sel->sel; - EINA_LIST_FOREACH(pd->drop_list, l, drop) - { - Drop_Format *df; - EINA_INLIST_FOREACH(drop->format_list, df) - { - for (int i = 0; sm_wl_convertion[i].translates ; ++i) - { - if (!(sm_wl_convertion[i].format & df->format)) continue; - - for (int j = 0; sm_wl_convertion[i].translates[j]; ++j) - { - if (!strncmp(type, sm_wl_convertion[i].translates[j], strlen(sm_wl_convertion[i].translates[j]))) - { - sel->request_obj = drop->obj; - return EINA_TRUE; - } - } - } - } - } - - return will_accept; -} - -static void -_wl_selection_parser(void *_data, int size, char ***ret_data, int *ret_count) -{ - char **files = NULL; - int num_files = 0; - char *data = NULL; - - data = malloc(size); - if (data && (size > 0)) - { - int i, is; - char *tmp; - char **t2; - - memcpy(data, _data, size); - if (data[size - 1]) - { - char *t; - - /* Isn't nul terminated */ - size++; - t = realloc(data, size); - if (!t) goto done; - data = t; - data[size - 1] = 0; - } - - tmp = malloc(size); - if (!tmp) goto done; - i = 0; - is = 0; - while ((is < size) && (data[is])) - { - if ((i == 0) && (data[is] == '#')) - for (; ((data[is]) && (data[is] != '\n')); is++) ; - else - { - if ((data[is] != '\r') && (data[is] != '\n')) - tmp[i++] = data[is++]; - else - { - while ((data[is] == '\r') || (data[is] == '\n')) - is++; - tmp[i] = 0; - num_files++; - t2 = realloc(files, num_files * sizeof(char *)); - if (t2) - { - files = t2; - files[num_files - 1] = strdup(tmp); - } - else - { - num_files--; - goto freetmp; - } - tmp[0] = 0; - i = 0; - } - } - } - if (i > 0) - { - tmp[i] = 0; - num_files++; - t2 = realloc(files, num_files * sizeof(char *)); - if (t2) - { - files = t2; - files[num_files - 1] = strdup(tmp); - } - else - { - num_files--; - goto freetmp; - } - } -freetmp: - free(tmp); - } -done: - free(data); - if (ret_data) *ret_data = files; - else - { - int i; - - for (i = 0; i < num_files; i++) free(files[i]); - free(files); - } - if (ret_count) *ret_count = num_files; -} - -static Eina_Bool -_wl_data_preparer_markup(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_MARKUP; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_uri(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel; - char *p, *stripstr = NULL; - char *data = ev->data; - Sel_Manager_Dropable *drop; - const char *type = NULL; - - sel_debug("In\n"); - - seat_sel = sel->seat_sel; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) type = drop->last.type; - - if ((type) && (!strcmp(type, "text/uri-list"))) - { - int num_files = 0; - char **files = NULL; - Efreet_Uri *uri; - Eina_Strbuf *strbuf; - int i; - - strbuf = eina_strbuf_new(); - if (!strbuf) return EINA_FALSE; - - _wl_selection_parser(ev->data, ev->len, &files, &num_files); - sel_debug("got a files list\n"); - - for (i = 0; i < num_files; i++) - { - uri = efreet_uri_decode(files[i]); - if (uri) - { - eina_strbuf_append(strbuf, uri->path); - efreet_uri_free(uri); - } - else - { - eina_strbuf_append(strbuf, files[i]); - } - if (i < (num_files - 1)) - eina_strbuf_append(strbuf, "\n"); - free(files[i]); - } - free(files); - stripstr = eina_strbuf_string_steal(strbuf); - eina_strbuf_free(strbuf); - } - else - { - Efreet_Uri *uri; - - p = (char *)eina_memdup((unsigned char *)data, ev->len, EINA_TRUE); - if (!p) return EINA_FALSE; - uri = efreet_uri_decode(p); - if (!uri) - { - /* Is there any reason why we care of URI without scheme? */ - if (p[0] == '/') stripstr = p; - else free(p); - } - else - { - free(p); - stripstr = strdup(uri->path); - efreet_uri_free(uri); - } - } - - if (!stripstr) - { - sel_debug("Couldn't find a file\n"); - return EINA_FALSE; - } - free(seat_sel->saved_types->imgfile); - - ddata->content.mem = stripstr; - ddata->content.len = strlen(stripstr); - ddata->action = sel->action; - ddata->format = sel->request_format; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_vcard(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_VCARD; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_image(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info) -{ - sel_debug("In\n"); - Tmp_Info *tmp; - int len = 0; - - tmp = _tempfile_new(ev->len); - if (!tmp) - return EINA_FALSE; - memcpy(tmp->map, ev->data, ev->len); - munmap(tmp->map, ev->len); - - len = strlen(tmp->filename); - ddata->format = EFL_UI_SELECTION_FORMAT_IMAGE; - ddata->content.mem = eina_memdup((unsigned char*)tmp->filename, len, EINA_TRUE); - ddata->content.len = len; - ddata->action = sel->action; - *tmp_info = tmp; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_text(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - - -static void -_wl_dropable_handle(Sel_Manager_Seat_Selection *seat_sel, Sel_Manager_Dropable *dropable, Evas_Coord x, Evas_Coord y) -{ - Sel_Manager_Dropable *d, *last_dropable = NULL; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Sel_Manager_Selection *sel; - Eina_Inlist *itr; - Eina_List *l; - Eina_Position2D pos; - - EINA_LIST_FOREACH(pd->drop_list, l, d) - { - if (d->last.in) - { - last_dropable = d; - break; - } - } - - sel = seat_sel->sel; - pos = EINA_POSITION2D(x, y); - /* If we are on the same object, just update the position */ - if ((dropable) && (last_dropable == dropable)) - { - Evas_Coord ox, oy; - Efl_Dnd_Drag_Pos pos_data; - Drop_Format *df; - - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(x - ox, y - oy); - pos_data.item = NULL; - } - else - { - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &pos_data.pos); - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = sel->action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - - return; - } - /* We leave the last dropable */ - if (last_dropable) - { - Drop_Format *df; - sel_debug("leave %p\n", last_dropable->obj); - last_dropable->last.in = EINA_FALSE; - - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - /* We enter the new dropable */ - if (dropable) - { - sel_debug("enter %p\n", dropable->obj); - Evas_Coord ox, oy; - Efl_Dnd_Drag_Pos pos_data; - Drop_Format *df; - - dropable->last.in = EINA_TRUE; - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(x - ox, y - oy); - pos_data.item = NULL; - } - else - { - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &pos_data.pos); - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = sel->action; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - } -} - -static void -_wl_dropable_all_clean(Sel_Manager_Seat_Selection *seat_sel, Ecore_Wl2_Window *win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!win) return; - - EINA_LIST_FOREACH(seat_sel->pd->drop_list, l, dropable) - { - if (_wl_window_get(dropable->obj) == win) - { - dropable->last.pos.x = 0; - dropable->last.pos.y = 0; - dropable->last.in = EINA_FALSE; - } - } -} - -static void -_wl_dropable_data_handle(Sel_Manager_Selection *sel, Ecore_Wl2_Event_Offer_Data_Ready *ev) -{ - Sel_Manager_Seat_Selection *seat_sel; - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Dropable *drop; - Ecore_Wl2_Window *win; - - sel_debug("In\n"); - seat_sel = sel->seat_sel; - pd = seat_sel->pd; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) - { - Sel_Manager_Atom *atom = NULL; - - atom = eina_hash_find(pd->type_hash, drop->last.type); - if (atom && atom->wl_data_preparer) - { - Efl_Ui_Selection_Data ddata; - Tmp_Info *tmp_info = NULL; - Eina_Bool success; - - sel_debug("Call notify for: %s\n", atom->name); - success = atom->wl_data_preparer(sel, &ddata, ev, &tmp_info); - if (success) - { - Sel_Manager_Dropable *dropable; - Eina_List *l; - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->obj == sel->request_obj) break; - dropable = NULL; - } - if (dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - if (!dropable->is_container) - { - ddata.pos.x = seat_sel->saved_types->pos.x; - ddata.pos.y = seat_sel->saved_types->pos.y; - } - else - { - //for container - Efl_Object *it = NULL; - Evas_Coord x0 = 0, y0 = 0; - Eina_Position2D pos, posret = {}; - - evas_object_geometry_get(dropable->obj, &x0, &y0, NULL, NULL); - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + x0, - seat_sel->saved_types->pos.y + y0); - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - ddata.action = seat_sel->drag_action; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - } - } - win = _wl_window_get(sel->request_obj); - ecore_wl2_dnd_drag_end(_wl_seat_get(win, NULL, seat_sel->seat)); - if (tmp_info) _tmpinfo_free(tmp_info); - return; - } - } - - win = _wl_window_get(sel->request_obj); - ecore_wl2_dnd_drag_end(_wl_seat_get(win, NULL, seat_sel->seat)); - seat_sel->saved_types->textreq = 0; -} - -static Eina_Bool -_wl_dnd_enter(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Enter *ev; - Eina_Array *known, *available; - Sel_Manager_Seat_Selection *seat_sel = data; - unsigned int i = 0; - - ev = event; - - available = ecore_wl2_offer_mimes_get(ev->offer); - - free(seat_sel->saved_types->types); - - seat_sel->saved_types->ntypes = eina_array_count(available); - seat_sel->saved_types->types = malloc(sizeof(char *) * seat_sel->saved_types->ntypes); - if (!seat_sel->saved_types->types) return EINA_FALSE; - - known = eina_array_new(5); - - for (i = 0; i < eina_array_count(available); i++) - { - seat_sel->saved_types->types[i] = - eina_stringshare_add(eina_array_data_get(available, i)); - if (seat_sel->saved_types->types[i] == seat_sel->pd->text_uri) - { - seat_sel->saved_types->textreq = 1; - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - } - } - - seat_sel->accept = EINA_FALSE; - for (i = 0; i < eina_array_count(available); i++) - { - if (_wl_drops_accept(seat_sel, eina_array_data_get(available, i))) - { - eina_array_push(known, strdup(eina_array_data_get(available, i))); - } - } - - ecore_wl2_offer_mimes_set(ev->offer, known); - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_leave(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Leave *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Dropable *drop; - sel_debug("In\n"); - - ev = event; - if ((drop = _wl_dropable_find(seat_sel->pd, ev->win))) - { - _wl_dropable_handle(seat_sel, NULL, 0, 0); - _wl_dropable_all_clean(seat_sel, ev->win); - } - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_position(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Motion *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Sel_Manager_Dropable *drop; - Eina_Bool will_accept = EINA_FALSE; - - ev = event; - - sel_debug("mouse pos %i %i\n", ev->x, ev->y); - seat_sel->drag_win_end.x = ev->x - seat_sel->drag_pos.x; - seat_sel->drag_win_end.y = ev->y - seat_sel->drag_pos.y; - - drop = _wl_dropable_find(pd, ev->win); - - if (drop) - { - Eina_Position2D pos = EINA_POSITION2D(ev->x, ev->y); - Evas *evas = NULL; - Eina_List *dropable_list = NULL; - - _dropable_coords_adjust(drop, &pos); - evas = _wl_evas_get_from_win(pd, ev->win); - if (evas) - dropable_list = _dropable_list_geom_find(pd, evas, pos.x, pos.y); - - /* check if there is dropable (obj) can accept this drop */ - if (dropable_list) - { - Efl_Ui_Selection_Format saved_format; - Eina_List *l; - Eina_Bool found = EINA_FALSE; - Sel_Manager_Dropable *dropable = NULL; - - saved_format = - _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes); - - EINA_LIST_FOREACH(dropable_list, l, dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - Efl_Ui_Selection_Format common_fmt = saved_format & df->format; - - if (common_fmt) - { - /* We found a target that can accept this type of data */ - int i, min_index = SELECTION_N_ATOMS; - - /* We have to find the first atom that corresponds to one - * of the supported data types. */ - for (i = 0; i < seat_sel->saved_types->ntypes; i++) - { - Sel_Manager_Atom *atom; - - atom = eina_hash_find(pd->type_hash, - seat_sel->saved_types->types[i]); - - if (atom && (atom->format & common_fmt)) - { - int atom_idx = (atom - pd->atom_list); - - if (min_index > atom_idx) - min_index = atom_idx; - } - } - if (min_index != SELECTION_N_ATOMS) - { - sel_debug("Found atom %s\n", pd->atom_list[min_index].name); - found = EINA_TRUE; - dropable->last.type = pd->atom_list[min_index].name; - dropable->last.format = common_fmt; - break; - } - } - } - if (found) break; - } - if (found) - { - Sel_Manager_Selection *sel = seat_sel->sel; - Evas_Coord ox = 0, oy = 0; - - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - - sel_debug("Candidate %p (%s)\n", - dropable->obj, efl_class_name_get(efl_class_get(dropable->obj))); - _wl_dropable_handle(seat_sel, dropable, pos.x - ox, pos.y - oy); - sel->request_obj = dropable->obj; - will_accept = EINA_TRUE; - } - else - { - //if not: send false status - sel_debug("dnd position (%d, %d) not in obj\n", pos.x, pos.y); - _wl_dropable_handle(seat_sel, NULL, 0, 0); - // CCCCCCC: call dnd exit on last obj - } - eina_list_free(dropable_list); - } - } - - seat_sel->accept = will_accept; - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept); - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_receive(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Offer_Data_Ready *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Selection *sel; - Ecore_Wl2_Offer *offer; - sel_debug("In\n"); - - ev = event; - sel = seat_sel->sel; - offer = sel->dnd_offer; - - if (offer != ev->offer) return ECORE_CALLBACK_PASS_ON; - - if (sel->request_obj) - { - Ecore_Wl2_Drag_Action action; - - action = ecore_wl2_offer_action_get(ev->offer); - if (action == ECORE_WL2_DRAG_ACTION_ASK) - ecore_wl2_offer_actions_set(ev->offer, ECORE_WL2_DRAG_ACTION_COPY, ECORE_WL2_DRAG_ACTION_COPY); - action = ecore_wl2_offer_action_get(ev->offer); - sel->action = _wl_to_elm(action); - - _wl_dropable_data_handle(sel, ev); - evas_object_event_callback_del_full(sel->request_obj, - EVAS_CALLBACK_DEL, - _wl_sel_obj_del2, sel); - sel->request_obj = NULL; - } - - ecore_wl2_offer_finish(ev->offer); - - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_wl_dnd_drop(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Drop *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Selection *sel; - Sel_Manager_Dropable *drop; - Eina_List *l; - - sel_debug("In\n"); - ev = event; - seat_sel->saved_types->pos = EINA_POSITION2D(ev->x, ev->y); - pd = seat_sel->pd; - sel = seat_sel->sel; - sel->dnd_offer = ev->offer; - - EINA_LIST_FOREACH(pd->drop_list, l, drop) - { - if (drop->last.in) - { - sel_debug("Request data of type %s; drop: %p\n", drop->last.type, drop); - sel->request_obj = drop->obj; - sel->request_format = drop->last.format; - evas_object_event_callback_add(sel->request_obj, - EVAS_CALLBACK_DEL, _wl_sel_obj_del2, - sel); - ecore_wl2_offer_receive(ev->offer, (char*)drop->last.type); - ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, _wl_dnd_receive, seat_sel); - - return ECORE_CALLBACK_PASS_ON; - } - } - - ecore_wl2_dnd_drag_end(_wl_seat_get(ev->win, NULL, seat_sel->seat)); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_sel_manager_drop_target_add(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *target_obj, - Efl_Ui_Selection_Format format, unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Sel_Manager_Seat_Selection *seat_sel = NULL; - Drop_Format *df; - - df = calloc(1, sizeof(Drop_Format)); - if (!df) return EINA_FALSE; - df->format = format; - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (!dropable) - { - //Create new drop - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) - { - free(df); - return EINA_FALSE; - } - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) - { - free(dropable); - free(df); - return EINA_FALSE; - } - dropable->obj = target_obj; - efl_key_data_set(target_obj, "__elm_dropable", dropable); - } - - dropable->format_list = eina_inlist_append(dropable->format_list, EINA_INLIST_GET(df)); - dropable->seat = seat; - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - - evas_object_event_callback_add(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del, pd); - - if (!seat_sel->enter_handler) - { - seat_sel->enter_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_ENTER, - _wl_dnd_enter, seat_sel); - seat_sel->leave_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_LEAVE, - _wl_dnd_leave, seat_sel); - seat_sel->pos_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, - _wl_dnd_position, seat_sel); - seat_sel->drop_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, - _wl_dnd_drop, seat_sel); - } - - return EINA_TRUE; -} -#endif - -#ifdef HAVE_ELEMENTARY_COCOA -static Sel_Manager_Seat_Selection * -_cocoa_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } - - return seat_sel; -} - -static Ecore_Cocoa_Window * -_cocoa_window_get(const Evas_Object *obj) -{ - Ecore_Cocoa_Window *win = NULL; - Evas_Object *_win; - - _win = elm_win_get(obj); - if (_win) - { - win = elm_win_cocoa_window_get(_win); - } - - if (!win) - { - CRI("WIN has not been retrieved!!!"); - } - - return win; -} - -static Ecore_Cocoa_Cnp_Type -_sel_format_to_ecore_cocoa_cnp_type(Efl_Ui_Selection_Format fmt) -{ - Ecore_Cocoa_Cnp_Type type = 0; - - if ((fmt & EFL_UI_SELECTION_FORMAT_TEXT) || - (fmt & EFL_UI_SELECTION_FORMAT_VCARD)) - type |= ECORE_COCOA_CNP_TYPE_STRING; - if (fmt & EFL_UI_SELECTION_FORMAT_HTML) - type |= ECORE_COCOA_CNP_TYPE_HTML; - if (fmt & EFL_UI_SELECTION_FORMAT_IMAGE) - type |= ECORE_COCOA_CNP_TYPE_IMAGE; - - return type; -} - -static void -_cocoa_sel_obj_del_req_cb(void *data, - Evas *e EINA_UNUSED, - Evas_Object *obj, - void *ev_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static void -_cocoa_sel_obj_del_cb(void *data, - Evas *e EINA_UNUSED, - Evas_Object *obj, - void *ev_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) - { - sel->owner = NULL; - } - //if (dragwidget == obj) dragwidget = NULL; -} - -static void -_job_pb_cb(void *data) -{ - Sel_Manager_Selection *sel = data; - Efl_Ui_Selection_Data ddata; - Ecore_Cocoa_Cnp_Type type, get_type; - void *pbdata; - int pbdata_len; - - if (sel->data_func) - { - ddata.pos.x = 0; - ddata.pos.y = 0; - - /* Pass to cocoa clipboard */ - type = _sel_format_to_ecore_cocoa_cnp_type(sel->request_format); - pbdata = ecore_cocoa_clipboard_get(&pbdata_len, type, &get_type); - - ddata.format = EFL_UI_SELECTION_FORMAT_NONE; - if (get_type & ECORE_COCOA_CNP_TYPE_STRING) - ddata.format |= EFL_UI_SELECTION_FORMAT_TEXT; - if (get_type & ECORE_COCOA_CNP_TYPE_IMAGE) - ddata.format |= EFL_UI_SELECTION_FORMAT_IMAGE; - if (get_type & ECORE_COCOA_CNP_TYPE_HTML) - ddata.format |= EFL_UI_SELECTION_FORMAT_HTML; - - ddata.content.mem = pbdata; - ddata.content.len = pbdata_len; - ddata.action = EFL_UI_SELECTION_ACTION_UNKNOWN; - sel->data_func(sel->data_func_data, sel->request_obj, &ddata); - free(pbdata); - } -} - -static Eina_Future * -_cocoa_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Cocoa_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Cocoa_Cnp_Type ecore_type; - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - seat_sel = _cocoa_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - if (data.len <= 0) return NULL; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - - sel->owner = owner; - sel->win = win; - sel->format = format; - - evas_object_event_callback_add(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - ELM_SAFE_FREE(sel->data.mem, free); - - if (format == EFL_UI_SELECTION_FORMAT_MARKUP) - { - //FIXME this code assumes that sel->data.mem has a \0 at the end - sel->data.mem = evas_textblock_text_markup_to_utf8(NULL, data.mem); - sel->data.len = strlen(sel->data.mem); - //set the new text - format = EFL_UI_SELECTION_FORMAT_TEXT; - } - else - { - sel->data = eina_slice_dup(data); - } - - if (sel->data.mem) - { - ecore_type = _sel_format_to_ecore_cocoa_cnp_type(format); - ecore_cocoa_clipboard_set(sel->data.mem, sel->data.len, ecore_type); - } - else - { - CRI("Failed to allocate memory!"); - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_cocoa_efl_sel_manager_selection_get(const Efl_Object *request, - Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type EINA_UNUSED, - Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_Cocoa_Window *win, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel; - sel->request_format = format; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); - - sel->win = win; - ecore_job_add(_job_pb_cb, sel); - - evas_object_event_callback_add(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); -} - -#endif - -// win32 specific stuff -//////////////////////////////////////////////////////////////////////////// -#ifdef HAVE_ELEMENTARY_WIN32 -static Sel_Manager_Seat_Selection * -_win32_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } - - return seat_sel; -} - -static char * -_win32_text_n_to_rn(char *intext) -{ - size_t size = 0, newlines = 0; - char *outtext = NULL, *p, *o; - - if (!intext) return NULL; - for (p = intext; *p; p++) - { - if (*p == '\n') newlines++; - size++; - } - outtext = malloc(size + newlines + 1); - if (!outtext) return intext; - for (p = intext, o = outtext; *p; p++, o++) - { - if (*p == '\n') - { - o++; - *p = '\r'; - } - *o = *p; - } - *o = '\0'; - free(intext); - return outtext; -} - -static void -_win32_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) sel->owner = NULL; -} - -static void -_win32_sel_obj_del2(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static Ecore_Win32_Window * -_win32_window_get(const Evas_Object *obj) -{ - Evas_Object *top; - Ecore_Win32_Window *win = NULL; - - if (elm_widget_is(obj)) - { - top = elm_widget_top_get(obj); - if (!top) - { - Evas_Object *par; - par = elm_widget_parent_widget_get(obj); - if (par) top = elm_widget_top_get(par); - } - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - win = elm_win_win32_window_get(top); - } - - if (!win) - { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; - - evas = evas_object_evas_get(obj); - if (!evas) return NULL; - - ee = ecore_evas_ecore_evas_get(evas); - if (!ee) return NULL; - - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - win = ecore_evas_win32_window_get(ee); - } - else - { - if ((strcmp(engine_name, ELM_SOFTWARE_WIN32) == 0) || - (strcmp(engine_name, ELM_SOFTWARE_DDRAW) == 0)) - return ecore_evas_win32_window_get(ee); - } - } - - return win; -} - -static Eina_Future * -_win32_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Win32_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return NULL; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - - seat_sel = _win32_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel_list + type; - if (sel->owner != owner) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - - } - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _win32_sel_obj_del, sel); - sel->active = EINA_TRUE; - sel->owner = owner; - sel->win = win; - if (sel->set) sel->set(win, sel->data.mem, sel->data.len); - sel->format = format; - - evas_object_event_callback_add - (sel->owner, EVAS_CALLBACK_DEL, _win32_sel_obj_del, sel); - - ELM_SAFE_FREE(sel->data.mem, free); - sel->data = eina_slice_dup(data); - if (!sel->data.mem) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_win32_efl_sel_manager_selection_clear(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Sel_Manager_Seat_Selection *seat_sel) -{ - Sel_Manager_Selection *sel; - Ecore_Win32_Window *win; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return; - - sel = seat_sel->sel_list + type; - - /* No longer this selection: Consider it gone! */ - if ((!sel->active) || (sel->owner != owner)) - return; - - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _win32_sel_obj_del, sel); - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _win32_sel_obj_del2, sel); - sel->owner = NULL; - sel->request_obj = NULL; - sel->active = EINA_FALSE; - ELM_SAFE_FREE(sel->data.mem, free); - /* sel->clear(win); */ -} - -static Eina_Bool -_win32_efl_sel_manager_selection_get(const Efl_Object *request, - Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, - Eina_Free_Cb data_func_free_cb, - Ecore_Win32_Window *win, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - void *data; - int size; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return EINA_FALSE; - - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel_list + type; - - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _win32_sel_obj_del2, sel); - sel->request_format = format; - sel->request_obj = (Evas_Object *)request; - sel->win = win; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - sel->get(win, &data, &size); - - if (!data || (size <= 0)) - goto cb_add; - - if ((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *str; - - str = (char *)malloc(size + 1); - if (str) - { - memcpy(str, data, size); - str[size] = '\0'; - data = _win32_text_n_to_rn(_elm_util_mkup_to_text(str)); - free(str); - if (data) - size = strlen(data); - else - size = 0; - } - else - { - free(data); - data = NULL; - } - } - - if (sel->data_func && data && (size > 0)) - { - Efl_Ui_Selection_Data sdata; - - sdata.pos.x = sdata.pos.y = 0; - sdata.format = EFL_UI_SELECTION_FORMAT_TEXT; - sdata.content.mem = data; - sdata.content.len = size; - sdata.action = sel->action; - sel->data_func(sel->data_func_data, sel->request_obj, &sdata); - } - - if (data) - free(data); - - cb_add: - evas_object_event_callback_add - (sel->request_obj, EVAS_CALLBACK_DEL, _win32_sel_obj_del2, sel); - - return EINA_TRUE; -} - -#endif /* HAVE_ELEMENTARY_WIN32 */ - - -static int -_drop_item_container_cmp(const void *d1, const void *d2) -{ - const Item_Container_Drop_Info *di = d1; - return (((uintptr_t)di->obj) - ((uintptr_t)d2)); -} - -static Eina_Bool -_drop_item_container_del(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *cont, Eina_Bool full) -{ - Item_Container_Drop_Info *di; - - di = eina_list_search_unsorted(pd->drop_cont_list, - _drop_item_container_cmp, cont); - if (di) - { - _all_drop_targets_cbs_del(pd, NULL, cont, NULL); - di->item_func_data = NULL; - di->item_func = NULL; - - if (full) - { - pd->drop_cont_list = eina_list_remove(pd->drop_cont_list, di); - free(di); - } - return EINA_TRUE; - } - - return EINA_FALSE; -} - -static inline Eina_List * -_anim_icons_make(Sel_Manager_Drag_Container *dc) -{ - Eina_List *list = NULL, *icon_list = NULL; - Evas_Object *obj; - - if (dc->icon_list_func) - { - DBG("calling icon_list_func"); - icon_list = dc->icon_list_func(dc->icon_list_func_data, dc->cont); - } - EINA_LIST_FREE(icon_list, obj) - { - DBG("one obj in icon_list"); - Anim_Icon *ai = calloc(1, sizeof(Anim_Icon)); - if (!ai) - { - ERR("Failed to allocate for icon!"); - continue; - } - - evas_object_geometry_get(obj, &ai->start.x, &ai->start.y, &ai->start.w, &ai->start.h); - evas_object_show(obj); - ai->obj = obj; - list = eina_list_append(list, ai); - } - DBG("made icon list"); - - return list; -} - -static void -_cont_obj_drag_done_cb(void *data, const Efl_Event *ev EINA_UNUSED) -{ - Sel_Manager_Drag_Container *dc = data; - elm_widget_scroll_freeze_pop(dc->cont); -} - -static Eina_Bool -_cont_obj_drag_start(void *data) -{ - DBG("going to start draging"); - Sel_Manager_Drag_Container *dc = data; - - dc->timer = NULL; - efl_event_callback_add(dc->cont, EFL_UI_DND_EVENT_DRAG_DONE, _cont_obj_drag_done_cb, dc); - elm_widget_scroll_freeze_push(dc->cont); - efl_ui_selection_manager_drag_start(dc->pd->sel_man, dc->cont, dc->format, - eina_rw_slice_slice_get(dc->data), dc->action, - dc->icon_func_data, dc->icon_func, dc->icon_func_free_cb, - dc->seat); - - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_drag_anim_play(void *data, double pos) -{ - Sel_Manager_Drag_Container *dc = data; - - if (dc->animator) - { - Eina_List *l; - Anim_Icon *ai; - Evas_Coord xm, ym; - - if (pos > 0.99) - { - dc->animator = NULL; - EINA_LIST_FOREACH(dc->icons, l, ai) - evas_object_hide(ai->obj); - - _cont_obj_drag_start(dc); - return ECORE_CALLBACK_CANCEL; - } - - evas_pointer_canvas_xy_get(dc->e, &xm, &ym); - EINA_LIST_FOREACH(dc->icons, l, ai) - { - int x, y, w, h; - w = ai->start.w - ((dc->final_icon.w - ai->start.w) * pos); - h = ai->start.h - ((dc->final_icon.h - ai->start.h) * pos); - x = ai->start.x - (pos * (ai->start.x + (w / 2) - xm)); - y = ai->start.y - (pos * (ai->start.y + (h / 2) - ym)); - evas_object_geometry_set(ai->obj, x, y, w, h); - } - - return ECORE_CALLBACK_RENEW; - } - - return ECORE_CALLBACK_CANCEL; -} - -static inline void -_drag_anim_start(Sel_Manager_Drag_Container *dc) -{ - - dc->timer = NULL; - if (dc->icon_func) - { - Eina_Position2D pos_ret; - Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_DND); - Evas_Object *final_icon = dc->icon_func(dc->icon_func_data, temp_win, dc->cont, &pos_ret); - evas_object_geometry_get(final_icon, NULL, NULL, &dc->final_icon.w, &dc->final_icon.h); - evas_object_del(final_icon); - evas_object_del(temp_win); - } - dc->animator = ecore_evas_animator_timeline_add(dc->e, dc->anim_duration, _drag_anim_play, dc); -} - -static Eina_Bool -_cont_obj_anim_start(void *data) -{ - sel_debug("In"); - Sel_Manager_Drag_Container *dc = data; - Efl_Object *it = NULL; - Eina_Position2D posret; //does not use - - if (dc->item_get_func) - it = dc->item_get_func(dc->item_get_func_data, dc->cont, dc->down, &posret); - dc->timer = NULL; - dc->format = EFL_UI_SELECTION_FORMAT_TARGETS; //default - dc->data.len = 0; - dc->action = EFL_UI_SELECTION_ACTION_COPY; //default - dc->icons = NULL; - - //failed to get mouse-down item, abort drag - if (!it) - return ECORE_CALLBACK_CANCEL; - - if (dc->drag_data_func) - { - dc->drag_data_func(dc->drag_data_func_data, dc->cont, - &dc->format, &dc->data, &dc->action); - if (EINA_DBL_EQ(dc->anim_duration, 0.0)) - { - _cont_obj_drag_start(dc); - } - else - { - dc->icons = _anim_icons_make(dc); - if (dc->icons) - { - _drag_anim_start(dc); - } - else - { - // even if we don't manage the icons animation, we have - // to wait until it is finished before beginning drag. - dc->timer = ecore_timer_add(dc->anim_duration, - _cont_obj_drag_start, dc); - } - } - } - - return ECORE_CALLBACK_CANCEL; -} - -static void -_abort_drag(Evas_Object *obj EINA_UNUSED, Sel_Manager_Drag_Container *dc) -{ - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - _item_container_del_internal(dc, EINA_FALSE); - - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - _anim_data_free(dc); -} - -static void -_cont_obj_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - Evas_Event_Mouse_Move *ev = event_info; - - if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) - { - _abort_drag(obj, dc); - } - if (dc && - (evas_device_class_get(ev->dev) == EVAS_DEVICE_CLASS_TOUCH)) - { - int dx, dy; - int fs = elm_config_finger_size_get(); - - dx = ev->cur.canvas.x - dc->down.x; - dy = ev->cur.canvas.y - dc->down.y; - if ((dx * dx + dy * dy) > (fs * fs)) - { - sel_debug("mouse moved too much - have to cancel DnD"); - _abort_drag(obj, dc); - } - } -} - -static void -_anim_data_free(Sel_Manager_Drag_Container *dc) -{ - if (dc) - { - ELM_SAFE_FREE(dc->animator, ecore_animator_del); - Anim_Icon *ai; - - EINA_LIST_FREE(dc->icons, ai) - { - evas_object_del(ai->obj); - free(ai); - } - dc->icons = NULL; - } -} - -static void -_cont_obj_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - - if (((Evas_Event_Mouse_Up *)event_info)->button != 1) - return; - - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - - _anim_data_free(dc); -} - -static void -_cont_obj_mouse_down_cb(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - Evas_Event_Mouse_Down *ev = event_info; - if (ev->button != 1) - return; - - dc->e = e; - dc->down.x = ev->canvas.x; - dc->down.y = ev->canvas.y; - - evas_object_event_callback_add(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - ecore_timer_del(dc->timer); - if (dc->time_to_drag) - { - dc->timer = ecore_timer_add(dc->time_to_drag, _cont_obj_anim_start, dc); - evas_object_event_callback_add(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - } - else - { - _cont_obj_anim_start(dc); - } -} - -static void -_item_container_del_internal(Sel_Manager_Drag_Container *dc, Eina_Bool full) -{ - if (dc) - { - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - if (dc->animator) - _anim_data_free(dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_DOWN, - _cont_obj_mouse_down_cb, dc); - if (full) - { - dc->item_get_func = NULL; - dc->item_get_func_data = NULL; - free(dc); - } - } -} - -static int -_drag_item_container_cmp(const void *d1, const void *d2) -{ - const Sel_Manager_Drag_Container *dc = d1; - return (((uintptr_t)dc->cont) - ((uintptr_t)d2)); -} -//exposed APIs -EOLIAN static Eina_Future * -_efl_ui_selection_manager_selection_set(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, unsigned int seat) -{ - Eina_Future *p = NULL; - - sel_debug("owner: %p, seat: %d, type: %d, format: %d", owner, seat, type, format); - if (type > EFL_UI_SELECTION_TYPE_CLIPBOARD) - { - ERR("Not supported format: %d", type); - return NULL; - } - -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(owner); - if (xwin) - p = _x11_efl_sel_manager_selection_set(pd, owner, type, format, data, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(owner); - if (win) - p = _wl_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(owner); - if (win) - p = _cocoa_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(owner); - if (win) - p = _win32_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif - - return p; -} - -//TODO: add support for local -EOLIAN static void -_efl_ui_selection_manager_selection_get(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - const Efl_Object *request, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, - Eina_Free_Cb data_func_free_cb, unsigned int seat) -{ - sel_debug("request: %p, seat: %d, type: %d, format: %d", request, seat, type, format); -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(request); - if (xwin) - _x11_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(request); - if (win) - _wl_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(request); - if (win) - _cocoa_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(request); - if (win) - _win32_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -} - -EOLIAN static void -_efl_ui_selection_manager_selection_clear(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, unsigned int seat) -{ - Eina_Bool local = EINA_FALSE; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel = NULL; - - sel_debug("owner: %p, seat: %d, type: %d", owner, seat, type); - seat_sel = _sel_manager_seat_selection_init(pd, seat); -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(obj); - if (xwin) - { - sel = seat_sel->sel_list + type; - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(obj); - if (win) - { - sel = seat_sel->sel; - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(obj); - if (win) - { - sel = seat_sel->sel; - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(obj); - { - sel = seat_sel->sel_list + type; - } -#endif - if (!sel) return; - if ((!sel->active) && (sel->owner != owner)) - { - return; - } - sel->active = EINA_FALSE; -#ifdef HAVE_ELEMENTARY_X - if (xwin) - { - seat_sel->sel_list[type].data.len = 0; - if (seat_sel->sel_list[type].data.mem) - { - free(seat_sel->sel_list[type].data.mem); - seat_sel->sel_list[type].data.mem = NULL; - } - if (sel->xwin != 0) local = EINA_TRUE; - if (!local) seat_sel->sel_list[type].clear(); - else - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - seat_sel->sel_list[type].owner = NULL; - } - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - if (win) - { - sel->selection_serial = ecore_wl2_dnd_selection_clear(_wl_seat_get(_wl_window_get(owner), owner, seat)); - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - if (win) - { - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); - sel->owner = NULL; - sel->request_obj = NULL; - ELM_SAFE_FREE(sel->data.mem, free); - sel->data.len = 0; - - ecore_cocoa_clipboard_clear(); - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - if (win) - { - _win32_efl_sel_manager_selection_clear(pd, owner, type, seat_sel); - } -#endif -} - -EOLIAN static Eina_Bool -_efl_ui_selection_manager_selection_has_owner(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd EINA_UNUSED, - Efl_Object *request, Efl_Ui_Selection_Type type, - unsigned int seat) -{ -#ifdef HAVE_ELEMENTARY_X - (void)seat; - if (_x11_xwin_get(request)) - { - Ecore_X_Atom xtype; - switch (type) - { - case EFL_UI_SELECTION_TYPE_PRIMARY: - xtype = ECORE_X_ATOM_SELECTION_PRIMARY; - break; - case EFL_UI_SELECTION_TYPE_SECONDARY: - xtype = ECORE_X_ATOM_SELECTION_SECONDARY; - break; - case EFL_UI_SELECTION_TYPE_DND: - xtype = ECORE_X_ATOM_SELECTION_XDND; - break; - default: - xtype = ECORE_X_ATOM_SELECTION_CLIPBOARD; - } - return !!ecore_x_selection_owner_get(xtype); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win; - - win = _wl_window_get(request); - if (win) - return !!ecore_wl2_dnd_selection_get(_wl_seat_get(win, request, seat)); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - // FIXME: need to check if there is clipboard data. Paste always enabled. - return EINA_TRUE; -#endif - return EINA_FALSE; -} - -EOLIAN static void -_efl_ui_selection_manager_drag_start(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Format format, - Eina_Slice data, Efl_Ui_Selection_Action action, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, - Eina_Free_Cb icon_func_free_cb, unsigned int seat) -{ -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - _x11_efl_sel_manager_drag_start(obj, pd, drag_obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(drag_obj); - if (win) - _wl_efl_sel_manager_drag_start(obj, pd, drag_obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 -#endif -#ifdef HAVE_ELEMENTARY_COCOA -#endif -} - -EOLIAN static void -_efl_ui_selection_manager_drag_cancel(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = _sel_manager_seat_selection_init(pd, seat); - -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - { - ecore_x_pointer_ungrab(); - ELM_SAFE_FREE(seat_sel->mouse_up_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->dnd_status_handler, ecore_event_handler_del); - ecore_x_dnd_abort(xwin); - if (seat_sel->drag_obj) - { - if (elm_widget_is(seat_sel->drag_obj)) - { - Evas_Object *win = elm_widget_top_get(seat_sel->drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - efl_event_callback_del(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - seat_sel->drag_obj = NULL; - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win; - - win = _wl_window_get(drag_obj); - if (win) - ecore_wl2_dnd_drag_end(_wl_seat_get(win, drag_obj, seat)); -#endif - - ELM_SAFE_FREE(seat_sel->drag_win, evas_object_del); -} - -EOLIAN static void -_efl_ui_selection_manager_drag_action_set(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Action action, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = _sel_manager_seat_selection_init(pd, seat); - if (seat_sel->drag_action == action) return; - seat_sel->drag_action = action; -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Atom actx; - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - { - actx = _x11_dnd_action_rev_map(action); - ecore_x_dnd_source_action_set(actx); - } -#endif -} - -//drop side -EOLIAN static Eina_Bool -_efl_ui_selection_manager_drop_target_add(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *target_obj, Efl_Ui_Selection_Format format, - unsigned int seat) -{ - Eina_Bool ret = EINA_FALSE; -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(target_obj); - if (xwin) - ret = _x11_sel_manager_drop_target_add(pd, target_obj, format, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(target_obj); - if (win) - ret = _wl_sel_manager_drop_target_add(pd, target_obj, format, seat); -#endif - return ret; -} - -EOLIAN static void -_efl_ui_selection_manager_drop_target_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *target_obj, Efl_Ui_Selection_Format format, - unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Sel_Manager_Seat_Selection *seat_sel; - Eina_Bool remove_handler = EINA_FALSE; - - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (dropable) - { - Eina_Inlist *itr; - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format == format) - { - dropable->format_list = eina_inlist_remove(dropable->format_list, - EINA_INLIST_GET(df)); - free(df); - } - } - if (!dropable->format_list) - { - pd->drop_list = eina_list_remove(pd->drop_list, dropable); - efl_key_data_set(target_obj, "__elm_dropable", NULL); - free(dropable); - evas_object_event_callback_del(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del); - } - } - -#ifdef HAVE_ELEMENTARY_X - if (pd->drop_list) - { - Eina_List *l; - Ecore_X_Window xwin; - Eina_Bool have_drop_list = EINA_FALSE; - - xwin = _x11_xwin_get(target_obj); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - if (!have_drop_list) - { - ecore_x_dnd_aware_set(xwin, EINA_FALSE); - remove_handler = EINA_TRUE; - } - } - else remove_handler = EINA_TRUE; -#endif - if (remove_handler) - { - seat_sel = _sel_manager_seat_selection_init(pd, seat); - ELM_SAFE_FREE(seat_sel->pos_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->drop_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->enter_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->leave_handler, ecore_event_handler_del); - } -} - -EOLIAN static void -_efl_ui_selection_manager_container_drop_item_add(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, Efl_Ui_Selection_Format format, - void *item_func_data, Efl_Dnd_Item_Get item_func, - Eina_Free_Cb item_func_free_cb EINA_UNUSED, - unsigned int seat) -{ - Item_Container_Drop_Info *di; - Sel_Manager_Dropable *dropable = NULL; - - if (_drop_item_container_del(pd, cont, EINA_FALSE)) - { - di = eina_list_search_unsorted(pd->drop_cont_list, _drop_item_container_cmp, obj); - if (!di) return; - } - else - { - di = calloc(1, sizeof(Item_Container_Drop_Info)); - if (!di) return; - - di->obj = obj; - pd->drop_cont_list = eina_list_append(pd->drop_cont_list, di); - } - di->item_func = item_func; - di->item_func_data = item_func_data; - - dropable = efl_key_data_get(cont, "__elm_dropable"); - if (!dropable) - { - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) return; - dropable->last.in = EINA_FALSE; - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) return; - dropable->obj = cont; - efl_key_data_set(cont, "__elm_dropable", dropable); - } - dropable->is_container = EINA_TRUE; - dropable->item_func = item_func; - dropable->item_func_data = item_func_data; - _efl_ui_selection_manager_drop_target_add(obj, pd, cont, format, seat); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drop_item_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, unsigned int seat EINA_UNUSED) -{ - _drop_item_container_del(pd, cont, EINA_TRUE); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drag_item_add(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, double time_to_drag, double anim_duration, - void *data_func_data, Efl_Dnd_Drag_Data_Get data_func, Eina_Free_Cb data_func_free_cb, - void *item_get_func_data, Efl_Dnd_Item_Get item_get_func, Eina_Free_Cb item_get_func_free_cb, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - void *icon_list_func_data, Efl_Dnd_Drag_Icon_List_Create icon_list_func, Eina_Free_Cb icon_list_func_free_cb, - unsigned int seat) -{ - //TODO: remove previous drag one - Sel_Manager_Drag_Container *dc = calloc(1, sizeof(Sel_Manager_Drag_Container)); - if (!dc) - { - ERR("Failed to allocate memory"); - return; - } - dc->cont = cont; - dc->time_to_drag = time_to_drag; - dc->anim_duration = anim_duration; - dc->drag_data_func_data = data_func_data; - dc->drag_data_func = data_func; - dc->drag_data_func_free_cb = data_func_free_cb; - dc->item_get_func_data = item_get_func_data; - dc->item_get_func = item_get_func; - dc->item_get_func_free_cb = item_get_func_free_cb; - dc->icon_func_data = icon_func_data; - dc->icon_func = icon_func; - dc->icon_func_free_cb = icon_func_free_cb; - dc->icon_list_func_data = icon_list_func_data; - dc->icon_list_func = icon_list_func; - dc->icon_list_func_free_cb = icon_list_func_free_cb; - dc->seat = seat; - dc->pd = pd; - - _sel_manager_seat_selection_init(pd, seat); - - pd->drag_cont_list = eina_list_append(pd->drag_cont_list, dc); - - evas_object_event_callback_add(cont, EVAS_CALLBACK_MOUSE_DOWN, - _cont_obj_mouse_down_cb, dc); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drag_item_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, unsigned int seat EINA_UNUSED) -{ - Sel_Manager_Drag_Container *dc = eina_list_search_unsorted(pd->drag_cont_list, - _drag_item_container_cmp, cont); - if (dc) - _item_container_del_internal(dc, EINA_TRUE); -} - -static Eo * -_efl_ui_selection_manager_efl_object_constructor(Eo *obj, Efl_Ui_Selection_Manager_Data *pd) -{ -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WL2) - const char *ev = getenv("ELM_DISPLAY"); -#endif - -#ifdef HAVE_ELEMENTARY_X - Eina_Bool init_x = EINA_FALSE; - Eina_Bool have_display = !!getenv("DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "x11")) /* and it is X11 */ - { - if (!have_display) /* if there is no $DISPLAY */ - { - ERR("$ELM_DISPLAY is set to x11 but $DISPLAY is not set"); - init_x = EINA_FALSE; - } - else /* if there is */ - init_x = EINA_TRUE; - } - else /* not X11 */ - init_x = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - if (have_display) /* If there is a $DISPLAY */ - init_x = EINA_TRUE; - else /* No $DISPLAY */ - init_x = EINA_FALSE; - } - if (init_x) - { - if (!ecore_x_init(NULL)) - { - ERR("Could not initialize Ecore_X"); - return NULL; - } - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Eina_Bool init_wl = EINA_FALSE; - Eina_Bool have_wl_display = !!getenv("WAYLAND_DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "wl")) /* and it is WL */ - { - /* always try to connect to wl when it is enforced */ - init_wl = EINA_TRUE; - } - else /* not wl */ - init_wl = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - /* If there is a $WAYLAND_DISPLAY */ - if ((have_wl_display) && (!getenv("DISPLAY"))) - init_wl = EINA_TRUE; - else /* No $WAYLAND_DISPLAY */ - init_wl = EINA_FALSE; - } - if (init_wl) - { - if (!ecore_wl2_init()) - { - ERR("Could not initialize Ecore_Wl2"); - return NULL; - } - _elm_wl_display = ecore_wl2_display_connect(NULL); - if (!_elm_wl_display) - { - ERR("Could not connect to Wayland Display"); - ecore_wl2_shutdown(); - return NULL; - } - } -#endif - - obj = efl_constructor(efl_super(obj, MY_CLASS)); - - pd->sel_man = obj; - pd->atom_list = calloc(1, SELECTION_N_ATOMS * sizeof(Sel_Manager_Atom)); - if (!pd->atom_list) - { - ERR("failed to allocate atom_list"); - return NULL; - } - pd->atom_list[SELECTION_ATOM_TARGETS].name = "TARGETS"; - pd->atom_list[SELECTION_ATOM_TARGETS].format = EFL_UI_SELECTION_FORMAT_TARGETS; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TARGETS].x_converter = _x11_targets_converter; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TARGETS].wl_converter = _wl_targets_converter; -#endif - pd->atom_list[SELECTION_ATOM_ATOM].name = "ATOM"; // for opera browser - pd->atom_list[SELECTION_ATOM_ATOM].format = EFL_UI_SELECTION_FORMAT_TARGETS; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_ATOM].x_converter = _x11_targets_converter; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_ATOM].wl_converter = _wl_targets_converter; -#endif - - pd->atom_list[SELECTION_ATOM_ELM].name = "application/x-elementary-markup"; - pd->atom_list[SELECTION_ATOM_ELM].format = EFL_UI_SELECTION_FORMAT_MARKUP; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_ELM].x_converter = _x11_general_converter; - pd->atom_list[SELECTION_ATOM_ELM].x_data_preparer = _x11_data_preparer_markup; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_ELM].wl_converter = _wl_general_converter; - pd->atom_list[SELECTION_ATOM_ELM].wl_data_preparer = _wl_data_preparer_markup; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].name = "text/uri-list"; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].x_converter = _x11_general_converter; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].x_data_preparer = _x11_data_preparer_uri; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].wl_converter = _wl_general_converter; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].wl_data_preparer = _wl_data_preparer_uri; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].name = "text/x-vcard"; - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].format = EFL_UI_SELECTION_FORMAT_VCARD; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].x_converter = _x11_vcard_send; - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].x_data_preparer = _x11_data_preparer_vcard; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].wl_data_preparer = _wl_data_preparer_vcard; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].name = "image/png"; - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].name = "image/jpeg"; - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].name = "image/x-ms-bmp"; - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].name = "image/gif"; - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].name = "image/tiff"; - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].name = "image/svg+xml"; - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].name = "image/x-xpixmap"; - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].name = "image/x-tga"; - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].name = "image/x-portable-pixmap"; - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_UTF8STRING].name = "UTF8_STRING"; - pd->atom_list[SELECTION_ATOM_UTF8STRING].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_UTF8STRING].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_UTF8STRING].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_UTF8STRING].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_UTF8STRING].wl_data_preparer = _wl_data_preparer_text, -#endif - - pd->atom_list[SELECTION_ATOM_STRING].name = "STRING"; - pd->atom_list[SELECTION_ATOM_STRING].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_STRING].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_STRING].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_STRING].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_STRING].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].name = "COMPOUND_TEXT"; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT].name = "TEXT"; - pd->atom_list[SELECTION_ATOM_TEXT].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].name = "text/plain;charset=utf-8"; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].name = "text/plain"; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].wl_data_preparer = _wl_data_preparer_text; -#endif - - - int i; -#ifdef HAVE_ELEMENTARY_X - if (ecore_x_display_get()) - { - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - pd->atom_list[i].x_atom = ecore_x_atom_get(pd->atom_list[i].name); - ecore_x_selection_converter_atom_add - (pd->atom_list[i].x_atom, pd->atom_list[i].x_converter); - } - pd->notify_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, - _efl_sel_manager_x11_selection_notify, pd); - pd->clear_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, - _x11_selection_clear, pd); - if (ECORE_X_EVENT_FIXES_SELECTION_NOTIFY) // If XFIXES is not available ECORE_X_EVENT_FIXES_SELECTION_NOTIFY would be NULL - pd->fix_handler = ecore_event_handler_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, - _x11_fixes_selection_notify, pd); - } -#endif - - pd->type_hash = eina_hash_string_small_new(NULL); - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - eina_hash_add(pd->type_hash, pd->atom_list[i].name, &pd->atom_list[i]); - } - pd->text_uri = eina_stringshare_add("text/uri-list"); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_elm_wl_display) - { - pd->send_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, - _wl_selection_send, pd); - pd->changed_handler = ecore_event_handler_add(ECORE_WL2_EVENT_SEAT_SELECTION, - _wl_selection_changed, pd); - pd->end_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_END, - _wl_dnd_end, pd); - } -#endif - managers = eina_list_append(managers, obj); - return obj; -} - -static void -_efl_ui_selection_manager_efl_object_destructor(Eo *obj, Efl_Ui_Selection_Manager_Data *pd) -{ - Sel_Manager_Seat_Selection *seat_sel; - Eina_List *l; - Sel_Manager_Dropable *dropable; - - managers = eina_list_remove(managers, obj); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - _drop_target_cbs_del(pd, dropable, dropable->obj); - } -#ifdef HAVE_ELEMENTARY_X - ecore_event_handler_del(pd->notify_handler); - ecore_event_handler_del(pd->clear_handler); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - ecore_event_handler_del(pd->send_handler); - ecore_event_handler_del(pd->changed_handler); - ecore_event_handler_del(pd->end_handler); -#endif - free(pd->atom_list); - EINA_LIST_FREE(pd->seat_list, seat_sel) - { - ecore_event_handler_del(seat_sel->pos_handler); - ecore_event_handler_del(seat_sel->drop_handler); - ecore_event_handler_del(seat_sel->enter_handler); - ecore_event_handler_del(seat_sel->leave_handler); -#ifdef HAVE_ELEMENTARY_X - free(seat_sel->sel_list); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - free(seat_sel->sel); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - free(seat_sel->sel); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - free(seat_sel->sel_list); -#endif - free(seat_sel->saved_types->types); - free(seat_sel->saved_types->imgfile); - free(seat_sel->saved_types); - } - eina_hash_free(pd->type_hash); - eina_stringshare_del(pd->text_uri); - - efl_destructor(efl_super(obj, MY_CLASS)); -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WL2) || defined(HAVE_ELEMENTARY_WIN32) - const char *ev = getenv("ELM_DISPLAY"); -#endif - -#ifdef HAVE_ELEMENTARY_X - Eina_Bool init_x = EINA_FALSE; - Eina_Bool have_display = !!getenv("DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "x11")) /* and it is X11 */ - { - if (!have_display) /* if there is no $DISPLAY */ - { - ERR("$ELM_DISPLAY is set to x11 but $DISPLAY is not set"); - init_x = EINA_FALSE; - } - else /* if there is */ - init_x = EINA_TRUE; - } - else /* not X11 */ - init_x = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - if (have_display) /* If there is a $DISPLAY */ - init_x = EINA_TRUE; - else /* No $DISPLAY */ - init_x = EINA_FALSE; - } - if (init_x) - { - if (ecore_x_display_get()) - ecore_x_shutdown(); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Eina_Bool init_wl = EINA_FALSE; - Eina_Bool have_wl_display = !!getenv("WAYLAND_DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "wl")) /* and it is WL */ - { - /* always try to connect to wl when it is enforced */ - init_wl = EINA_TRUE; - } - else /* not wl */ - init_wl = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - /* If there is a $WAYLAND_DISPLAY */ - if ((have_wl_display) && (!getenv("DISPLAY"))) - init_wl = EINA_TRUE; - else /* No $WAYLAND_DISPLAY */ - init_wl = EINA_FALSE; - } - if (init_wl) - { - if (!managers) ecore_wl2_display_disconnect(_elm_wl_display); - ecore_wl2_shutdown(); - } -#endif -} - -#ifdef HAVE_ELEMENTARY_X -static void -_set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel) -{ - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].debug = "Primary"; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].ecore_sel = ECORE_X_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].set = ecore_x_selection_primary_set; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].clear = ecore_x_selection_primary_clear; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].request = ecore_x_selection_primary_request; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].debug = "Secondary"; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].ecore_sel = ECORE_X_SELECTION_SECONDARY; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].set = ecore_x_selection_secondary_set; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].clear = ecore_x_selection_secondary_clear; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].request = ecore_x_selection_secondary_request; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_DND].debug = "DnD"; - sel_list[EFL_UI_SELECTION_TYPE_DND].ecore_sel = ECORE_X_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_DND].request = ecore_x_selection_xdnd_request; - sel_list[EFL_UI_SELECTION_TYPE_DND].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].debug = "Clipboard"; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].ecore_sel = ECORE_X_SELECTION_CLIPBOARD; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].set = ecore_x_selection_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].clear = ecore_x_selection_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].request = ecore_x_selection_clipboard_request; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].seat_sel = seat_sel; -} -#endif -#ifdef HAVE_ELEMENTARY_WIN32 -static void -_set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel) -{ - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].debug = "Primary"; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].ecore_sel = ECORE_WIN32_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].set = ecore_win32_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].clear = ecore_win32_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].get = ecore_win32_clipboard_get; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].debug = "Secondary"; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].ecore_sel = ECORE_WIN32_SELECTION_OTHER; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_DND].debug = "DnD"; - sel_list[EFL_UI_SELECTION_TYPE_DND].ecore_sel = ECORE_WIN32_SELECTION_OTHER; - sel_list[EFL_UI_SELECTION_TYPE_DND].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].debug = "Clipboard"; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].ecore_sel = ECORE_WIN32_SELECTION_CLIPBOARD; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].set = ecore_win32_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].clear = ecore_win32_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].seat_sel = seat_sel; -} -#endif - -#include "efl_ui_selection_manager.eo.c" diff --git a/src/lib/elementary/efl_ui_selection_manager.eo b/src/lib/elementary/efl_ui_selection_manager.eo deleted file mode 100644 index e7df9cce77..0000000000 --- a/src/lib/elementary/efl_ui_selection_manager.eo +++ /dev/null @@ -1,139 +0,0 @@ -import efl_ui_dnd_types; - -class @beta Efl.Ui.Selection_Manager extends Efl.Object { - methods { - selection_set @beta { - [[Set selection]] - params { - @in owner: Efl.Object; [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in format: Efl.Ui.Selection_Format; [[Selection format]] - @in data: Eina.Slice; [[Selection data]] - @in seat: uint @optional;[[Specified seat for multiple seats case.]] - } - return: future; [[Future for tracking when the selection is lost]] - } - selection_get @beta { - [[Get selection]] - params { - @in request: const(Efl.Object); [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]] - @in seat: uint @optional;[[Specified seat for multiple seats case.]] - } - } - selection_clear @beta { - params { - @in owner: Efl.Object; [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint @optional; [[Specified seat for multiple seats case.]] - } - } - selection_has_owner @beta { - [[Check if the request object has selection or not]] - params { - @in request: Efl.Object; [[Request object]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint @optional; [[Specified seat for multiple seats case.]] - } - return: bool; [[EINA_TRUE if the request object has selection, otherwise, EINA_FALSE]] - } - drag_start @beta { - [[This starts a drag and drop process at the drag side. - During dragging, there are three events emitted as belows: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE - ]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in format: Efl.Ui.Selection_Format; [[Data format]] - @in data: Eina.Slice; [[Data to transfer]] - @in action: Efl.Ui.Selection_Action; [[Action when data is transferred]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_action_set @beta { - [[This sets the action for the drag]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in action: Efl.Ui.Selection_Action; [[Drag action]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_cancel @beta { - [[This cancels the on-going drag]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drag_item_add @beta { - [[This registers a drag for items in a container. Many items can be - dragged at a time. During dragging, there are three events emitted: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE.]] - params { - @in cont: Efl.Object; [[Container object]] - @in time_to_drag: double; [[Time since mouse down happens to drag starts]] - @in anim_duration: double; [[animation duration]] - @in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]] - @in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]] - @in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations]] - @in seat: uint; [[Specified seat for multiple seats case]] - } - } - container_drag_item_del @beta { - [[Remove drag function of items in the container object.]] - params { - @in cont: Efl.Object; [[Container object]] - @in seat: uint; [[Specified seat for multiple seats case]] - } - } - drop_target_add @beta { - [[Add a dropable target. There are four events emitted: - - EFL_UI_DND_DROP_DRAG_ENTER - - EFL_UI_DND_DROP_DRAG_LEAVE - - EFL_UI_DND_DROP_DRAG_POS - - EFL_UI_DND_DROP_DRAG_DROP.]] - params { - @in target_obj: Efl.Object; [[Drop target]] - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - return: bool; [[$true on success, $false otherwise]] - } - drop_target_del @beta { - [[Remove a dropable target]] - params { - @in target_obj: Efl.Object; [[Drop target]] - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drop_item_add @beta { - [[Add dropable target for a container in which items can drop to it]] - params { - @in cont: Efl.Object; [[Container object]] - @in format: Efl.Ui.Selection_Format; [[Accepted data formats]] - @in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drop_item_del @beta { - [[Remove dropable target for the container]] - params { - @in cont: Efl.Object; [[Container object]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - } - implements { - Efl.Object.constructor; - Efl.Object.destructor; - } -} diff --git a/src/lib/elementary/efl_ui_selection_types.eot b/src/lib/elementary/efl_ui_selection_types.eot deleted file mode 100644 index cbe5e0dc7b..0000000000 --- a/src/lib/elementary/efl_ui_selection_types.eot +++ /dev/null @@ -1,60 +0,0 @@ -enum @beta Efl.Ui.Selection_Type -{ - [[Selection type]] - primary, [[Primary text selection (highlighted or selected text)]] - secondary, [[Used when primary selection is in use]] - dnd, [[Drag and Drop]] - clipboard [[Clipboard selection (ctrl+C)]] -} - -enum @beta Efl.Ui.Selection_Format -{ - [[Selection format]] - targets = -1, [[For matching every possible atom]] - none = 0x0, [[Content is from outside of EFL]] - text = 0x01, [[Plain unformatted text: Used for things that don't want rich markup]] - markup = 0x2, [[Edje textblock markup, including inline images]] - image = 0x4, [[Images]] - vcard = 0x08, [[Vcards]] - html = 0x10 [[Raw HTML-like data (eg. webkit)]] -} - -enum @beta Efl.Ui.Selection_Action -{ - [[Defines the kind of action associated with the drop data]] - unknown, [[Action type is unknown]] - copy, [[Copy the data]] - move, [[Move the data]] - private, [[Private action type]] - ask, [[Ask the user what to do]] - list, [[List the data]] - link, [[Link the data]] - description [[Describe the data]] -} - -struct @beta Efl.Ui.Selection_Data -{ - [[Structure holding the info about selected data]] - pos: Eina.Position2D; [[Coordinates of the drop (DND operations only)]] - format: Efl.Ui.Selection_Format; [[Format of the selection]] - content: Eina.Slice; [[Selection data]] - action: Efl.Ui.Selection_Action; [[Action to perform with the data]] - item: Efl.Object; [[Item under the drag position. It is only available for container]] -} - -function @beta Efl.Ui.Selection_Data_Ready { - [[Function pointer for getting selection]] - params { - @in obj: Efl.Object; [[Object which requested for the selection]] - @in seldata: ptr(Efl.Ui.Selection_Data); [[Selection data]] - } -}; - -struct @beta Efl.Ui.Selection_Changed -{ - [[Selection-changed specific information.]] // TODO: This needs to be filled in. - type: Efl.Ui.Selection_Type; [[Selection type]] - seat: int; [[The seat on which the selection changed, or NULL for "default"]] - display: void_ptr; [[The display connection object, NULL under X11]] - exist: bool; [[EINA_TRUE if the selection has an owner]] -} diff --git a/src/lib/elementary/efl_ui_tags.c b/src/lib/elementary/efl_ui_tags.c index 95c5ce59d7..5cc37badda 100644 --- a/src/lib/elementary/efl_ui_tags.c +++ b/src/lib/elementary/efl_ui_tags.c @@ -757,7 +757,7 @@ _view_init(Evas_Object *obj, Efl_Ui_Tags_Data *sd) sd->entry = efl_add(EFL_UI_TEXTBOX_CLASS, sd->box, efl_text_multiline_set(efl_added, EINA_FALSE), efl_text_set(efl_added, ""), - efl_ui_textbox_cnp_mode_set(efl_added, EFL_UI_SELECTION_FORMAT_MARKUP), + efl_ui_textbox_cnp_dnd_mode_set(efl_added, EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP), efl_input_text_input_panel_autoshow_set(efl_added, EINA_FALSE), efl_text_interactive_editable_set(efl_added, EINA_TRUE), efl_composite_attach(obj, efl_added)); diff --git a/src/lib/elementary/efl_ui_textbox.c b/src/lib/elementary/efl_ui_textbox.c index a53c265d38..2831dca6d7 100644 --- a/src/lib/elementary/efl_ui_textbox.c +++ b/src/lib/elementary/efl_ui_textbox.c @@ -22,7 +22,6 @@ typedef struct _Efl_Ui_Textbox_Data Efl_Ui_Textbox_Data; typedef struct _Efl_Ui_Text_Rectangle Efl_Ui_Text_Rectangle; typedef struct _Anchor Anchor; -typedef struct _Selection_Loss_Data Selection_Loss_Data; /** * Base widget smart data extended with entry instance data. @@ -69,7 +68,7 @@ struct _Efl_Ui_Textbox_Data const char *hover_style; /**< style of a hover object */ } anchor_hover; - Efl_Ui_Selection_Format cnp_mode; + const char *cnp_mime_type; Elm_Sel_Format drop_format; struct { @@ -81,11 +80,7 @@ struct _Efl_Ui_Textbox_Data Eina_Size2D scroll; Eina_Size2D layout; } last; - struct - { - Eina_Future *primary; - Eina_Future *clipboard; - } sel_future; + Efl_Ui_Textbox_Cnp_Content content; Eina_Bool sel_handles_enabled : 1; Eina_Bool start_handler_down : 1; Eina_Bool start_handler_shown : 1; @@ -147,12 +142,6 @@ struct _Efl_Ui_Text_Rectangle Evas_Object *obj_bg, *obj_fg, *obj; }; -struct _Selection_Loss_Data -{ - Eo *obj; - Efl_Ui_Selection_Type stype; -}; - #define MY_CLASS EFL_UI_TEXTBOX_CLASS #define MY_CLASS_PFX efl_ui_textbox #define MY_CLASS_NAME "Efl.Ui.Textbox" @@ -208,7 +197,7 @@ static void _anchors_free(Efl_Ui_Textbox_Data *sd); static void _selection_defer(Eo *obj, Efl_Ui_Textbox_Data *sd); static Eina_Position2D _decoration_calc_offset(Efl_Ui_Textbox_Data *sd); static void _update_text_theme(Eo *obj, Efl_Ui_Textbox_Data *sd); -static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Selection_Type type); +static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type); static Eina_Bool _key_action_copy(Evas_Object *obj, const char *params); static Eina_Bool _key_action_paste(Evas_Object *obj, const char *params); @@ -407,16 +396,19 @@ _update_selection_handler(Eo *obj) } } -static void -_selection_data_cb(void *data EINA_UNUSED, Eo *obj, - Efl_Ui_Selection_Data *sel_data) +static Eina_Value +_selection_data_cb(Efl_Ui_Textbox *obj, void *data EINA_UNUSED, const Eina_Value value) { + Eina_Content *content; + Eina_Slice slice; Efl_Text_Cursor *cur, *start, *end; Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 }; - char *buf = eina_slice_strdup(sel_data->content); - size_t len = sel_data->content.len; + if (eina_value_type_get(&value) != EINA_VALUE_TYPE_CONTENT) + return EINA_VALUE_EMPTY; + content = eina_value_to_content(&value); + slice = eina_content_data_get(content); efl_text_interactive_selection_cursors_get(obj, &start, &end); if (!efl_text_cursor_equal(start, end)) { @@ -426,83 +418,130 @@ _selection_data_cb(void *data EINA_UNUSED, Eo *obj, cur = efl_text_interactive_main_cursor_get(obj); info.type = EFL_TEXT_CHANGE_TYPE_INSERT; info.position = efl_text_cursor_position_get(cur); - info.length = len; - info.content = buf; - if (sel_data->format == EFL_UI_SELECTION_FORMAT_MARKUP) + info.length = slice.len; + info.content = slice.mem; + if (eina_streq(eina_content_type_get(content), "application/x-elementary-markup")) { - efl_text_cursor_markup_insert(cur, buf); + efl_text_cursor_markup_insert(cur, slice.mem); + } + else if (!strncmp(eina_content_type_get(content), "image/", strlen("image/"))) + { + Eina_Strbuf *result = eina_strbuf_new(); + eina_strbuf_append_printf(result, ""); + efl_text_cursor_markup_insert(cur, eina_strbuf_string_get(result)); + eina_strbuf_free(result); } else // TEXT { - efl_text_cursor_text_insert(cur, buf); + efl_text_cursor_text_insert(cur, slice.mem); } efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info); - free(buf); + + return EINA_VALUE_EMPTY; +} + +static Eina_Array* +_figure_out_types(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) +{ + Eina_Array *types = eina_array_new(10); + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP) + eina_array_push(types, "application/x-elementary-markup"); + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE) + { + eina_array_push(types, "image/png"); + eina_array_push(types, "image/jpeg"); + eina_array_push(types, "image/x-ms-bmp"); + eina_array_push(types, "image/gif"); + eina_array_push(types, "image/tiff"); + eina_array_push(types, "image/svg+xml"); + eina_array_push(types, "image/x-xpixmap"); + eina_array_push(types, "image/x-tga"); + eina_array_push(types, "image/x-portable-pixmap"); + } + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT) + eina_array_push(types, "text/plain;charset=utf-8"); + return types; +} + +static Eina_Bool +_accepting_drops(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Accessor *mime_types) +{ + int i = 0; + const char *mime_type; + + if (efl_ui_widget_disabled_get(obj)) return EINA_FALSE; + + EINA_ACCESSOR_FOREACH(mime_types, i, mime_type) + { + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT && + eina_streq(mime_type, "text/plain;charset=utf-8")) + return EINA_TRUE; + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE && + strncmp(mime_type, "image/", strlen("image/"))) + return EINA_TRUE; + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP && + eina_streq(mime_type, "application/x-elementary-markup")) + return EINA_TRUE; + } + return EINA_FALSE; } static void _dnd_enter_cb(void *data EINA_UNUSED, - Evas_Object *obj) + const Efl_Event *ev) { - efl_ui_focus_util_focus(obj); + Efl_Ui_Dnd_Event *dnd_enter = ev->info; + EFL_UI_TEXT_DATA_GET(ev->object, sd); + if (_accepting_drops(ev->object, sd, dnd_enter->available_types)) + efl_ui_focus_util_focus(ev->object); } static void -_dnd_leave_cb(void *data EINA_UNUSED, - Evas_Object *obj EINA_UNUSED) +_dnd_pos_cb(void *data EINA_UNUSED, const Efl_Event *ev) { -} + Efl_Ui_Dnd_Event *dnd_pos = ev->info; + Eina_Position2D po, pe, pos; + EFL_UI_TEXT_DATA_GET(ev->object, sd); + int cursor_pos; -static void -_dnd_pos_cb(void *data EINA_UNUSED, - Evas_Object *obj, - Evas_Coord x, - Evas_Coord y, - Elm_Xdnd_Action action EINA_UNUSED) -{ - int pos; - Eina_Rect o, e; + if (!_accepting_drops(ev->object, sd, dnd_pos->available_types)) + return; - EFL_UI_TEXT_DATA_GET(obj, sd); - - o = efl_gfx_entity_geometry_get(obj); - e = efl_gfx_entity_geometry_get(sd->entry_edje); - x = x + o.x - e.x; - y = y + o.y - e.y; + po = efl_gfx_entity_position_get(ev->object); + pe = efl_gfx_entity_position_get(sd->entry_edje); + pos.x = dnd_pos->position.x + po.x - pe.x; + pos.y = dnd_pos->position.y + po.x - pe.y; edje_object_part_text_cursor_coord_set - (sd->entry_edje, "efl.text", EDJE_CURSOR_USER, x, y); - pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "efl.text", EDJE_CURSOR_USER, pos.x, pos.y); + cursor_pos = edje_object_part_text_cursor_pos_get (sd->entry_edje, "efl.text", EDJE_CURSOR_USER); edje_object_part_text_cursor_pos_set(sd->entry_edje, "efl.text", - EDJE_CURSOR_MAIN, pos); + EDJE_CURSOR_MAIN, cursor_pos); } -static Eina_Bool -_dnd_drop_cb(void *data EINA_UNUSED, - Evas_Object *obj, - Elm_Selection_Data *drop) +static void +_dnd_drop_cb(void *data EINA_UNUSED, const Efl_Event *ev) { - Eina_Bool rv; + Efl_Ui_Dnd_Event *drop = ev->info; + Eina_Future *future; + Eina_Array *types; - EFL_UI_TEXT_DATA_GET(obj, sd); + EFL_UI_TEXT_DATA_GET(ev->object, sd); + types = _figure_out_types(ev->object, sd); - rv = edje_object_part_text_cursor_coord_set - (sd->entry_edje, "efl.text", EDJE_CURSOR_MAIN, drop->x, drop->y); + if (!_accepting_drops(ev->object, sd, drop->available_types)) + return; - if (!rv) WRN("Warning: Failed to position cursor: paste anyway"); + future = efl_ui_dnd_drop_data_get(ev->object, 0, eina_array_iterator_new(types)); + eina_array_free(types); - //rv = _selection_data_cb(NULL, obj, drop); - - return rv; -} - -static Elm_Sel_Format -_get_drop_format(Evas_Object *obj) -{ - if (efl_text_interactive_editable_get(obj) && (efl_text_multiline_get(obj)) && (!efl_text_password_get(obj)) && (!efl_ui_widget_disabled_get(obj))) - return EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_IMAGE; - return EFL_UI_SELECTION_FORMAT_MARKUP; + efl_future_then(ev->object, future, _selection_data_cb); } /* we can't reuse layout's here, because it's on entry_edje only */ @@ -516,12 +555,6 @@ _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Ein efl_ui_widget_disabled_set(efl_super(obj, MY_CLASS), disabled); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - emission = efl_ui_widget_disabled_get(obj) ? "efl,state,disabled" : "efl,state,enabled"; efl_layout_signal_emit(sd->entry_edje, emission, "efl"); if (sd->scroll) @@ -529,15 +562,6 @@ _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Ein efl_ui_scrollable_scroll_freeze_set(obj, efl_ui_widget_disabled_get(obj)); } - if (!efl_ui_widget_disabled_get(obj)) - { - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - } _update_text_theme(obj, sd); } @@ -804,83 +828,36 @@ _popup_position(Evas_Object *obj) efl_gfx_entity_geometry_set(sd->popup, EINA_RECT(r.x + cx, r.y + cy, m.w, m.h)); } -static Eina_Value -_selection_lost_cb(void *data, const Eina_Value value) +static void +_selection_lost_cb(void *data EINA_UNUSED, const Efl_Event *ev) { - Selection_Loss_Data *sdata = data; - EFL_UI_TEXT_DATA_GET(sdata->obj, sd); + Efl_Ui_Cnp_Buffer *buffer = ev->info; + EFL_UI_TEXT_DATA_GET(ev->object, sd); - efl_text_interactive_all_unselect(sdata->obj); - _selection_defer(sdata->obj, sd); - switch (sdata->stype) + if (*buffer == EFL_UI_CNP_BUFFER_SELECTION) { - case EFL_UI_SELECTION_TYPE_CLIPBOARD: - sd->sel_future.clipboard = NULL; - break; - case EFL_UI_SELECTION_TYPE_PRIMARY: - default: - sd->sel_future.primary = NULL; - break; + efl_text_interactive_all_unselect(ev->object); + _selection_defer(ev->object, sd); } - - return value; } static void -_selection_store(Efl_Ui_Selection_Type seltype, +_selection_store(Efl_Ui_Cnp_Buffer buffer, Evas_Object *obj) { char *sel; Efl_Text_Cursor *start, *end; - Efl_Ui_Selection_Format selformat = EFL_UI_SELECTION_FORMAT_MARKUP; - Eina_Slice slice; - Selection_Loss_Data *ldata; - Eina_Future *f; - - EFL_UI_TEXT_DATA_GET(obj, sd); + Eina_Content *content; efl_text_interactive_selection_cursors_get(obj, &start, &end); sel = efl_text_cursor_range_markup_get(start, end); if ((!sel) || (!sel[0])) return; /* avoid deleting our own selection */ - slice.len = strlen(sel); - slice.mem = sel; + content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(sel), "text/plain"); - switch (seltype) - { - case EFL_UI_SELECTION_TYPE_CLIPBOARD: - if (sd->sel_future.clipboard) - { - eina_future_cancel(sd->sel_future.clipboard); - } + efl_ui_selection_set(obj, buffer, content, 0); - f = sd->sel_future.clipboard = efl_ui_selection_set(obj, seltype, - selformat, slice, 1); - break; - - case EFL_UI_SELECTION_TYPE_PRIMARY: - default: - if (sd->sel_future.primary) - { - eina_future_cancel(sd->sel_future.primary); - } - - f = sd->sel_future.primary = efl_ui_selection_set(obj, seltype, - selformat, slice, 1); - break; - } - - ldata = calloc(1, sizeof(Selection_Loss_Data)); - if (!ldata) goto end; - - ldata->obj = obj; - eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata); - - //if (seltype == EFL_UI_SELECTION_TYPE_CLIPBOARD) - // eina_stringshare_replace(&sd->cut_sel, sel); - -end: free(sel); } @@ -956,7 +933,7 @@ _menu_call(Evas_Object *obj) { Eina_Bool ownersel; - ownersel = elm_selection_selection_has_owner(obj); + ownersel = elm_cnp_clipboard_selection_has_owner(obj); /* prevent stupid blank hoversel */ if (efl_text_interactive_have_selection_get(obj) && efl_text_password_get(obj)) return; if (_elm_config->desktop_entry && (!efl_text_interactive_have_selection_get(obj)) && ((!efl_text_interactive_editable_get(obj)) || (!ownersel))) @@ -1133,7 +1110,7 @@ _mouse_down_cb(void *data, const Efl_Event *event) if (ev->button == 2) { - _efl_ui_textbox_selection_paste_type(data, EFL_UI_SELECTION_TYPE_PRIMARY); + _efl_ui_textbox_selection_paste_type(data, sd, EFL_UI_CNP_BUFFER_SELECTION); } /* If right button is pressed and context menu disabled is true, @@ -1654,10 +1631,18 @@ _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd) { Eo *text_obj; + sd->content = EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP; + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); if (!elm_widget_theme_klass_get(obj)) elm_widget_theme_klass_set(obj, "text"); + + efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_lost_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_ENTER, _dnd_enter_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_POS, _dnd_pos_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_DROP, _dnd_drop_cb, NULL); + obj = efl_constructor(efl_super(obj, MY_CLASS)); efl_event_callback_add(obj, EFL_INPUT_EVENT_LONGPRESSED, _long_press_cb, obj); @@ -1674,11 +1659,9 @@ _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd) efl_composite_attach(obj, text_obj); sd->entry_edje = wd->resize_obj; - sd->cnp_mode = EFL_UI_SELECTION_FORMAT_TEXT; sd->context_menu_enabled = EINA_TRUE; efl_text_interactive_editable_set(obj, EINA_TRUE); efl_text_interactive_selection_allowed_set(obj, EINA_TRUE); - sd->drop_format = EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_IMAGE; sd->last.scroll = EINA_SIZE2D(0, 0); sd->sel_handles_enabled = EINA_FALSE; @@ -1691,12 +1674,6 @@ _efl_ui_textbox_efl_object_finalize(Eo *obj, { obj = efl_finalize(efl_super(obj, MY_CLASS)); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY); _update_guide_text(obj, sd); @@ -1805,11 +1782,6 @@ _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, E efl_text_replacement_char_set(obj, ENTRY_PASSWORD_MASK_CHARACTER_UTF8); efl_text_password_set(sd->text_obj, password); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (password) { efl_text_multiline_set(obj, EINA_FALSE); @@ -1819,12 +1791,6 @@ _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, E else { efl_text_multiline_set(obj, EINA_TRUE); - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); efl_input_text_input_content_type_set(obj, ((efl_input_text_input_content_type_get(obj) | EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE) & ~EFL_INPUT_TEXT_CONTENT_TYPE_SENSITIVE_DATA)); efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY); } @@ -1891,19 +1857,8 @@ _efl_ui_textbox_efl_text_interactive_editable_set(Eo *obj, Efl_Ui_Textbox_Data * efl_ui_widget_theme_apply(obj); efl_ui_widget_focus_allow_set(obj, editable); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (editable) { - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (sd->cursor) { efl_gfx_entity_visible_set(sd->cursor, EINA_TRUE); @@ -1961,7 +1916,7 @@ _efl_ui_textbox_selection_cut(Eo *obj, Efl_Ui_Textbox_Data *sd) /*In password mode, cut will remove text only*/ if (!efl_text_password_get(obj)) - _selection_store(EFL_UI_SELECTION_TYPE_CLIPBOARD, obj); + _selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj); efl_text_interactive_selection_cursors_get(obj, &start, &end); start_pos = efl_text_cursor_position_get(start); @@ -1993,25 +1948,27 @@ _efl_ui_textbox_selection_copy(Eo *obj, Efl_Ui_Textbox_Data *sd) efl_layout_signal_emit(sd->entry_edje, "efl,state,select,off", "efl"); efl_ui_widget_scroll_hold_pop(obj); } - _selection_store(EFL_UI_SELECTION_TYPE_CLIPBOARD, obj); + _selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj); efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_COPY, NULL); } - static void -_efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Selection_Type type) +_efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type) { - Efl_Ui_Selection_Format formats = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP; + Eina_Future *future; + Eina_Array *types = _figure_out_types(obj, sd); - efl_ui_selection_get(obj, type, formats, - NULL, _selection_data_cb, NULL, 1); + future = efl_ui_selection_get(obj, type, 0, eina_array_iterator_new(types)); + + efl_future_then(obj, future, _selection_data_cb); efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_PASTE, NULL); + eina_array_free(types); } EOLIAN static void -_efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd EINA_UNUSED) +_efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd) { - _efl_ui_textbox_selection_paste_type(obj, EFL_UI_SELECTION_TYPE_CLIPBOARD); + _efl_ui_textbox_selection_paste_type(obj, sd, EFL_UI_CNP_BUFFER_COPY_AND_PASTE); } EOLIAN static void @@ -2028,44 +1985,15 @@ _efl_ui_textbox_context_menu_enabled_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textb } EOLIAN static void -_efl_ui_textbox_cnp_mode_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Selection_Format cnp_mode) +_efl_ui_textbox_cnp_dnd_mode_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Efl_Ui_Textbox_Cnp_Content content) { - Elm_Sel_Format dnd_format = EFL_UI_SELECTION_FORMAT_MARKUP; - - if (cnp_mode != EFL_UI_SELECTION_FORMAT_TARGETS) - { - if (cnp_mode & EFL_UI_SELECTION_FORMAT_VCARD) - ERR("VCARD format not supported for copy & paste!"); - else if (cnp_mode & EFL_UI_SELECTION_FORMAT_HTML) - ERR("HTML format not supported for copy & paste!"); - cnp_mode &= ~EFL_UI_SELECTION_FORMAT_VCARD; - cnp_mode &= ~EFL_UI_SELECTION_FORMAT_HTML; - } - - if (sd->cnp_mode == cnp_mode) return; - sd->cnp_mode = cnp_mode; - if (sd->cnp_mode == EFL_UI_SELECTION_FORMAT_TEXT) - dnd_format = EFL_UI_SELECTION_FORMAT_TEXT; - else if (cnp_mode == EFL_UI_SELECTION_FORMAT_IMAGE) - dnd_format |= EFL_UI_SELECTION_FORMAT_IMAGE; - - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - sd->drop_format = dnd_format; - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); + sd->content = content; } -EOLIAN static Efl_Ui_Selection_Format -_efl_ui_textbox_cnp_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) +EOLIAN static Efl_Ui_Textbox_Cnp_Content +_efl_ui_textbox_cnp_dnd_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) { - return sd->cnp_mode; + return sd->content; } EOLIAN static void @@ -3279,7 +3207,7 @@ _efl_ui_textbox_selection_changed_cb(void *data, const Efl_Event *event EINA_UNU Eo *obj = data; EFL_UI_TEXT_DATA_GET(obj, sd); _edje_signal_emit(sd, "selection,changed", "efl.text"); - _selection_store(EFL_UI_SELECTION_TYPE_PRIMARY, obj); + _selection_store(EFL_UI_CNP_BUFFER_SELECTION, obj); _selection_defer(obj, sd); } diff --git a/src/lib/elementary/efl_ui_textbox.eo b/src/lib/elementary/efl_ui_textbox.eo index 2b7ccf9472..ff0898b6fc 100644 --- a/src/lib/elementary/efl_ui_textbox.eo +++ b/src/lib/elementary/efl_ui_textbox.eo @@ -1,3 +1,10 @@ +enum Efl.Ui.Textbox_Cnp_Content { + Nothing = 0, [[You can paste or drop nothing]] + Text = 1, [[You can paste normal Text]] + Markup = 3, [[You can paste Markup (Normal text is also just markup)]] + Image = 4, [[You can paste Images]] +} + class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Clickable, Efl.Access.Text, Efl.Access.Editable.Text composites @@ -31,8 +38,7 @@ class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Click enabled: bool; [[$true to enable the contextual menu.]] } } - @property cnp_mode @beta { - /* FIXME: Efl.Ui.Selection_Format does not allow markup without images! */ + @property cnp_dnd_mode @beta { [[Control pasting of text and images for the widget. Normally the entry allows both text and images to be pasted. @@ -44,7 +50,7 @@ class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Click get { } values { - format: Efl.Ui.Selection_Format; [[Format for copy & paste.]] + allowed_formats : Efl.Ui.Textbox_Cnp_Content; [[Format for cnp]] } } @property selection_handles_enabled { diff --git a/src/lib/elementary/efl_ui_win.c b/src/lib/elementary/efl_ui_win.c index 2430b50638..7235cd1bea 100644 --- a/src/lib/elementary/efl_ui_win.c +++ b/src/lib/elementary/efl_ui_win.c @@ -213,6 +213,9 @@ struct _Efl_Ui_Win_Data int ignore_frame_resize; Eina_Bool req_wh : 1; Eina_Bool req_xy : 1; + Eina_Array *selection_changed; + Eina_Array *planned_changes; + Eina_Inarray *drop_target; struct { short pointer_move; @@ -382,6 +385,8 @@ static void _elm_win_frame_style_update(Efl_Ui_Win_Data *sd, Eina_Bool force_emi static inline void _elm_win_need_frame_adjust(Efl_Ui_Win_Data *sd, const char *engine); static void _elm_win_resize_objects_eval(Evas_Object *obj, Eina_Bool force_resize); static void _elm_win_frame_obj_update(Efl_Ui_Win_Data *sd, Eina_Bool force); +static void _ee_backbone_init(Efl_Ui_Win *obj, Efl_Ui_Win_Data *pd); +static void _ee_backbone_shutdown(Efl_Ui_Win *obj, Efl_Ui_Win_Data *pd); static inline Efl_Ui_Win_Type _elm_win_type_to_efl_ui_win_type(Elm_Win_Type type) @@ -5933,6 +5938,7 @@ _efl_ui_win_efl_object_finalize(Eo *obj, Efl_Ui_Win_Data *sd) efl_file_mmap_get(efl_super(efl_part(obj, "background"), EFL_UI_WIN_PART_CLASS))) efl_file_load(efl_part(obj, "background")); } + _ee_backbone_init(obj, sd); return obj; } @@ -5968,6 +5974,8 @@ _efl_ui_win_efl_object_destructor(Eo *obj, Efl_Ui_Win_Data *pd EINA_UNUSED) if (pd->finalize_future) eina_future_cancel(pd->finalize_future); + _ee_backbone_shutdown(obj, pd); + efl_destructor(efl_super(obj, MY_CLASS)); efl_unref(pd->provider); @@ -5984,6 +5992,7 @@ _efl_ui_win_efl_object_constructor(Eo *obj, Efl_Ui_Win_Data *pd) pd->provider = efl_add_ref(EFL_UI_FOCUS_PARENT_PROVIDER_STANDARD_CLASS, NULL); pd->profile.available = eina_array_new(4); pd->max_w = pd->max_h = -1; + pd->planned_changes = eina_array_new(10); // For bindings: if no parent, allow simple unref if (!efl_parent_get(obj)) @@ -9187,6 +9196,211 @@ elm_win_teamwork_uri_open(Efl_Ui_Win *obj EINA_UNUSED, const char *uri EINA_UNUS ERR("Calling deprecrated function '%s'", __FUNCTION__); } +/* What here follows is code that implements the glue between ecore evas and efl_ui* side */ +typedef struct { + Eo *obj; + Eina_Bool currently_inside; +} Ui_Dnd_Target; + +static inline Efl_Ui_Cnp_Buffer +_ui_buffer_get(Ecore_Evas_Selection_Buffer buffer) +{ + if (buffer == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + return EFL_UI_CNP_BUFFER_SELECTION; + else if (buffer == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return EFL_UI_CNP_BUFFER_COPY_AND_PASTE; + + return -1; +} + +void +_register_selection_changed(Efl_Ui_Selection *selection) +{ + ELM_WIN_DATA_GET(efl_provider_find(selection, EFL_UI_WIN_CLASS), pd); + + eina_array_push(pd->planned_changes, selection); +} + +static Eina_Bool +_remove_object(void *data, void *gdata) +{ + if (data == gdata) + return EINA_FALSE; + return EINA_TRUE; +} + +static void +_selection_changed_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + Efl_Ui_Wm_Selection_Changed changed = { + .seat = seat, + .buffer = _ui_buffer_get(selection), + .caused_by = eina_array_count(pd->planned_changes) > 0 ? eina_array_data_get(pd->planned_changes, 0) : NULL, + }; + + for (unsigned int i = 0; i < eina_array_count(pd->selection_changed); ++i) + { + Eo *obj = eina_array_data_get(pd->selection_changed, i); + + efl_event_callback_call(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &changed); + } + + if (changed.caused_by) + eina_array_remove(pd->planned_changes, _remove_object, changed.caused_by); +} + +static void +_motion_cb(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + Efl_Ui_Dnd_Event ev = {p, seat, ecore_evas_drop_available_types_get(ee, seat)}; + + if (target->currently_inside && !inside) + { + target->currently_inside = EINA_FALSE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_LEAVE, &ev); + } + else if (!target->currently_inside && inside) + { + target->currently_inside = EINA_TRUE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_ENTER, &ev); + } + else if (target->currently_inside && inside) + { + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_POS, &ev); + } + eina_accessor_free(ev.available_types); + } +} + +static void +_enter_state_change_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, Eina_Bool move_inside) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + Efl_Ui_Dnd_Event ev = {p, seat, ecore_evas_drop_available_types_get(ee, seat)}; + + if (inside && move_inside) + { + target->currently_inside = EINA_TRUE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_ENTER, &ev); + } + else if (!move_inside && !target->currently_inside) + { + target->currently_inside = EINA_FALSE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_LEAVE, &ev); + } + } +} + +static void +_drop_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, const char *action) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + Efl_Ui_Dnd_Drop_Event ev = {{p, seat, ecore_evas_drop_available_types_get(ee, seat)}, action}; + + if (inside) + { + EINA_SAFETY_ON_FALSE_RETURN(target->currently_inside); + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_DROP, &ev); + } + } +} + +static void +_ee_backbone_init(Efl_Ui_Win *obj EINA_UNUSED, Efl_Ui_Win_Data *pd) +{ + pd->selection_changed = eina_array_new(1); + pd->drop_target = eina_inarray_new(sizeof(Ui_Dnd_Target), 1); + + ecore_evas_callback_selection_changed_set(pd->ee, _selection_changed_cb); + ecore_evas_callback_drop_drop_set(pd->ee, _drop_cb); + ecore_evas_callback_drop_motion_set(pd->ee, _motion_cb); + ecore_evas_callback_drop_state_changed_set(pd->ee, _enter_state_change_cb); +} + +static void +_ee_backbone_shutdown(Efl_Ui_Win *obj EINA_UNUSED, Efl_Ui_Win_Data *pd) +{ + ecore_evas_callback_selection_changed_set(pd->ee, NULL); + ecore_evas_callback_drop_drop_set(pd->ee, NULL); + ecore_evas_callback_drop_motion_set(pd->ee, NULL); + ecore_evas_callback_drop_state_changed_set(pd->ee, NULL); + + eina_array_free(pd->selection_changed); + pd->selection_changed = NULL; + eina_inarray_free(pd->drop_target); + pd->drop_target = NULL; + +} + +static Eina_Bool +_remove(void *data, void *gdata) +{ + if (data == gdata) + return EINA_FALSE; + return EINA_TRUE; +} + +void +_drop_event_register(Eo *obj) +{ + Ui_Dnd_Target target = {obj, EINA_FALSE}; + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + EINA_SAFETY_ON_NULL_RETURN(pd); + + eina_inarray_push(pd->drop_target, &target); +} + +void +_drop_event_unregister(Eo *obj) +{ + int idx = -1; + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + if (target->obj == obj) + { + //FIXME emit drop + target->currently_inside = EINA_FALSE; + idx = i; + } + } + if (idx != -1) + eina_inarray_remove_at(pd->drop_target, idx); +} + +void +_selection_changed_event_register(Eo *obj) +{ + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + eina_array_push(pd->selection_changed, obj); +} +void +_selection_changed_event_unregister(Eo *obj) +{ + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + eina_array_remove(pd->selection_changed, _remove, obj); +} /* Internal EO APIs and hidden overrides */ ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_win, Efl_Ui_Win_Data) diff --git a/src/lib/elementary/elm_cnp.c b/src/lib/elementary/elm_cnp.c new file mode 100644 index 0000000000..b4c1c930de --- /dev/null +++ b/src/lib/elementary/elm_cnp.c @@ -0,0 +1,235 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include + +#include "elm_priv.h" +#include "elm_entry_eo.h" + +static inline Ecore_Evas_Selection_Buffer +_elm_sel_type_to_ee_type(Elm_Sel_Type type) +{ + if (type == ELM_SEL_TYPE_PRIMARY) + return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER; + if (type == ELM_SEL_TYPE_XDND) + return ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER; + if (type == ELM_SEL_TYPE_CLIPBOARD) + return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER; + return ECORE_EVAS_SELECTION_BUFFER_LAST; +} + +static inline Eina_Array* +_elm_sel_format_to_mime_type(Elm_Sel_Format format) +{ + Eina_Array *ret = eina_array_new(10); + if (format & ELM_SEL_FORMAT_TEXT) + eina_array_push(ret, eina_stringshare_add("text/plain;charset=utf-8")); + if (format & ELM_SEL_FORMAT_MARKUP) + eina_array_push(ret, eina_stringshare_add("application/x-elementary-markup")); + if (format & ELM_SEL_FORMAT_IMAGE) + { + eina_array_push(ret, "image/png"); + eina_array_push(ret, "image/jpeg"); + eina_array_push(ret, "image/x-ms-bmp"); + eina_array_push(ret, "image/gif"); + eina_array_push(ret, "image/tiff"); + eina_array_push(ret, "image/svg+xml"); + eina_array_push(ret, "image/x-xpixmap"); + eina_array_push(ret, "image/x-tga"); + eina_array_push(ret, "image/x-portable-pixmap"); + } + if (format & ELM_SEL_FORMAT_VCARD) + eina_array_push(ret, eina_stringshare_add("text/vcard")); + if (format & ELM_SEL_FORMAT_HTML) + eina_array_push(ret, eina_stringshare_add("application/xhtml+xml")); + + if (eina_array_count(ret) == 0) + ERR("Specified mime type is not available"); + + return ret; +} + +static inline const Elm_Sel_Format +_mime_type_to_elm_sel_format(const char *mime_type) +{ + if (eina_streq(mime_type, "text/vcard")) + return ELM_SEL_FORMAT_VCARD; + else if (eina_streq(mime_type, "application/x-elementary-markup")) + return ELM_SEL_FORMAT_MARKUP; + else if (eina_streq(mime_type, "application/xhtml+xml")) + return ELM_SEL_FORMAT_HTML; + else if (!strncmp(mime_type, "text/", strlen("text/"))) + return ELM_SEL_FORMAT_TEXT; + else if (!strncmp(mime_type, "image/", strlen("image/"))) + return ELM_SEL_FORMAT_IMAGE; + + return ELM_SEL_FORMAT_NONE; +} + +EAPI Eina_Bool +elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, + Elm_Sel_Format format, + const void *buf, size_t buflen) +{ + Eina_Content *content; + Ecore_Evas *ee; + const char *mime_type; + Eina_Slice data; + Eina_Array *tmp; + + if (format == ELM_SEL_FORMAT_TEXT && ((char*)buf)[buflen - 1] != '\0') + { + data.mem = eina_memdup((unsigned char *)buf, buflen, EINA_TRUE); + data.len = buflen + 1; + } + else + { + data.mem = buf; + data.len = buflen; + } + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + + tmp = _elm_sel_format_to_mime_type(format); + if (eina_array_count(tmp) != 1) + { + ERR("You cannot specify more than one format when setting selection"); + } + mime_type = eina_array_data_get(tmp, 0); + content = eina_content_new(data, mime_type); + _register_selection_changed(obj); + + return ecore_evas_selection_set(ee, 0, _elm_sel_type_to_ee_type(selection), content); +} + +EAPI Eina_Bool +elm_object_cnp_selection_clear(Evas_Object *obj, + Elm_Sel_Type selection) +{ + Ecore_Evas *ee; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + return ecore_evas_selection_set(ee, 0, _elm_sel_type_to_ee_type(selection), NULL); +} + +EAPI Eina_Bool +elm_cnp_clipboard_selection_has_owner(Evas_Object *obj) +{ + Ecore_Evas *ee; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + return ecore_evas_selection_exists(ee, 0, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); + +} + +typedef struct _Sel_Lost_Data Sel_Lost_Data; +struct _Sel_Lost_Data +{ + const Evas_Object *obj; + Elm_Sel_Type type; + void *udata; + Elm_Selection_Loss_Cb loss_cb; +}; + +static void +_seleciton_changed_cb(void *data, const Efl_Event *ev) +{ + Sel_Lost_Data *ldata = data; + Efl_Ui_Wm_Selection_Changed *changed = ev->info; + + if (changed->buffer != EFL_UI_CNP_BUFFER_SELECTION) + return; + + if (ldata->obj == changed->caused_by) + return; + + ldata->loss_cb(ldata->udata, ldata->type); + free(data); + efl_event_callback_del(ev->object, ev->desc, _seleciton_changed_cb, data); +} + +EAPI void +elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, Elm_Selection_Loss_Cb func, const void *data) +{ + Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data)); + + if (!ldata) return; + ldata->obj = obj; + ldata->type = type; + ldata->udata = (void *)data; + ldata->loss_cb = func; + efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _seleciton_changed_cb, ldata); +} + +typedef struct { + Elm_Drop_Cb data_cb; + void *data; + Elm_Sel_Format format; +} Callback_Storage; + +static Eina_Value +_callback_storage_deliver(Eo *obj, void *data, const Eina_Value value) +{ + Callback_Storage *cb_storage = data; + Eina_Content *content = eina_value_to_content(&value); + Elm_Sel_Format format = _mime_type_to_elm_sel_format(eina_content_type_get(content)); + Eina_Slice cdata; + + cdata = eina_content_data_get(content); + Elm_Selection_Data d = { 0 }; + d.data = eina_memdup((unsigned char*)cdata.bytes, cdata.len, EINA_FALSE); + d.len = cdata.len; + d.format = _mime_type_to_elm_sel_format(eina_content_type_get(content)); + + if (cb_storage->data_cb) + { + cb_storage->data_cb(cb_storage->data, obj, &d); + } + else + { + EINA_SAFETY_ON_FALSE_RETURN_VAL(format == ELM_SEL_FORMAT_TEXT || format == ELM_SEL_FORMAT_MARKUP || format == ELM_SEL_FORMAT_HTML, EINA_VALUE_EMPTY); + + _elm_entry_entry_paste(obj, (const char *) d.data); + } + free(d.data); + + return EINA_VALUE_EMPTY; +} + +static Eina_Value +_callback_storage_error(Eo *obj EINA_UNUSED, void *data EINA_UNUSED, Eina_Error error) +{ + ERR("Content cound not be received because of %s.", eina_error_msg_get(error)); + return EINA_VALUE_EMPTY; +} + +static void +_callback_storage_free(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED) +{ + free(data); +} + +EAPI Eina_Bool +elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type selection, + Elm_Sel_Format format, + Elm_Drop_Cb data_cb, void *udata) +{ + Ecore_Evas *ee; + Eina_Array *mime_types; + Eina_Future *future; + Callback_Storage *storage; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + mime_types = _elm_sel_format_to_mime_type(format); + future = ecore_evas_selection_get(ee, 0, _elm_sel_type_to_ee_type(selection), eina_array_iterator_new(mime_types)); + storage = calloc(1,sizeof(Callback_Storage)); + storage->data_cb = data_cb; + storage->data = udata; + storage->format = format; + + efl_future_then(obj, future, _callback_storage_deliver, _callback_storage_error, _callback_storage_free, EINA_VALUE_TYPE_CONTENT, storage); + + return EINA_TRUE; +} diff --git a/src/lib/elementary/elm_cnp.h b/src/lib/elementary/elm_cnp.h index 5feda3acc0..06346e40a5 100644 --- a/src/lib/elementary/elm_cnp.h +++ b/src/lib/elementary/elm_cnp.h @@ -43,8 +43,6 @@ * @{ */ -# include - /** * Event notifying that the selection has changed * @see Elm_Cnp_Event_Selection_Changed diff --git a/src/lib/elementary/elm_dnd.c b/src/lib/elementary/elm_dnd.c new file mode 100644 index 0000000000..b128da0126 --- /dev/null +++ b/src/lib/elementary/elm_dnd.c @@ -0,0 +1,806 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + + +#include +#include "elm_priv.h" + +int ELM_CNP_EVENT_SELECTION_CHANGED; + +typedef struct { + void *enter_data, *leave_data, *pos_data, *drop_data; + Elm_Drag_State enter_cb; + Elm_Drag_State leave_cb; + Elm_Drag_Pos pos_cb; + Elm_Drop_Cb drop_cb; + Eina_Array *mime_types; + Elm_Sel_Format format; + Elm_Xdnd_Action action; +} Elm_Drop_Target; + +static const char* +_action_to_string(Elm_Xdnd_Action action) +{ + if (action == ELM_XDND_ACTION_COPY) return "copy"; + if (action == ELM_XDND_ACTION_MOVE) return "move"; + if (action == ELM_XDND_ACTION_PRIVATE) return "private"; + if (action == ELM_XDND_ACTION_ASK) return "ask"; + if (action == ELM_XDND_ACTION_LIST) return "list"; + if (action == ELM_XDND_ACTION_LINK) return "link"; + if (action == ELM_XDND_ACTION_DESCRIPTION) return "description"; + return "unknown"; +} + +static Elm_Xdnd_Action +_string_to_action(const char* action) +{ + if (eina_streq(action, "copy")) return ELM_XDND_ACTION_COPY; + else if (eina_streq(action, "move")) return ELM_XDND_ACTION_MOVE; + else if (eina_streq(action, "privat")) return ELM_XDND_ACTION_PRIVATE; + else if (eina_streq(action, "ask")) return ELM_XDND_ACTION_ASK; + else if (eina_streq(action, "list")) return ELM_XDND_ACTION_LIST; + else if (eina_streq(action, "link")) return ELM_XDND_ACTION_LINK; + else if (eina_streq(action, "description")) return ELM_XDND_ACTION_DESCRIPTION; + return ELM_XDND_ACTION_UNKNOWN; +} + +static void +_enter_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + + if (target->enter_cb) + target->enter_cb(target->enter_data, ev->object); +} + +static void +_leave_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + + if (target->leave_cb) + target->leave_cb(target->leave_data, ev->object); +} + +static void +_pos_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + Efl_Ui_Dnd_Event *event = ev->info; + + if (target->pos_cb) + target->pos_cb(target->pos_data, ev->object, event->position.x, event->position.y, target->action); //FIXME action +} + +static Eina_Value +_deliver_content(Eo *obj, void *data, const Eina_Value value) +{ + Elm_Drop_Target *target = data; + Elm_Selection_Data sel_data; + Eina_Content *content = eina_value_to_content(&value); + + sel_data.data = (void*)eina_content_data_get(content).mem; + sel_data.len = eina_content_data_get(content).len; + sel_data.action = target->action; + sel_data.format = target->format; + + if (target->drop_cb) + target->drop_cb(target->drop_data, obj, &sel_data); + + return EINA_VALUE_EMPTY; +} + +static void +_drop_cb(void *data, const Efl_Event *ev) +{ + Efl_Ui_Dnd_Drop_Event *event = ev->info; + Elm_Drop_Target *target = data; + target->action = _string_to_action(event->action); + efl_future_then(ev->object, efl_ui_dnd_drop_data_get(ev->object, 0, eina_array_iterator_new(target->mime_types)), + .success = _deliver_content, + .data = target + ); +} + +static void +_inv_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + elm_drop_target_del(ev->object, target->format, target->enter_cb, target->enter_data, target->leave_cb, + target->leave_data, target->pos_cb, target->pos_data, target->drop_cb, target->drop_data); +} + +EFL_CALLBACKS_ARRAY_DEFINE(drop_target_cb, + {EFL_UI_DND_EVENT_DROP_ENTER, _enter_cb}, + {EFL_UI_DND_EVENT_DROP_LEAVE, _leave_cb}, + {EFL_UI_DND_EVENT_DROP_POS, _pos_cb}, + {EFL_UI_DND_EVENT_DROP_DROP, _drop_cb}, + {EFL_EVENT_INVALIDATE, _inv_cb} +) + +static Eina_Hash *target_register = NULL; + +static Eina_Array* +_format_to_mime_array(Elm_Sel_Format format) +{ + Eina_Array *ret = eina_array_new(10); + + if (format & ELM_SEL_FORMAT_TEXT) + eina_array_push(ret, "text/plain;charset=utf-8"); + if (format & ELM_SEL_FORMAT_MARKUP) + eina_array_push(ret, "application/x-elementary-markup"); + if (format & ELM_SEL_FORMAT_IMAGE) + { + eina_array_push(ret, "image/png"); + eina_array_push(ret, "image/jpeg"); + eina_array_push(ret, "image/x-ms-bmp"); + eina_array_push(ret, "image/gif"); + eina_array_push(ret, "image/tiff"); + eina_array_push(ret, "image/svg+xml"); + eina_array_push(ret, "image/x-xpixmap"); + eina_array_push(ret, "image/x-tga"); + eina_array_push(ret, "image/x-portable-pixmap"); + } + if (format & ELM_SEL_FORMAT_VCARD) + eina_array_push(ret, "text/vcard"); + if (format & ELM_SEL_FORMAT_HTML) + eina_array_push(ret, "text/html"); + + return ret; +} + +EAPI Eina_Bool +elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format, + Elm_Drag_State enter_cb, void *enter_data, + Elm_Drag_State leave_cb, void *leave_data, + Elm_Drag_Pos pos_cb, void *pos_data, + Elm_Drop_Cb drop_cb, void *drop_data) +{ + + Elm_Drop_Target *target = calloc(1, sizeof(Elm_Drop_Target)); + target->enter_cb = enter_cb; + target->enter_data = enter_data; + target->leave_cb = leave_cb; + target->leave_data = leave_data; + target->pos_cb = pos_cb; + target->pos_data = pos_data; + target->drop_cb = drop_cb; + target->drop_data = drop_data; + target->mime_types = _format_to_mime_array(format); + target->format = format; + + efl_event_callback_array_add(obj, drop_target_cb(), target); + + if (!target_register) + target_register = eina_hash_pointer_new(NULL); + eina_hash_list_append(target_register, &obj, target); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, + Elm_Drag_State enter_cb, void *enter_data, + Elm_Drag_State leave_cb, void *leave_data, + Elm_Drag_Pos pos_cb, void *pos_data, + Elm_Drop_Cb drop_cb, void *drop_data) +{ + Elm_Drop_Target *target; + Eina_List *n, *found = NULL; + + if (!target_register) + return EINA_TRUE; + Eina_List *targets = eina_hash_find(target_register, &obj); + + if (!targets) + return EINA_TRUE; + + EINA_LIST_FOREACH(targets, n, target) + { + if (target->enter_cb == enter_cb && target->enter_data == enter_data && + target->leave_cb == leave_cb && target->leave_data == leave_data && + target->pos_cb == pos_cb && target->pos_data == pos_data && + target->drop_cb == drop_cb && target->drop_data == drop_data && + target->format == format) + { + + found = n; + break; + } + } + if (found) + { + efl_event_callback_array_del(obj, drop_target_cb(), eina_list_data_get(found)); + eina_hash_list_remove(target_register, &obj, target); + eina_array_free(target->mime_types); + free(target); + } + + return EINA_TRUE; +} + +struct _Item_Container_Drag_Info +{ /* Info kept for containers to support drag */ + Evas_Object *obj; + Ecore_Timer *tm; /* When this expires, start drag */ + double anim_tm; /* Time period to set tm */ + double tm_to_drag; /* Time period to set tm */ + Elm_Xy_Item_Get_Cb itemgetcb; + Elm_Item_Container_Data_Get_Cb data_get; + + Evas_Coord x_down; /* Mouse down x cord when drag starts */ + Evas_Coord y_down; /* Mouse down y cord when drag starts */ + + /* Some extra information needed to impl default anim */ + Evas *e; + Eina_List *icons; /* List of icons to animate (Anim_Icon) */ + int final_icon_w; /* We need the w and h of the final icon for the animation */ + int final_icon_h; + Ecore_Animator *ea; + + Elm_Drag_User_Info user_info; +}; +typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info; + +struct _Anim_Icon +{ + int start_x; + int start_y; + int start_w; + int start_h; + Evas_Object *o; +}; +typedef struct _Anim_Icon Anim_Icon; +static Eina_List *cont_drag_tg = NULL; /* List of Item_Container_Drag_Info */ + +static Eina_Bool elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full); +static void _cont_obj_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); +static void _cont_obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); +static void _cont_obj_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info); + +static void +_cont_drag_done_cb(void *data, Evas_Object *obj EINA_UNUSED) +{ + Item_Container_Drag_Info *st = data; + elm_widget_scroll_freeze_pop(st->obj); + if (st->user_info.dragdone) + st->user_info.dragdone(st->user_info.donecbdata, NULL, EINA_FALSE); /*FIXME*/ +} + +static Eina_Bool +_cont_obj_drag_start(void *data) +{ /* Start a drag-action when timer expires */ + Item_Container_Drag_Info *st = data; + st->tm = NULL; + Elm_Drag_User_Info *info = &st->user_info; + if (info->dragstart) info->dragstart(info->startcbdata, st->obj); + elm_widget_scroll_freeze_push(st->obj); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + elm_drag_start( /* Commit the start only if data_get successful */ + st->obj, info->format, + info->data, info->action, + info->createicon, info->createdata, + info->dragpos, info->dragdata, + info->acceptcb, info->acceptdata, + _cont_drag_done_cb, st); + ELM_SAFE_FREE(info->data, free); + + return ECORE_CALLBACK_CANCEL; +} + +static inline Eina_List * +_anim_icons_make(Eina_List *icons) +{ /* Make local copies of all icons, add them to list */ + Eina_List *list = NULL, *itr; + Evas_Object *o; + + EINA_LIST_FOREACH(icons, itr, o) + { /* Now add icons to animation window */ + Anim_Icon *st = calloc(1, sizeof(*st)); + + if (!st) + { + ERR("Failed to allocate memory for icon!"); + continue; + } + + evas_object_geometry_get(o, &st->start_x, &st->start_y, &st->start_w, &st->start_h); + evas_object_show(o); + st->o = o; + list = eina_list_append(list, st); + } + + return list; +} + +static Eina_Bool +_drag_anim_play(void *data, double pos) +{ /* Impl of the animation of icons, called on frame time */ + Item_Container_Drag_Info *st = data; + Eina_List *l; + Anim_Icon *sti; + + if (st->ea) + { + if (pos > 0.99) + { + st->ea = NULL; /* Avoid deleting on mouse up */ + EINA_LIST_FOREACH(st->icons, l, sti) + evas_object_hide(sti->o); + + _cont_obj_drag_start(st); /* Start dragging */ + return ECORE_CALLBACK_CANCEL; + } + + Evas_Coord xm, ym; + evas_pointer_canvas_xy_get(st->e, &xm, &ym); + EINA_LIST_FOREACH(st->icons, l, sti) + { + int x, y, h, w; + w = sti->start_w + ((st->final_icon_w - sti->start_w) * pos); + h = sti->start_h + ((st->final_icon_h - sti->start_h) * pos); + x = sti->start_x - (pos * ((sti->start_x + (w/2) - xm))); + y = sti->start_y - (pos * ((sti->start_y + (h/2) - ym))); + evas_object_move(sti->o, x, y); + evas_object_resize(sti->o, w, h); + } + + return ECORE_CALLBACK_RENEW; + } + + return ECORE_CALLBACK_CANCEL; +} + +static inline Eina_Bool +_drag_anim_start(void *data) +{ /* Start default animation */ + Item_Container_Drag_Info *st = data; + + st->tm = NULL; + /* Now we need to build an (Anim_Icon *) list */ + st->icons = _anim_icons_make(st->user_info.icons); + if (st->user_info.createicon) + { + Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_DND); + Evas_Object *final_icon = st->user_info.createicon(st->user_info.createdata, temp_win, NULL, NULL); + evas_object_geometry_get(final_icon, NULL, NULL, &st->final_icon_w, &st->final_icon_h); + evas_object_del(final_icon); + evas_object_del(temp_win); + } + st->ea = ecore_animator_timeline_add(st->anim_tm, _drag_anim_play, st); + + return EINA_FALSE; +} + +static Eina_Bool +_cont_obj_anim_start(void *data) +{ /* Start a drag-action when timer expires */ + Item_Container_Drag_Info *st = data; + int xposret, yposret; /* Unused */ + Elm_Object_Item *it = (st->itemgetcb) ? + (st->itemgetcb(st->obj, st->x_down, st->y_down, &xposret, &yposret)) + : NULL; + + st->tm = NULL; + st->user_info.format = ELM_SEL_FORMAT_TARGETS; /* Default */ + st->icons = NULL; + st->user_info.data = NULL; + st->user_info.action = ELM_XDND_ACTION_COPY; /* Default */ + + if (!it) /* Failed to get mouse-down item, abort drag */ + return ECORE_CALLBACK_CANCEL; + + if (st->data_get) + { /* collect info then start animation or start dragging */ + if (st->data_get( /* Collect drag info */ + st->obj, /* The container object */ + it, /* Drag started on this item */ + &st->user_info)) + { + if (st->user_info.icons) + _drag_anim_start(st); + else + { + if (st->anim_tm) + { + // even if we don't manage the icons animation, we have + // to wait until it is finished before beginning drag. + st->tm = ecore_timer_add(st->anim_tm, _cont_obj_drag_start, st); + } + else + _cont_obj_drag_start(st); /* Start dragging, no anim */ + } + } + } + + return ECORE_CALLBACK_CANCEL; +} + +static int +_drag_item_container_cmp(const void *d1, + const void *d2) +{ + const Item_Container_Drag_Info *st = d1; + return (((uintptr_t) (st->obj)) - ((uintptr_t) d2)); +} + +void +_anim_st_free(Item_Container_Drag_Info *st) +{ /* Stops and free mem of ongoing animation */ + if (st) + { + ELM_SAFE_FREE(st->ea, ecore_animator_del); + Anim_Icon *sti; + + EINA_LIST_FREE(st->icons, sti) + { + evas_object_del(sti->o); + free(sti); + } + + st->icons = NULL; + } +} + +static void +_cont_obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Cancel any drag waiting to start on timeout */ + Item_Container_Drag_Info *st = data; + + if (((Evas_Event_Mouse_Up *)event_info)->button != 1) + return; /* We only process left-click at the moment */ + + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st); + + ELM_SAFE_FREE(st->tm, ecore_timer_del); + + _anim_st_free(st); +} + +static void +_cont_obj_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Cancel any drag waiting to start on timeout */ + if (((Evas_Event_Mouse_Move *)event_info)->event_flags & EVAS_EVENT_FLAG_ON_HOLD) + { + Item_Container_Drag_Info *st = data; + + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st); + elm_drag_item_container_del_internal(obj, EINA_FALSE); + + ELM_SAFE_FREE(st->tm, ecore_timer_del); + + _anim_st_free(st); + } +} + +static Eina_Bool +elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full) +{ + Item_Container_Drag_Info *st = + eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj); + + if (st) + { + ELM_SAFE_FREE(st->tm, ecore_timer_del); /* Cancel drag-start timer */ + + if (st->ea) /* Cancel ongoing default animation */ + _anim_st_free(st); + + if (full) + { + st->itemgetcb = NULL; + st->data_get = NULL; + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_MOUSE_DOWN, _cont_obj_mouse_down, st); + + cont_drag_tg = eina_list_remove(cont_drag_tg, st); + ELM_SAFE_FREE(st->user_info.data, free); + free(st); + } + + return EINA_TRUE; + } + return EINA_FALSE; +} + +static void +_cont_obj_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Launch a timer to start dragging */ + Evas_Event_Mouse_Down *ev = event_info; + if (ev->button != 1) + return; /* We only process left-click at the moment */ + + Item_Container_Drag_Info *st = data; + evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_MOVE, + _cont_obj_mouse_move, st); + + evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_UP, + _cont_obj_mouse_up, st); + + ecore_timer_del(st->tm); + + st->e = e; + st->x_down = ev->canvas.x; + st->y_down = ev->canvas.y; + st->tm = ecore_timer_add(st->tm_to_drag, _cont_obj_anim_start, st); +} +EAPI Eina_Bool +elm_drag_item_container_del(Evas_Object *obj) +{ + return elm_drag_item_container_del_internal(obj, EINA_TRUE); +} + +EAPI Eina_Bool +elm_drag_item_container_add(Evas_Object *obj, + double anim_tm, + double tm_to_drag, + Elm_Xy_Item_Get_Cb itemgetcb, + Elm_Item_Container_Data_Get_Cb data_get) +{ + Item_Container_Drag_Info *st; + + if (elm_drag_item_container_del_internal(obj, EINA_FALSE)) + { /* Updating info of existing obj */ + st = eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj); + if (!st) return EINA_FALSE; + } + else + { + st = calloc(1, sizeof(*st)); + if (!st) return EINA_FALSE; + + st->obj = obj; + cont_drag_tg = eina_list_append(cont_drag_tg, st); + + /* Register for mouse callback for container to start/abort drag */ + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, + _cont_obj_mouse_down, st); + } + + st->tm = NULL; + st->anim_tm = anim_tm; + st->tm_to_drag = tm_to_drag; + st->itemgetcb = itemgetcb; + st->data_get = data_get; + return EINA_TRUE; +} + +static Eina_List *cont_drop_tg = NULL; /* List of Item_Container_Drop_Info */ + +struct _Item_Container_Drop_Info +{ /* Info kept for containers to support drop */ + Evas_Object *obj; + Elm_Xy_Item_Get_Cb itemgetcb; + Elm_Drop_Item_Container_Cb dropcb; + Elm_Drag_Item_Container_Pos poscb; +}; +typedef struct _Item_Container_Drop_Info Item_Container_Drop_Info; + + +typedef struct +{ + Evas_Object *obj; + /* FIXME: Cache window */ + Eina_Inlist *cbs_list; /* List of Dropable_Cbs * */ + struct { + Evas_Coord x, y; + Eina_Bool in : 1; + const char *type; + Elm_Sel_Format format; + } last; +} Dropable; + +static int +_drop_item_container_cmp(const void *d1, + const void *d2) +{ + const Item_Container_Drop_Info *st = d1; + return (((uintptr_t) (st->obj)) - ((uintptr_t) d2)); +} + +static void +_elm_item_container_pos_cb(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action) +{ /* obj is the container pointer */ + Elm_Object_Item *it = NULL; + int xposret = 0; + int yposret = 0; + + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st && st->poscb) + { /* Call container drop func with specific item pointer */ + int xo = 0; + int yo = 0; + + evas_object_geometry_get(obj, &xo, &yo, NULL, NULL); + if (st->itemgetcb) + it = st->itemgetcb(obj, x+xo, y+yo, &xposret, &yposret); + + st->poscb(data, obj, it, x, y, xposret, yposret, action); + } +} + +static Eina_Bool +_elm_item_container_drop_cb(void *data, Evas_Object *obj , Elm_Selection_Data *ev) +{ /* obj is the container pointer */ + Elm_Object_Item *it = NULL; + int xposret = 0; + int yposret = 0; + + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st && st->dropcb) + { /* Call container drop func with specific item pointer */ + int xo = 0; + int yo = 0; + + evas_object_geometry_get(obj, &xo, &yo, NULL, NULL); + if (st->itemgetcb) + it = st->itemgetcb(obj, ev->x+xo, ev->y+yo, &xposret, &yposret); + + return st->dropcb(data, obj, it, ev, xposret, yposret); + } + + return EINA_FALSE; +} + +static Eina_Bool +elm_drop_item_container_del_internal(Evas_Object *obj, Eina_Bool full) +{ + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st) + { + // temp until st is stored inside data of obj. + //FIXME delete this drop container + st->itemgetcb= NULL; + st->poscb = NULL; + st->dropcb = NULL; + + if (full) + { + cont_drop_tg = eina_list_remove(cont_drop_tg, st); + free(st); + } + + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EAPI Eina_Bool +elm_drop_item_container_add(Evas_Object *obj, + Elm_Sel_Format format, + Elm_Xy_Item_Get_Cb itemgetcb, + Elm_Drag_State entercb, void *enterdata, + Elm_Drag_State leavecb, void *leavedata, + Elm_Drag_Item_Container_Pos poscb, void *posdata, + Elm_Drop_Item_Container_Cb dropcb, void *dropdata) +{ + Item_Container_Drop_Info *st; + + if (elm_drop_item_container_del_internal(obj, EINA_FALSE)) + { /* Updating info of existing obj */ + st = eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + if (!st) return EINA_FALSE; + } + else + { + st = calloc(1, sizeof(*st)); + if (!st) return EINA_FALSE; + + st->obj = obj; + cont_drop_tg = eina_list_append(cont_drop_tg, st); + } + + st->itemgetcb = itemgetcb; + st->poscb = poscb; + st->dropcb = dropcb; + elm_drop_target_add(obj, format, + entercb, enterdata, + leavecb, leavedata, + _elm_item_container_pos_cb, posdata, + _elm_item_container_drop_cb, dropdata); + return EINA_TRUE; +} + + +EAPI Eina_Bool +elm_drop_item_container_del(Evas_Object *obj) +{ + return elm_drop_item_container_del_internal(obj, EINA_TRUE); +} + +typedef struct { + void *dragdata, *acceptdata, *donecbdata; + Elm_Drag_Pos dragposcb; + Elm_Drag_Accept acceptcb; + Elm_Drag_State dragdonecb; +} Elm_Drag_Data; + +static void +_drag_finished_cb(void *data, const Efl_Event *ev) +{ + Elm_Drag_Data *dd = data; + Eina_Bool *accepted = ev->info; + + if (dd->acceptcb) + dd->acceptcb(dd->acceptdata, ev->object, *accepted); + + if (dd->dragdonecb) + dd->dragdonecb(dd->donecbdata, ev->object); + + efl_event_callback_del(ev->object, EFL_UI_DND_EVENT_DRAG_FINISHED, _drag_finished_cb, dd); + free(dd); +} + +EAPI Eina_Bool +elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, + const char *data, Elm_Xdnd_Action action, + Elm_Drag_Icon_Create_Cb createicon, + void *createdata, + Elm_Drag_Pos dragpos, void *dragdata, + Elm_Drag_Accept acceptcb, void *acceptdata, + Elm_Drag_State dragdone, void *donecbdata) +{ + Eina_Array *mime_types; + Eina_Content *content; + Efl_Content *ui; + int x, y, w, h; + Efl_Ui_Widget *widget; + Elm_Drag_Data *dd; + const char *str_action; + + str_action = _action_to_string(action); + dd = calloc(1, sizeof(Elm_Drag_Data)); + dd->dragposcb = dragpos; + dd->dragdata = dragdata; + dd->acceptcb = acceptcb; + dd->acceptdata = acceptdata; + dd->dragdonecb = dragdone; + dd->donecbdata = donecbdata; + mime_types = _format_to_mime_array(format); + if (eina_array_count(mime_types) != 1) + { + WRN("You passed more than one format, this is not going to work well"); + } + content = eina_content_new((Eina_Slice) EINA_SLICE_STR_FULL(data), eina_array_data_get(mime_types, 0)); + ui = efl_ui_dnd_drag_start(obj, content, str_action, 0); + widget = createicon(createdata, ui, &x, &y); + evas_object_geometry_get(widget, NULL, NULL, &w, &h); + evas_object_show(widget); + efl_content_set(ui, widget); + efl_gfx_entity_size_set(ui, EINA_SIZE2D(w, h)); + eina_array_free(mime_types); + + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_FINISHED, _drag_finished_cb, dd); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drag_cancel(Evas_Object *obj) +{ + efl_ui_dnd_drag_cancel(obj, 0); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drag_action_set(Evas_Object *obj EINA_UNUSED, Elm_Xdnd_Action action EINA_UNUSED) +{ + ERR("This operation is not supported anymore."); + return EINA_FALSE; +} diff --git a/src/lib/elementary/elm_entry.c b/src/lib/elementary/elm_entry.c index ab1f11544b..e3a81dea76 100644 --- a/src/lib/elementary/elm_entry.c +++ b/src/lib/elementary/elm_entry.c @@ -708,7 +708,7 @@ _selection_data_cb(void *data EINA_UNUSED, char *entry_tag; int len; static const char *tag_string = - ""; + ""; len = strlen(tag_string) + strlen(buf); entry_tag = alloca(len + 1); @@ -1628,7 +1628,7 @@ _selection_store(Elm_Sel_Type seltype, if ((!sel) || (!sel[0])) return; /* avoid deleting our own selection */ elm_cnp_selection_set - (obj, seltype, ELM_SEL_FORMAT_MARKUP, sel, strlen(sel)); + (obj, seltype, ELM_SEL_FORMAT_MARKUP, sel, strlen(sel) + 1); elm_cnp_selection_loss_callback_set(obj, seltype, _selection_clear, obj); if (seltype == ELM_SEL_TYPE_CLIPBOARD) eina_stringshare_replace(&sd->cut_sel, sel); @@ -1731,7 +1731,7 @@ _menu_call(Evas_Object *obj) const char *context_menu_orientation; Eina_Bool ownersel; - ownersel = elm_selection_selection_has_owner(obj); + ownersel = elm_cnp_clipboard_selection_has_owner(obj); if (!sd->items) { /* prevent stupid blank hoversel */ diff --git a/src/lib/elementary/elm_main.c b/src/lib/elementary/elm_main.c index d6c2b2a82f..ddda1337b9 100644 --- a/src/lib/elementary/elm_main.c +++ b/src/lib/elementary/elm_main.c @@ -910,7 +910,6 @@ elm_quicklaunch_sub_shutdown(void) _elm_module_shutdown(); if (_elm_prefs_initted) _elm_prefs_shutdown(); - _efl_ui_dnd_shutdown(); elm_color_class_shutdown(); } diff --git a/src/lib/elementary/elm_priv.h b/src/lib/elementary/elm_priv.h index 89878716f3..7a3da94cb7 100644 --- a/src/lib/elementary/elm_priv.h +++ b/src/lib/elementary/elm_priv.h @@ -165,7 +165,6 @@ # include "efl_ui_focus_parent_provider.eo.h" # include "efl_ui_focus_parent_provider_standard.eo.h" -# include "efl_ui_selection_manager.eo.h" # include "efl_datetime_manager.eo.h" extern const char *_efl_model_property_itemw; @@ -668,9 +667,6 @@ void _elm_prefs_data_init(void); void _elm_prefs_data_shutdown(void); /* init functions for dnd and cnp */ -Eo* _efl_ui_selection_manager_get(Eo *obj); -void _efl_ui_dnd_shutdown(void); - int _elm_ews_wm_init(void); void _elm_ews_wm_shutdown(void); void _elm_ews_wm_rescale(Elm_Theme *th, @@ -1060,4 +1056,10 @@ typedef struct Efl_Ui_Shared_Win_Data* efl_ui_win_shared_data_get(Efl_Ui_Win *win); +void _selection_changed_event_register(Eo *obj); +void _selection_changed_event_unregister(Eo *obj); +void _drop_event_register(Eo *obj); +void _drop_event_unregister(Eo *obj); +void _register_selection_changed(Efl_Ui_Selection *selection); + #endif diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index 0cb3fc7db9..6dea02ed9f 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -142,7 +142,6 @@ pub_eo_files = [ 'elm_code_widget.eo', 'efl_ui_selection.eo', 'efl_ui_dnd.eo', - 'efl_ui_dnd_container.eo', 'efl_ui_focus_manager_window_root.eo', 'efl_ui_spotlight_container.eo', 'efl_ui_spotlight_manager.eo', @@ -210,8 +209,6 @@ endforeach pub_eo_types_files = [ 'elm_general.eot', 'efl_ui.eot', - 'efl_ui_selection_types.eot', - 'efl_ui_dnd_types.eot' ] foreach eo_file : pub_eo_types_files @@ -235,7 +232,6 @@ priv_eo_files = [ 'efl_ui_focus_parent_provider.eo', 'efl_ui_focus_parent_provider_standard.eo', 'efl_ui_state_model.eo', - 'efl_ui_selection_manager.eo', 'efl_datetime_manager.eo', 'efl_ui_size_model.eo', 'efl_ui_homogeneous_model.eo', @@ -785,6 +781,8 @@ elementary_src = [ 'elm_icon.c', 'efl_ui_image.c', 'elm_index.c', + 'elm_cnp.c', + 'elm_dnd.c', 'efl_access_object.c', 'efl_access_action.c', 'efl_access_component.c', @@ -907,7 +905,6 @@ elementary_src = [ 'efl_ui_scroller.c', 'efl_ui_scroll_manager.c', 'efl_ui_pan.c', - 'efl_ui_selection_manager.c', 'efl_ui_selection_manager_private.h', 'efl_ui_selection.c', 'efl_datetime_manager.c', diff --git a/src/lib/eo/eina_types.eot b/src/lib/eo/eina_types.eot index 04d728a8d3..5d1e9cf0f8 100644 --- a/src/lib/eo/eina_types.eot +++ b/src/lib/eo/eina_types.eot @@ -60,6 +60,8 @@ struct @extern Eina.Matrix3 { zz: double; [[ZZ value.]] } +struct @extern Eina.Content; + struct @extern Eina.Matrix4 { [[A bidimensional array of floating point values with 4 rows and 4 columns. diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c index 95d0f36bd0..9aa455553d 100644 --- a/src/lib/evas/canvas/evas_main.c +++ b/src/lib/evas/canvas/evas_main.c @@ -120,6 +120,21 @@ _efl_gfx_image_load_error_to_evas_load_error(Eina_Error err) return EVAS_LOAD_ERROR_GENERIC; } +static Eina_Content* +_markup_to_utf8(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + char *utf8 = evas_textblock_text_markup_to_utf8(NULL, slice.mem); + return eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(utf8), to_type); +} + +static Eina_Content* +_utf8_to_markup(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + char *markup = evas_textblock_text_utf8_to_markup(NULL, slice.mem); + return eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(markup), to_type); +} EAPI int evas_init(void) @@ -179,6 +194,9 @@ evas_init(void) _efl_gfx_image_load_error_init(); + eina_content_converter_conversion_register("application/x-elementary-markup", "text/plain;charset=utf-8", _markup_to_utf8); + eina_content_converter_conversion_register("text/plain;charset=utf-8", "application/x-elementary-markup", _utf8_to_markup); + return _evas_init_count; shutdown_filter: diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c b/src/modules/ecore_evas/engines/x/ecore_evas_x.c index 2dbd2ec60a..d82e16ac2f 100644 --- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c +++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c @@ -4201,6 +4201,15 @@ _ecore_evas_x_selection_init(void) "text/x-vcard", "text/uri-list", "application/x-elementary-markup", + "image/png", + "image/jpeg", + "image/x-ms-bmp", + "image/gif", + "image/tiff", + "image/svg+xml", + "image/x-xpixmap", + "image/x-tga", + "image/x-portable-pixmap", "ATOM", "TARGETS", NULL diff --git a/src/tests/elementary/efl_ui_test_text.c b/src/tests/elementary/efl_ui_test_text.c index b7886544f1..0944afa0ef 100644 --- a/src/tests/elementary/efl_ui_test_text.c +++ b/src/tests/elementary/efl_ui_test_text.c @@ -44,6 +44,12 @@ EFL_START_TEST(text_cnp) } EFL_END_TEST +static void +_stop_event_soon(void *data EINA_UNUSED, const Efl_Event *ev) +{ + efl_event_callback_stop(ev->object); +} + EFL_START_TEST(text_all_select_all_unselect) { Eo *txt; @@ -57,7 +63,7 @@ EFL_START_TEST(text_all_select_all_unselect) efl_event_callback_add(efl_added, EFL_TEXT_INTERACTIVE_EVENT_SELECTION_CHANGED, increment_int_changed, &i_selection) ); - + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_text_set(txt, "Hello"); efl_text_interactive_all_select(txt); Efl_Text_Cursor *c1=NULL, *c2 =NULL; @@ -122,6 +128,7 @@ EFL_START_TEST(text_selection) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello"); get_me_to_those_events(txt); @@ -160,7 +167,7 @@ EFL_START_TEST(text_user_change) txt = efl_add(EFL_UI_TEXTBOX_CLASS, win, efl_event_callback_add(efl_added, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, user_changed, &info) ); - + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_text_set(txt, "Hello"); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_interactive_all_select(txt); @@ -177,6 +184,7 @@ EFL_START_TEST(text_scroll_mode) Eo *txt, *win, *cur; win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); cur = efl_text_interactive_main_cursor_get(txt); efl_text_set(txt, "Hello"); /*scroll mode is false by default*/ @@ -199,6 +207,7 @@ EFL_START_TEST(text_change_event) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello"); int i_changed = 0; @@ -223,6 +232,7 @@ EFL_START_TEST(text_keys_handler) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello");