#include "e.h" #ifdef HAVE_WAYLAND EINTERN void e_gadget_runner_init(void); EINTERN void e_gadget_runner_shutdown(void); EINTERN void e_gadget_runner_save(void); #endif #define SNAP_DISTANCE 5 #define E_GADGET_TYPE 0xE31337 #define IS_HORIZ(orient) \ ((orient) == E_GADGET_SITE_ORIENT_HORIZONTAL) #define IS_VERT(orient) \ ((orient) == E_GADGET_SITE_ORIENT_VERTICAL) #define ZGS_GET(obj) \ E_Gadget_Site *zgs; \ zgs = evas_object_data_get((obj), "__e_gadget_site"); \ if (!zgs) abort() typedef struct E_Gadget_Config E_Gadget_Config; typedef struct E_Gadget_Site { Eina_Stringshare *name; Eina_Bool autoadd; E_Gadget_Site_Gravity gravity; E_Gadget_Site_Orient orient; E_Gadget_Site_Anchor anchor; Eina_List *gadgets; Eina_Inlist *gadget_list; Eina_Bool longpressed : 1; Eina_Bool dragged : 1; Evas_Coord down_1_x, down_1_y, down_3_x, down_3_y; Ecore_Timer *down_timer; Evas_Object *layout; Evas_Object *events; E_Gadget_Style_Cb style_cb; E_Gadget_Context_Cb context_cb; E_Gadget_Context_Cb context_cancel_cb; int cur_size; Ecore_Job *calc_job; E_Gadget_Config *action; Ecore_Event_Handler *move_handler; Ecore_Event_Handler *mouse_up_handler; Evas_Object *editor; } E_Gadget_Site; struct E_Gadget_Config { EINA_INLIST; int id; struct { Eina_Stringshare *domain; Eina_Stringshare *type; } external; int zone; Eina_Stringshare *type; E_Object *e_obj_inherit; Evas_Object *display; Evas_Object *gadget; struct { Evas_Object *obj; int minw, minh; Eina_Stringshare *name; } style; E_Gadget_Configure_Cb configure; Evas_Object *cfg_object; E_Gadget_Menu_Populate_Cb populate; Eina_List *popups; E_Gadget_Site *site; E_Menu *menu; struct { Evas_Object *popup; Evas_Smart_Cb allow; Evas_Smart_Cb deny; void *data; } allow_deny; Eina_Hash *drop_handlers; double x, y; //fixed % positioning double w, h; //fixed % sizing Evas_Point offset; //offset from mouse down Evas_Point down; //coords from mouse down E_Gadget_Config *orig; //gadget is a copy of the original gadget during a move E_Gadget_Site_Anchor resizing; Eina_Bool moving E_BITFIELD; Eina_Bool display_del E_BITFIELD; //deleted using ->display }; typedef struct E_Gadget_Sites { Eina_List *sites; } E_Gadget_Sites; typedef struct E_Gadget_External_Type { E_Gadget_External_Create_Cb cb; E_Gadget_External_Wizard_Cb wizard; E_Gadget_External_Name_Cb name; } E_Gadget_External_Type; typedef struct E_Gadget_Type { E_Gadget_Create_Cb cb; E_Gadget_Wizard_Cb wizard; } E_Gadget_Type; typedef struct Gadget_Item { Evas_Object *box; Evas_Object *editor; Evas_Object *gadget; Evas_Object *site; Elm_Object_Item *it; } Gadget_Item; #define DESKLOCK_DEMO_LAYER (E_LAYER_CLIENT_POPUP - 100) static Eina_List *desktop_handlers; static Evas_Object *desktop_rect; static Evas_Object *desktop_editor; static Eina_Bool added; static Evas_Object *pointer_site; static Eina_List *pointer_site_handlers; static Eina_Hash *gadget_external_domains; static Eina_Hash *gadget_types; static E_Gadget_Sites *sites; static Eina_List *handlers; static Evas_Object *comp_site; static E_Action *move_act; static E_Action *resize_act; static E_Action *configure_act; static E_Config_DD *edd_sites; static E_Config_DD *edd_site; static E_Config_DD *edd_gadget; static void _gadget_object_finalize(E_Gadget_Config *zgc); static Eina_Bool _gadget_object_create(E_Gadget_Config *zgc); static void _editor_pointer_site_init(E_Gadget_Site_Orient orient, Evas_Object *site, Evas_Object *editor, Eina_Bool ); static void _gadget_drop_handler_moveresize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED); static void _edit_site_del(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _site_recalc_job_cb(E_Gadget_Site *zgs) { zgs->calc_job = NULL; evas_object_smart_need_recalculate_set(zgs->layout, 1); } static void _site_recalc_job(E_Gadget_Site *zgs) { if (zgs->calc_job) ecore_job_del(zgs->calc_job); zgs->calc_job = ecore_job_add((Ecore_Cb)_site_recalc_job_cb, zgs); } static E_Gadget_External_Type * _gadget_external_type_get(const char *domain, const char *type) { Eina_Hash *h; if (!gadget_external_domains) return NULL; h = eina_hash_find(gadget_external_domains, domain); if (!h) return NULL; return eina_hash_find(h, type); } static Eina_Bool _editor_site_visible(void) { Eina_List *l; E_Gadget_Site *zgs; if (desktop_editor) return evas_object_visible_get(desktop_editor); EINA_LIST_FOREACH(sites->sites, l, zgs) if (zgs->editor && evas_object_visible_get(zgs->editor)) return EINA_TRUE; return EINA_FALSE; } static void _comp_site_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { Eina_List *l; E_Gadget_Config *zgc; evas_object_resize(data, e_comp->w, e_comp->h); ZGS_GET(comp_site); EINA_LIST_FOREACH(zgs->gadgets, l, zgc) { if (!zgc->display) _gadget_object_create(zgc); else if (!e_comp_zone_number_get(zgc->zone)) evas_object_del(zgc->display); } } static void _gadget_free(E_Gadget_Config *zgc) { if (zgc->menu) { e_menu_deactivate(zgc->menu); e_object_del(E_OBJECT(zgc->menu)); zgc->menu = NULL; } evas_object_del(zgc->display); eina_stringshare_del(zgc->type); eina_stringshare_del(zgc->external.type); eina_stringshare_del(zgc->external.domain); eina_stringshare_del(zgc->style.name); free(zgc); } static E_Gadget_Config * _gadget_at_xy(E_Gadget_Site *zgs, int x, int y, E_Gadget_Config *exclude) { Eina_List *l; E_Gadget_Config *zgc, *saved = NULL; EINA_LIST_FOREACH(zgs->gadgets, l, zgc) { int ox, oy, ow, oh; if (!zgc->gadget) continue; evas_object_geometry_get(zgc->display, &ox, &oy, &ow, &oh); if (E_INSIDE(x, y, ox, oy, ow, oh)) { if (zgc == exclude) saved = zgc; else return zgc; } } return saved; } static void _gravity_apply(E_Gadget_Site *zgs, E_Gadget_Site_Gravity gravity) { double ax = 0.5, ay = 0.5; switch (gravity) { case E_GADGET_SITE_GRAVITY_LEFT: ax = 0; break; case E_GADGET_SITE_GRAVITY_RIGHT: ax = 1; break; default: break; } switch (gravity) { case E_GADGET_SITE_GRAVITY_TOP: ay = 0; break; case E_GADGET_SITE_GRAVITY_BOTTOM: ay = 1; break; default: break; } elm_box_align_set(zgs->layout, ax, ay); evas_object_smart_callback_call(zgs->layout, "gadget_site_gravity", NULL); } static void _gadget_reparent(E_Gadget_Site *zgs, E_Gadget_Config *zgc) { Eina_Inlist *l = EINA_INLIST_GET(zgc); E_Gadget_Config *z; if (!zgs->orient) { evas_object_layer_set(zgc->display, evas_object_layer_get(zgs->layout)); evas_object_stack_below(zgc->display, zgs->events); if (evas_object_visible_get(zgs->events)) evas_object_show(zgc->display); return; } switch (zgs->gravity) { case E_GADGET_SITE_GRAVITY_NONE: /* fake */ break; case E_GADGET_SITE_GRAVITY_LEFT: case E_GADGET_SITE_GRAVITY_TOP: for (l = l->prev; l; l = l->prev) { z = EINA_INLIST_CONTAINER_GET(l, E_Gadget_Config); if (!z->display) continue; elm_box_pack_after(zgs->layout, zgc->display, z->display); return; } elm_box_pack_end(zgs->layout, zgc->display); break; default: for (l = l->next; l; l = l->next) { z = EINA_INLIST_CONTAINER_GET(l, E_Gadget_Config); if (!z->display) continue; elm_box_pack_before(zgs->layout, zgc->display, z->display); return; } /* right aligned: pack on left */ elm_box_pack_start(zgs->layout, zgc->display); } } static void _desktop_rect_obj_add(Evas_Object *obj) { if (!desktop_rect) return; evas_object_smart_member_add(obj, desktop_rect); evas_object_propagate_events_set(obj, 0); if (e_comp->autoclose.obj != obj) return; evas_object_smart_member_add(e_comp->autoclose.rect, desktop_rect); evas_object_propagate_events_set(e_comp->autoclose.rect, 0); } static void _gadget_popup_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; if (desktop_editor) evas_object_show(desktop_editor); zgc->popups = eina_list_remove(zgc->popups, event_info); } static void _gadget_popup(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) { E_Gadget_Config *zgc = data; E_Gadget_Site *zgs = zgc->site; if (event_info && elm_object_widget_check(event_info)) elm_object_tree_focus_allow_set(event_info, 0); if (event_info) _desktop_rect_obj_add(event_info); evas_object_smart_callback_call(zgs->layout, "gadget_site_popup", event_info); if (!event_info) return; evas_object_event_callback_add(event_info, EVAS_CALLBACK_HIDE, _gadget_popup_hide, zgc); if (desktop_editor) evas_object_hide(desktop_editor); if (eina_list_data_find(zgc->popups, event_info)) ERR("gadget_popup called multiple times for same popup"); zgc->popups = eina_list_append(zgc->popups, event_info); } static void _gadget_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; zgc->display_del = obj == zgc->display; if (!e_object_is_del(zgc->e_obj_inherit)) e_object_del(zgc->e_obj_inherit); } static void _gadget_util_allow_deny_cleanup(E_Gadget_Config *zgc) { zgc->allow_deny.allow = zgc->allow_deny.deny = NULL; zgc->allow_deny.data = NULL; evas_object_hide(zgc->allow_deny.popup); E_FREE_FUNC(zgc->allow_deny.popup, evas_object_del); } static void _gadget_drop_handler_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; if (zgc->drop_handlers)//may be calling during object_free eina_hash_del_by_key(zgc->drop_handlers, &obj); } static void _gadget_object_free(E_Object *eobj) { E_Gadget_Config *zgc; Evas_Object *g; g = e_object_data_get(eobj); zgc = evas_object_data_get(g, "__e_gadget"); evas_object_smart_callback_call(zgc->site->layout, "gadget_destroyed", zgc->gadget); evas_object_event_callback_del_full(zgc->gadget, EVAS_CALLBACK_DEL, _gadget_del, zgc); if (zgc->display_del || (zgc->gadget == zgc->display)) zgc->display = NULL; else { evas_object_event_callback_del_full(zgc->display, EVAS_CALLBACK_DEL, _gadget_del, zgc); E_FREE_FUNC(zgc->display, evas_object_del); } zgc->gadget = NULL; if (zgc->drop_handlers) { Evas_Object **drop_object; Eina_Iterator *it = eina_hash_iterator_key_new(zgc->drop_handlers); EINA_ITERATOR_FOREACH(it, drop_object) { evas_object_event_callback_del(*drop_object, EVAS_CALLBACK_MOVE, _gadget_drop_handler_moveresize); evas_object_event_callback_del(*drop_object, EVAS_CALLBACK_RESIZE, _gadget_drop_handler_moveresize); evas_object_event_callback_del(*drop_object, EVAS_CALLBACK_DEL, _gadget_drop_handler_del); } eina_iterator_free(it); } E_FREE_FUNC(zgc->drop_handlers, eina_hash_free); E_FREE_FUNC(zgc->gadget, evas_object_del); E_FREE_FUNC(zgc->cfg_object, evas_object_del); E_FREE_FUNC(zgc->style.obj, evas_object_del); _gadget_util_allow_deny_cleanup(zgc); E_FREE(zgc->e_obj_inherit); zgc->configure = NULL; zgc->display_del = zgc->moving = zgc->resizing = 0; if (zgc->id == -1) _gadget_free(zgc); } static void _gadget_remove(E_Gadget_Config *zgc) { int id = zgc->id; evas_object_smart_callback_call(zgc->site->layout, "gadget_removed", zgc->gadget); zgc->site->gadget_list = eina_inlist_remove(zgc->site->gadget_list, EINA_INLIST_GET(zgc)); zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); if (id >= 0) { _gadget_free(zgc); e_config_save_queue(); } else evas_object_del(zgc->display); } static void _gadget_wizard_end(void *data, int id) { E_Gadget_Config *zgc = data; zgc->id = id; evas_object_smart_callback_call(zgc->site->layout, "gadget_site_unlocked", NULL); e_comp_ungrab_input(1, 1); if (id > 0) { _gadget_object_finalize(zgc); added = 0; } else _gadget_remove(zgc); } static void _gadget_wizard_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; if (zgc->cfg_object == obj) zgc->cfg_object = NULL; if (desktop_editor) evas_object_show(desktop_editor); } static void _gadget_object_hints(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; _site_recalc_job(zgc->site); } static Eina_Bool _gadget_object_create(E_Gadget_Config *zgc) { E_Gadget_Type *t = NULL; E_Gadget_External_Type *te = NULL; Evas_Object *g; if (zgc->external.domain) { te = _gadget_external_type_get(zgc->external.domain, zgc->external.type); if (!te) return EINA_TRUE; //can't create yet } else { t = eina_hash_find(gadget_types, zgc->type); if (!t) return EINA_TRUE; //can't create yet } if (!zgc->id) { if ((t && t->wizard) || (te && te->wizard)) { if (t) zgc->cfg_object = t->wizard(_gadget_wizard_end, zgc, zgc->site->layout); else zgc->cfg_object = te->wizard(_gadget_wizard_end, zgc, zgc->external.type, zgc->site->layout); if (!zgc->cfg_object) { added = 1; if (desktop_editor) evas_object_show(desktop_editor); return EINA_FALSE; } e_comp_grab_input(1, 1); evas_object_event_callback_add(zgc->cfg_object, EVAS_CALLBACK_DEL, _gadget_wizard_del, zgc); _desktop_rect_obj_add(zgc->cfg_object); evas_object_smart_callback_call(zgc->site->layout, "gadget_site_popup", zgc->cfg_object); evas_object_smart_callback_call(zgc->site->layout, "gadget_site_locked", NULL); return EINA_TRUE; } } if (desktop_editor) evas_object_show(desktop_editor); if ((zgc->zone >= 0) && (!e_comp_zone_number_get(zgc->zone))) return EINA_FALSE; /* if id is < 0, gadget creates dummy config for demo use * if id is 0, gadget creates new config and returns id * otherwise, config of `id` is applied to created object * * a gadget should return NULL for any demo instance where it * should not be shown */ if (t) g = t->cb(zgc->site->layout, &zgc->id, zgc->site->orient); else g = te->cb(zgc->site->layout, zgc->external.type, &zgc->id, zgc->site->orient); if (zgc->id < 0) { if (!g) return EINA_FALSE; } EINA_SAFETY_ON_NULL_RETURN_VAL(g, EINA_FALSE); added = 1; zgc->e_obj_inherit = E_OBJECT_ALLOC(E_Object, E_GADGET_TYPE, _gadget_object_free); e_object_data_set(zgc->e_obj_inherit, g); zgc->gadget = zgc->display = g; evas_object_event_callback_add(g, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _gadget_object_hints, zgc); evas_object_smart_callback_add(g, "gadget_popup", _gadget_popup, zgc); evas_object_data_set(g, "__e_gadget", zgc); if (zgc->site->style_cb) zgc->site->style_cb(zgc->site->layout, zgc->style.name, g); if (!zgc->site->orient) evas_object_smart_need_recalculate_set(zgc->site->layout, 1); evas_object_event_callback_priority_add(g, EVAS_CALLBACK_DEL, EVAS_CALLBACK_PRIORITY_AFTER, _gadget_del, zgc); _gadget_reparent(zgc->site, zgc); if (elm_object_widget_check(zgc->gadget)) elm_object_tree_focus_allow_set(zgc->gadget, 0); evas_object_raise(zgc->site->events); evas_object_smart_callback_call(zgc->site->layout, "gadget_created", g); evas_object_show(zgc->display); if (zgc->site->editor) _desktop_rect_obj_add(zgc->display); return EINA_TRUE; } static void _gadget_object_finalize(E_Gadget_Config *zgc) { zgc->moving = 0; if (_gadget_object_create(zgc)) { if (!zgc->display) return; evas_object_smart_callback_call(zgc->site->layout, "gadget_added", zgc->gadget); e_config_save_queue(); return; } zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); zgc->site->gadget_list = eina_inlist_remove(zgc->site->gadget_list, EINA_INLIST_GET(zgc)); eina_stringshare_del(zgc->type); eina_stringshare_del(zgc->external.type); eina_stringshare_del(zgc->external.domain); free(zgc); } static void _site_gadget_aspect(E_Gadget_Config *zgc, Evas_Coord *ww, Evas_Coord *hh, int ax, int ay, Evas_Aspect_Control aspect) { if (aspect && ax && ay) { switch (aspect) { case EVAS_ASPECT_CONTROL_HORIZONTAL: *hh = (*ww * (double)ay / ax) + 0.99999999; break; case EVAS_ASPECT_CONTROL_VERTICAL: *ww = (*hh * (double)ax / ay) + 0.99999999; break; default: if (IS_HORIZ(zgc->site->orient)) *ww = (*hh * (double)ax / ay) + 0.99999999; else if (IS_VERT(zgc->site->orient)) *hh = (*ww * (double)ay / ax) + 0.99999999; else if (aspect) { double ar = ax / (double) ay; if (ax == ay) { if (*ww > *hh) *hh = *ww; else *ww = *hh; } else if (ar > 1.0) *hh = (*ww * (double)ay / ax) + 0.99999999; else *ww = (*hh * (double)ax / ay) + 0.99999999; } } } } static Eina_Bool _site_gadget_resize(Evas_Object *g, int w, int h, Evas_Coord *ww, Evas_Coord *hh, Evas_Coord *ow, Evas_Coord *oh) { Evas_Coord mnw, mnh, mxw, mxh; E_Gadget_Config *zgc; Evas_Aspect_Control aspect; int ax, ay; double ex, ey; Eina_Bool ret = EINA_FALSE; zgc = evas_object_data_get(g, "__e_gadget"); w -= zgc->style.minw; h -= zgc->style.minh; evas_object_size_hint_min_get(g, &mnw, &mnh); evas_object_size_hint_max_get(g, &mxw, &mxh); evas_object_size_hint_aspect_get(g, &aspect, &ax, &ay); evas_object_size_hint_weight_get(g, &ex, &ey); if (IS_HORIZ(zgc->site->orient)) { *ww = mnw, *hh = h; if (!(*ww)) *ww = *hh; if (dblequal(ex, EVAS_HINT_EXPAND) && (!aspect)) ret = EINA_TRUE; } else if (IS_VERT(zgc->site->orient)) { *hh = mnh, *ww = w; if (!(*hh)) *hh = *ww; if (dblequal(ey, EVAS_HINT_EXPAND) && (!aspect)) ret = EINA_TRUE; } else { *ww = mnw, *hh = mnh; if ((!(*ww)) || ((*ww) < w)) *ww = w; if ((!(*hh)) || ((*hh) < h)) *hh = h; } _site_gadget_aspect(zgc, ww, hh, ax, ay, aspect); *ww += zgc->style.minw; *hh += zgc->style.minh; *ow = *ww, *oh = *hh; if ((!ax) && (!ay)) { if ((mxw >= 0) && (mxw < *ow)) *ow = mxw; if ((mxh >= 0) && (mxh < *oh)) *oh = mxh; } if (!zgc->site->orient) { if ((w < (*ow)) || (h < (*oh))) { if (evas_smart_objects_calculating_get(e_comp->evas)) _site_recalc_job(zgc->site); else evas_object_smart_need_recalculate_set(zgc->site->layout, 1); } } //fprintf(stderr, "%s: %dx%d\n", zgc->type, *ow, *oh); evas_object_resize(zgc->display, *ow, *oh); return ret; } static void _site_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { int x, y, w, h; E_Gadget_Site *zgs = data; evas_object_geometry_get(obj, &x, &y, &w, &h); evas_object_geometry_set(zgs->events, x, y, w, h); evas_object_raise(zgs->events); if (!zgs->orient) evas_object_smart_need_recalculate_set(zgs->layout, 1); } static void _site_layout_orient(Evas_Object *o, E_Gadget_Site *zgs) { Evas_Coord x, y, w, h, xx, yy; Eina_List *l; double ax, ay; E_Gadget_Config *zgc; int mw, mh, sw, sh, rw, rh, bw, bh, prev_w = 0, prev_h = 0; int groups = 0, avg; Eina_Bool prev_ex = 0, after = 0; struct Size { Evas_Coord_Size size; Evas_Coord_Size clipped; Evas_Coord_Size before; Evas_Coord_Size after; Eina_Bool expand; Evas_Object *obj; } *size, *psize = NULL; Eina_List *expand = NULL, *gadgets = NULL; Evas_Coord_Size parent_size; evas_object_geometry_get(o, &x, &y, &w, &h); if ((!w) && (!h)) return; parent_size.w = parent_size.h = -1; evas_object_smart_callback_call(elm_object_parent_widget_get(zgs->layout), "gadget_site_parent_size_request", &parent_size); if ((parent_size.w < 0) || (parent_size.h < 0)) evas_object_geometry_get(elm_object_parent_widget_get(zgs->layout), NULL, NULL, &bw, &bh); else bw = parent_size.w, bh = parent_size.h; rw = bw, rh = bh; evas_object_size_hint_min_get(o, &mw, &mh); evas_object_size_hint_min_get(zgs->layout, &sw, &sh); evas_object_geometry_set(zgs->events, x, y, w, h); evas_object_box_align_get(o, &ax, &ay); xx = x; yy = y; EINA_LIST_FOREACH(zgs->gadgets, l, zgc) { int ww, hh, ow, oh; Eina_Bool ex; if (!zgc->display) continue; ex = _site_gadget_resize(zgc->gadget, w, h, &ww, &hh, &ow, &oh); if (ex && prev_ex) { /* multiple spacers */ evas_object_resize(zgc->display, 0, 0); continue; } size = E_NEW(struct Size, 1); size->size.w = ww; size->size.h = hh; size->clipped.w = ow; size->clipped.h = oh; size->expand = ex; if (ex) { if (psize) { psize->after.w = prev_w, psize->after.h = prev_h; groups++; } psize = size; size->before.w = prev_w; size->before.h = prev_h; prev_w = prev_h = 0; } size->obj = zgc->display; prev_w += ow; prev_h += oh; prev_ex = ex; gadgets = eina_list_append(gadgets, size); if (ex) { expand = eina_list_append(expand, size); continue; } if (IS_HORIZ(zgs->orient)) rw = MAX(rw - ow, 0); else if (IS_VERT(zgs->orient)) rh = MAX(rh - oh, 0); } if (expand) { size = eina_list_last_data_get(expand); psize = eina_list_last_data_get(gadgets); if (size != psize) { if ((!size->after.w) && (!size->after.h)) { size->after.w = prev_w, size->after.h = prev_h; groups++; } } if (!groups) groups++; size = eina_list_data_get(expand); if (IS_HORIZ(zgs->orient)) { after = !size->before.w; avg = (bw - rw) / groups; } else { after = !size->before.h; avg = (bh - rh) / groups; } } EINA_LIST_FREE(expand, size) { if (IS_HORIZ(zgs->orient)) { if (rw) { size->size.w = size->clipped.w = rw / eina_list_count(expand); if (eina_list_count(expand) > 1) { int gw; if (after) gw = size->after.w; else gw = size->before.w; if (gw > avg) size->size.w = size->clipped.w -= (gw - avg); else size->size.w = size->clipped.w += abs(gw - avg); size->size.w = size->clipped.w -= size->after.w / 2; size->size.w = size->clipped.w = MAX(size->size.w, 0); rw -= size->size.w; } } else size->size.w = size->clipped.w = 0; } else if (IS_VERT(zgs->orient)) { if (rh) { size->size.h = size->clipped.h = rh / eina_list_count(expand); if (eina_list_count(expand) > 1) { int gh; if (after) gh = size->after.h; else gh = size->before.h; if (gh > avg) size->size.h = size->clipped.h -= (gh - avg); else size->size.h = size->clipped.h += abs(gh - avg); size->size.h = size->clipped.h -= size->after.h / 2; size->size.h = size->clipped.h = MAX(size->size.h, 0); rh -= size->size.h; } } else size->size.h = size->clipped.h = 0; } evas_object_resize(size->obj, size->clipped.w, size->clipped.h); } if (zgs->gravity % 2)//left/top { EINA_LIST_FREE(gadgets, size) { Evas_Coord gx = xx, gy = yy; if (IS_HORIZ(zgs->orient)) gx += (Evas_Coord)(((double)(size->size.w - size->clipped.w)) * 0.5), gy += (h / 2) - (size->clipped.h / 2); else if (IS_VERT(zgs->orient)) gy += (Evas_Coord)(((double)(size->size.h - size->clipped.h)) * 0.5), gx += (w / 2) - (size->clipped.w / 2); evas_object_move(size->obj, gx, gy); if (IS_HORIZ(zgs->orient)) xx += size->clipped.w; else yy += size->clipped.h; free(size); } } else if (zgs->gravity) { if (IS_HORIZ(zgs->orient)) xx += w; else yy += h; E_LIST_REVERSE_FREE(gadgets, size) { Evas_Coord gx = xx, gy = yy; if (IS_HORIZ(zgs->orient)) gx -= (Evas_Coord)(((double)(size->size.w - size->clipped.w)) * 0.5) + size->clipped.w, gy += (h / 2) - (size->clipped.h / 2); else gy -= (Evas_Coord)(((double)(size->size.h - size->clipped.h)) * 0.5) + size->clipped.h, gx += (w / 2) - (size->clipped.w / 2); evas_object_move(size->obj, gx, gy); if (IS_HORIZ(zgs->orient)) xx -= size->clipped.w; else yy -= size->clipped.h; free(size); } } if (IS_HORIZ(zgs->orient)) zgs->cur_size = abs(xx - x); else if (IS_VERT(zgs->orient)) zgs->cur_size = abs(yy - y); w = IS_HORIZ(zgs->orient) ? zgs->cur_size : w; h = IS_VERT(zgs->orient) ? zgs->cur_size : h; if ((w == mw) && (h == mh) && (sw == sh) && (sw == -1)) { /* FIXME: https://phab.enlightenment.org/T4747 */ evas_object_size_hint_min_set(o, -1, -1); } evas_object_size_hint_min_set(o, w, h); } static void _site_layout(Evas_Object *o, Evas_Object_Box_Data *priv EINA_UNUSED, void *data) { E_Gadget_Site *zgs = data; Evas_Coord x, y, w, h;//, px, py; Eina_List *l; double ax, ay; E_Gadget_Config *zgc; evas_object_geometry_get(o, &x, &y, &w, &h); evas_object_geometry_set(zgs->events, x, y, w, h); evas_object_box_align_get(o, &ax, &ay); if (zgs->orient) { _site_layout_orient(o, zgs); return; } if ((!w) || (!h)) return; EINA_LIST_FOREACH(zgs->gadgets, l, zgc) { Evas_Coord gx = x, gy = y; int ww, hh, ow, oh; E_Zone *zone; if (!zgc->display) continue; if (zgc->moving) { if (zgs->layout != pointer_site) continue; _site_gadget_resize(zgc->gadget, w, h, &ww, &hh, &ow, &oh); } else { if (zgc->zone >= 0) { zone = e_comp_zone_number_get(zgc->zone); x = gx = zone->x; y = gy = zone->y; w = zone->w; h = zone->h; } _site_gadget_resize(zgc->gadget, w * zgc->w, h * zgc->h, &ww, &hh, &ow, &oh); if (zgc->x > -1.0) { gx = x + zgc->x * w; gx += (Evas_Coord)(((double)(ww - ow)) * 0.5 * -ax); } if (zgc->y > -1.0) { gy = y + zgc->y * h; gy += (Evas_Coord)(((double)(hh - oh)) * 0.5 * -ay); } } if (zgs->gravity) { #if 0//FIXME if (zgs->gravity % 2)//left/top { if (gx < px) gx = px; } else if () { if (gx > px) gx = px; } if (zgs->gravity % 2)//left/top { if (gy < py) gy = py; } else { if (gy > py) gy = py; } #endif } evas_object_move(zgc->display, gx, gy); #if 0//FIXME if (zgs->gravity is horizontal or something) px = gx + (-ax * ow); else py = gy + (-ay * oh); #endif if (eina_list_count(zgs->gadgets) == 1) { int mw, mh, sw, sh; evas_object_size_hint_min_get(o, &mw, &mh); evas_object_size_hint_min_get(zgs->layout, &sw, &sh); if ((ow == mw) && (oh == mh) && (sw == sh) && (sw == -1)) { /* FIXME: https://phab.enlightenment.org/T4747 */ evas_object_size_hint_min_set(o, -1, -1); } evas_object_size_hint_min_set(o, ow, oh); } } } static Eina_Bool _gadget_mouse_resize(E_Gadget_Config *zgc, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev) { int x, y, w, h;//site geom int ox, oy, ow, oh;//gadget geom double gw, gh; int dx, dy; int ax, ay; Evas_Aspect_Control aspect; evas_object_geometry_get(zgc->display, &ox, &oy, &ow, &oh); evas_object_size_hint_aspect_get(zgc->gadget, &aspect, &ax, &ay); if (zgc->zone >= 0) { E_Zone *zone; zone = e_comp_zone_number_get(zgc->zone); x = zone->x, y = zone->y, w = zone->w, h = zone->h; } else evas_object_geometry_get(zgc->site->layout, &x, &y, &w, &h); /* restore screen-based geometry to canvas size */ gw = zgc->w * w; gh = zgc->h * h; /* apply mouse movement to canvas size */ dx = ev->x - zgc->down.x, dy = ev->y - zgc->down.y; if (zgc->resizing & E_GADGET_SITE_ANCHOR_LEFT) gw -= dx; else gw += dx; if (zgc->resizing & E_GADGET_SITE_ANCHOR_TOP) gh -= dy; else gh += dy; /* apply aspect based on mouse position change */ dx = abs(ev->x - zgc->down.x); dy = abs(ev->y - zgc->down.y); if (dx > dy) { /* use horizontal motion if most of event is horizontal */ int ww = lround(gw), hh = lround(gh); _site_gadget_aspect(zgc, &ww, &hh, ax, ay, EVAS_ASPECT_CONTROL_HORIZONTAL); gh = hh; } else if (dy > dx) { /* use vertical motion if most of event is vertical */ int ww = lround(gw), hh = lround(gh); _site_gadget_aspect(zgc, &ww, &hh, ax, ay, EVAS_ASPECT_CONTROL_VERTICAL); gw = ww; } else if ((dx == dy) && (ax != ay)) { /* use aspect values to calculate equal motion on both axes */ int ww = lround(gw), hh = lround(gh); if (ax > ay) { _site_gadget_aspect(zgc, &ww, &hh, ax, ay, EVAS_ASPECT_CONTROL_VERTICAL); gw = ww; } else { _site_gadget_aspect(zgc, &ww, &hh, ax, ay, EVAS_ASPECT_CONTROL_HORIZONTAL); gh = hh; } } /* calculate new position based on resize amount */ dx = ev->x - zgc->down.x, dy = ev->y - zgc->down.y; if (zgc->resizing & E_GADGET_SITE_ANCHOR_LEFT) { zgc->x = (((zgc->x + zgc->w) * (double)w) - gw) / (double)w; } if (zgc->resizing & E_GADGET_SITE_ANCHOR_TOP) { zgc->y = (((zgc->y + zgc->h) * (double)h) - gh) / (double)h; } zgc->w = gw / w; zgc->h = gh / h; zgc->down.x = ev->x; zgc->down.y = ev->y; evas_object_smart_need_recalculate_set(zgc->site->layout, 1); e_config_save_queue(); return ECORE_CALLBACK_RENEW; } static void _gadget_util_add(E_Gadget_Site *zgs, const char *domain, const char *type, int id) { E_Gadget_Config *zgc; zgc = E_NEW(E_Gadget_Config, 1); zgc->id = id; if (domain) { zgc->external.domain = eina_stringshare_add(domain); zgc->external.type = eina_stringshare_add(type); } else zgc->type = eina_stringshare_add(type); zgc->x = zgc->y = -1; zgc->site = zgs; zgc->zone = -1; if (zgc->site->orient) zgc->w = zgc->h = -1; else { E_Zone *zone = e_zone_current_get(); zgc->w = (96 * e_scale) / (double)zone->w; zgc->h = (96 * e_scale) / (double)zone->h; } zgc->site->gadgets = eina_list_append(zgc->site->gadgets, zgc); zgs->gadget_list = eina_inlist_append(zgs->gadget_list, EINA_INLIST_GET(zgc)); _gadget_object_finalize(zgc); } static Eina_Bool _gadget_act_resize_end(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) { E_Gadget_Config *zgc; Evas_Object *g; if (obj->type != E_GADGET_TYPE) return EINA_FALSE; g = e_object_data_get(obj); zgc = evas_object_data_get(g, "__e_gadget"); zgc->resizing = 0; E_FREE_FUNC(zgc->site->move_handler, ecore_event_handler_del); evas_object_smart_need_recalculate_set(zgc->site->layout, 1); return EINA_TRUE; } static void _gadget_popups_clear(E_Gadget_Config *zgc) { Eina_List *l, *ll; Evas_Object *popup; EINA_LIST_FOREACH_SAFE(zgc->popups, l, ll, popup) evas_object_del(popup); } static Eina_Bool _gadget_act_move(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) { E_Gadget_Config *zgc, *z; Evas_Object *g; int w, h; if (obj->type != E_GADGET_TYPE) return EINA_FALSE; g = e_object_data_get(obj); zgc = evas_object_data_get(g, "__e_gadget"); zgc->moving = 1; _editor_pointer_site_init(zgc->site->orient, NULL, NULL, 1); e_gadget_site_owner_setup(pointer_site, zgc->site->anchor, NULL, NULL, NULL); ZGS_GET(pointer_site); if (zgc->external.domain) _gadget_util_add(zgs, zgc->external.domain, zgc->external.type, zgc->id); else _gadget_util_add(zgs, NULL, zgc->type, zgc->id); z = eina_list_data_get(zgs->gadgets); if (!z) { E_FREE_FUNC(pointer_site, evas_object_del); zgc->moving = 0; return EINA_TRUE; } _gadget_popups_clear(zgc); z->moving = 1; evas_object_pass_events_set(zgc->site->layout, 1); evas_object_geometry_get(g, NULL, NULL, &w, &h); evas_object_resize(pointer_site, w, h); eina_stringshare_refplace(&z->style.name, zgc->style.name); z->orig = zgc; return EINA_TRUE; } static Eina_Bool _gadget_act_resize(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev) { E_Gadget_Config *zgc; Evas_Object *g; int x, y, w, h; if (obj->type != E_GADGET_TYPE) return EINA_FALSE; g = e_object_data_get(obj); zgc = evas_object_data_get(g, "__e_gadget"); if (zgc->site->orient) return EINA_FALSE; _gadget_popups_clear(zgc); evas_object_geometry_get(g, &x, &y, &w, &h); if (ev->canvas.x < x + (w / 3)) zgc->resizing = E_GADGET_SITE_ANCHOR_LEFT; else if (ev->canvas.x > x + (w * 2 / 3)) zgc->resizing = E_GADGET_SITE_ANCHOR_RIGHT; if (ev->canvas.y < y + (h / 3)) zgc->resizing |= E_GADGET_SITE_ANCHOR_TOP; else if (ev->canvas.y > y + (h * 2 / 3)) zgc->resizing |= E_GADGET_SITE_ANCHOR_BOTTOM; if (!zgc->site->move_handler) zgc->site->move_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, (Ecore_Event_Handler_Cb)_gadget_mouse_resize, zgc); return EINA_TRUE; } static void _gadget_act_configure_object_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; zgc->cfg_object = NULL; } static void _gadget_configure(E_Gadget_Config *zgc) { if (!zgc->configure) return; if (zgc->cfg_object) { evas_object_raise(zgc->cfg_object); evas_object_show(zgc->cfg_object); return; } zgc->cfg_object = zgc->configure(zgc->gadget); if (!zgc->cfg_object) return; evas_object_event_callback_add(zgc->cfg_object, EVAS_CALLBACK_DEL, _gadget_act_configure_object_del, zgc); evas_object_smart_callback_call(zgc->display, "gadget_popup", zgc->cfg_object); } static void _gadget_menu_populate(E_Gadget_Config *zgc, E_Menu *m) { if (!zgc->populate) return; zgc->populate(zgc->gadget, m); } static Eina_Bool _gadget_act_configure(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) { E_Gadget_Config *zgc; Evas_Object *g; if (obj->type != E_GADGET_TYPE) return EINA_FALSE; g = e_object_data_get(obj); zgc = evas_object_data_get(g, "__e_gadget"); _gadget_configure(zgc); return EINA_TRUE; } static void _gadget_menu_remove(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Gadget_Config *zgc = data; _gadget_remove(zgc); } static void _gadget_menu_configure(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { _gadget_configure(data); } static void _gadget_style_menu_item_del(void *mi) { eina_stringshare_del(e_object_data_get(mi)); } static void _gadget_menu_style(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Gadget_Config *zgc = data; Eina_Stringshare *style = e_object_data_get(E_OBJECT(mi)); eina_stringshare_refplace(&zgc->style.name, style); if (zgc->site->style_cb) zgc->site->style_cb(zgc->site->layout, style, zgc->gadget); } static void _gadget_menu(Evas_Object *g, unsigned int timestamp) { E_Gadget_Config *zgc; E_Menu_Item *mi; E_Menu *subm; int x, y; zgc = evas_object_data_get(g, "__e_gadget"); _gadget_popups_clear(zgc); zgc->menu = e_menu_new(); e_menu_hold_mode_set(zgc->menu, EINA_FALSE); if (zgc->type) { char buf[1024]; strncpy(buf, zgc->type, sizeof(buf) - 1); buf[0] = toupper(buf[0]); e_menu_title_set(zgc->menu, buf); } evas_object_smart_callback_call(g, "gadget_menu", zgc->menu); if (zgc->configure) { mi = e_menu_item_new(zgc->menu); e_menu_item_label_set(mi, _("Settings")); e_util_menu_item_theme_icon_set(mi, "configure"); e_menu_item_callback_set(mi, _gadget_menu_configure, zgc); } if (zgc->menu->items) { mi = e_menu_item_new(zgc->menu); e_menu_item_separator_set(mi, 1); } subm = e_menu_new(); e_menu_hold_mode_set(subm, EINA_FALSE); evas_object_smart_callback_call(zgc->site->layout, "gadget_site_style_menu", subm); if (e_object_data_get(E_OBJECT(subm))) { Eina_List *styles = e_object_data_get(E_OBJECT(subm)); Eina_Stringshare *style; mi = e_menu_item_new(zgc->menu); e_menu_item_label_set(mi, _("Look")); e_util_menu_item_theme_icon_set(mi, "preferences-look"); e_menu_item_submenu_set(mi, subm); e_object_unref(E_OBJECT(subm)); EINA_LIST_FREE(styles, style) { char buf[1024]; if (eina_streq(style, "base")) { eina_stringshare_del(style); continue; } mi = e_menu_item_new(subm); strncpy(buf, style, sizeof(buf) - 1); buf[0] = toupper(buf[0]); e_menu_item_label_set(mi, buf); snprintf(buf, sizeof(buf), "enlightenment/%s", style); e_util_menu_item_theme_icon_set(mi, buf); e_menu_item_radio_group_set(mi, 1); e_menu_item_radio_set(mi, 1); e_menu_item_toggle_set(mi, style == zgc->style.name); e_menu_item_disabled_set(mi, mi->toggle); e_object_data_set(E_OBJECT(mi), style); E_OBJECT_DEL_SET(mi, _gadget_style_menu_item_del); e_menu_item_callback_set(mi, _gadget_menu_style, zgc); } } else e_object_del(E_OBJECT(subm)); mi = e_menu_item_new(zgc->menu); evas_object_smart_callback_call(zgc->site->layout, "gadget_site_owner_menu", mi); if (mi->label) { mi = e_menu_item_new(zgc->menu); e_menu_item_separator_set(mi, 1); } else e_object_del(E_OBJECT(mi)); mi = e_menu_item_new(zgc->menu); e_menu_item_label_set(mi, _("Delete")); e_util_menu_item_theme_icon_set(mi, "list-remove"); e_menu_item_callback_set(mi, _gadget_menu_remove, zgc); evas_pointer_canvas_xy_get(e_comp->evas, &x, &y); e_menu_activate_mouse(zgc->menu, e_zone_current_get(), x, y, 1, 1, E_MENU_POP_DIRECTION_AUTO, timestamp); _desktop_rect_obj_add(zgc->menu->comp_object); evas_object_smart_callback_call(zgc->site->layout, "gadget_site_popup", zgc->menu->comp_object); } static void _gadget_menu_cancel(Evas_Object *g, unsigned int timestamp EINA_UNUSED) { E_Gadget_Config *zgc; zgc = evas_object_data_get(g, "__e_gadget"); if (zgc->menu) { e_menu_deactivate(zgc->menu); e_object_del(E_OBJECT(zgc->menu)); zgc->menu = NULL; } } static Eina_Bool _site_longpress_menu(void *data) { E_Gadget_Site *zgs = data; E_Gadget_Config *zgc; Evas_Object *g = NULL; zgs->down_timer = NULL; zgs->longpressed = EINA_TRUE; zgc = _gadget_at_xy(zgs, zgs->down_1_x, zgs->down_1_y, NULL); if (zgc) g = zgc->gadget; if (zgs->context_cb) zgs->context_cb(zgs->layout, g, ecore_loop_time_get() * 1000); return EINA_FALSE; } static Eina_Bool _site_mouse_up_handle(E_Gadget_Site *zgs, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev) { if (e_bindings_mouse_up_ecore_event_handle(E_BINDING_CONTEXT_ANY, zgs->action->e_obj_inherit, ev)) { evas_object_pointer_mode_set(zgs->events, EVAS_OBJECT_POINTER_MODE_NOGRAB); zgs->action = NULL; E_FREE_FUNC(zgs->mouse_up_handler, ecore_event_handler_del); } return ECORE_CALLBACK_RENEW; } static void _site_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { E_Gadget_Site *zgs = data; E_Gadget_Config *zgc; Evas_Event_Mouse_Down *ev = event_info; E_Action *act; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; zgc = _gadget_at_xy(zgs, ev->output.x, ev->output.y, NULL); if (zgc) { ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; act = e_bindings_mouse_down_evas_event_handle(E_BINDING_CONTEXT_ANY, zgc->e_obj_inherit, event_info); if (!act) ev->event_flags &= ~EVAS_EVENT_FLAG_ON_HOLD; else if (act->func.end_mouse) { int x, y; evas_object_pointer_mode_set(obj, EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN); zgs->action = zgc; if (!zgs->mouse_up_handler) zgs->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, (Ecore_Event_Handler_Cb)_site_mouse_up_handle, zgs); evas_object_geometry_get(zgc->display, &x, &y, NULL, NULL); zgc->offset.x = ev->canvas.x - x; zgc->offset.y = ev->canvas.y - y; zgc->down.x = ev->canvas.x; zgc->down.y = ev->canvas.y; } if (act) return; } if (ev->button == 1) { zgs->longpressed = EINA_FALSE; zgs->dragged = EINA_FALSE; zgs->down_1_x = ev->canvas.x; zgs->down_1_y = ev->canvas.y; E_FREE_FUNC(zgs->down_timer, ecore_timer_del); zgs->down_timer = ecore_timer_add(1.0, _site_longpress_menu, zgs); } else if (ev->button == 3) { zgs->down_3_x = ev->canvas.x; zgs->down_3_y = ev->canvas.y; } } static void _site_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { E_Gadget_Site *zgs = data; Evas_Event_Mouse_Up *ev = event_info; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if (ev->button == 1) { E_FREE_FUNC(zgs->down_timer, ecore_timer_del); if ((zgs->longpressed) || (zgs->dragged)) { ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; zgs->longpressed = EINA_FALSE; zgs->dragged = EINA_FALSE; } } else if (ev->button == 3) { if (!is_dragged(ev->canvas.x - zgs->down_3_x, ev->canvas.y - zgs->down_3_y)) { E_Gadget_Config *zgc; Evas_Object *g = NULL; zgc = _gadget_at_xy(zgs, zgs->down_3_x, zgs->down_3_y, NULL); if (zgc) g = zgc->gadget; if (zgs->context_cb) zgs->context_cb(zgs->layout, g, ev->timestamp); ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; } } } static void _site_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { E_Gadget_Site *zgs = data; Evas_Event_Mouse_Move *ev = event_info; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if ((zgs->down_timer) || (zgs->longpressed)) { if (is_dragged(ev->cur.canvas.x - zgs->down_1_x, ev->cur.canvas.y - zgs->down_1_y)) { if (zgs->down_timer) { E_FREE_FUNC(zgs->down_timer, ecore_timer_del); } if (!zgs->dragged) { E_Gadget_Config *zgc; Evas_Object *g = NULL; zgs->dragged = EINA_TRUE; zgc = _gadget_at_xy(zgs, zgs->down_1_x, zgs->down_1_y, NULL); if (zgc) g = zgc->gadget; if (zgs->context_cancel_cb) zgs->context_cancel_cb(zgs->layout, g, ev->timestamp); } } } } static void _site_drop(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) { E_Gadget_Site *zgs = data, *drop; Eina_List *l; E_Gadget_Config *zgc, *dzgc; int mx, my; int x, y, w, h; drop = evas_object_data_get(event_info, "__e_gadget_site"); evas_pointer_canvas_xy_get(e_comp->evas, &mx, &my); evas_object_geometry_get(zgs->layout, &x, &y, &w, &h); if (!E_INSIDE(mx, my, x, y, w, h)) return; EINA_LIST_FOREACH(zgs->gadgets, l, zgc) { if (!zgc->display) continue; evas_object_geometry_get(zgc->display, &x, &y, &w, &h); if (E_INSIDE(mx, my, x, y, w, h)) break; } if (zgc) { Eina_Bool pre = EINA_FALSE; if (IS_HORIZ(zgs->orient)) { if (mx <= x + (w / 2)) pre = EINA_TRUE; } else if (IS_VERT(zgs->orient)) { if (my <= y + (h / 2)) pre = EINA_TRUE; } else {} //FIXME if (zgs->orient) { Eina_List *ll; if (pre) EINA_LIST_REVERSE_FOREACH(drop->gadgets, ll, dzgc) { evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); if (dzgc->id == -1) dzgc->id = 0; evas_object_del(dzgc->gadget); zgs->gadget_list = eina_inlist_prepend_relative(zgs->gadget_list, EINA_INLIST_GET(dzgc), EINA_INLIST_GET(zgc)); zgs->gadgets = eina_list_prepend_relative_list(zgs->gadgets, dzgc, l); dzgc->site = zgs; dzgc->zone = -1; _gadget_object_finalize(dzgc); } else EINA_LIST_REVERSE_FOREACH(drop->gadgets, ll, dzgc) { evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); if (dzgc->id == -1) dzgc->id = 0; evas_object_del(dzgc->gadget); zgs->gadget_list = eina_inlist_append_relative(zgs->gadget_list, EINA_INLIST_GET(dzgc), EINA_INLIST_GET(zgc)); zgs->gadgets = eina_list_append_relative_list(zgs->gadgets, dzgc, l); dzgc->site = zgs; dzgc->zone = -1; _gadget_object_finalize(dzgc); } } else { int dx, dy, dw, dh, gx, gy, gw, gh; /* FIXME: this should place _(around)_ the gadget that got dropped on */ evas_object_geometry_get(drop->layout, &dx, &dy, &dw, &dh); evas_object_geometry_get(zgs->layout, &x, &y, &w, &h); EINA_LIST_FOREACH(drop->gadgets, l, dzgc) { E_Zone *zone; /* calculate positioning offsets and normalize based on drop point */ evas_object_geometry_get(dzgc->display, &gx, &gy, &gw, &gh); evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->display); if ((w == e_comp->w) && (h == e_comp->h)) { zone = e_comp_object_util_zone_get(dzgc->display); dzgc->zone = zone->num; x = zone->x, y = zone->y, w = zone->w, h = zone->h; } else dzgc->zone = -1; if (dzgc->id == -1) dzgc->id = 0; evas_object_del(dzgc->gadget); zgs->gadget_list = eina_inlist_append(zgs->gadget_list, EINA_INLIST_GET(dzgc)); zgs->gadgets = eina_list_append(zgs->gadgets, dzgc); dzgc->x = ((gx - dx) / (double)dw) + ((mx - x) / (double)w); dzgc->y = ((gy - dy) / (double)dh) + ((my - y) / (double)h); dzgc->w = gw / (double)w; dzgc->h = gh / (double)h; dzgc->site = zgs; _gadget_object_finalize(dzgc); } } } else { if (zgs->orient) { if (mx >= x) //right of all exiting gadgets { EINA_LIST_FOREACH(drop->gadgets, l, dzgc) { evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); if (dzgc->id == -1) dzgc->id = 0; evas_object_del(dzgc->gadget); zgs->gadget_list = eina_inlist_append(zgs->gadget_list, EINA_INLIST_GET(dzgc)); zgs->gadgets = eina_list_append(zgs->gadgets, dzgc); dzgc->site = zgs; dzgc->zone = -1; _gadget_object_finalize(dzgc); } } else { EINA_LIST_REVERSE_FOREACH(drop->gadgets, l, dzgc) { evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); evas_object_del(dzgc->gadget); zgs->gadget_list = eina_inlist_prepend(zgs->gadget_list, EINA_INLIST_GET(dzgc)); zgs->gadgets = eina_list_prepend(zgs->gadgets, dzgc); dzgc->site = zgs; if (dzgc->id == -1) dzgc->id = 0; dzgc->zone = -1; _gadget_object_finalize(dzgc); } } } else { int dx, dy, dw, dh, gx, gy, gw, gh; evas_object_geometry_get(drop->layout, &dx, &dy, &dw, &dh); evas_object_geometry_get(zgs->layout, &x, &y, &w, &h); EINA_LIST_FOREACH(drop->gadgets, l, dzgc) { E_Zone *zone; /* calculate positioning offsets and normalize based on drop point */ evas_object_geometry_get(dzgc->display, &gx, &gy, &gw, &gh); evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->display); if ((w == e_comp->w) && (h == e_comp->h)) { zone = e_comp_object_util_zone_get(dzgc->display); dzgc->zone = zone->num; x = zone->x, y = zone->y, w = zone->w, h = zone->h; } else dzgc->zone = -1; if (dzgc->id == -1) dzgc->id = 0; evas_object_del(dzgc->gadget); zgs->gadget_list = eina_inlist_append(zgs->gadget_list, EINA_INLIST_GET(dzgc)); zgs->gadgets = eina_list_append(zgs->gadgets, dzgc); dzgc->x = ((gx - dx) / (double)dw) + ((mx - x - (mx - gx)) / (double)w); dzgc->y = ((gy - dy) / (double)dh) + ((my - y - (my - gy)) / (double)h); dzgc->w = gw / (double)w; dzgc->h = gh / (double)h; dzgc->site = zgs; _gadget_object_finalize(dzgc); } } } drop->gadget_list = NULL; drop->gadgets = eina_list_free(drop->gadgets); evas_object_smart_need_recalculate_set(zgs->layout, 1); e_config_save_queue(); } static void _site_restack(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Gadget_Site *zgs = data; if (!evas_object_smart_parent_get(zgs->layout)) { Eina_List *l; E_Gadget_Config *zgc; int layer; layer = evas_object_layer_get(obj); if (!zgs->orient) { EINA_LIST_FOREACH(zgs->gadgets, l, zgc) if (zgc->display) evas_object_layer_set(zgc->display, layer); } evas_object_layer_set(zgs->events, layer); } evas_object_raise(zgs->events); } static void _site_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Site *zgs = data; E_Gadget_Config *zgc; Eina_List *l, *ll; E_FREE_FUNC(zgs->events, evas_object_del); E_FREE_FUNC(zgs->move_handler, ecore_event_handler_del); E_FREE_FUNC(zgs->mouse_up_handler, ecore_event_handler_del); E_FREE_FUNC(zgs->calc_job, ecore_job_del); EINA_LIST_FOREACH_SAFE(zgs->gadgets, l, ll, zgc) evas_object_del(zgc->display); zgs->layout = NULL; zgs->cur_size = 0; zgs->action = NULL; zgs->style_cb = NULL; if (zgs->name) return; eina_stringshare_del(zgs->name); E_FREE_FUNC(zgs->down_timer, ecore_timer_del); free(zgs); } static void _site_style(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Site *zgs = data; E_Gadget_Config *zgc; Eina_List *l; if (!zgs->style_cb) return; EINA_LIST_FOREACH(zgs->gadgets, l, zgc) if (zgc->display) zgc->site->style_cb(zgc->site->layout, zgc->style.name, zgc->gadget); } static void _site_visibility(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Gadget_Site *zgs = data; E_Gadget_Config *zgc; Eina_List *l; Eina_Bool vis = evas_object_visible_get(obj); EINA_LIST_FOREACH(zgs->gadgets, l, zgc) if (zgc->display) { if (vis) evas_object_show(zgc->display); else evas_object_hide(zgc->display); } } static void _site_create(E_Gadget_Site *zgs) { zgs->layout = elm_box_add(e_comp->elm); evas_object_name_set(zgs->layout, zgs->name); elm_box_horizontal_set(zgs->layout, zgs->orient == E_GADGET_SITE_ORIENT_HORIZONTAL); _gravity_apply(zgs, zgs->gravity); if (!zgs->orient) { /* add dummy content to allow recalc to work */ elm_box_pack_end(zgs->layout, elm_box_add(zgs->layout)); } elm_box_layout_set(zgs->layout, _site_layout, zgs, NULL); evas_object_event_callback_add(zgs->layout, EVAS_CALLBACK_DEL, _site_del, zgs); evas_object_event_callback_add(zgs->layout, EVAS_CALLBACK_RESTACK, _site_restack, zgs); zgs->events = evas_object_rectangle_add(e_comp->evas); evas_object_name_set(zgs->events, "zgs->events"); evas_object_event_callback_add(zgs->layout, EVAS_CALLBACK_MOVE, _site_move, zgs); evas_object_smart_callback_add(zgs->layout, "gadget_site_dropped", _site_drop, zgs); evas_object_smart_callback_add(zgs->layout, "gadget_site_style", _site_style, zgs); evas_object_pointer_mode_set(zgs->events, EVAS_OBJECT_POINTER_MODE_NOGRAB); evas_object_color_set(zgs->events, 0, 0, 0, 0); evas_object_repeat_events_set(zgs->events, 1); evas_object_show(zgs->events); evas_object_event_callback_add(zgs->events, EVAS_CALLBACK_MOUSE_DOWN, _site_mouse_down, zgs); evas_object_event_callback_add(zgs->events, EVAS_CALLBACK_MOUSE_UP, _site_mouse_up, zgs); evas_object_event_callback_add(zgs->events, EVAS_CALLBACK_MOUSE_MOVE, _site_mouse_move, zgs); if (!zgs->orient) { evas_object_event_callback_add(zgs->layout, EVAS_CALLBACK_SHOW, _site_visibility, zgs); evas_object_event_callback_add(zgs->layout, EVAS_CALLBACK_HIDE, _site_visibility, zgs); } evas_object_data_set(zgs->layout, "__e_gadget_site", zgs); E_LIST_FOREACH(zgs->gadgets, _gadget_object_create); evas_object_layer_set(zgs->events, evas_object_layer_get(zgs->layout)); evas_object_raise(zgs->events); } static void _site_auto_add_comp_object_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Site *zgs = data; Eina_List *l, *ll; E_Gadget_Config *zgc; /* prune unconfigured gadgets */ EINA_LIST_FOREACH_SAFE(zgs->gadgets, l, ll, zgc) if (zgc->id <= 0) _gadget_remove(zgc); e_config_save_queue(); evas_object_del(zgs->layout); } static void _site_auto_add(E_Gadget_Site *zgs, Evas_Object *comp_object) { int x, y, w, h; _site_create(zgs); evas_object_event_callback_add(comp_object, EVAS_CALLBACK_DEL, _site_auto_add_comp_object_del, zgs); evas_object_layer_set(zgs->layout, evas_object_layer_get(comp_object)); evas_object_stack_above(zgs->layout, comp_object); evas_object_geometry_get(comp_object, &x, &y, &w, &h); evas_object_geometry_set(zgs->layout, x, y, w, h); } static Eina_Bool _site_auto_comp_object_handler(void *d EINA_UNUSED, int t EINA_UNUSED, E_Event_Comp_Object *ev) { const char *name; Eina_List *l; E_Gadget_Site *zgs; name = evas_object_name_get(ev->comp_object); if (!name) return ECORE_CALLBACK_RENEW; EINA_LIST_FOREACH(sites->sites, l, zgs) if (zgs->autoadd && eina_streq(zgs->name, name)) { if (!zgs->layout) _site_auto_add(zgs, ev->comp_object); break; } return ECORE_CALLBACK_RENEW; } static void _site_zone_hover_update(Evas_Object *r, E_Zone *zone) { int zx, zy, zw, zh; e_zone_useful_geometry_get(zone, &zx, &zy, &zw, &zh); evas_object_geometry_set(r, zx, zy, zw, zh); } static void _site_zone_hover_rect_new(E_Zone *zone) { Evas_Object *r = elm_box_add(e_comp->elm); _site_zone_hover_update(r, zone); e_comp_object_util_del_list_append(zone->bg_event_object, r); evas_object_data_set(zone->bg_event_object, "gadget_hover_rect", r); } static Eina_Bool _site_zones_update(void *d EINA_UNUSED, int t EINA_UNUSED, E_Event_Zone_Move_Resize *ev) { Evas_Object *r; r = evas_object_data_get(ev->zone->bg_event_object, "gadget_hover_rect"); _site_zone_hover_update(r, ev->zone); return ECORE_CALLBACK_RENEW; } static Eina_Bool _site_auto_comp_update() { E_Gadget_Site *zgs; Eina_List *l; Evas_Object *r; E_Zone *zone; EINA_LIST_FOREACH(sites->sites, l, zgs) { E_Gadget_Config *zgc = eina_list_data_get(zgs->gadgets); if (!zgc) continue; if (zgc->zone == -1) continue; evas_object_smart_need_recalculate_set(zgs->layout, 1); } EINA_LIST_FOREACH(e_comp->zones, l, zone) { r = evas_object_data_get(zone->bg_event_object, "gadget_hover_rect"); if (!r) _site_zone_hover_rect_new(zone); } return ECORE_CALLBACK_RENEW; } static Evas_Object * _site_util_add(E_Gadget_Site_Orient orient, const char *name, Eina_Bool autoadd) { E_Gadget_Site *zgs; Eina_List *l; Evas_Object *parent; if (name) { EINA_LIST_FOREACH(sites->sites, l, zgs) if (eina_streq(zgs->name, name)) { if (zgs->layout) return zgs->layout; goto out; } } zgs = E_NEW(E_Gadget_Site, 1); zgs->name = eina_stringshare_add(name); zgs->autoadd = autoadd; if (name) sites->sites = eina_list_append(sites->sites, zgs); out: zgs->orient = orient; switch (orient) { case E_GADGET_SITE_ORIENT_HORIZONTAL: zgs->gravity = E_GADGET_SITE_GRAVITY_LEFT; break; case E_GADGET_SITE_ORIENT_VERTICAL: zgs->gravity = E_GADGET_SITE_GRAVITY_TOP; break; default: break; } if (autoadd) { parent = evas_object_name_find(e_comp->evas, name); if (parent) _site_auto_add(zgs, parent); } else _site_create(zgs); return zgs->layout; } E_API Evas_Object * e_gadget_site_add(E_Gadget_Site_Orient orient, const char *name) { return _site_util_add(orient, name, 0); } E_API Evas_Object * e_gadget_site_auto_add(E_Gadget_Site_Orient orient, const char *name) { return _site_util_add(orient, name, 1); } E_API void e_gadget_site_del(Evas_Object *obj) { Eina_List *l, *ll; E_Gadget_Config *zgc; ZGS_GET(obj); EINA_LIST_FOREACH_SAFE(zgs->gadgets, l, ll, zgc) _gadget_remove(zgc); sites->sites = eina_list_remove(sites->sites, zgs); evas_object_del(zgs->layout); eina_stringshare_del(zgs->name); free(zgs); } E_API E_Gadget_Site_Anchor e_gadget_site_anchor_get(Evas_Object *obj) { ZGS_GET(obj); return zgs->anchor; } E_API void e_gadget_site_owner_setup(Evas_Object *obj, E_Gadget_Site_Anchor an, E_Gadget_Style_Cb cb, E_Gadget_Context_Cb context_cb, E_Gadget_Context_Cb context_cancel_cb) { Evas_Object *parent; ZGS_GET(obj); zgs->anchor = an; zgs->style_cb = cb; zgs->context_cb = context_cb; zgs->context_cancel_cb = context_cancel_cb; evas_object_smart_callback_call(zgs->layout, "gadget_site_anchor", NULL); parent = evas_object_smart_parent_get(obj); if (parent) evas_object_smart_member_add(zgs->events, parent); else evas_object_smart_member_del(zgs->events); } E_API E_Gadget_Site_Orient e_gadget_site_orient_get(Evas_Object *obj) { ZGS_GET(obj); return zgs->orient; } E_API E_Gadget_Site_Gravity e_gadget_site_gravity_get(Evas_Object *obj) { ZGS_GET(obj); return zgs->gravity; } E_API void e_gadget_site_gravity_set(Evas_Object *obj, E_Gadget_Site_Gravity gravity) { ZGS_GET(obj); if (zgs->gravity == gravity) return; zgs->gravity = gravity; _gravity_apply(zgs, gravity); evas_object_smart_need_recalculate_set(zgs->layout, 1); } E_API Eina_List * e_gadget_site_gadgets_list(Evas_Object *obj) { Eina_List *l, *list = NULL; E_Gadget_Config *zgc; ZGS_GET(obj); EINA_LIST_FOREACH(zgs->gadgets, l, zgc) if (zgc->display) list = eina_list_append(list, zgc->gadget); return list; } E_API void e_gadget_site_gadget_add(Evas_Object *obj, const char *type, Eina_Bool demo) { int id = 0; demo = !!demo; id -= demo; EINA_SAFETY_ON_NULL_RETURN(gadget_types); ZGS_GET(obj); _gadget_util_add(zgs, NULL, type, id); } E_API void e_gadget_site_gadget_external_add(Evas_Object *obj, const char *domain, const char *type, Eina_Bool demo) { int id = 0; demo = !!demo; id -= demo; EINA_SAFETY_ON_NULL_RETURN(gadget_types); ZGS_GET(obj); _gadget_util_add(zgs, domain, type, id); } E_API Evas_Object * e_gadget_site_get(Evas_Object *g) { E_Gadget_Config *zgc; EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN_VAL(zgc, NULL); return zgc->site->layout; } E_API Eina_Bool e_gadget_site_is_desklock(Evas_Object *obj) { const char *name; ZGS_GET(obj); name = evas_object_name_get(obj); return name && strstr(name, "desklock"); } E_API void e_gadget_configure_cb_set(Evas_Object *g, E_Gadget_Configure_Cb cb) { E_Gadget_Config *zgc; EINA_SAFETY_ON_NULL_RETURN(g); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN(zgc); zgc->configure = cb; } E_API void e_gadget_configure(Evas_Object *g) { E_Gadget_Config *zgc; if (e_desklock_state_get()) return; EINA_SAFETY_ON_NULL_RETURN(g); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN(zgc); _gadget_configure(zgc); } E_API void e_gadget_menu_populate_cb_set(Evas_Object *g, E_Gadget_Menu_Populate_Cb cb) { E_Gadget_Config *zgc; EINA_SAFETY_ON_NULL_RETURN(g); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN(zgc); zgc->populate = cb; } E_API void e_gadget_menu_populate(Evas_Object *g, E_Menu *m) { E_Gadget_Config *zgc; if (e_desklock_state_get()) return; EINA_SAFETY_ON_NULL_RETURN(g); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN(zgc); _gadget_menu_populate(zgc, m); } E_API Eina_Stringshare * e_gadget_type_get(Evas_Object *g) { E_Gadget_Config *zgc; EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN_VAL(zgc, NULL); return zgc->external.type ?: zgc->type; } E_API void e_gadget_type_add(const char *type, E_Gadget_Create_Cb callback, E_Gadget_Wizard_Cb wizard) { E_Gadget_Type *t; Eina_List *l, *ll; E_Gadget_Site *zgs; E_Gadget_Config *zgc; EINA_SAFETY_ON_TRUE_RETURN(!!eina_hash_find(gadget_types, type)); t = E_NEW(E_Gadget_Type, 1); t->cb = callback; t->wizard = wizard; eina_hash_add(gadget_types, type, t); EINA_LIST_FOREACH(sites->sites, l, zgs) if (zgs->layout) EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) if (eina_streq(type, zgc->type)) _gadget_object_create(zgc); } E_API void e_gadget_type_del(const char *type) { Eina_List *l, *ll; E_Gadget_Site *zgs; E_Gadget_Config *zgc; char buf[1024]; strncpy(buf, type, sizeof(buf) - 1); if (!gadget_types) return; EINA_LIST_FOREACH(sites->sites, l, zgs) { EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) if (eina_streq(buf, zgc->type)) evas_object_del(zgc->gadget); } eina_hash_del_by_key(gadget_types, type); } E_API void e_gadget_external_type_add(const char *domain, const char *type, E_Gadget_External_Create_Cb callback, E_Gadget_External_Wizard_Cb wizard) { E_Gadget_External_Type *te; Eina_List *l, *ll; E_Gadget_Site *zgs; E_Gadget_Config *zgc; Eina_Hash *h = NULL; if (gadget_external_domains) { h = eina_hash_find(gadget_external_domains, domain); if (h) EINA_SAFETY_ON_TRUE_RETURN(!!eina_hash_find(h, type)); } else gadget_external_domains = eina_hash_string_superfast_new((Eina_Free_Cb)eina_hash_free); if (!h) { h = eina_hash_string_superfast_new(free); eina_hash_add(gadget_external_domains, domain, h); } te = E_NEW(E_Gadget_External_Type, 1); te->cb = callback; te->wizard = wizard; eina_hash_add(h, type, te); EINA_LIST_FOREACH(sites->sites, l, zgs) if (zgs->layout) EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) if (eina_streq(domain, zgc->external.domain) && eina_streq(type, zgc->external.type)) _gadget_object_create(zgc); } E_API void e_gadget_external_type_name_cb_set(const char *domain, const char *type, E_Gadget_External_Name_Cb name) { E_Gadget_External_Type *te; te = _gadget_external_type_get(domain, type); EINA_SAFETY_ON_NULL_RETURN(te); te->name = name; } E_API void e_gadget_external_type_del(const char *domain, const char *type) { Eina_List *l, *ll; E_Gadget_Site *zgs; E_Gadget_Config *zgc; if (!gadget_external_domains) return; if (!sites) return; EINA_LIST_FOREACH(sites->sites, l, zgs) { EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) if (eina_streq(domain, zgc->external.domain)) { if ((!type) || eina_streq(type, zgc->external.type)) evas_object_del(zgc->gadget); } } if (type) { Eina_Hash *h; h = eina_hash_find(gadget_external_domains, domain); EINA_SAFETY_ON_NULL_RETURN(h); eina_hash_del_by_key(h, type); if (!eina_hash_population(h)) eina_hash_del_by_key(gadget_external_domains, domain); } else eina_hash_del_by_key(gadget_external_domains, domain); } E_API Eina_Iterator * e_gadget_type_iterator_get(void) { return gadget_types ? eina_hash_iterator_key_new(gadget_types) : NULL; } E_API void e_gadget_del(Evas_Object *g) { E_Gadget_Config *zgc; EINA_SAFETY_ON_NULL_RETURN(g); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN(zgc); _gadget_remove(zgc); } static void _gadget_drop_handler_moveresize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { int x, y, w, h; evas_object_geometry_get(obj, &x, &y, &w, &h); e_drop_handler_geometry_set(data, x, y, w, h); } E_API Evas_Object * e_gadget_drop_handler_add(Evas_Object *g, void *data, void (*enter_cb)(void *data, const char *type, void *event), void (*move_cb)(void *data, const char *type, void *event), void (*leave_cb)(void *data, const char *type, void *event), void (*drop_cb)(void *data, const char *type, void *event), const char **types, unsigned int num_types) { E_Gadget_Config *zgc; int x, y, w, h; Evas_Object *drop_object; E_Drop_Handler *drop_handler; EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN_VAL(zgc, NULL); if (!zgc->drop_handlers) zgc->drop_handlers = eina_hash_pointer_new((Eina_Free_Cb)e_drop_handler_del); evas_object_geometry_get(zgc->display, &x, &y, &w, &h); drop_handler = e_drop_handler_add(zgc->e_obj_inherit, NULL, data, enter_cb, move_cb, leave_cb, drop_cb, types, num_types, x, y, w, h); drop_object = evas_object_rectangle_add(e_comp->evas); drop_handler->base = drop_object; evas_object_color_set(drop_object, 0, 0, 0, 0); e_object_data_set(E_OBJECT(drop_handler), drop_object); evas_object_data_set(drop_object, "gadget_drop_handler", drop_handler); evas_object_geometry_set(drop_object, x, y, w, h); evas_object_pass_events_set(drop_object, 1); evas_object_layer_set(drop_object, evas_object_layer_get(zgc->display)); evas_object_event_callback_add(drop_object, EVAS_CALLBACK_MOVE, _gadget_drop_handler_moveresize, drop_handler); evas_object_event_callback_add(drop_object, EVAS_CALLBACK_RESIZE, _gadget_drop_handler_moveresize, drop_handler); evas_object_event_callback_add(drop_object, EVAS_CALLBACK_DEL, _gadget_drop_handler_del, zgc); eina_hash_add(zgc->drop_handlers, &drop_object, drop_handler); return drop_object; } static void _gadget_style_hints(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; evas_object_smart_need_recalculate_set(zgc->site->layout, 1); } E_API Evas_Object * e_gadget_util_layout_style_init(Evas_Object *g, Evas_Object *style) { E_Gadget_Config *zgc; Evas_Object *prev; const char *grp; EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN_VAL(zgc, NULL); prev = zgc->style.obj; if ((!prev) && (!style)) return NULL; zgc->style.obj = style; if (style) { elm_layout_file_get(style, NULL, &grp); eina_stringshare_replace(&zgc->style.name, strrchr(grp, '/') + 1); evas_object_event_callback_priority_add(style, EVAS_CALLBACK_DEL, EVAS_CALLBACK_PRIORITY_AFTER, _gadget_del, zgc); } else eina_stringshare_replace(&zgc->style.name, NULL); if (prev) evas_object_event_callback_del_full(prev, EVAS_CALLBACK_DEL, _gadget_del, zgc); e_config_save_queue(); zgc->display = style ?: zgc->gadget; E_FILL(zgc->display); E_EXPAND(zgc->display); if (zgc->site->gravity) { elm_box_pack_before(zgc->site->layout, zgc->display, prev ?: zgc->gadget); if (prev) elm_box_unpack(zgc->site->layout, prev); } evas_object_raise(zgc->site->events); if (prev) evas_object_event_callback_del(prev, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _gadget_style_hints); if (!style) return prev; evas_object_data_set(style, "__e_gadget", zgc); elm_layout_sizing_eval(style); evas_object_smart_calculate(style); evas_object_size_hint_min_get(style, &zgc->style.minw, &zgc->style.minh); evas_object_event_callback_add(style, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _gadget_style_hints, zgc); evas_object_show(style); if (zgc->display != zgc->gadget) evas_object_smart_callback_add(zgc->display, "gadget_popup", _gadget_popup, zgc); return prev; } static void _gadget_util_ctxpopup_visibility(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { e_comp_shape_queue(); } static void _gadget_util_ctxpopup_moveresize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { e_comp_shape_queue(); } E_API void e_gadget_util_ctxpopup_place(Evas_Object *g, Evas_Object *ctx, Evas_Object *pos_obj) { int x, y, w, h; E_Layer layer; E_Gadget_Config *zgc; Evas_Object *content; E_Zone *zone; Elm_Ctxpopup_Direction first, second; EINA_SAFETY_ON_NULL_RETURN(g); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN(zgc); content = elm_object_content_get(ctx); zone = e_comp_object_util_zone_get(g); elm_ctxpopup_hover_parent_set(ctx, evas_object_data_get(zone->bg_event_object, "gadget_hover_rect")); layer = MAX(evas_object_layer_get(pos_obj ?: g), E_LAYER_POPUP); evas_object_layer_set(ctx, layer); evas_object_geometry_get(pos_obj ?: g, &x, &y, &w, &h); if (zgc->site->anchor & E_GADGET_SITE_ANCHOR_TOP) y += h; if (zgc->site->anchor & E_GADGET_SITE_ANCHOR_LEFT) x += w; if (zgc->site->orient == E_GADGET_SITE_ORIENT_HORIZONTAL) { x += w / 2; first = ELM_CTXPOPUP_DIRECTION_UP, second = ELM_CTXPOPUP_DIRECTION_DOWN; if (zgc->site->anchor & E_GADGET_SITE_ANCHOR_TOP) first = ELM_CTXPOPUP_DIRECTION_DOWN, second = ELM_CTXPOPUP_DIRECTION_UP; } else if (zgc->site->orient == E_GADGET_SITE_ORIENT_VERTICAL) { y += h / 2; first = ELM_CTXPOPUP_DIRECTION_LEFT, second = ELM_CTXPOPUP_DIRECTION_RIGHT; if (zgc->site->anchor & E_GADGET_SITE_ANCHOR_LEFT) first = ELM_CTXPOPUP_DIRECTION_RIGHT, second = ELM_CTXPOPUP_DIRECTION_LEFT; } else { int zx, zy, zw, zh; e_zone_useful_geometry_get(e_comp_object_util_zone_get(pos_obj ?: g), &zx, &zy, &zw, &zh); if (x < zx + (zw / 2)) { second = ELM_CTXPOPUP_DIRECTION_RIGHT; x += w / 2; } else second = ELM_CTXPOPUP_DIRECTION_LEFT; if (y < zy + (zh / 2)) { first = ELM_CTXPOPUP_DIRECTION_DOWN; y += h; } else first = ELM_CTXPOPUP_DIRECTION_UP; } elm_ctxpopup_direction_priority_set(ctx, first, second, 0, 0); evas_object_move(ctx, x, y); evas_object_event_callback_add(ctx, EVAS_CALLBACK_SHOW, _gadget_util_ctxpopup_visibility, NULL); evas_object_event_callback_add(ctx, EVAS_CALLBACK_HIDE, _gadget_util_ctxpopup_visibility, NULL); if (content) { evas_object_event_callback_add(content, EVAS_CALLBACK_MOVE, _gadget_util_ctxpopup_moveresize, NULL); evas_object_event_callback_add(content, EVAS_CALLBACK_RESIZE, _gadget_util_ctxpopup_moveresize, NULL); } _desktop_rect_obj_add(ctx); evas_object_smart_callback_call(g, "gadget_popup", ctx); if (evas_object_visible_get(ctx)) e_comp_shape_queue(); } static void _gadget_util_allow(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; zgc->allow_deny.allow(zgc->allow_deny.data, zgc->gadget, NULL); _gadget_util_allow_deny_cleanup(zgc); } static void _gadget_util_deny(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Config *zgc = data; zgc->allow_deny.deny(zgc->allow_deny.data, zgc->gadget, NULL); _gadget_util_allow_deny_cleanup(zgc); } E_API void e_gadget_util_allow_deny_ctxpopup(Evas_Object *g, const char *text, Evas_Smart_Cb allow_cb, Evas_Smart_Cb deny_cb, const void *data) { Evas_Object *ctx, *tb, *lbl, *bt; E_Gadget_Config *zgc; EINA_SAFETY_ON_NULL_RETURN(g); zgc = evas_object_data_get(g, "__e_gadget"); EINA_SAFETY_ON_NULL_RETURN(zgc); /* FIXME */ EINA_SAFETY_ON_TRUE_RETURN(!!zgc->allow_deny.popup); EINA_SAFETY_ON_NULL_RETURN(allow_cb); EINA_SAFETY_ON_NULL_RETURN(deny_cb); EINA_SAFETY_ON_NULL_RETURN(text); zgc->allow_deny.allow = allow_cb; zgc->allow_deny.deny = deny_cb; zgc->allow_deny.data = (void*)data; ctx = elm_ctxpopup_add(e_comp->elm); elm_object_style_set(ctx, "noblock"); tb = elm_table_add(ctx); E_EXPAND(tb); E_FILL(tb); evas_object_show(tb); lbl = elm_label_add(ctx); E_FILL(lbl); elm_object_text_set(lbl, text); evas_object_show(lbl); elm_table_pack(tb, lbl, 0, 0, 2, 2); bt = elm_button_add(ctx); evas_object_show(bt); E_EXPAND(bt); E_FILL(bt); elm_object_text_set(bt, _("Deny")); evas_object_smart_callback_add(bt, "clicked", _gadget_util_deny, zgc); elm_table_pack(tb, bt, 0, 2, 1, 1); bt = elm_button_add(ctx); evas_object_show(bt); E_EXPAND(bt); E_FILL(bt); elm_object_text_set(bt, _("Allow")); evas_object_smart_callback_add(bt, "clicked", _gadget_util_allow, zgc); elm_table_pack(tb, bt, 1, 2, 1, 1); elm_object_content_set(ctx, tb); e_gadget_util_ctxpopup_place(g, ctx, NULL); zgc->allow_deny.popup = e_comp_object_util_add(ctx, E_COMP_OBJECT_TYPE_NONE); evas_object_layer_set(zgc->allow_deny.popup, E_LAYER_POPUP); evas_object_show(zgc->allow_deny.popup); } EINTERN void e_gadget_save(void) { e_config_domain_save("e_gadget_sites", edd_sites, sites); #ifdef HAVE_WAYLAND e_gadget_runner_save(); #endif } EINTERN void e_gadget_site_rename(const char *name, const char *newname) { Eina_List *l; E_Gadget_Site *zgs; EINA_LIST_FOREACH(sites->sites, l, zgs) if (eina_streq(zgs->name, name)) { eina_stringshare_replace(&zgs->name, newname); e_config_save_queue(); break; } } static void _desktop_gadget_context(Evas_Object *site EINA_UNUSED, Evas_Object *g, unsigned int timestamp) { if (g) _gadget_menu(g, timestamp); } static void _desktop_gadget_context_cancel(Evas_Object *site EINA_UNUSED, Evas_Object *g, unsigned int timestamp) { if (g) _gadget_menu_cancel(g, timestamp); } EINTERN void e_gadget_init(void) { gadget_types = eina_hash_string_superfast_new(free); edd_gadget = E_CONFIG_DD_NEW("E_Gadget_Config", E_Gadget_Config); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, id, INT); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, zone, INT); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, type, STR); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, external.domain, STR); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, external.type, STR); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, style.name, STR); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, x, DOUBLE); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, y, DOUBLE); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, w, DOUBLE); E_CONFIG_VAL(edd_gadget, E_Gadget_Config, h, DOUBLE); edd_site = E_CONFIG_DD_NEW("E_Gadget_Site", E_Gadget_Site); E_CONFIG_VAL(edd_site, E_Gadget_Site, gravity, UINT); E_CONFIG_VAL(edd_site, E_Gadget_Site, orient, UINT); E_CONFIG_VAL(edd_site, E_Gadget_Site, anchor, UINT); E_CONFIG_VAL(edd_site, E_Gadget_Site, autoadd, UCHAR); E_CONFIG_VAL(edd_site, E_Gadget_Site, name, STR); E_CONFIG_LIST(edd_site, E_Gadget_Site, gadgets, edd_gadget); edd_sites = E_CONFIG_DD_NEW("E_Gadget_Sites", E_Gadget_Sites); E_CONFIG_LIST(edd_sites, E_Gadget_Sites, sites, edd_site); sites = e_config_domain_load("e_gadget_sites", edd_sites); if (sites) { Eina_List *l; E_Gadget_Site *zgs; EINA_LIST_FOREACH(sites->sites, l, zgs) { Eina_List *ll; E_Gadget_Config *zgc; EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) { zgs->gadget_list = eina_inlist_append(zgs->gadget_list, EINA_INLIST_GET(zgc)); zgc->site = zgs; } } } else sites = E_NEW(E_Gadget_Sites, 1); move_act = e_action_add("gadget_move"); e_action_predef_name_set(_("Gadgets"), _("Move gadget"), "gadget_move", NULL, NULL, 0); move_act->func.go_mouse = _gadget_act_move; resize_act = e_action_add("gadget_resize"); e_action_predef_name_set(_("Gadgets"), _("Resize gadget"), "gadget_resize", NULL, NULL, 0); resize_act->func.go_mouse = _gadget_act_resize; resize_act->func.end_mouse = _gadget_act_resize_end; configure_act = e_action_add("gadget_configure"); e_action_predef_name_set(_("Gadgets"), _("Configure gadget"), "gadget_configure", NULL, NULL, 0); configure_act->func.go_mouse = _gadget_act_configure; E_LIST_HANDLER_APPEND(handlers, E_EVENT_COMP_OBJECT_ADD, _site_auto_comp_object_handler, NULL); E_LIST_HANDLER_APPEND(handlers, E_EVENT_COMPOSITOR_UPDATE, _site_auto_comp_update, NULL); E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_USEFUL_GEOMETRY_CHANGED, _site_zones_update, NULL); E_LIST_FOREACH(e_comp->zones, _site_zone_hover_rect_new); comp_site = e_comp->canvas->gadget_site = e_gadget_site_add(E_GADGET_SITE_ORIENT_NONE, "__desktop"); evas_object_event_callback_add(e_comp->canvas->resize_object, EVAS_CALLBACK_RESIZE, _comp_site_resize, comp_site); ZGS_GET(comp_site); zgs->context_cb = _desktop_gadget_context; zgs->context_cancel_cb = _desktop_gadget_context_cancel; evas_object_layer_set(comp_site, E_LAYER_DESKTOP); evas_object_resize(comp_site, e_comp->w, e_comp->h); #ifdef HAVE_WAYLAND e_gadget_runner_init(); #endif } EINTERN void e_gadget_shutdown(void) { E_Gadget_Site *zgs; #ifdef HAVE_WAYLAND e_gadget_runner_shutdown(); #endif E_FREE_LIST(handlers, ecore_event_handler_del); E_CONFIG_DD_FREE(edd_gadget); E_CONFIG_DD_FREE(edd_site); E_CONFIG_DD_FREE(edd_sites); EINA_LIST_FREE(sites->sites, zgs) { E_FREE_LIST(zgs->gadgets, _gadget_free); evas_object_del(zgs->layout); eina_stringshare_del(zgs->name); free(zgs); } E_FREE(sites); e_action_del("gadget_move"); e_action_del("gadget_resize"); e_action_del("gadget_configure"); e_action_predef_name_del(_("Gadgets"), _("Move gadget")); e_action_predef_name_del(_("Gadgets"), _("Resize gadget")); e_action_predef_name_del(_("Gadgets"), _("Configure gadget")); move_act = resize_act = configure_act = NULL; E_FREE_FUNC(gadget_types, eina_hash_free); E_FREE_FUNC(gadget_external_domains, eina_hash_free); } ////////////////////////////////////////////////////// //// EDITOR ///// ////////////////////////////////////////////////////// static void _editor_resize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { int w, h, size; Elm_Object_Item *it; evas_object_geometry_get(obj, NULL, NULL, &w, &h); size = MAX(w, h); size = MAX(size / 4, 100); elm_gengrid_item_size_set(obj, size, size); for (it = elm_gengrid_first_item_get(obj); it; it = elm_gengrid_item_next_get(it)) { Gadget_Item *gi = elm_object_item_data_get(it); evas_object_size_hint_max_set(gi->gadget, lround(size * 0.95), lround(size * 0.95)); } } static void _editor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { Evas_Object *site = evas_object_data_get(obj, "__gadget_site"); if (site) { evas_object_event_callback_del(site, EVAS_CALLBACK_DEL, _edit_site_del); ZGS_GET(site); zgs->editor = NULL; } evas_object_event_callback_del_full(data, EVAS_CALLBACK_RESIZE, _editor_resize, obj); } static void _editor_item_del(void *data, Evas_Object *obj EINA_UNUSED) { Gadget_Item *gi = data; elm_box_unpack_all(gi->box); free(data); } static void _editor_pointer_site_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { e_comp_ungrab_input(1, 1); free(data); pointer_site = NULL; E_FREE_LIST(pointer_site_handlers, ecore_event_handler_del); } static void _editor_site_hints(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { int x, y, w, h; evas_object_size_hint_min_get(obj, &w, &h); evas_pointer_canvas_xy_get(e_comp->evas, &x, &y); evas_object_geometry_set(pointer_site, x - (w / 2), y - (h / 2), w, h); } static Eina_Bool _editor_pointer_button(Gadget_Item *active, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev) { int x, y, w, h; E_Gadget_Site *zgs, *zzgs = NULL; if (active->site) { evas_object_geometry_get(active->site, &x, &y, &w, &h); if (evas_object_smart_need_recalculate_get(active->site)) evas_object_smart_calculate(active->site); if ((ev->buttons == 1) && E_INSIDE(ev->x, ev->y, x, y, w, h)) evas_object_smart_callback_call(active->site, "gadget_site_dropped", pointer_site); e_comp_canvas_feed_mouse_up(0); evas_object_pass_events_set(active->site, 0); evas_object_pass_events_set(desktop_editor, 0); elm_object_disabled_set(active->editor, 1); e_comp_object_util_del_list_remove(active->editor, pointer_site); } else { E_Gadget_Config *zgc, *z; Eina_List *l; if (ev->buttons == 1) { EINA_LIST_FOREACH(sites->sites, l, zgs) { if (!zgs->layout) continue; if (!evas_object_visible_get(zgs->events)) continue; evas_object_geometry_get(zgs->layout, &x, &y, &w, &h); if (!E_INSIDE(ev->x, ev->y, x, y, w, h)) continue; /* FIXME: technically not accurate since objects on the same layer * will have different stacking, but walking object trees sucks */ if ((!zzgs) || (evas_object_layer_get(zzgs->layout) < evas_object_layer_get(zgs->layout))) zzgs = zgs; } } zgs = evas_object_data_get(pointer_site, "__e_gadget_site"); zgc = eina_list_data_get(zgs->gadgets); e_comp_canvas_feed_mouse_up(0); evas_object_pass_events_set(zgc->orig->site->layout, 0); evas_object_pass_events_set(desktop_editor, 0); if (zzgs) { /* fake the moving gadget as being on the pointer site */ z = zgc->orig; zgc->site->gadget_list = eina_inlist_remove(zgc->site->gadget_list, EINA_INLIST_GET(zgc)); zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); if (evas_object_smart_need_recalculate_get(zzgs->layout)) evas_object_smart_calculate(zzgs->layout); evas_object_geometry_get(zgc->display, &x, &y, NULL, NULL); evas_object_move(z->display, x, y); z->site->gadget_list = eina_inlist_remove(z->site->gadget_list, EINA_INLIST_GET(z)); z->site->gadgets = eina_list_remove(z->site->gadgets, z); zgs->gadgets = eina_list_append(zgs->gadgets, z); z->site = zgs; evas_object_smart_callback_call(zzgs->layout, "gadget_site_dropped", pointer_site); _gadget_free(zgc); } } E_FREE_FUNC(pointer_site, evas_object_del); return ECORE_CALLBACK_RENEW; } static Eina_Bool _editor_pointer_move(Gadget_Item *active EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev) { int w, h; evas_object_geometry_get(pointer_site, NULL, NULL, &w, &h); evas_object_move(pointer_site, ev->x - (w / 2), ev->y - (h / 2)); if (!e_gadget_site_orient_get(pointer_site)) evas_object_smart_need_recalculate_set(pointer_site, 1); return ECORE_CALLBACK_RENEW; } static Eina_Bool _editor_pointer_wheel(Gadget_Item *active EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Wheel *ev) { int w, h; evas_object_geometry_get(pointer_site, NULL, NULL, &w, &h); evas_object_resize(pointer_site, w - (ev->z * 10 * e_scale), h - (ev->z * 10 * e_scale)); evas_object_smart_need_recalculate_set(pointer_site, 1); return ECORE_CALLBACK_RENEW; } static void _editor_pointer_site_init(E_Gadget_Site_Orient orient, Evas_Object *site, Evas_Object *editor, Eina_Bool up) { Gadget_Item *active; Evas_Object *rect; int size; pointer_site = e_gadget_site_add(orient, NULL); if (site && (orient == E_GADGET_SITE_ORIENT_HORIZONTAL)) evas_object_geometry_get(site, NULL, NULL, NULL, &size); else if (site && (orient == E_GADGET_SITE_ORIENT_VERTICAL)) evas_object_geometry_get(site, NULL, NULL, &size, NULL); else size = 96 * e_scale; evas_object_resize(pointer_site, size, size); evas_object_layer_set(pointer_site, E_LAYER_MENU); evas_object_pass_events_set(pointer_site, 1); evas_object_show(pointer_site); active = E_NEW(Gadget_Item, 1); active->editor = editor; active->site = site; if (active->site) evas_object_pass_events_set(active->site, 1); evas_object_event_callback_add(pointer_site, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _editor_site_hints, active); evas_object_event_callback_add(pointer_site, EVAS_CALLBACK_DEL, _editor_pointer_site_del, active); E_LIST_HANDLER_APPEND(pointer_site_handlers, ECORE_EVENT_MOUSE_MOVE, _editor_pointer_move, active); if (!orient) E_LIST_HANDLER_APPEND(pointer_site_handlers, ECORE_EVENT_MOUSE_WHEEL, _editor_pointer_wheel, active); E_LIST_HANDLER_APPEND(pointer_site_handlers, up ? ECORE_EVENT_MOUSE_BUTTON_UP : ECORE_EVENT_MOUSE_BUTTON_DOWN, _editor_pointer_button, active); rect = evas_object_rectangle_add(e_comp->evas); evas_object_resize(rect, e_comp->w, e_comp->h); evas_object_color_set(rect, 0, 0, 0, 0); evas_object_layer_set(rect, E_LAYER_MENU + 1); e_comp_object_util_del_list_append(pointer_site, rect); evas_object_show(rect); e_comp_grab_input(1, 1); } static void _editor_gadget_new(void *data, Evas_Object *obj, void *event_info) { Gadget_Item *gi = data; E_Gadget_Site_Orient orient; E_Gadget_Config *zgc; zgc = evas_object_data_get(gi->gadget, "__e_gadget"); evas_object_hide(desktop_editor); evas_object_pass_events_set(desktop_editor, 1); orient = e_gadget_site_orient_get(gi->site); _editor_pointer_site_init(orient, gi->site, gi->editor, 0); if (zgc->external.domain) e_gadget_site_gadget_external_add(pointer_site, zgc->external.domain, e_gadget_type_get(gi->gadget), 1); else e_gadget_site_gadget_add(pointer_site, e_gadget_type_get(gi->gadget), 1); ZGS_GET(pointer_site); { zgc = eina_list_data_get(zgs->gadgets); zgc->moving = 1; } elm_object_disabled_set(gi->editor, 1); if (eina_streq(evas_object_type_get(obj), "elm_genlist")) elm_genlist_item_selected_set(event_info, 0); else elm_gengrid_item_selected_set(event_info, 0); } static Evas_Object * _editor_content_get(void *data, Evas_Object *obj, const char *part, Evas_Object *old) { Gadget_Item *gi = data; Eina_Bool gl = eina_streq(evas_object_type_get(obj), "elm_genlist"); if (eina_streq(part, "elm.swallow.icon")) { if (gl) return NULL; } else if (!gl) return NULL; if (old) { if (gi->box == old) return old; elm_box_unpack_all(old); elm_box_unpack(gi->box, gi->gadget); elm_box_pack_end(old, gi->gadget); gi->box = old; return old; } gi->box = elm_box_add(obj); elm_box_horizontal_set(gi->box, 1); elm_box_pack_end(gi->box, gi->gadget); return gi->box; } static char * _editor_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED) { char buf[1024]; Gadget_Item *gi = data; E_Gadget_Config *zgc; zgc = evas_object_data_get(gi->gadget, "__e_gadget"); if (zgc->external.domain) { E_Gadget_External_Type *te; te = _gadget_external_type_get(zgc->external.domain, zgc->external.type); if (te->name) return te->name(zgc->external.type); ERR("No name cb for external gadget provider!"); return strdup(_("ERROR: NO NAME PROVIDED")); } strncpy(buf, e_gadget_type_get(gi->gadget), sizeof(buf) - 1); buf[0] = toupper(buf[0]); return strdup(buf); } static void _editor_gadget_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { Gadget_Item *gi = data; elm_object_item_del(gi->it); } static int _editor_sort(Elm_Object_Item *ita, Elm_Object_Item *itb) { Gadget_Item *a = elm_object_item_data_get(ita); Gadget_Item *b = elm_object_item_data_get(itb); return strcasecmp(e_gadget_type_get(a->gadget), e_gadget_type_get(b->gadget)); } E_API Evas_Object * e_gadget_editor_add(Evas_Object *parent, Evas_Object *site) { Evas_Object *list, *tempsite, *g; Eina_Iterator *it; Eina_List *gadgets; const char *type; E_Gadget_Site_Orient orient = e_gadget_site_orient_get(site); static Elm_Genlist_Item_Class gli = { .version = ELM_GENLIST_ITEM_CLASS_VERSION, .func = { .text_get = _editor_text_get, .reusable_content_get = _editor_content_get, .del = _editor_item_del, }, }; if (orient) { orient = E_GADGET_SITE_ORIENT_HORIZONTAL; list = elm_genlist_add(parent); elm_genlist_homogeneous_set(list, 1); elm_genlist_mode_set(list, ELM_LIST_COMPRESS); } else { list = elm_gengrid_add(parent); evas_object_event_callback_add(list, EVAS_CALLBACK_RESIZE, _editor_resize, NULL); } elm_scroller_bounce_set(list, 0, 0); elm_scroller_policy_set(list, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO); tempsite = e_gadget_site_add(orient, NULL); evas_object_name_set(tempsite, evas_object_name_get(site)); e_gadget_site_gravity_set(tempsite, E_GADGET_SITE_GRAVITY_NONE); it = e_gadget_type_iterator_get(); /* FIXME: no types available */ EINA_ITERATOR_FOREACH(it, type) { E_Gadget_Config *zgc; e_gadget_site_gadget_add(tempsite, type, 1); ZGS_GET(tempsite); zgc = eina_list_last_data_get(zgs->gadgets); if ((zgc) && (!zgc->gadget)) _gadget_remove(zgc); } eina_iterator_free(it); if (gadget_external_domains) { Eina_Hash_Tuple *tup; it = eina_hash_iterator_tuple_new(gadget_external_domains); EINA_ITERATOR_FOREACH(it, tup) { const char *domain = tup->key; Eina_Hash *h = tup->data; E_Gadget_Config *zgc; Eina_Iterator *typeit = eina_hash_iterator_key_new(h); EINA_ITERATOR_FOREACH(typeit, type) { e_gadget_site_gadget_external_add(tempsite, domain, type, 1); ZGS_GET(tempsite); zgc = eina_list_last_data_get(zgs->gadgets); if (!zgc->gadget) _gadget_remove(zgc); } eina_iterator_free(typeit); } eina_iterator_free(it); } gadgets = e_gadget_site_gadgets_list(tempsite); EINA_LIST_FREE(gadgets, g) { Gadget_Item *gi; gi = E_NEW(Gadget_Item, 1); gi->editor = list; gi->gadget = g; gi->site = site; E_EXPAND(g); E_FILL(g); evas_object_pass_events_set(g, 1); evas_object_event_callback_add(g, EVAS_CALLBACK_DEL, _editor_gadget_del, gi); if (orient) gi->it = elm_genlist_item_sorted_insert(list, &gli, gi, NULL, 0, (Eina_Compare_Cb)_editor_sort, _editor_gadget_new, gi); else gi->it = elm_gengrid_item_sorted_insert(list, &gli, gi, (Eina_Compare_Cb)_editor_sort, _editor_gadget_new, gi); } evas_object_event_callback_add(list, EVAS_CALLBACK_DEL, _editor_del, parent); e_comp_object_util_del_list_append(list, tempsite); ZGS_GET(site); evas_object_event_callback_add(site, EVAS_CALLBACK_DEL, _edit_site_del, zgs); evas_object_data_set(list, "__gadget_site", site); /* FIXME: embedded editors? */ zgs->editor = list; if (desktop_rect) { Eina_List *l; E_Gadget_Config *zgc; EINA_LIST_FOREACH(zgs->gadgets, l, zgc) _desktop_rect_obj_add(zgc->display); } added = 0; return list; } static void _editor_show(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { if (obj == desktop_editor) evas_object_pass_events_set(desktop_editor, 0); } E_API Evas_Object * e_gadget_site_edit(Evas_Object *site) { Evas_Object *comp_object, *popup, *editor, *tb, *r; E_Zone *zone, *czone; ZGS_GET(site); EINA_SAFETY_ON_TRUE_RETURN_VAL(!!zgs->editor, NULL); zone = e_comp_object_util_zone_get(site); czone = e_zone_current_get(); if (zone != czone) { int x, y, w, h; evas_object_geometry_get(site, &x, &y, &w, &h); if (E_INTERSECTS(x, y, w, h, czone->x, czone->y, czone->w, czone->h)) zone = czone; } popup = elm_popup_add(e_comp->elm); elm_popup_scrollable_set(popup, EINA_FALSE); elm_popup_allow_events_set(popup, 1); tb = elm_table_add(popup); elm_object_content_set(popup, tb); r = evas_object_rectangle_add(e_comp->evas); evas_object_size_hint_min_set(r, zone->w / 2, 1); e_comp_object_util_del_list_append(tb, r); elm_table_pack(tb, r, 0, 0, 2, 1); r = evas_object_rectangle_add(e_comp->evas); evas_object_size_hint_min_set(r, 1, zone->h / 2); e_comp_object_util_del_list_append(tb, r); elm_table_pack(tb, r, 0, 1, 1, 1); editor = e_gadget_editor_add(e_comp->elm, site); elm_table_pack(tb, editor, 0, 1, 2, 2); evas_object_show(editor); E_EXPAND(editor); E_FILL(editor); comp_object = e_comp_object_util_add(popup, E_COMP_OBJECT_TYPE_NONE); evas_object_layer_set(comp_object, E_LAYER_POPUP); evas_object_show(comp_object); evas_object_event_callback_add(comp_object, EVAS_CALLBACK_SHOW, _editor_show, NULL); evas_object_resize(comp_object, zone->w / 2, zone->h / 2); e_comp_object_util_center_on_zone(comp_object, zone); return comp_object; } static void _edit_end() { if (desktop_editor) { E_Action *act; act = e_action_find("desk_deskshow_toggle"); if (act) act->func.go(E_OBJECT(e_comp_object_util_zone_get(desktop_editor)), NULL); evas_object_hide(desktop_editor); E_FREE_FUNC(desktop_editor, evas_object_del); } E_FREE_FUNC(desktop_rect, evas_object_del); E_FREE_LIST(desktop_handlers, ecore_event_handler_del); e_comp_ungrab_input(1, 1); } static void _edit_site_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Gadget_Site *zgs = data; evas_object_data_del(zgs->editor, "__gadget_site"); zgs->editor = NULL; _edit_end(); } static void _gadget_desklock_del(void) { e_desklock_hide(); desktop_editor = NULL; _edit_end(); } static void _gadget_desklock_clear(void) { Eina_List *l; E_Gadget_Site *zgs; EINA_LIST_FOREACH(sites->sites, l, zgs) if (zgs->autoadd && zgs->layout && strstr(zgs->name, "desklock.")) { E_LIST_FOREACH(zgs->gadgets, _gadget_remove); } } static Eina_Bool _gadget_desklock_key_handler(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Key *ev) { if ((!_editor_site_visible()) && (!pointer_site)) return ECORE_CALLBACK_RENEW; if (eina_streq(ev->key, "Escape")) { if (pointer_site) { E_FREE_FUNC(pointer_site, evas_object_del); if (desktop_editor) evas_object_show(desktop_editor); } else _gadget_desklock_del(); } else if (eina_streq(ev->key, "Delete") || eina_streq(ev->key, "BackSpace")) _gadget_desklock_clear(); return ECORE_CALLBACK_DONE; } static void _gadget_desklock_mouse_up_handler(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Down *ev = event_info; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if (ev->button != 1) return; if (!_editor_site_visible()) return; if (!added) _gadget_desklock_del(); added = 0; } static void _gadget_moved() { added = 1; } static Eina_List *desktop_editor_move_handlers; static Evas_Point desktop_editor_move_point; static E_Zone *desktop_editor_move_zone; static void _desktop_editor_mouse_up_job(void *d) { evas_object_repeat_events_set(d, 1); } static Eina_Bool _desktop_editor_mouse_up(void *d, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev EINA_UNUSED) { E_FREE_LIST(desktop_editor_move_handlers, ecore_event_handler_del); evas_object_pointer_mode_set(d, EVAS_OBJECT_POINTER_MODE_NOGRAB); ecore_job_add(_desktop_editor_mouse_up_job, d); return ECORE_CALLBACK_RENEW; } static Eina_Bool _desktop_editor_mouse_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev) { int x, y, w, h; int nx, ny; evas_object_geometry_get(desktop_editor, &x, &y, &w, &h); nx = x + ev->x - desktop_editor_move_point.x; ny = y + ev->y - desktop_editor_move_point.y; desktop_editor_move_point.x = ev->x; desktop_editor_move_point.y = ev->y; if (!E_CONTAINS(desktop_editor_move_zone->x, desktop_editor_move_zone->y, desktop_editor_move_zone->w, desktop_editor_move_zone->h, nx, ny, w, h)) { if (nx < desktop_editor_move_zone->x) nx = desktop_editor_move_zone->x; if (ny < desktop_editor_move_zone->y) ny = desktop_editor_move_zone->y; if (nx + w > desktop_editor_move_zone->x + desktop_editor_move_zone->w) nx = desktop_editor_move_zone->x + desktop_editor_move_zone->w - w; if (ny + h > desktop_editor_move_zone->y + desktop_editor_move_zone->h) ny = desktop_editor_move_zone->y + desktop_editor_move_zone->h - h; } evas_object_move(desktop_editor, nx, ny); return ECORE_CALLBACK_RENEW; } static void _desktop_editor_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Mouse_Down *ev = event_info; uintptr_t button = (uintptr_t)(uintptr_t*)data; uintptr_t modifiers = button % 10000; int i; const char *names[] = { "Shift", "Control", "Alt", "Win", "AltGr", }; button = (button - modifiers) / 10000; if (button != (unsigned int)ev->button) return; for (i = 0; modifiers && i < 5; i++) { if (!(modifiers & (1 << i))) continue; if (evas_key_modifier_is_set(ev->modifiers, names[i])) modifiers &= ~(1 << i); } if (modifiers) return; desktop_editor_move_point.x = ev->output.x; desktop_editor_move_point.y = ev->output.y; desktop_editor_move_zone = e_comp_object_util_zone_get(obj); evas_object_pointer_mode_set(obj, EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN); evas_object_repeat_events_set(obj, 0); E_LIST_HANDLER_APPEND(desktop_editor_move_handlers, ECORE_EVENT_MOUSE_MOVE, _desktop_editor_mouse_move, obj); E_LIST_HANDLER_APPEND(desktop_editor_move_handlers, ECORE_EVENT_MOUSE_BUTTON_UP, _desktop_editor_mouse_up, obj); } static void _desktop_editor_restack(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { evas_object_layer_set(data, evas_object_layer_get(obj)); } static void _desktop_editor_moveresize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { int x, y, w, h; evas_object_geometry_get(obj, &x, &y, &w, &h); evas_object_geometry_set(data, x, y, w, h); } static void _desktop_editor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { evas_object_del(data); E_FREE_LIST(desktop_editor_move_handlers, ecore_event_handler_del); } static void _desktop_editor_visibility(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { if (evas_object_visible_get(obj)) { evas_object_show(data); evas_object_pointer_mode_set(data, EVAS_OBJECT_POINTER_MODE_NOGRAB); } else { evas_object_hide(data); evas_object_pointer_mode_set(data, EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN); } } static void _desktop_editor_text_add(void) { Evas_Object *txt, *tb, *popup = e_comp_object_util_get(desktop_editor); unsigned int button, modifiers; char *hotkeys; hotkeys = e_bindings_mouse_action_modifiers_text_generate(E_BINDING_CONTEXT_ANY, "gadget_move", &modifiers, &button); tb = elm_object_content_get(popup); if (hotkeys) { char buf[4096]; Evas_Object *bx, *r; elm_object_content_unset(popup); r = evas_object_rectangle_add(e_comp->evas); evas_object_repeat_events_set(r, 1); _desktop_rect_obj_add(r); evas_object_layer_set(r, evas_object_layer_get(desktop_editor)); evas_object_color_set(r, 0, 0, 0, 0); evas_object_show(r); bx = elm_box_add(popup); evas_object_event_callback_add(bx, EVAS_CALLBACK_MOVE, _desktop_editor_moveresize, r); evas_object_event_callback_add(bx, EVAS_CALLBACK_RESIZE, _desktop_editor_moveresize, r); evas_object_event_callback_add(desktop_editor, EVAS_CALLBACK_RESTACK, _desktop_editor_restack, r); evas_object_event_callback_add(desktop_editor, EVAS_CALLBACK_DEL, _desktop_editor_del, r); evas_object_event_callback_add(desktop_editor, EVAS_CALLBACK_SHOW, _desktop_editor_visibility, r); evas_object_event_callback_add(desktop_editor, EVAS_CALLBACK_HIDE, _desktop_editor_visibility, r); evas_object_show(bx); elm_object_content_set(popup, bx); elm_box_pack_end(bx, tb); txt = elm_label_add(tb); elm_box_pack_start(bx, txt); evas_object_show(txt); snprintf(buf, sizeof(buf), _("The current binding to move gadgets and this dialog is %s+Mouse %d"), hotkeys, button); elm_object_text_set(txt, buf); evas_object_pointer_mode_set(r, EVAS_OBJECT_POINTER_MODE_NOGRAB); button = (button * 10000) + modifiers; evas_object_event_callback_add(r, EVAS_CALLBACK_MOUSE_DOWN, _desktop_editor_mouse_down, (uintptr_t*)(uintptr_t)button); } txt = elm_label_add(tb); evas_object_show(txt); elm_object_text_set(txt, _("Press Escape or click the background to exit." "Use Backspace or Delete to remove all gadgets from this screen")); elm_table_pack(tb, txt, 0, 3, 2, 1); } static Eina_Bool _gadget_desklock_handler(void *d EINA_UNUSED, int t EINA_UNUSED, E_Event_Comp_Object *ev) { const char *name; Evas_Object *site, *comp_object; name = evas_object_name_get(ev->comp_object); if (!name) return ECORE_CALLBACK_RENEW; if (strncmp(name, "desklock", 8)) return ECORE_CALLBACK_RENEW; evas_object_layer_set(ev->comp_object, DESKLOCK_DEMO_LAYER - 1); site = e_gadget_site_auto_add(E_GADGET_SITE_ORIENT_NONE, name); _desktop_rect_obj_add(site); evas_object_smart_callback_add(site, "gadget_moved", _gadget_moved, NULL); evas_object_layer_set(site, DESKLOCK_DEMO_LAYER); ZGS_GET(site); desktop_editor = comp_object = e_gadget_site_edit(site); _desktop_editor_text_add(); _desktop_rect_obj_add(zgs->events); _desktop_rect_obj_add(comp_object); e_comp_object_util_del_list_append(ev->comp_object, comp_object); return ECORE_CALLBACK_RENEW; } E_API void e_gadget_site_desklock_edit(void) { desktop_rect = evas_object_event_grabber_add(e_comp->evas); evas_object_resize(desktop_rect, e_comp->w, e_comp->h); evas_object_layer_set(desktop_rect, E_LAYER_MAX - 100); evas_object_show(desktop_rect); E_LIST_HANDLER_APPEND(desktop_handlers, E_EVENT_COMP_OBJECT_ADD, _gadget_desklock_handler, NULL); E_LIST_HANDLER_APPEND(desktop_handlers, ECORE_EVENT_KEY_DOWN, _gadget_desklock_key_handler, NULL); evas_object_event_callback_add(desktop_rect, EVAS_CALLBACK_MOUSE_UP, _gadget_desklock_mouse_up_handler, NULL); e_desklock_demo(); e_comp_grab_input(1, 1); } static Eina_Bool _gadget_desktop_key_handler(void *data, int t EINA_UNUSED, Ecore_Event_Key *ev) { if ((!_editor_site_visible()) && (!pointer_site)) return ECORE_CALLBACK_RENEW; if (eina_streq(ev->key, "Escape")) { if (pointer_site) { E_FREE_FUNC(pointer_site, evas_object_del); if (desktop_editor) evas_object_show(desktop_editor); } else _edit_end(); } else if (eina_streq(ev->key, "Delete") || eina_streq(ev->key, "BackSpace")) { E_Gadget_Site *zgs = data; E_LIST_FOREACH(zgs->gadgets, _gadget_remove); } return ECORE_CALLBACK_DONE; } static void _gadget_desktop_mouse_up_handler(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Down *ev = event_info; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if (ev->button != 1) return; if (!_editor_site_visible()) return; if (!added) _edit_end(); added = 0; } E_API void e_gadget_site_desktop_edit(Evas_Object *site) { E_Action *act; ZGS_GET(site); desktop_rect = evas_object_event_grabber_add(e_comp->evas); evas_object_event_callback_add(desktop_rect, EVAS_CALLBACK_DEL, _edit_end, NULL); evas_object_resize(desktop_rect, e_comp->w, e_comp->h); evas_object_layer_set(desktop_rect, E_LAYER_MAX - 100); evas_object_show(desktop_rect); _desktop_rect_obj_add(site); E_LIST_HANDLER_APPEND(desktop_handlers, ECORE_EVENT_KEY_DOWN, _gadget_desktop_key_handler, zgs); evas_object_event_callback_add(desktop_rect, EVAS_CALLBACK_MOUSE_UP, _gadget_desktop_mouse_up_handler, NULL); desktop_editor = e_gadget_site_edit(site); _desktop_editor_text_add(); _desktop_rect_obj_add(desktop_editor); evas_object_smart_callback_add(site, "gadget_moved", _gadget_moved, NULL); evas_object_show(desktop_editor); act = e_action_find("desk_deskshow_toggle"); if (act) act->func.go(E_OBJECT(e_comp_object_util_zone_get(desktop_editor)), NULL); e_comp_grab_input(1, 1); }