diff --git a/configure.ac b/configure.ac
index f2b448e58..71a1ea4f7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1121,6 +1121,7 @@ src/modules/packagekit/module.desktop
src/modules/wl_desktop_shell/module.desktop
src/modules/wireless/module.desktop
src/modules/time/module.desktop
+src/modules/luncher/module.desktop
data/xsession/enlightenment.desktop
data/etc/sysactions.conf
data/units/enlightenment.service
diff --git a/src/bin/e_module.c b/src/bin/e_module.c
index 25ec3a7b1..9bfc3170b 100644
--- a/src/bin/e_module.c
+++ b/src/bin/e_module.c
@@ -1009,6 +1009,7 @@ _e_module_whitelist_check(void)
"ibox",
"layout",
"lokker",
+ "luncher",
"mixer",
"msgbus",
"notification",
diff --git a/src/modules/Makefile.mk b/src/modules/Makefile.mk
index 0962f9ee9..ed74f598c 100644
--- a/src/modules/Makefile.mk
+++ b/src/modules/Makefile.mk
@@ -94,6 +94,8 @@ include src/modules/Makefile_teamwork.mk
include src/modules/Makefile_lokker.mk
+include src/modules/Makefile_luncher.mk
+
include src/modules/Makefile_shot.mk
include src/modules/Makefile_backlight.mk
diff --git a/src/modules/Makefile_luncher.mk b/src/modules/Makefile_luncher.mk
new file mode 100644
index 000000000..d867ff8de
--- /dev/null
+++ b/src/modules/Makefile_luncher.mk
@@ -0,0 +1,23 @@
+EXTRA_DIST += src/modules/luncher/module.desktop.in \
+src/modules/luncher/e-module-luncher.edj
+if USE_MODULE_IBAR
+luncherdir = $(MDIR)/luncher
+luncher_DATA = src/modules/luncher/e-module-luncher.edj \
+ src/modules/luncher/module.desktop
+
+
+luncherpkgdir = $(MDIR)/luncher/$(MODULE_ARCH)
+luncherpkg_LTLIBRARIES = src/modules/luncher/module.la
+
+src_modules_luncher_module_la_LIBADD = $(MOD_LIBS)
+src_modules_luncher_module_la_CPPFLAGS = $(MOD_CPPFLAGS) -Wall
+src_modules_luncher_module_la_LDFLAGS = $(MOD_LDFLAGS)
+src_modules_luncher_module_la_SOURCES = src/modules/luncher/mod.c \
+ src/modules/luncher/luncher.h \
+ src/modules/luncher/bar.c \
+ src/modules/luncher/config.c
+
+PHONIES += luncher install-luncher
+luncher: $(luncherpkg_LTLIBRARIES) $(luncher_DATA)
+install-luncher: install-luncherDATA install-luncherpkgLTLIBRARIES
+endif
diff --git a/src/modules/conf_applications/e_int_config_apps.c b/src/modules/conf_applications/e_int_config_apps.c
index 91ac0baf3..7e2267511 100644
--- a/src/modules/conf_applications/e_int_config_apps.c
+++ b/src/modules/conf_applications/e_int_config_apps.c
@@ -84,7 +84,7 @@ e_int_config_apps_ibar(Evas_Object *parent EINA_UNUSED, const char *params EINA_
e_user_dir_concat_static(buff, "applications/bar/default/.order");
data = E_NEW(E_Config_Data, 1);
- data->title = eina_stringshare_add(_("IBar Applications"));
+ data->title = eina_stringshare_add(_("Launcher Applications"));
data->dialog = eina_stringshare_add("applications/ibar_applications");
data->icon = eina_stringshare_add("preferences-applications-ibar");
data->filename = eina_stringshare_add(buff);
@@ -98,7 +98,7 @@ e_int_config_apps_ibar_other(Evas_Object *parent EINA_UNUSED, const char *path)
if (!path) return NULL;
data = E_NEW(E_Config_Data, 1);
- data->title = eina_stringshare_add(_("IBar Applications"));
+ data->title = eina_stringshare_add(_("Launcher Applications"));
data->dialog = eina_stringshare_add("internal/ibar_other");
data->icon = eina_stringshare_add("preferences-applications-ibar");
data->filename = eina_stringshare_add(path);
diff --git a/src/modules/conf_applications/e_mod_main.c b/src/modules/conf_applications/e_mod_main.c
index 41ddea27d..cee7f37ba 100644
--- a/src/modules/conf_applications/e_mod_main.c
+++ b/src/modules/conf_applications/e_mod_main.c
@@ -30,7 +30,7 @@ e_modapi_init(E_Module *m)
"user-bookmarks",
e_int_config_apps_favs);
e_configure_registry_item_add("applications/ibar_applications", 40,
- _("IBar Applications"), NULL,
+ _("Launcher Applications"), NULL,
"preferences-applications-ibar",
e_int_config_apps_ibar);
e_configure_registry_item_add("applications/screen_lock_applications", 45,
@@ -59,7 +59,7 @@ e_modapi_init(E_Module *m)
e_int_config_deskenv);
e_configure_registry_category_add("internal", -1, _("Internal"), NULL,
"enlightenment/internal");
- e_configure_registry_item_add("internal/ibar_other", -1, _("IBar Other"),
+ e_configure_registry_item_add("internal/ibar_other", -1, _("Launcher Other"),
NULL, "preferences-system-windows",
e_int_config_apps_ibar_other);
diff --git a/src/modules/luncher/bar.c b/src/modules/luncher/bar.c
new file mode 100644
index 000000000..187f38a14
--- /dev/null
+++ b/src/modules/luncher/bar.c
@@ -0,0 +1,1773 @@
+#include "luncher.h"
+static Eina_List *handlers;
+static Evas_Object *current_preview;
+static Eina_Bool current_preview_menu;
+static Eina_Bool _bar_icon_preview_show(void *data);
+
+static Evas_Object *
+_bar_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_comp_object_util_zone_get(g), inst, EINA_TRUE);
+}
+
+static const char *
+_bar_location_get(Instance *inst)
+{
+ const char *s = "float";
+
+ E_Gadget_Site_Orient orient = e_gadget_site_orient_get(e_gadget_site_get(inst->o_main));
+ E_Gadget_Site_Anchor anchor = e_gadget_site_anchor_get(e_gadget_site_get(inst->o_main));
+
+ if (anchor & E_GADGET_SITE_ANCHOR_LEFT)
+ {
+ if (anchor & E_GADGET_SITE_ANCHOR_TOP)
+ {
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ s = "top";
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ s = "left";
+ break;
+ case E_GADGET_SITE_ORIENT_NONE:
+ s = "left";
+ break;
+ }
+ }
+ else if (anchor & E_GADGET_SITE_ANCHOR_BOTTOM)
+ {
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ s = "bottom";
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ s = "left";
+ break;
+ case E_GADGET_SITE_ORIENT_NONE:
+ s = "left";
+ break;
+ }
+ }
+ else
+ s = "left";
+ }
+ else if (anchor & E_GADGET_SITE_ANCHOR_RIGHT)
+ {
+ if (anchor & E_GADGET_SITE_ANCHOR_TOP)
+ {
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ s = "top";
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ s = "right";
+ break;
+ case E_GADGET_SITE_ORIENT_NONE:
+ s = "right";
+ break;
+ }
+ }
+ else if (anchor & E_GADGET_SITE_ANCHOR_BOTTOM)
+ {
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ s = "bottom";
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ s = "right";
+ break;
+ case E_GADGET_SITE_ORIENT_NONE:
+ s = "right";
+ break;
+ }
+ }
+ else
+ s = "right";
+ }
+ else if (anchor & E_GADGET_SITE_ANCHOR_TOP)
+ s = "top";
+ else if (anchor & E_GADGET_SITE_ANCHOR_BOTTOM)
+ s = "bottom";
+ else
+ {
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ s = "bottom";
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ s = "left";
+ break;
+ default: break;
+ }
+ }
+ return s;
+}
+
+static Icon *
+_bar_icon_match(Instance *inst, E_Client *ec)
+{
+ Icon *ic = NULL;
+ Eina_Bool has_desktop = EINA_FALSE;
+
+ if (ec->exe_inst)
+ {
+ if (ec->exe_inst->desktop)
+ has_desktop = EINA_TRUE;
+ }
+
+ if (has_desktop)
+ ic = eina_hash_find(inst->icons_desktop_hash, ec->exe_inst->desktop->orig_path);
+ if (has_desktop && !ic)
+ ic = eina_hash_find(inst->icons_clients_hash, ec);
+ if (!ic)
+ ic = eina_hash_find(inst->icons_clients_hash, ec);
+
+ return ic;
+}
+
+static void
+_bar_instance_watch(void *data, E_Exec_Instance *ex, E_Exec_Watch_Type type)
+{
+ Icon *ic = data;
+ char buf[4096];
+
+ 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;
+ if (!ic->execs)
+ {
+ snprintf(buf, sizeof(buf), "e,state,on,%s", _bar_location_get(ic->inst));
+ elm_layout_signal_emit(ic->o_layout, buf, "e");
+ }
+ if (!eina_list_data_find(ic->execs, ex))
+ ic->execs = eina_list_append(ic->execs, ex);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+_bar_icon_del(Instance *inst, Icon *ic)
+{
+ inst->icons = eina_list_remove(inst->icons, ic);
+ evas_object_del(ic->o_layout);
+ evas_object_del(ic->o_icon);
+ eina_hash_del_by_data(inst->icons_desktop_hash, ic);
+ eina_hash_del_by_data(inst->icons_clients_hash, ic);
+ if (ic->desktop)
+ efreet_desktop_unref(ic->desktop);
+ eina_list_free(ic->execs);
+ eina_list_free(ic->clients);
+ eina_stringshare_del(ic->icon);
+ eina_stringshare_del(ic->key);
+ if (ic->exec)
+ e_exec_instance_watcher_del(ic->exec, _bar_instance_watch, ic);
+ ic->exec = NULL;
+ E_FREE(ic);
+}
+
+static void
+_bar_icon_menu_settings_clicked(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+ Evas_Object *popup = evas_object_data_get(obj, "popup");
+
+ elm_ctxpopup_dismiss(popup);
+ e_gadget_configure(ic->inst->o_main);
+}
+
+static void
+_bar_icon_menu_add_clicked(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+ Evas_Object *popup = evas_object_data_get(obj, "popup");
+
+ elm_ctxpopup_dismiss(popup);
+ e_order_append(ic->inst->order, ic->desktop);
+}
+
+static void
+_bar_icon_menu_remove_clicked(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+ Evas_Object *popup = evas_object_data_get(obj, "popup");
+
+ elm_ctxpopup_dismiss(popup);
+ e_order_remove(ic->inst->order, ic->desktop);
+}
+
+static void
+_bar_icon_menu_properties_clicked(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+ Evas_Object *popup = evas_object_data_get(obj, "popup");
+
+ elm_ctxpopup_dismiss(popup);
+ e_desktop_edit(ic->desktop);
+}
+
+static void
+_bar_icon_menu_action_clicked(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Efreet_Desktop_Action *action = (Efreet_Desktop_Action*)data;
+ Evas_Object *popup = evas_object_data_get(obj, "popup");
+
+ elm_ctxpopup_dismiss(popup);
+ e_exec(e_zone_current_get(), NULL, action->exec, NULL, "luncher");
+}
+
+static void
+_bar_icon_menu_icon_mouse_out(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ elm_layout_signal_emit(obj, "e,state,unfocused", "e");
+}
+
+static void
+_bar_icon_menu_icon_mouse_in(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ elm_layout_signal_emit(obj, "e,state,focused", "e");
+}
+
+static Evas_Object *
+_bar_icon_menu_item_new(Icon *ic, Evas_Object *popup, Evas_Object *parent, const char *name, const char *icon)
+{
+ const char *path = NULL, *k = NULL;
+ int len = 0;
+ Evas_Object *layout, *label, *img;
+
+ layout = elm_layout_add(parent);
+ e_theme_edje_object_set(layout, "e/gadget/luncher/preview",
+ "e/gadget/luncher/preview");
+ evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_IN, _bar_icon_menu_icon_mouse_in, NULL);
+ evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_OUT, _bar_icon_menu_icon_mouse_out, NULL);
+ elm_layout_signal_emit(layout, "e,state,icon,menu", "e");
+ elm_box_pack_end(parent, layout);
+ evas_object_data_set(layout, "popup", popup);
+ evas_object_show(layout);
+
+ label = elm_label_add(layout);
+ elm_object_style_set(label, "luncher_preview");
+ elm_label_ellipsis_set(label, EINA_TRUE);
+ elm_object_text_set(label, name);
+ evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_FILL);
+ elm_layout_content_set(layout, "e.swallow.title", label);
+ evas_object_show(label);
+
+ img = elm_icon_add(layout);
+ evas_object_size_hint_aspect_set(img, EVAS_ASPECT_CONTROL_BOTH, 1, 1);
+ if (!icon)
+ path = NULL;
+ else if (strncmp(icon, "/", 1) && !ecore_file_exists(icon))
+ {
+ path = efreet_icon_path_find(e_config->icon_theme, icon, ic->inst->size);
+ if (!path)
+ {
+ if (e_util_strcmp(e_config->icon_theme, "hicolor"))
+ path = efreet_icon_path_find("hicolor", icon, ic->inst->size);
+ }
+ }
+ else if (ecore_file_exists(icon))
+ {
+ path = icon;
+ }
+ if (!path)
+ {
+ char buf[4096];
+ snprintf(buf, sizeof(buf), "e/icons/%s", 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";
+ }
+ }
+ if (path && icon)
+ {
+ len = strlen(icon);
+ if ((len > 4) && (!strcasecmp(icon + len - 4, ".edj")))
+ k = "icon";
+ }
+ elm_image_file_set(img, path, k);
+ elm_layout_content_set(layout, "e.swallow.icon", img);
+ evas_object_show(img);
+
+ elm_layout_sizing_eval(layout);
+
+ return layout;
+}
+
+static void
+_bar_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;
+ if (!dropped)
+ bar_recalculate(inst);
+}
+
+static void
+_bar_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 (!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" };
+
+ if (ic->preview)
+ {
+ evas_object_del(ic->preview_box);
+ ic->preview_box = NULL;
+ elm_ctxpopup_dismiss(ic->preview);
+ ic->preview = NULL;
+ current_preview = NULL;
+ current_preview_menu = EINA_FALSE;
+ ic->active = EINA_FALSE;
+ }
+ 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, _bar_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
+_bar_drag_timer(void *data)
+{
+ Icon *ic = data;
+
+ ic->drag_timer = NULL;
+ ic->drag.start = 1;
+ return EINA_FALSE;
+}
+
+static void
+_bar_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 (ev->button == 1)
+ {
+ ic->drag.x = ev->output.x;
+ ic->drag.y = ev->output.y;
+ if (ic->drag_timer)
+ ecore_timer_del(ic->drag_timer);
+ ic->drag_timer = ecore_timer_add(.35, _bar_drag_timer, ic);
+ }
+ if (ev->button == 3)
+ {
+ Evas_Object *popup, *box, *item, *sep;
+ Eina_List *l = NULL;
+ Efreet_Desktop_Action *action;
+ E_Gadget_Site_Orient orient = e_gadget_site_orient_get(e_gadget_site_get(ic->inst->o_main));
+
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+
+ popup = elm_ctxpopup_add(e_comp->elm);
+ elm_object_style_set(popup, "noblock");
+ evas_object_size_hint_min_set(popup, ic->inst->size, ic->inst->size);
+
+ box = elm_box_add(popup);
+ evas_object_size_hint_align_set(box, 0, 0);
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ elm_box_horizontal_set(box, EINA_TRUE);
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ elm_box_horizontal_set(box, EINA_FALSE);
+ break;
+ default:
+ elm_box_horizontal_set(box, EINA_FALSE);
+ }
+
+ if (ic->desktop)
+ {
+ if (ic->desktop->actions)
+ {
+ EINA_LIST_FOREACH(ic->desktop->actions, l, action)
+ {
+ item = _bar_icon_menu_item_new(ic, popup, box, action->name, action->icon);
+ evas_object_event_callback_add(item, EVAS_CALLBACK_MOUSE_UP, _bar_icon_menu_action_clicked, action);
+ }
+ sep = elm_separator_add(box);
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ elm_separator_horizontal_set(item, EINA_TRUE);
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ elm_separator_horizontal_set(item, EINA_FALSE);
+ break;
+ default:
+ elm_separator_horizontal_set(item, EINA_FALSE);
+ }
+ elm_box_pack_end(box, sep);
+ evas_object_show(sep);
+ }
+ }
+ item = _bar_icon_menu_item_new(ic, popup, box, _("Icon Properties"), "preferences-applications");
+ evas_object_event_callback_add(item, EVAS_CALLBACK_MOUSE_UP, _bar_icon_menu_properties_clicked, ic);
+ if (ic->in_order)
+ {
+ item = _bar_icon_menu_item_new(ic, popup, box, _("Remove From Bar"), "list-remove");
+ evas_object_event_callback_add(item, EVAS_CALLBACK_MOUSE_UP, _bar_icon_menu_remove_clicked, ic);
+ }
+ else
+ {
+ item = _bar_icon_menu_item_new(ic, popup, box, _("Add To Bar"), "list-add");
+ evas_object_event_callback_add(item, EVAS_CALLBACK_MOUSE_UP, _bar_icon_menu_add_clicked, ic);
+ }
+ item = _bar_icon_menu_item_new(ic, popup, box, _("Luncher Settings"), "configure");
+ evas_object_event_callback_add(item, EVAS_CALLBACK_MOUSE_UP, _bar_icon_menu_settings_clicked, ic);
+
+ elm_object_content_set(popup, box);
+ evas_object_show(box);
+
+ e_gadget_util_ctxpopup_place(ic->inst->o_main, popup, ic->o_layout);
+ e_comp_object_util_autoclose(popup, NULL, NULL, NULL);
+ evas_object_layer_set(popup, E_LAYER_POPUP);
+ evas_object_show(popup);
+ }
+}
+
+static void
+_bar_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->button == 1)
+ {
+ if (ic->drag_timer)
+ ecore_timer_del(ic->drag_timer);
+ 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, _bar_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);
+ }
+ }
+ }
+ else if (ev->button == 1 && !ic->in_order)
+ {
+ if (ic->preview)
+ {
+ evas_object_del(ic->preview_box);
+ ic->preview_box = NULL;
+ elm_ctxpopup_dismiss(ic->preview);
+ ic->preview = NULL;
+ }
+ current_preview = NULL;
+ current_preview_menu = EINA_FALSE;
+ _bar_icon_preview_show(ic);
+ }
+}
+
+static Eina_Bool
+_bar_icon_preview_hide(void *data)
+{
+ Icon *ic = data;
+
+ ic->mouse_out_timer = NULL;
+
+ if (!ic->preview)
+ return EINA_FALSE;
+
+ evas_object_del(ic->preview_box);
+ ic->preview_box = NULL;
+ elm_ctxpopup_dismiss(ic->preview);
+ ic->preview = NULL;
+ current_preview = NULL;
+ current_preview_menu = EINA_FALSE;
+ ic->active = EINA_FALSE;
+
+ return EINA_FALSE;
+}
+
+static void
+_bar_icon_preview_item_mouse_out(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ elm_layout_signal_emit(obj, "e,state,unfocused", "e");
+}
+
+static void
+_bar_icon_preview_item_mouse_in(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ elm_layout_signal_emit(obj, "e,state,focused", "e");
+}
+
+static void
+_bar_icon_preview_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+
+ if (current_preview_menu)
+ return;
+ if (ic->mouse_out_timer)
+ ecore_timer_del(ic->mouse_out_timer);
+ ic->mouse_out_timer = ecore_timer_add(0.75, _bar_icon_preview_hide, ic);
+}
+
+static void
+_bar_icon_preview_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+
+ if (ic->mouse_out_timer)
+ ecore_timer_del(ic->mouse_out_timer);
+ ic->mouse_out_timer = NULL;
+}
+
+static void
+_bar_icon_preview_menu_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+
+ evas_object_event_callback_del_full(obj, EVAS_CALLBACK_HIDE, _bar_icon_preview_menu_hide, ic);
+ if (ic)
+ {
+ if (ic->preview)
+ {
+ current_preview_menu = EINA_FALSE;
+ _bar_icon_preview_mouse_out(ic, NULL, NULL, NULL);
+ }
+ }
+}
+
+static void
+_bar_icon_preview_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data)
+{
+ E_Client *ec = data;
+ Evas_Event_Mouse_Up *ev = event_data;
+ Icon *ic = evas_object_data_get(current_preview, "icon");
+
+ if (ev->button == 3)
+ {
+ e_int_client_menu_show(ec, ev->canvas.x, ev->canvas.y, 0, ev->timestamp);
+ evas_object_event_callback_add(ec->border_menu->comp_object, EVAS_CALLBACK_HIDE,
+ _bar_icon_preview_menu_hide, ic);
+ current_preview_menu = EINA_TRUE;
+ return;
+ }
+ e_client_activate(ec, 1);
+ if (current_preview)
+ {
+ elm_ctxpopup_dismiss(current_preview);
+ }
+ current_preview = NULL;
+ current_preview_menu = EINA_FALSE;
+}
+
+static void
+_bar_icon_preview_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data EINA_UNUSED)
+{
+ Evas_Object *img = data;
+
+ evas_object_del(img);
+}
+
+static void
+_bar_icon_preview_client_add(Icon *ic, E_Client *ec)
+{
+ Evas_Object *layout, *label, *img;
+
+ layout = elm_layout_add(ic->preview_box);
+ e_theme_edje_object_set(layout, "e/gadget/luncher/preview",
+ "e/gadget/luncher/preview");
+ evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_IN,
+ _bar_icon_preview_item_mouse_in, ic);
+ evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_OUT,
+ _bar_icon_preview_item_mouse_out, ic);
+ elm_box_pack_end(ic->preview_box, layout);
+ evas_object_show(layout);
+
+ label = elm_label_add(layout);
+ elm_object_style_set(label, "luncher_preview");
+ elm_label_ellipsis_set(label, EINA_TRUE);
+ elm_object_text_set(label, e_client_util_name_get(ec));
+ evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_FILL);
+ elm_layout_content_set(layout, "e.swallow.title", label);
+ evas_object_show(label);
+
+ img = e_comp_object_util_mirror_add(ec->frame);
+ edje_extern_object_aspect_set(img, EDJE_ASPECT_CONTROL_BOTH, ec->client.w, ec->client.h);
+ elm_layout_content_set(layout, "e.swallow.icon", img);
+ evas_object_show(img);
+
+ if (!(ec->desk->visible) || (ec->iconic))
+ elm_layout_signal_emit(layout, "e,state,invisible", "e");
+
+ evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_UP,
+ _bar_icon_preview_mouse_up, ec);
+ evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL,
+ _bar_icon_preview_del, img);
+ elm_layout_sizing_eval(layout);
+}
+
+static Eina_Bool
+_bar_icon_preview_show(void *data)
+{
+ Icon *ic = data;
+ Eina_List *l, *ll;
+ E_Client *ec;
+ E_Exec_Instance *ex;
+ Eina_List *clients = NULL;
+ E_Gadget_Site_Orient orient;
+ int count = 0;
+
+ if (!ic)
+ return EINA_FALSE;
+ ic->mouse_in_timer = NULL;
+ if (ic->drag.dnd)
+ return EINA_FALSE;
+ if (!ic->inst && !ic->inst->o_icon_con)
+ return EINA_FALSE;
+
+ orient = e_gadget_site_orient_get(e_gadget_site_get(ic->inst->o_main));
+
+ if (current_preview)
+ {
+ elm_ctxpopup_dismiss(current_preview);
+ }
+ current_preview = NULL;
+ current_preview_menu = EINA_FALSE;
+
+ if (!eina_list_count(ic->execs) && !eina_list_count(ic->clients))
+ return EINA_FALSE;
+
+ ic->preview = elm_ctxpopup_add(e_comp->elm);
+ elm_object_style_set(ic->preview, "noblock");
+ evas_object_size_hint_min_set(ic->preview, ic->inst->size, ic->inst->size);
+ evas_object_event_callback_add(ic->preview, EVAS_CALLBACK_MOUSE_IN,
+ _bar_icon_preview_mouse_in, ic);
+ evas_object_event_callback_add(ic->preview, EVAS_CALLBACK_MOUSE_OUT,
+ _bar_icon_preview_mouse_out, ic);
+
+ ic->preview_box = elm_box_add(ic->preview);
+ evas_object_size_hint_align_set(ic->preview_box, 0, 0);
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ elm_box_horizontal_set(ic->preview_box, EINA_TRUE);
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ elm_box_horizontal_set(ic->preview_box, EINA_FALSE);
+ break;
+ default:
+ elm_box_horizontal_set(ic->preview_box, EINA_FALSE);
+ }
+ EINA_LIST_FOREACH(ic->execs, l, ex)
+ {
+ EINA_LIST_FOREACH(ex->clients, ll, ec)
+ clients = eina_list_append(clients, ec);
+ }
+ EINA_LIST_FOREACH(ic->clients, l, ec)
+ clients = eina_list_append(clients, ec);
+
+ EINA_LIST_FREE(clients, ec)
+ {
+ if (!ec->netwm.state.skip_taskbar && !e_client_util_ignored_get(ec))
+ {
+ if (!e_client_util_is_popup(ec))
+ {
+ _bar_icon_preview_client_add(ic, ec);
+
+ count++;
+ }
+ }
+ }
+
+ if (!count)
+ {
+ evas_object_del(ic->preview_box);
+ ic->preview_box = NULL;
+ elm_ctxpopup_dismiss(ic->preview);
+ ic->preview = NULL;
+ return EINA_FALSE;
+ }
+ elm_object_content_set(ic->preview, ic->preview_box);
+ evas_object_show(ic->preview_box);
+
+ e_gadget_util_ctxpopup_place(ic->inst->o_main, ic->preview, ic->o_layout);
+ evas_object_layer_set(ic->preview, E_LAYER_POPUP);
+ evas_object_show(ic->preview);
+
+ evas_object_data_del(ic->preview, "icon");
+ evas_object_data_set(ic->preview, "icon", ic);
+ current_preview = ic->preview;
+
+ return EINA_FALSE;
+}
+
+static void
+_bar_icon_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+ Eina_Bool clients = EINA_FALSE;
+
+ elm_object_tooltip_show(obj);
+ elm_layout_signal_emit(ic->o_layout, "e,state,focused", "e");
+ ic->active = EINA_TRUE;
+
+ if (ic->mouse_out_timer)
+ ecore_timer_del(ic->mouse_out_timer);
+ ic->mouse_out_timer = NULL;
+ if (ic->mouse_in_timer)
+ ecore_timer_del(ic->mouse_in_timer);
+ if (eina_list_count(ic->execs) || eina_list_count(ic->clients))
+ clients = EINA_TRUE;
+ if (current_preview && clients && !current_preview_menu)
+ {
+ Icon *icon = evas_object_data_get(current_preview, "icon");
+ if (icon->preview)
+ {
+ evas_object_del(icon->preview_box);
+ icon->preview_box = NULL;
+ elm_ctxpopup_dismiss(icon->preview);
+ icon->preview = NULL;
+ }
+ current_preview = NULL;
+ current_preview_menu = EINA_FALSE;
+ _bar_icon_preview_show(ic);
+ }
+ else
+ ic->mouse_in_timer = ecore_timer_add(1.0, _bar_icon_preview_show, ic);
+}
+
+static void
+_bar_icon_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+
+ elm_object_tooltip_hide(obj);
+ elm_layout_signal_emit(ic->o_layout, "e,state,unfocused", "e");
+ if (!ic->preview)
+ ic->active = EINA_FALSE;
+ if (ic->mouse_in_timer)
+ ecore_timer_del(ic->mouse_in_timer);
+ ic->mouse_in_timer = NULL;
+ if (ic->mouse_out_timer)
+ ecore_timer_del(ic->mouse_out_timer);
+ ic->mouse_out_timer = ecore_timer_add(0.45, _bar_icon_preview_hide, ic);
+}
+
+static void
+_bar_exec_new_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Icon *ic = data;
+ E_Client *ec = e_comp_object_client_get(obj);
+
+ if (ic->preview)
+ _bar_icon_preview_client_add(ic, ec);
+ evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_SHOW, _bar_exec_new_show, ic);
+}
+
+static Icon *
+_bar_icon_add(Instance *inst, Efreet_Desktop *desktop, E_Client *non_desktop_client)
+{
+ const char *path = NULL, *k = NULL;
+ int len = 0;
+ Icon *ic;
+ const Eina_List *l;
+
+ ic = E_NEW(Icon, 1);
+ if (desktop)
+ 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");
+ evas_object_size_hint_min_set(ic->o_layout, inst->size, inst->size);
+ elm_box_pack_end(inst->o_icon_con, ic->o_layout);
+ evas_object_show(ic->o_layout);
+
+ ic->o_icon = elm_icon_add(ic->o_layout);
+ E_EXPAND(ic->o_icon);
+
+ ic->o_overlay = elm_icon_add(ic->o_layout);
+ E_EXPAND(ic->o_overlay);
+
+ 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, inst->size);
+ if (!path)
+ {
+ if (e_util_strcmp(e_config->icon_theme, "hicolor"))
+ path = efreet_icon_path_find("hicolor", desktop->icon, inst->size);
+ }
+ }
+ else if (ecore_file_exists(desktop->icon))
+ {
+ path = desktop->icon;
+ }
+ if (!path)
+ {
+ char buf[4096];
+ 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";
+ }
+ }
+ if (path && desktop->icon && !k)
+ {
+ len = strlen(desktop->icon);
+ if ((len > 4) && (!strcasecmp(desktop->icon + len - 4, ".edj")))
+ k = "icon";
+ }
+ }
+ else if (non_desktop_client)
+ {
+ E_Client *ec = non_desktop_client;
+ if (!ec->internal_icon)
+ {
+ eina_stringshare_replace(&ic->icon, e_theme_edje_file_get("base/theme/icons", "e/icons/unknown"));
+ eina_stringshare_replace(&ic->key, "e/icons/unknown");
+ }
+ else
+ {
+ eina_stringshare_replace(&ic->icon, ec->internal_icon);
+ eina_stringshare_replace(&ic->key, ec->internal_icon_key);
+ }
+ if (strncmp(ic->icon, "/", 1))
+ {
+ path = efreet_icon_path_find(e_config->icon_theme, ic->icon, inst->size);
+ if (!path)
+ {
+ if (e_util_strcmp(e_config->icon_theme, "hicolor"))
+ path = efreet_icon_path_find("hicolor", ic->icon, inst->size);
+ }
+ }
+ else if (ecore_file_exists(ic->icon))
+ path = ic->icon;
+ if (path && !ic->key)
+ {
+ len = strlen(path);
+ if ((len > 4) && (!strcasecmp(path + len - 4, ".edj")))
+ k = "icon";
+ if (k)
+ eina_stringshare_replace(&ic->key, k);
+ }
+ else if (!path)
+ {
+ path = e_theme_edje_file_get("base/theme/icons", "e/icons/unknown");
+ k = "e/icons/unknown";
+ }
+ else
+ k = ic->key;
+ }
+ elm_image_file_set(ic->o_icon, path, k);
+
+ if (desktop)
+ elm_object_tooltip_text_set(ic->o_icon, desktop->name);
+ else if (non_desktop_client && non_desktop_client->icccm.class)
+ elm_object_tooltip_text_set(ic->o_icon, non_desktop_client->icccm.class);
+ else if (non_desktop_client && non_desktop_client->icccm.name)
+ elm_object_tooltip_text_set(ic->o_icon, non_desktop_client->icccm.name);
+ else if (non_desktop_client && non_desktop_client->icccm.title)
+ elm_object_tooltip_text_set(ic->o_icon, non_desktop_client->icccm.title);
+ else if (non_desktop_client && non_desktop_client->netwm.name)
+ elm_object_tooltip_text_set(ic->o_icon, non_desktop_client->netwm.name);
+ else
+ elm_object_tooltip_text_set(ic->o_icon, _("Unknown"));
+
+ 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,
+ _bar_icon_mouse_up, ic);
+ evas_object_event_callback_priority_add(ic->o_icon, EVAS_CALLBACK_MOUSE_DOWN, 0,
+ _bar_icon_mouse_down, ic);
+ evas_object_event_callback_add(ic->o_icon, EVAS_CALLBACK_MOUSE_MOVE,
+ _bar_icon_mouse_move, ic);
+ evas_object_event_callback_add(ic->o_icon, EVAS_CALLBACK_MOUSE_IN,
+ _bar_icon_mouse_in, ic);
+ evas_object_event_callback_add(ic->o_icon, EVAS_CALLBACK_MOUSE_OUT,
+ _bar_icon_mouse_out, ic);
+ evas_object_show(ic->o_icon);
+
+ elm_image_file_set(ic->o_overlay, path, k);
+ evas_object_size_hint_aspect_set(ic->o_overlay, EVAS_ASPECT_CONTROL_BOTH, 1, 1);
+ elm_layout_content_set(ic->o_layout, "e.swallow.overlay", ic->o_overlay);
+ evas_object_show(ic->o_overlay);
+
+ if (desktop)
+ eina_hash_add(inst->icons_desktop_hash, eina_stringshare_add(desktop->orig_path), ic);
+ else
+ eina_hash_add(inst->icons_clients_hash, non_desktop_client, ic);
+
+ if (desktop)
+ {
+ l = e_exec_desktop_instances_find(desktop);
+ if (l)
+ {
+ char buf[4096];
+ snprintf(buf, sizeof(buf), "e,state,on,%s", _bar_location_get(inst));
+ elm_layout_signal_emit(ic->o_layout, buf, "e");
+ ic->execs = eina_list_clone(l);
+ }
+ }
+ else
+ ic->clients = eina_list_append(ic->clients, non_desktop_client);
+ elm_layout_sizing_eval(ic->o_layout);
+ return ic;
+}
+
+static Eina_Bool
+_bar_cb_client_remove(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Client_Property *ev)
+{
+ Instance *inst = NULL;
+ Eina_List *l = NULL;
+
+ EINA_LIST_FOREACH(luncher_instances, l, inst)
+ {
+ Icon *ic = NULL;
+
+ if (ev->ec)
+ ic = _bar_icon_match(inst, ev->ec);
+
+ if (ic)
+ {
+ if (ic->starting) elm_layout_signal_emit(ic->o_layout, "e,state,started", "e");
+ ic->starting = EINA_FALSE;
+ if (ev->ec->exe_inst)
+ ic->execs = eina_list_remove(ic->execs, ev->ec->exe_inst);
+ if (ev->ec)
+ ic->clients = eina_list_remove(ic->clients, ev->ec);
+ if (!eina_list_count(ic->execs) && !eina_list_count(ic->clients))
+ {
+ elm_layout_signal_emit(ic->o_layout, "e,state,off", "e");
+ if (!ic->in_order)
+ _bar_icon_del(inst, ic);
+ }
+ }
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_bar_cb_exec_del(void *data EINA_UNUSED, int type EINA_UNUSED, E_Exec_Instance *ex)
+{
+ Instance *inst = NULL;
+ Eina_List *l = NULL;
+ E_Client *ec = NULL;
+
+ EINA_LIST_FOREACH(ex->clients, l, ec)
+ {
+ if (!ec->netwm.state.skip_taskbar)
+ {
+ break;
+ }
+ }
+ EINA_LIST_FOREACH(luncher_instances, l, inst)
+ {
+ Icon *ic = NULL;
+ if (!inst || !inst->icons_desktop_hash)
+ return ECORE_CALLBACK_RENEW;
+ ic = eina_hash_find(inst->icons_desktop_hash, ex->desktop->orig_path);
+ if (ic)
+ {
+ if (ic->starting) elm_layout_signal_emit(ic->o_layout, "e,state,started", "e");
+ ic->starting = EINA_FALSE;
+ ic->execs = eina_list_remove(ic->execs, ex);
+ ic->clients = eina_list_remove(ic->clients, ec);
+ if (!eina_list_count(ic->execs) && !eina_list_count(ic->clients))
+ {
+ elm_layout_signal_emit(ic->o_layout, "e,state,off", "e");
+ if (!ic->in_order)
+ _bar_icon_del(inst, ic);
+ }
+ }
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_bar_cb_exec_client_prop(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Client_Property *ev)
+{
+ Instance *inst = NULL;
+ E_Client *ec = NULL;
+ Eina_List *l = NULL;
+ Eina_Bool skip;
+ Eina_Bool has_desktop = EINA_TRUE;
+
+ if (e_client_util_ignored_get(ev->ec))
+ return ECORE_CALLBACK_RENEW;
+ if ((!(ev->property & E_CLIENT_PROPERTY_NETWM_STATE)) && (!(ev->property & E_CLIENT_PROPERTY_ICON))
+ && (!(ev->property & E_CLIENT_PROPERTY_URGENCY)))
+ return ECORE_CALLBACK_RENEW;
+
+ if (!ev->ec->exe_inst)
+ has_desktop = EINA_FALSE;
+ if (ev->ec->exe_inst)
+ {
+ if (!ev->ec->exe_inst->desktop)
+ has_desktop = EINA_FALSE;
+ }
+ if (has_desktop)
+ {
+ skip = EINA_TRUE;
+ EINA_LIST_FOREACH(ev->ec->exe_inst->clients, l, ec)
+ {
+ if (!ec->netwm.state.skip_taskbar)
+ {
+ skip = EINA_FALSE;
+ break;
+ }
+ }
+ }
+ else
+ skip = ev->ec->netwm.state.skip_taskbar;
+
+ EINA_LIST_FOREACH(luncher_instances, l, inst)
+ {
+ Icon *ic = NULL;
+ char buf[4096];
+
+ if (ev->ec)
+ ic = _bar_icon_match(inst, ev->ec);
+
+ if (skip && !ic) continue;
+ if (!skip)
+ {
+ if (ic)
+ {
+ if ((ev->property & E_CLIENT_PROPERTY_URGENCY))
+ {
+ if (ev->ec->urgent)
+ elm_layout_signal_emit(ic->o_layout, "e,state,urgent", "e");
+ else
+ elm_layout_signal_emit(ic->o_layout, "e,state,normal", "e");
+ return ECORE_CALLBACK_RENEW;
+ }
+ if (ic->starting) elm_layout_signal_emit(ic->o_layout, "e,state,started", "e");
+ ic->starting = EINA_FALSE;
+ snprintf(buf, sizeof(buf), "e,state,on,%s", _bar_location_get(inst));
+ elm_layout_signal_emit(ic->o_layout, buf, "e");
+ if (has_desktop)
+ {
+ if (!eina_list_data_find(ic->execs, ev->ec->exe_inst))
+ ic->execs = eina_list_append(ic->execs, ev->ec->exe_inst);
+ }
+ else
+ {
+ if (!eina_list_data_find(ic->clients, ev->ec))
+ ic->clients = eina_list_append(ic->clients, ev->ec);
+ }
+ }
+ else
+ {
+ if (has_desktop)
+ ic = _bar_icon_add(inst, ev->ec->exe_inst->desktop, NULL);
+ else
+ ic = _bar_icon_add(inst, NULL, ev->ec);
+ snprintf(buf, sizeof(buf), "e,state,on,%s", _bar_location_get(inst));
+ elm_layout_signal_emit(ic->o_layout, buf, "e");
+ ic->in_order = EINA_FALSE;
+ inst->icons = eina_list_append(inst->icons, ic);
+ }
+ }
+ else
+ {
+ if (has_desktop)
+ ic->execs = eina_list_remove(ic->execs, ev->ec->exe_inst);
+ if (ev->ec)
+ ic->clients = eina_list_remove(ic->clients, ev->ec);
+ if (!eina_list_count(ic->execs) && !eina_list_count(ic->clients))
+ {
+ if (!ic->in_order)
+ _bar_icon_del(inst, ic);
+ else
+ elm_layout_signal_emit(ic->o_layout, "e,state,off", "e");
+ }
+ }
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_bar_cb_exec_new(void *data EINA_UNUSED, int type, E_Exec_Instance *ex)
+{
+ Instance *inst = NULL;
+ E_Client *ec = NULL;
+ Eina_List *l = NULL;
+ Eina_Bool skip;
+
+ if (type == E_EVENT_EXEC_NEW_CLIENT)
+ {
+ ec = eina_list_data_get(ex->clients);
+ skip = ec->netwm.state.skip_taskbar;
+ }
+ else
+ {
+ skip = EINA_TRUE;
+ EINA_LIST_FOREACH(ex->clients, l, ec)
+ {
+ if (!ec->netwm.state.skip_taskbar)
+ {
+ skip = EINA_FALSE;
+ break;
+ }
+ }
+ }
+ EINA_LIST_FOREACH(luncher_instances, l, inst)
+ {
+ Icon *ic = NULL;
+ char buf[4096];
+
+ if (ec)
+ ic = _bar_icon_match(inst, ec);
+
+ if (ic)
+ {
+ if (skip) continue;
+ if (ic->starting) elm_layout_signal_emit(ic->o_layout, "e,state,started", "e");
+ ic->starting = EINA_FALSE;
+ snprintf(buf, sizeof(buf), "e,state,on,%s", _bar_location_get(inst));
+ elm_layout_signal_emit(ic->o_layout, buf, "e");
+ if (ex->desktop)
+ {
+ if (!eina_list_data_find(ic->execs, ex))
+ ic->execs = eina_list_append(ic->execs, ex);
+ evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW,
+ _bar_exec_new_show, ic);
+ }
+ else
+ {
+ if (!eina_list_data_find(ic->clients, ec))
+ ic->clients = eina_list_append(ic->clients, ec);
+ evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW,
+ _bar_exec_new_show, ic);
+ }
+ }
+ else
+ {
+ if (skip) continue;
+ if (ex->desktop)
+ ic = _bar_icon_add(inst, ex->desktop, NULL);
+ else
+ ic = _bar_icon_add(inst, NULL, ec);
+ snprintf(buf, sizeof(buf), "e,state,on,%s", _bar_location_get(inst));
+ elm_layout_signal_emit(ic->o_layout, buf, "e");
+ ic->in_order = EINA_FALSE;
+ inst->icons = eina_list_append(inst->icons, ic);
+ }
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_bar_empty(Instance *inst)
+{
+ if (inst->icons)
+ {
+ Icon *ic;
+
+ elm_box_clear(inst->o_icon_con);
+ EINA_LIST_FREE(inst->icons, ic)
+ _bar_icon_del(inst, ic);
+ eina_list_free(inst->icons);
+ inst->icons = NULL;
+ }
+}
+
+static void
+_bar_fill(Instance *inst)
+{
+ const Eina_Hash *execs = e_exec_instances_get();
+ Eina_Iterator *it;
+ Eina_List *l, *ll, *lll;
+ E_Exec_Instance *ex;
+ Icon *ic;
+ char buf[4096];
+
+ if (inst->order)
+ {
+ Efreet_Desktop *desktop;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(inst->order->desktops, l, desktop)
+ {
+ ic = _bar_icon_add(inst, desktop, NULL);
+ ic->in_order = EINA_TRUE;
+ inst->icons = eina_list_append(inst->icons, ic);
+ }
+ }
+ it = eina_hash_iterator_data_new(execs);
+ EINA_ITERATOR_FOREACH(it, l)
+ {
+ EINA_LIST_FOREACH(l, ll, ex)
+ {
+ E_Client *ec;
+ Eina_Bool skip = EINA_TRUE;
+
+ EINA_LIST_FOREACH(ex->clients, lll, ec)
+ {
+ if (!ec->netwm.state.skip_taskbar)
+ {
+ skip = EINA_FALSE;
+ break;
+ }
+ if (skip) continue;
+ ic = _bar_icon_match(inst, ec);
+ if (ic)
+ {
+ if (!eina_list_data_find(ic->execs, ex))
+ ic->execs = eina_list_append(ic->execs, ex);
+ continue;
+ }
+ ic = _bar_icon_add(inst, ex->desktop, NULL);
+ snprintf(buf, sizeof(buf), "e,state,on,%s", _bar_location_get(inst));
+ elm_layout_signal_emit(ic->o_layout, buf, "e");
+ ic->in_order = EINA_FALSE;
+ inst->icons = eina_list_append(inst->icons, ic);
+ }
+ }
+ }
+}
+
+static void
+_bar_resize_job(void *data)
+{
+ Instance *inst = data;
+ Eina_List *l;
+ Icon *ic;
+ E_Gadget_Site_Orient orient = e_gadget_site_orient_get(e_gadget_site_get(inst->o_main));
+ Evas_Coord x, y, w, h, size;
+
+ if (inst)
+ {
+ evas_object_geometry_get(inst->o_main, &x, &y, &w, &h);
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ size = h;
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ size = w;
+ break;
+ default:
+ size = h;
+ }
+ inst->size = size;
+ EINA_LIST_FOREACH(inst->icons, l, ic)
+ {
+ const char *path = NULL, *key = NULL;
+ int len = 0;
+
+ if (ic->desktop)
+ {
+ if (!ic->desktop->icon)
+ path = NULL;
+ else if (strncmp(ic->desktop->icon, "/", 1) && !ecore_file_exists(ic->desktop->icon))
+ {
+ path = efreet_icon_path_find(e_config->icon_theme, ic->desktop->icon, inst->size);
+ if (!path)
+ {
+ if (e_util_strcmp(e_config->icon_theme, "hicolor"))
+ path = efreet_icon_path_find("hicolor", ic->desktop->icon, inst->size);
+ }
+ }
+ else if (ecore_file_exists(ic->desktop->icon))
+ {
+ path = ic->desktop->icon;
+ }
+ if (!path)
+ {
+ elm_image_file_set(ic->o_icon, e_theme_edje_file_get("base/theme/icons", "e/icons/unknown"),
+ "e/icons/unknown");
+ elm_image_file_set(ic->o_overlay, e_theme_edje_file_get("base/theme/icons", "e/icons/unknown"),
+ "e/icons/unknown");
+ }
+ if (path && ic->desktop->icon)
+ {
+ len = strlen(ic->desktop->icon);
+ if ((len > 4) && (!strcasecmp(ic->desktop->icon + len - 4, ".edj")))
+ key = "icon";
+
+ elm_image_file_set(ic->o_icon, path, key);
+ elm_image_file_set(ic->o_overlay, path, key);
+ }
+ }
+ 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, inst->size);
+ if (!path)
+ {
+ if (e_util_strcmp(e_config->icon_theme, "hicolor"))
+ path = efreet_icon_path_find("hicolor", ic->icon, inst->size);
+ }
+ }
+ else if (ecore_file_exists(ic->icon))
+ {
+ path = ic->icon;
+ }
+ if (!path)
+ {
+ elm_image_file_set(ic->o_icon, e_theme_edje_file_get("base/theme/icons", "e/icons/unknown"),
+ "e/icons/unknown");
+ elm_image_file_set(ic->o_overlay, e_theme_edje_file_get("base/theme/icons", "e/icons/unknown"),
+ "e/icons/unknown");
+ }
+ else
+ {
+ elm_image_file_set(ic->o_icon, path, ic->key);
+ elm_image_file_set(ic->o_overlay, path, ic->key);
+ }
+ }
+ else
+ {
+ elm_image_file_set(ic->o_icon, e_theme_edje_file_get("base/theme/icons", "e/icons/unknown"),
+ "e/icons/unknown");
+ elm_image_file_set(ic->o_overlay, e_theme_edje_file_get("base/theme/icons", "e/icons/unknown"),
+ "e/icons/unknown");
+ }
+ evas_object_size_hint_min_set(ic->o_layout, inst->size, inst->size);
+ }
+ inst->resize_job = NULL;
+ }
+}
+
+static Eina_Bool
+_bar_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->resize_job) return ECORE_CALLBACK_RENEW;
+ inst->resize_job = ecore_job_add(_bar_resize_job, inst);
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_bar_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(_bar_resize_job, inst);
+}
+
+static void
+_bar_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data EINA_UNUSED)
+{
+ Instance *inst = data;
+
+ if (inst->drop_handler)
+ evas_object_del(inst->drop_handler);
+ luncher_instances = eina_list_remove(luncher_instances, inst);
+ free(inst);
+}
+
+static void
+_bar_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
+_bar_drop_leave(void *data, const char *type EINA_UNUSED, void *event_data EINA_UNUSED)
+{
+ Instance *inst = data;
+
+ evas_object_del(inst->place_holder);
+ inst->place_holder = NULL;
+}
+
+static void
+_bar_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;
+
+ 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;
+ }
+ elm_box_unpack(inst->o_icon_con, inst->place_holder);
+ elm_box_pack_before(inst->o_icon_con, inst->place_holder, inst->drop_before->o_layout);
+}
+
+static void
+_bar_drop_enter(void *data, const char *type EINA_UNUSED, void *event_data EINA_UNUSED)
+{
+ Instance *inst = data;
+
+ 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
+_bar_removed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_data)
+{
+ Instance *inst = data;
+ char buf[PATH_MAX];
+
+ 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);
+ eina_hash_free(inst->icons_desktop_hash);
+ eina_hash_free(inst->icons_clients_hash);
+ E_FREE(inst->cfg);
+}
+
+static void
+_bar_iconify_end(void *data, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
+{
+ E_Client *ec = data;
+
+ evas_object_layer_set(ec->frame, ec->layer);
+ ec->layer_block = 0;
+ if (ec->iconic)
+ evas_object_hide(ec->frame);
+}
+
+static Eina_Bool
+_bar_iconify_start(void *data, Evas_Object *obj, const char *signal EINA_UNUSED)
+{
+ Instance *inst = data;
+ Icon *ic = NULL;
+ E_Client *ec;
+ int ox, oy, ow, oh;
+
+ ec = e_comp_object_client_get(obj);
+
+ if (ec)
+ ic = _bar_icon_match(inst, ec);
+
+ if (!ic) return EINA_FALSE;
+ ec->layer_block = 1;
+ evas_object_layer_set(ec->frame, E_LAYER_CLIENT_PRIO);
+ evas_object_geometry_get(ic->o_layout, &ox, &oy, &ow, &oh);
+ e_comp_object_effect_set(ec->frame, "iconify/luncher");
+ e_comp_object_effect_params_set(ec->frame, 1, (int[]){ec->x, ec->y, ec->w, ec->h, ox, oy, ow, oh}, 8);
+ e_comp_object_effect_params_set(ec->frame, 0, (int[]){!!strcmp(signal, "e,action,iconify")}, 1);
+ e_comp_object_effect_start(ec->frame, _bar_iconify_end, ec);
+ return EINA_TRUE;
+}
+
+static void
+_bar_anchor_changed_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ Instance *inst = data;
+
+ if (inst && inst->o_icon_con)
+ {
+ _bar_empty(inst);
+ _bar_fill(inst);
+ }
+}
+
+static void
+_bar_order_update(void *data, E_Order *eo EINA_UNUSED)
+{
+ Instance *inst = data;
+
+ bar_recalculate(inst);
+}
+
+static void
+_bar_created_cb(void *data, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Instance *inst = data;
+ char buf[PATH_MAX];
+ const char *drop[] = { "enlightenment/desktop", "enlightenment/border", "text/uri-list" };
+ E_Gadget_Site_Orient orient = e_gadget_site_orient_get(e_gadget_site_get(inst->o_main));
+
+ inst->o_icon_con = elm_box_add(inst->o_main);
+ elm_box_homogeneous_set(inst->o_icon_con, EINA_TRUE);
+ E_EXPAND(inst->o_icon_con);
+ switch (orient)
+ {
+ case E_GADGET_SITE_ORIENT_HORIZONTAL:
+ elm_box_horizontal_set(inst->o_icon_con, EINA_TRUE);
+ break;
+ case E_GADGET_SITE_ORIENT_VERTICAL:
+ elm_box_horizontal_set(inst->o_icon_con, EINA_FALSE);
+ break;
+ default:
+ elm_box_horizontal_set(inst->o_icon_con, EINA_TRUE);
+ }
+ elm_layout_content_set(inst->o_main, "e.swallow.bar", 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, _bar_gadget_configure);
+ evas_object_smart_callback_del_full(obj, "gadget_created", _bar_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, _bar_order_update, inst);
+
+ inst->iconify_provider = e_comp_object_effect_mover_add(80, "e,action,*iconify",
+ _bar_iconify_start, inst);
+
+ _bar_fill(inst);
+
+ inst->drop_handler =
+ e_gadget_drop_handler_add(inst->o_main, inst,
+ _bar_drop_enter, _bar_drop_move,
+ _bar_drop_leave, _bar_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, _bar_resize, 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);
+
+ ci->id = eina_list_count(luncher_config->items)+1;
+ ci->dir = eina_stringshare_add("default");
+ luncher_config->items = eina_list_append(luncher_config->items, ci);
+
+ return ci;
+}
+
+EINTERN void
+bar_recalculate(Instance *inst)
+{
+ if (inst && inst->o_icon_con)
+ {
+ _bar_empty(inst);
+ _bar_fill(inst);
+ }
+}
+
+EINTERN void
+bar_reorder(Instance *inst)
+{
+ char buf[PATH_MAX];
+
+ if (inst)
+ {
+ _bar_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, _bar_order_update, inst);
+ _bar_fill(inst);
+ }
+}
+
+EINTERN Evas_Object *
+bar_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient)
+{
+ Instance *inst;
+
+ inst = E_NEW(Instance, 1);
+ inst->size = 0;
+ inst->resize_job = NULL;
+ inst->cfg = _conf_item_get(id);
+ *id = inst->cfg->id;
+ inst->icons_desktop_hash = eina_hash_string_superfast_new(NULL);
+ inst->icons_clients_hash = eina_hash_pointer_new(NULL);
+ inst->o_main = elm_layout_add(parent);
+ e_theme_edje_object_set(inst->o_main, "e/gadget/luncher/bar",
+ "e/gadget/luncher/bar");
+ evas_object_event_callback_add(inst->o_main, EVAS_CALLBACK_DEL, _bar_del, inst);
+ evas_object_smart_callback_add(parent, "gadget_created", _bar_created_cb, inst);
+ evas_object_smart_callback_add(parent, "gadget_site_anchor", _bar_anchor_changed_cb, inst);
+ evas_object_smart_callback_add(parent, "gadget_removed", _bar_removed_cb, inst);
+ evas_object_show(inst->o_main);
+
+ E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_ICON_THEME,
+ _bar_cb_update_icons, NULL);
+ E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_ICON_CACHE_UPDATE,
+ _bar_cb_update_icons, NULL);
+ E_LIST_HANDLER_APPEND(handlers, E_EVENT_EXEC_NEW,
+ _bar_cb_exec_new, NULL);
+ E_LIST_HANDLER_APPEND(handlers, E_EVENT_EXEC_NEW_CLIENT,
+ _bar_cb_exec_new, NULL);
+ E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_PROPERTY,
+ _bar_cb_exec_client_prop, NULL);
+ E_LIST_HANDLER_APPEND(handlers, E_EVENT_EXEC_DEL,
+ _bar_cb_exec_del, NULL);
+ E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_REMOVE,
+ _bar_cb_client_remove, NULL);
+
+ if (inst->cfg->id < 0) return inst->o_main;
+ luncher_instances = eina_list_append(luncher_instances, inst);
+
+ current_preview = NULL;
+ current_preview_menu = EINA_FALSE;
+
+ return inst->o_main;
+}
+
diff --git a/src/modules/luncher/config.c b/src/modules/luncher/config.c
new file mode 100644
index 000000000..73404ba66
--- /dev/null
+++ b/src/modules/luncher/config.c
@@ -0,0 +1,377 @@
+#include "luncher.h"
+
+static void
+_config_close(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ luncher_config->list = NULL;
+ evas_object_del(luncher_config->config_dialog);
+ luncher_config->config_dialog = NULL;
+ e_config_save_queue();
+}
+
+static void
+_config_source_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Instance *inst = data;
+ const char *dir = elm_object_item_text_get(elm_list_selected_item_get(luncher_config->list));
+
+ if (!strcmp(inst->cfg->dir, dir))
+ return;
+ if (inst->cfg->dir) eina_stringshare_del(inst->cfg->dir);
+ inst->cfg->dir = NULL;
+ if (dir) inst->cfg->dir = eina_stringshare_ref(dir);
+ bar_reorder(inst);
+}
+
+static void
+_config_populate_order_list(Evas_Object *list, Instance *inst)
+{
+ Eina_List *dirs;
+ char buf[4096], *file;
+ size_t len;
+ Elm_Object_Item *it;
+
+ elm_list_clear(list);
+
+ len = e_user_dir_concat_static(buf, "applications/bar");
+ if (len + 2 >= sizeof(buf)) return;
+ dirs = ecore_file_ls(buf);
+
+ buf[len] = '/';
+ len++;
+
+ EINA_LIST_FREE(dirs, file)
+ {
+ if (file[0] == '.') continue;
+ if (eina_strlcpy(buf + len, file, sizeof(buf) - len) >= sizeof(buf) - len)
+ continue;
+ if (ecore_file_is_dir(buf))
+ {
+ it = elm_list_item_append(list, file, NULL, NULL, _config_source_changed, inst);
+ if ((inst->cfg->dir) && (!strcmp(inst->cfg->dir, file)))
+ elm_list_item_selected_set(it, EINA_TRUE);
+ }
+ free(file);
+ }
+ elm_list_go(list);
+}
+
+static void
+_config_source_cancel(void *data)
+{
+ Instance *inst = data;
+
+ config_luncher(e_zone_current_get(), inst, luncher_config->bar);
+}
+
+static void
+_config_source_added(void *data, char *text)
+{
+ Instance *inst = data;
+ char buf[4096];
+ char tmp[4096] = {0};
+ FILE *f;
+ size_t len;
+
+ len = e_user_dir_snprintf(buf, sizeof(buf), "applications/bar/%s", text);
+ if (len + sizeof("/.order") >= sizeof(buf)) return;
+ while (!ecore_file_exists(buf))
+ {
+ ecore_file_mkdir(buf);
+ memcpy(buf + len, "/.order", sizeof("/.order"));
+ e_user_dir_concat_static(tmp, "applications/bar/default/.order");
+ if (ecore_file_cp(tmp, buf)) break;
+ f = fopen(buf, "w");
+ if (!f) break;
+ /* Populate this .order file with some defaults */
+ snprintf(tmp, sizeof(tmp),
+ "terminology.desktop\n"
+ "sylpheed.desktop\n"
+ "firefox.desktop\n"
+ "openoffice.desktop\n"
+ "xchat.desktop\n"
+ "gimp.desktop\n");
+ fwrite(tmp, sizeof(char), strlen(tmp), f);
+ fclose(f);
+ break;
+ }
+ config_luncher(e_zone_current_get(), inst, luncher_config->bar);
+}
+
+static void
+_config_source_deleted(void *data)
+{
+ char buf[4096];
+ Instance *inst = data;
+
+ if (e_user_dir_snprintf(buf, sizeof(buf), "applications/bar/%s", inst->cfg->dir) >= sizeof(buf))
+ return;
+ if (ecore_file_is_dir(buf))
+ ecore_file_recursive_rm(buf);
+ e_object_del(E_OBJECT(inst->order));
+ config_luncher(e_zone_current_get(), inst, luncher_config->bar);
+}
+
+static void
+_config_source_add(void *data, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Instance *inst = data;
+
+ evas_object_del(luncher_config->config_dialog);
+ e_entry_dialog_show(_("Create new Luncher source"), "enlightenment",
+ _("Enter a name for this new source:"), "", NULL, NULL,
+ _config_source_added, _config_source_cancel, inst);
+}
+
+static void
+_config_source_del(void *data, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Instance *inst = data;
+ char buf[4096];
+
+ evas_object_del(luncher_config->config_dialog);
+ snprintf(buf, sizeof(buf), _("You requested to delete \"%s\".
"
+ "Are you sure you want to delete this bar source?"),
+ inst->cfg->dir);
+ e_confirm_dialog_show(_("Are you sure you want to delete this bar source?"),
+ "application-exit", buf, _("Delete"), _("Keep"),
+ _config_source_deleted, _config_source_cancel, inst, inst,
+ NULL, NULL);
+}
+
+static void
+_config_contents(void *data, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Instance *inst = data;
+ Evas_Object *popup = evas_object_data_get(obj, "popup");
+
+ if (e_configure_registry_exists("applications/ibar_applications"))
+ {
+ char path[PATH_MAX];
+ e_user_dir_snprintf(path, sizeof(path), "applications/bar/%s/.order",
+ inst->cfg->dir);
+ e_configure_registry_call("internal/ibar_other", NULL, path);
+ evas_object_del(popup);
+ }
+
+}
+
+static void
+_config_create_icon(void *data, Evas_Object *obj, void *event_data EINA_UNUSED)
+{
+ Instance *inst = data;
+ Evas_Object *popup = evas_object_data_get(obj, "popup");
+
+ if (e_configure_registry_exists("applications/new_application"))
+ {
+ char path[PATH_MAX];
+ e_user_dir_snprintf(path, sizeof(path), "applications/bar/%s/.order",
+ inst->cfg->dir);
+ e_configure_registry_call("applications/new_application", NULL, path);
+ evas_object_del(popup);
+ }
+}
+
+static void
+_icon_theme_file_set(Evas_Object *img, const char *icon)
+{
+ const char *path = NULL, *k = NULL;
+ int len = 0;
+
+ if (!icon)
+ path = NULL;
+ else if (strncmp(icon, "/", 1) && !ecore_file_exists(icon))
+ {
+ path = efreet_icon_path_find(e_config->icon_theme, icon, 48);
+ if (!path)
+ {
+ if (e_util_strcmp(e_config->icon_theme, "hicolor"))
+ path = efreet_icon_path_find("hicolor", icon, 48);
+ }
+ }
+ else if (ecore_file_exists(icon))
+ {
+ path = icon;
+ }
+ if (!path)
+ {
+ char buf[4096];
+ snprintf(buf, sizeof(buf), "e/icons/%s", 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";
+ }
+ }
+ if (path && icon)
+ {
+ len = strlen(icon);
+ if ((len > 4) && (!strcasecmp(icon + len - 4, ".edj")))
+ k = "icon";
+ }
+ elm_image_file_set(img, path, k);
+}
+
+EINTERN Evas_Object *
+config_luncher(E_Zone *zone, Instance *inst, Eina_Bool bar)
+{
+ Evas_Object *popup, *tb, *lbl, *fr, *box, *list;
+ Evas_Object *butbox, *sep, *hbox, *img, *but;
+
+ luncher_config->bar = bar;
+
+ popup = elm_popup_add(e_comp->elm);
+ E_EXPAND(popup);
+ elm_popup_allow_events_set(popup, 1);
+ elm_popup_scrollable_set(popup, 1);
+
+ tb = elm_table_add(popup);
+ E_EXPAND(tb);
+ evas_object_size_hint_align_set(tb, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(tb);
+ elm_object_content_set(popup, tb);
+
+ lbl = elm_label_add(tb);
+ evas_object_size_hint_weight_set(lbl, EVAS_HINT_EXPAND, 0.0);
+ evas_object_size_hint_align_set(lbl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_object_style_set(lbl, "marker");
+ evas_object_show(lbl);
+ elm_object_text_set(lbl, _("Luncher Configuration"));
+ elm_table_pack(tb, lbl, 0, 0, 1, 1);
+
+ box = elm_box_add(tb);
+ elm_box_horizontal_set(box, EINA_FALSE);
+ E_EXPAND(box);
+ evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_table_pack(tb, box, 0, 1, 1, 1);
+ evas_object_show(box);
+
+ fr = elm_frame_add(box);
+ elm_object_text_set(fr, _("Icon Order"));
+ E_EXPAND(fr);
+ evas_object_size_hint_align_set(fr, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_pack_end(box, fr);
+ evas_object_show(fr);
+
+ box = elm_box_add(fr);
+ elm_box_horizontal_set(box, EINA_FALSE);
+ E_EXPAND(box);
+ evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(box);
+
+ hbox = elm_box_add(box);
+ elm_box_horizontal_set(hbox, EINA_TRUE);
+ elm_box_homogeneous_set(hbox, EINA_FALSE);
+ evas_object_size_hint_expand_set(hbox, 0.0, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_pack_end(box, hbox);
+ evas_object_show(hbox);
+
+ list = elm_list_add(hbox);
+ E_ALIGN(list, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ E_WEIGHT(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ elm_box_pack_end(hbox, list);
+ elm_list_select_mode_set(list, ELM_OBJECT_SELECT_MODE_ALWAYS);
+ elm_scroller_content_min_limit(list, 1, 1);
+ evas_object_show(list);
+ luncher_config->list = list;
+ _config_populate_order_list(list, inst);
+
+ butbox = elm_box_add(hbox);
+ elm_box_horizontal_set(butbox, EINA_FALSE);
+ E_EXPAND(butbox);
+ evas_object_size_hint_align_set(butbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_pack_end(hbox, butbox);
+ evas_object_show(butbox);
+
+ sep = elm_separator_add(box);
+ elm_separator_horizontal_set(sep, EINA_TRUE);
+ elm_box_pack_end(box, sep);
+ evas_object_show(sep);
+
+ img = elm_icon_add(butbox);
+ evas_object_size_hint_aspect_set(img, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+ _icon_theme_file_set(img, "list-add");
+ evas_object_show(img);
+
+ but = elm_button_add(butbox);
+ elm_object_part_content_set(but, "icon", img);
+ elm_object_text_set(but, _("Add"));
+ E_EXPAND(but);
+ evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_data_set(but, "popup", popup);
+ evas_object_smart_callback_add(but, "clicked", _config_source_add, inst);
+ elm_box_pack_end(butbox, but);
+ evas_object_show(but);
+
+ img = elm_icon_add(butbox);
+ evas_object_size_hint_aspect_set(img, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+ _icon_theme_file_set(img, "list-remove");
+ evas_object_show(img);
+
+ but = elm_button_add(butbox);
+ elm_object_part_content_set(but, "icon", img);
+ elm_object_text_set(but, _("Delete"));
+ E_EXPAND(but);
+ evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_data_set(but, "popup", popup);
+ evas_object_smart_callback_add(but, "clicked", _config_source_del, inst);
+ elm_box_pack_end(butbox, but);
+ evas_object_show(but);
+
+ hbox = elm_box_add(box);
+ elm_box_horizontal_set(hbox, EINA_TRUE);
+ elm_box_homogeneous_set(hbox, EINA_TRUE);
+ E_EXPAND(box);
+ evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_pack_end(box, hbox);
+ evas_object_show(hbox);
+
+ img = elm_icon_add(hbox);
+ evas_object_size_hint_aspect_set(img, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+ _icon_theme_file_set(img, "document-new");
+ evas_object_show(img);
+
+ but = elm_button_add(hbox);
+ elm_object_part_content_set(but, "icon", img);
+ elm_object_text_set(but, _("Create New Icon"));
+ E_EXPAND(but);
+ evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_data_set(but, "popup", popup);
+ evas_object_smart_callback_add(but, "clicked", _config_create_icon, inst);
+ elm_box_pack_end(hbox, but);
+ evas_object_show(but);
+
+ img = elm_icon_add(hbox);
+ evas_object_size_hint_aspect_set(img, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+ _icon_theme_file_set(img, "list-add");
+ evas_object_show(img);
+
+ but = elm_button_add(hbox);
+ elm_object_part_content_set(but, "icon", img);
+ elm_object_text_set(but, _("Contents"));
+ E_EXPAND(but);
+ evas_object_size_hint_align_set(but, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_data_set(but, "popup", popup);
+ evas_object_smart_callback_add(but, "clicked", _config_contents, inst);
+ elm_box_pack_end(hbox, but);
+ evas_object_show(but);
+
+ elm_object_content_set(fr, box);
+
+ popup = e_comp_object_util_add(popup, E_COMP_OBJECT_TYPE_NONE);
+ evas_object_layer_set(popup, E_LAYER_POPUP);
+ evas_object_resize(popup, zone->w / 4, zone->h / 3);
+ e_comp_object_util_center(popup);
+ evas_object_show(popup);
+ e_comp_object_util_autoclose(popup, NULL, e_comp_object_util_autoclose_on_escape, NULL);
+ evas_object_event_callback_add(popup, EVAS_CALLBACK_DEL, _config_close, NULL);
+
+ return luncher_config->config_dialog = popup;
+}
+
diff --git a/src/modules/luncher/e-module-luncher.edj b/src/modules/luncher/e-module-luncher.edj
new file mode 100644
index 000000000..f2dd5d4bb
Binary files /dev/null and b/src/modules/luncher/e-module-luncher.edj differ
diff --git a/src/modules/luncher/luncher.h b/src/modules/luncher/luncher.h
new file mode 100644
index 000000000..7ab9c1dc3
--- /dev/null
+++ b/src/modules/luncher/luncher.h
@@ -0,0 +1,87 @@
+#ifndef LUNCHER_H
+#define LUNCHER_H
+
+#include "e.h"
+
+E_API extern E_Module_Api e_modapi;
+
+E_API void *e_modapi_init (E_Module *m);
+E_API int e_modapi_shutdown (E_Module *m);
+E_API int e_modapi_save (E_Module *m);
+
+typedef struct _Config Config;
+typedef struct _Config_Item Config_Item;
+typedef struct _Instance Instance;
+typedef struct _Icon Icon;
+
+struct _Config
+{
+ Eina_List *items;
+
+ E_Module *module;
+ Evas_Object *config_dialog;
+ Evas_Object *list;
+ Eina_Bool bar;
+};
+
+struct _Config_Item
+{
+ int id;
+ Eina_Stringshare *dir;
+};
+
+struct _Instance
+{
+ Evas_Object *o_main;
+ Evas_Object *o_icon_con;
+ E_Order *order;
+ Config_Item *cfg;
+ Eina_List *icons;
+ Eina_Hash *icons_desktop_hash;
+ Eina_Hash *icons_clients_hash;
+ Evas_Coord size;
+ Ecore_Job *resize_job;
+ E_Comp_Object_Mover *iconify_provider;
+ Evas_Object *drop_handler;
+ Evas_Object *place_holder;
+ Icon *drop_before;
+};
+
+struct _Icon
+{
+ Instance *inst;
+ Evas_Object *o_layout;
+ Evas_Object *o_icon;
+ Evas_Object *o_overlay;
+ Evas_Object *preview;
+ Evas_Object *preview_box;
+ E_Exec_Instance *exec;
+ Efreet_Desktop *desktop;
+ Eina_List *execs;
+ Eina_List *clients;
+ Ecore_Timer *mouse_in_timer;
+ Ecore_Timer *mouse_out_timer;
+ Ecore_Timer *drag_timer;
+ Eina_Stringshare *icon;
+ Eina_Stringshare *key;
+ Eina_Bool in_order;
+ Eina_Bool active;
+ Eina_Bool starting;
+ struct
+ {
+ unsigned char start : 1;
+ unsigned char dnd : 1;
+ int x, y;
+ } drag;
+};
+
+EINTERN Evas_Object *config_luncher(E_Zone *zone, Instance *inst, Eina_Bool bar);
+EINTERN Evas_Object *bar_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient);
+EINTERN void bar_reorder(Instance *inst);
+EINTERN void bar_recalculate(Instance *inst);
+
+extern Config *luncher_config;
+extern Eina_List *luncher_instances;
+extern E_Module *module;
+
+#endif
diff --git a/src/modules/luncher/mod.c b/src/modules/luncher/mod.c
new file mode 100644
index 000000000..91109f92e
--- /dev/null
+++ b/src/modules/luncher/mod.c
@@ -0,0 +1,87 @@
+#include "luncher.h"
+static E_Config_DD *conf_edd = NULL;
+static E_Config_DD *conf_item_edd = NULL;
+Eina_List *luncher_instances = NULL;
+E_Module *module = NULL;
+Config *luncher_config = NULL;
+
+EINTERN void
+luncher_init(void)
+{
+ conf_item_edd = E_CONFIG_DD_NEW("Luncher_Config_Item", Config_Item);
+#undef T
+#undef D
+#define T Config_Item
+#define D conf_item_edd
+ E_CONFIG_VAL(D, T, id, INT);
+ E_CONFIG_VAL(D, T, dir, STR);
+
+ conf_edd = E_CONFIG_DD_NEW("Luncher_Config", Config);
+#undef T
+#undef D
+#define T Config
+#define D conf_edd
+ E_CONFIG_LIST(D, T, items, conf_item_edd);
+
+ luncher_config = e_config_domain_load("module.luncher", conf_edd);
+
+ if (!luncher_config)
+ {
+ Config_Item *ci;
+
+ luncher_config = E_NEW(Config, 1);
+ ci = E_NEW(Config_Item, 1);
+ ci->id = 0;
+ ci->dir = eina_stringshare_add("default");
+ luncher_config->items = eina_list_append(luncher_config->items, ci);
+ }
+ e_gadget_type_add("Luncher Bar", bar_create, NULL);
+}
+
+EINTERN void
+luncher_shutdown(void)
+{
+ if (luncher_config)
+ {
+ Config_Item *ci;
+ EINA_LIST_FREE(luncher_config->items, ci)
+ {
+ eina_stringshare_del(ci->dir);
+ free(ci);
+ }
+ E_FREE(luncher_config);
+ }
+ E_CONFIG_DD_FREE(conf_edd);
+ E_CONFIG_DD_FREE(conf_item_edd);
+
+ e_gadget_type_del("Luncher Bar");
+}
+
+E_API E_Module_Api e_modapi =
+{
+ E_MODULE_API_VERSION,
+ "Luncher"
+};
+
+E_API void *
+e_modapi_init(E_Module *m)
+{
+ luncher_init();
+
+ module = m;
+ return m;
+}
+
+E_API int
+e_modapi_shutdown(E_Module *m EINA_UNUSED)
+{
+ luncher_shutdown();
+ return 1;
+}
+
+E_API int
+e_modapi_save(E_Module *m EINA_UNUSED)
+{
+ e_config_domain_save("module.luncher", conf_edd, luncher_config);
+ return 1;
+}
diff --git a/src/modules/luncher/module.desktop.in b/src/modules/luncher/module.desktop.in
new file mode 100644
index 000000000..75c268c50
--- /dev/null
+++ b/src/modules/luncher/module.desktop.in
@@ -0,0 +1,37 @@
+[Desktop Entry]
+Encoding=UTF-8
+Type=Link
+Name=Luncher
+Name[ca]=Luncher
+Name[cs]=Lišta spouštěčů
+Name[de]=Luncher
+Name[eo]=Breto Luncher
+Name[fi]=Luncher
+Name[fr]=Luncher
+Name[gl]=Luncher
+Name[ja]=Luncher
+Name[ms]=Luncher
+Name[pl]=Luncher
+Name[ru]=Luncher
+Name[sr]=И-трака
+Name[tr]=Luncher
+Comment=Iconic application launcher.
+Comment[ca]=Barra d'icones per a executar aplicacions.
+Comment[cs]=Lišta se spouštěči.
+Comment[de]=Symbolbasierter Anwendungsstarter.
+Comment[el]=Εικονικός εκκινητής εφαρμογών.
+Comment[eo]=Lanĉilo de piktograma aplikaĵo.
+Comment[es]=Lanzador de aplicaciones con íconos.
+Comment[fi]=Ikoninen sovelluskäynnistin.
+Comment[fr]=Barre d'icones permettant de lancer des applications.
+Comment[gl]=Unha barra de iconas para iniciar aplicativos.
+Comment[hu]=Ikonokkal bővíthető alkalmazásindító modul.
+Comment[it]=Una barra di icone per il lancio di applicazioni.
+Comment[ja]=Iconic アプリケーションランチャー
+Comment[ms]=Pelancar aplikasi ikonik
+Comment[pt]=Barra para iniciar aplicações
+Comment[ru]=Панель для запуска приложений, представленных в виде значков.
+Comment[sr]=Трака иконица покретача програма.
+Comment[tr]=Uygulama başlatıcı.
+Icon=e-module-ibar
+X-Enlightenment-ModuleType=utils