You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

3535 lines
110 KiB

#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;