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.
 
 
 

744 lines
21 KiB

#include "luncher.h"
static Eina_List *handlers;
static Elm_Gengrid_Item_Class _grid_icon_class;
static void _grid_resize_job(void *data);
static void
_grid_aspect(Instance *inst)
{
Evas_Coord w, h, square, size;
if (!eina_list_count(inst->icons))
return;
evas_object_geometry_get(inst->o_main, 0, 0, &w, &h);
size = 0;
if ((w + h) > 1)
{
square = w + h;
size = floor((square / eina_list_count(inst->icons)));
}
inst->size = size;
elm_gengrid_item_size_set(inst->o_icon_con, size, size);
}
static Eina_Bool
_grid_check_modifiers(Evas_Modifier *modifiers)
{
if ((evas_key_modifier_is_set(modifiers, "Alt")) ||
(evas_key_modifier_is_set(modifiers, "Control")) ||
(evas_key_modifier_is_set(modifiers, "Shift")))
return EINA_TRUE;
return EINA_FALSE;
}
static Evas_Object *
_grid_gadget_configure(Evas_Object *g)
{
if (!luncher_config) return NULL;
if (luncher_config->config_dialog) return NULL;
Instance *inst = evas_object_data_get(g, "instance");
return config_luncher(e_zone_current_get(), inst, EINA_TRUE);
}
static void
_grid_instance_watch(void *data, E_Exec_Instance *ex EINA_UNUSED, E_Exec_Watch_Type type)
{
Icon *ic = data;
switch (type)
{
case E_EXEC_WATCH_STARTED:
if (ic->starting) elm_layout_signal_emit(ic->o_layout, "e,state,started", "e");
ic->starting = EINA_FALSE;
break;
default:
break;
}
}
static void
_grid_icon_del(Instance *inst, Icon *ic)
{
inst->icons = eina_list_remove(inst->icons, ic);
evas_object_del(ic->o_icon);
evas_object_del(ic->o_layout);
if (ic->desktop)
efreet_desktop_unref(ic->desktop);
eina_stringshare_del(ic->icon);
eina_stringshare_del(ic->key);
if (ic->exec)
e_exec_instance_watcher_del(ic->exec, _grid_instance_watch, ic);
ic->exec = NULL;
_grid_aspect(inst);
E_FREE(ic);
}
static void
_grid_icon_drag_done(E_Drag *drag, int dropped)
{
Instance *inst = e_object_data_get(E_OBJECT(drag));
efreet_desktop_unref(drag->data);
if (!inst) return;
evas_object_smart_callback_call(e_gadget_site_get(inst->o_main), "gadget_site_unlocked", NULL);
if (!dropped)
grid_recalculate(inst);
}
static void
_grid_icon_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data)
{
Icon *ic = data;
Evas_Event_Mouse_Move *ev = event_data;
int dx, dy;
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
if (_grid_check_modifiers(ev->modifiers)) return;
if (!ic->drag.start) return;
dx = ev->cur.output.x - ic->drag.x;
dy = ev->cur.output.y - ic->drag.y;
if (((dx * dx) + (dy * dy)) >
(e_config->drag_resist * e_config->drag_resist))
{
E_Drag *d;
Evas_Object *o;
Evas_Coord x, y, w, h;
unsigned int size;
const char *drag_types[] = { "enlightenment/desktop" };
ic->drag.dnd = 1;
ic->drag.start = 0;
evas_object_geometry_get(ic->o_icon, &x, &y, &w, &h);
d = e_drag_new(x, y, drag_types, 1,
ic->desktop, -1, NULL, _grid_icon_drag_done);
d->button_mask = evas_pointer_button_down_mask_get(e_comp->evas);
efreet_desktop_ref(ic->desktop);
size = MAX(w, h);
o = e_util_desktop_icon_add(ic->desktop, size, e_drag_evas_get(d));
e_drag_object_set(d, o);
e_drag_resize(d, w, h);
e_drag_start(d, ic->drag.x, ic->drag.y);
e_object_data_set(E_OBJECT(d), ic->inst);
if (ic->in_order)
e_order_remove(ic->inst->order, ic->desktop);
}
}
static Eina_Bool
_grid_drag_timer(void *data)
{
Icon *ic = data;
ic->drag_timer = NULL;
ic->drag.start = 1;
evas_object_smart_callback_call(e_gadget_site_get(ic->inst->o_main), "gadget_site_locked", NULL);
return EINA_FALSE;
}
static void
_grid_icon_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data)
{
Icon *ic = data;
Evas_Event_Mouse_Up *ev = event_data;
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
if (_grid_check_modifiers(ev->modifiers)) return;
if (ev->button == 1)
{
ic->drag.x = ev->output.x;
ic->drag.y = ev->output.y;
E_FREE_FUNC(ic->drag_timer, ecore_timer_del);
ic->drag_timer = ecore_timer_loop_add(.35, _grid_drag_timer, ic);
}
if (ev->button == 3)
{
e_gadget_configure(ic->inst->o_main);
}
}
static void
_grid_icon_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data)
{
Icon *ic = data;
Evas_Event_Mouse_Up *ev = event_data;
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
if (_grid_check_modifiers(ev->modifiers)) return;
if (ev->button == 1)
{
E_FREE_FUNC(ic->drag_timer, ecore_timer_del);
if (ic->drag.dnd)
{
ic->drag.start = 0;
ic->drag.dnd = 0;
return;
}
}
if (ev->button == 1 && ic->desktop)
{
if (ic->desktop->type == EFREET_DESKTOP_TYPE_APPLICATION)
{
E_Exec_Instance *ex;
ex = e_exec(e_zone_current_get(), ic->desktop, NULL, NULL, "luncher");
ic->exec = ex;
e_exec_instance_watcher_add(ex, _grid_instance_watch, ic);
if (!ic->starting) elm_layout_signal_emit(ic->o_layout, "e,state,starting", "e");
ic->starting = EINA_TRUE;
}
else if (ic->desktop->type == EFREET_DESKTOP_TYPE_LINK)
{
if (!strncasecmp(ic->desktop->url, "file:", 5))
{
E_Action *act;
act = e_action_find("fileman");
if (act)
act->func.go(NULL, ic->desktop->url + 5);
}
}
}
}
static void
_grid_icon_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data)
{
Icon *ic = data;
Evas_Event_Mouse_In *ev = event_data;
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
if (_grid_check_modifiers(ev->modifiers)) return;
evas_object_raise(ic->o_layout);
if (!ic->inst->cfg->hide_tooltips)
elm_object_tooltip_show(obj);
ic->active = EINA_TRUE;
elm_layout_signal_emit(ic->o_layout, "e,state,focused", "e");
}
static void
_grid_icon_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
{
Icon *ic = data;
if (!ic->inst->cfg->hide_tooltips)
elm_object_tooltip_hide(obj);
elm_layout_signal_emit(ic->o_layout, "e,state,unfocused", "e");
}
static Evas_Object *
_gengrid_icon_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
{
Icon *ic = data;
if (strcmp(part, "elm.swallow.icon"))
return NULL;
return ic->o_layout;
}
static void
_grid_icon_file_set(Icon *ic, Efreet_Desktop *desktop)
{
const char *path = NULL, *k = NULL;
char buf[4096];
if (desktop)
{
if (!desktop->icon)
path = NULL;
else if (strncmp(desktop->icon, "/", 1) && !ecore_file_exists(desktop->icon))
{
path = efreet_icon_path_find(e_config->icon_theme, desktop->icon, ic->inst->size);
if (!path)
{
if (e_util_strcmp(e_config->icon_theme, "hicolor"))
path = efreet_icon_path_find("hicolor", desktop->icon, ic->inst->size);
}
}
else if (ecore_file_exists(desktop->icon))
{
path = desktop->icon;
}
if (!path && desktop->icon)
{
snprintf(buf, sizeof(buf), "e/icons/%s", desktop->icon);
if (eina_list_count(e_theme_collection_items_find("base/theme/icons", buf)))
{
path = e_theme_edje_file_get("base/theme/icons", buf);
k = buf;
}
else
{
path = e_theme_edje_file_get("base/theme/icons", "e/icons/unknown");
k = "e/icons/unknown";
}
}
else if (!path && !desktop->icon)
{
path = e_theme_edje_file_get("base/theme/icons", "e/icons/unknown");
k = "e/icons/unknown";
}
}
else if (ic->icon)
{
if (strncmp(ic->icon, "/", 1) && !ecore_file_exists(ic->icon))
{
path = efreet_icon_path_find(e_config->icon_theme, ic->icon, ic->inst->size);
if (!path)
{
if (e_util_strcmp(e_config->icon_theme, "hicolor"))
path = efreet_icon_path_find("hicolor", ic->icon, ic->inst->size);
}
}
else if (ecore_file_exists(ic->icon))
{
path = ic->icon;
k = ic->key;
}
if (!path)
{
path = e_theme_edje_file_get("base/theme/icons", "e/icons/unknown");
k = "e/icons/unknown";
}
}
else
{
path = e_theme_edje_file_get("base/theme/icons", "e/icons/unknown");
k = "e/icons/unknown";
}
elm_image_file_set(ic->o_icon, path, k);
}
static Icon *
_grid_icon_add(Instance *inst, Efreet_Desktop *desktop)
{
Icon *ic;
ic = E_NEW(Icon, 1);
efreet_desktop_ref(desktop);
ic->desktop = desktop;
ic->inst = inst;
ic->preview = NULL;
ic->preview_box = NULL;
ic->mouse_in_timer = NULL;
ic->mouse_out_timer = NULL;
ic->active = EINA_FALSE;
ic->starting = EINA_FALSE;
ic->exec = NULL;
ic->o_layout = elm_layout_add(inst->o_icon_con);
e_theme_edje_object_set(ic->o_layout, "e/gadget/luncher/icon",
"e/gadget/luncher/icon");
E_FILL(ic->o_layout);
evas_object_show(ic->o_layout);
ic->o_icon = elm_icon_add(ic->o_layout);
E_EXPAND(ic->o_icon);
_grid_icon_file_set(ic, desktop);
elm_object_tooltip_text_set(ic->o_icon, desktop->name);
elm_object_tooltip_orient_set(ic->o_icon, ELM_TOOLTIP_ORIENT_CENTER);
elm_object_tooltip_style_set(ic->o_icon, "luncher");
evas_object_size_hint_aspect_set(ic->o_icon, EVAS_ASPECT_CONTROL_BOTH, 1, 1);
elm_layout_content_set(ic->o_layout, "e.swallow.icon", ic->o_icon);
evas_object_event_callback_add(ic->o_icon, EVAS_CALLBACK_MOUSE_UP,
_grid_icon_mouse_up, ic);
evas_object_event_callback_priority_add(ic->o_icon, EVAS_CALLBACK_MOUSE_DOWN, 0,
_grid_icon_mouse_down, ic);
evas_object_event_callback_add(ic->o_icon, EVAS_CALLBACK_MOUSE_MOVE,
_grid_icon_mouse_move, ic);
evas_object_event_callback_add(ic->o_icon, EVAS_CALLBACK_MOUSE_IN,
_grid_icon_mouse_in, ic);
evas_object_event_callback_add(ic->o_icon, EVAS_CALLBACK_MOUSE_OUT,
_grid_icon_mouse_out, ic);
evas_object_show(ic->o_icon);
elm_layout_sizing_eval(ic->o_layout);
elm_gengrid_item_append(inst->o_icon_con, &_grid_icon_class, ic, NULL, NULL);
_grid_aspect(inst);
return ic;
}
static void
_grid_empty(Instance *inst)
{
if (inst->icons)
{
elm_gengrid_clear(inst->o_icon_con);
while (inst->icons)
_grid_icon_del(inst, eina_list_data_get(inst->icons));
inst->icons = NULL;
}
}
static void
_grid_fill(Instance *inst)
{
Icon *ic;
if (inst->order)
{
Efreet_Desktop *desktop;
Eina_List *list;
EINA_LIST_FOREACH(inst->order->desktops, list, desktop)
{
ic = _grid_icon_add(inst, desktop);
ic->in_order = EINA_TRUE;
inst->icons = eina_list_append(inst->icons, ic);
}
}
}
static void
_grid_resize_job(void *data)
{
Instance *inst = data;
Eina_List *l;
Icon *ic;
if (inst)
{
elm_layout_sizing_eval(inst->o_main);
_grid_aspect(inst);
EINA_LIST_FOREACH(inst->icons, l, ic)
_grid_icon_file_set(ic, ic->desktop);
inst->resize_job = NULL;
}
}
static Eina_Bool
_grid_cb_update_icons(EINA_UNUSED void *data, EINA_UNUSED int ev_type, EINA_UNUSED void *ev)
{
Instance *inst = NULL;
Eina_List *l = NULL;
EINA_LIST_FOREACH(luncher_instances, l, inst)
{
if (inst->bar) continue;
if (inst->resize_job) return ECORE_CALLBACK_RENEW;
inst->resize_job = ecore_job_add(_grid_resize_job, inst);
}
return ECORE_CALLBACK_PASS_ON;
}
static void
_grid_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data EINA_UNUSED)
{
Instance *inst = data;
if (inst->resize_job) return;
inst->resize_job = ecore_job_add(_grid_resize_job, inst);
}
static void
_grid_removed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_data)
{
Instance *inst = data;
char buf[4096];
if (inst->o_main != event_data) return;
if (e_user_dir_snprintf(buf, sizeof(buf), "applications/bar/%s", inst->cfg->dir) >= sizeof(buf))
return;
luncher_config->items = eina_list_remove(luncher_config->items, inst->cfg);
eina_stringshare_del(inst->cfg->dir);
E_FREE(inst->cfg);
}
static void
_grid_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
{
Instance *inst = data;
evas_object_smart_callback_del_full(e_gadget_site_get(obj), "gadget_removed", _grid_removed_cb, inst);
e_object_del(E_OBJECT(inst->order));
E_FREE_FUNC(inst->drop_handler, evas_object_del);
luncher_instances = eina_list_remove(luncher_instances, inst);
free(inst);
}
static void
_grid_drop_drop(void *data, const char *type, void *event_data)
{
Instance *inst = data;
E_Event_Dnd_Drop *ev = event_data;
Efreet_Desktop *desktop = NULL;
Eina_List *l = NULL;
Icon *ic = NULL;
evas_object_del(inst->place_holder);
inst->place_holder = NULL;
if (!strcmp(type, "enlightenment/desktop"))
desktop = ev->data;
else if (!strcmp(type, "enlightenment/border"))
{
E_Client *ec;
ec = ev->data;
desktop = ec->desktop;
if (!desktop)
{
desktop = e_desktop_client_create(ec);
efreet_desktop_save(desktop);
e_desktop_edit(desktop);
}
}
else if (!strcmp(type, "text/uri-list"))
l = ev->data;
ic = inst->drop_before;
if (ic)
{
if (desktop)
e_order_prepend_relative(inst->order, desktop, ic->desktop);
else
e_order_files_prepend_relative(inst->order, l, ic->desktop);
}
else
{
if (desktop)
e_order_append(inst->order, desktop);
else
e_order_files_append(inst->order, l);
}
}
static void
_grid_drop_leave(void *data, const char *type EINA_UNUSED, void *event_data EINA_UNUSED)
{
Instance *inst = data;
inst->inside = EINA_FALSE;
evas_object_del(inst->place_holder);
inst->place_holder = NULL;
}
static void
_grid_drop_move(void *data, const char *type EINA_UNUSED, void *event_data)
{
Instance *inst = data;
E_Event_Dnd_Move *ev = event_data;
Evas_Coord x = ev->x, y = ev->y;
Eina_List *l;
Icon *ic;
if (!inst->inside)
return;
EINA_LIST_FOREACH(inst->icons, l, ic)
{
Evas_Coord dx, dy, dw, dh;
if (!ic->in_order) continue;
evas_object_geometry_get(ic->o_layout, &dx, &dy, &dw, &dh);
if (E_INSIDE(x, y, dx, dy, dw, dh))
inst->drop_before = ic;
}
if (inst->drop_before)
elm_gengrid_item_insert_before(inst->o_icon_con, &_grid_icon_class, inst->place_holder, inst->drop_before->o_layout, NULL, NULL);
}
static void
_grid_drop_enter(void *data, const char *type EINA_UNUSED, void *event_data EINA_UNUSED)
{
Instance *inst = data;
inst->inside = EINA_TRUE;
inst->place_holder = evas_object_rectangle_add(evas_object_evas_get(inst->o_icon_con));
evas_object_color_set(inst->place_holder, 0, 0, 0, 0);
evas_object_size_hint_min_set(inst->place_holder, inst->size, inst->size);
evas_object_size_hint_max_set(inst->place_holder, inst->size, inst->size);
evas_object_show(inst->place_holder);
}
static void
_grid_anchor_changed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Instance *inst = data;
if (inst && inst->o_icon_con)
{
grid_recalculate(inst);
}
}
static void
_grid_order_update(void *data, E_Order *eo EINA_UNUSED)
{
Instance *inst = data;
if (inst && inst->o_icon_con)
{
grid_recalculate(inst);
}
}
static void
_grid_created_cb(void *data, Evas_Object *obj, void *event_data EINA_UNUSED)
{
Instance *inst = data;
char buf[4096];
const char *drop[] = { "enlightenment/desktop", "enlightenment/border", "text/uri-list" };
inst->o_icon_con = elm_gengrid_add(inst->o_main);
elm_object_style_set(inst->o_icon_con, "no_inset_shadow");
elm_gengrid_align_set(inst->o_icon_con, 0.5, 0.5);
elm_gengrid_select_mode_set(inst->o_icon_con, ELM_OBJECT_SELECT_MODE_NONE);
E_FILL(inst->o_icon_con);
elm_layout_content_set(inst->o_main, "e.swallow.grid", inst->o_icon_con);
evas_object_show(inst->o_icon_con);
evas_object_data_set(inst->o_main, "instance", inst);
evas_object_data_set(inst->o_icon_con, "instance", inst);
e_gadget_configure_cb_set(inst->o_main, _grid_gadget_configure);
evas_object_smart_callback_del_full(obj, "gadget_created", _grid_created_cb, data);
if (!inst->cfg->dir)
inst->cfg->dir = eina_stringshare_add("default");
if (inst->cfg->dir[0] != '/')
e_user_dir_snprintf(buf, sizeof(buf), "applications/bar/%s/.order",
inst->cfg->dir);
else
eina_strlcpy(buf, inst->cfg->dir, sizeof(buf));
inst->order = e_order_new(buf);
e_order_update_callback_set(inst->order, _grid_order_update, inst);
_grid_fill(inst);
inst->drop_handler =
e_gadget_drop_handler_add(inst->o_main, inst,
_grid_drop_enter, _grid_drop_move,
_grid_drop_leave, _grid_drop_drop,
drop, 3);
elm_layout_content_set(inst->o_main, "e.swallow.drop", inst->drop_handler);
evas_object_show(inst->drop_handler);
evas_object_event_callback_add(inst->o_main, EVAS_CALLBACK_RESIZE, _grid_resize, inst);
_grid_aspect(inst);
}
static Config_Item *
_conf_item_get(int *id)
{
Config_Item *ci;
Eina_List *l;
if (*id > 0)
{
EINA_LIST_FOREACH(luncher_config->items, l, ci)
if (*id == ci->id) return ci;
}
ci = E_NEW(Config_Item, 1);
if (*id != -1)
ci->id = eina_list_count(luncher_config->items)+1;
else
ci->id = -1;
ci->dir = eina_stringshare_add("default");
luncher_config->items = eina_list_append(luncher_config->items, ci);
return ci;
}
static void
_grid_recalculate_job(void *data)
{
Instance *inst = data;
if (inst)
{
if (inst->o_icon_con)
{
_grid_empty(inst);
_grid_fill(inst);
}
inst->recalc_job = NULL;
}
}
EINTERN void
grid_recalculate(Instance *inst)
{
E_FREE_FUNC(inst->recalc_job, ecore_job_del);
inst->recalc_job = ecore_job_add(_grid_recalculate_job, inst);
}
EINTERN void
grid_reorder(Instance *inst)
{
char buf[4096];
if (inst)
{
E_FREE_FUNC(inst->recalc_job, ecore_job_del);
_grid_empty(inst);
if (!inst->cfg->dir)
inst->cfg->dir = eina_stringshare_add("default");
if (inst->cfg->dir[0] != '/')
e_user_dir_snprintf(buf, sizeof(buf), "applications/bar/%s/.order",
inst->cfg->dir);
else
eina_strlcpy(buf, inst->cfg->dir, sizeof(buf));
e_object_del(E_OBJECT(inst->order));
inst->order = e_order_new(buf);
e_order_update_callback_set(inst->order, _grid_order_update, inst);
_grid_fill(inst);
}
}
EINTERN Evas_Object *
grid_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient)
{
Instance *inst;
if (orient) return NULL;
if (e_gadget_site_is_desklock(parent)) return NULL;
inst = E_NEW(Instance, 1);
inst->size = 0;
inst->resize_job = NULL;
inst->cfg = _conf_item_get(id);
*id = inst->cfg->id;
inst->inside = EINA_FALSE;
inst->bar = EINA_FALSE;
if (!inst->cfg->preview_size)
inst->cfg->preview_size = 64;
_grid_icon_class.item_style = "luncher";
_grid_icon_class.func.text_get = NULL;
_grid_icon_class.func.content_get = _gengrid_icon_get;
_grid_icon_class.func.state_get = NULL;
_grid_icon_class.func.del = NULL;
inst->o_main = elm_layout_add(parent);
e_theme_edje_object_set(inst->o_main, "e/gadget/luncher/grid",
"e/gadget/luncher/grid");
evas_object_event_callback_add(inst->o_main, EVAS_CALLBACK_DEL, _grid_del, inst);
evas_object_smart_callback_add(parent, "gadget_created", _grid_created_cb, inst);
evas_object_smart_callback_add(parent, "gadget_site_anchor", _grid_anchor_changed_cb, inst);
evas_object_smart_callback_add(parent, "gadget_removed", _grid_removed_cb, inst);
evas_object_show(inst->o_main);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_ICON_THEME,
_grid_cb_update_icons, NULL);
E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_ICON_CACHE_UPDATE,
_grid_cb_update_icons, NULL);
if (inst->cfg->id < 0) return inst->o_main;
luncher_instances = eina_list_append(luncher_instances, inst);
return inst->o_main;
}