diff --git a/configure.ac b/configure.ac
index 9d4fa7e52..0489347e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -860,6 +860,7 @@ AC_E_OPTIONAL_MODULE([everything], true)
AC_E_OPTIONAL_MODULE([systray], true)
AC_E_OPTIONAL_MODULE([comp], true)
AC_E_OPTIONAL_MODULE([physics], true, [CHECK_MODULE_PHYSICS])
+AC_E_OPTIONAL_MODULE([quickaccess], true)
AC_E_OPTIONAL_MODULE([shot], true)
AC_E_OPTIONAL_MODULE([backlight], true)
AC_E_OPTIONAL_MODULE([tasks], true)
@@ -1029,6 +1030,8 @@ src/modules/comp/Makefile
src/modules/comp/module.desktop
src/modules/physics/Makefile
src/modules/physics/module.desktop
+src/modules/quickaccess/Makefile
+src/modules/quickaccess/module.desktop
src/modules/shot/Makefile
src/modules/shot/module.desktop
src/modules/backlight/Makefile
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index e65791342..6215dd443 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -179,6 +179,10 @@ if USE_MODULE_PHYSICS
SUBDIRS += physics
endif
+if USE_MODULE_QUICKACCESS
+SUBDIRS += quickaccess
+endif
+
if USE_MODULE_OFONO
SUBDIRS += ofono
endif
diff --git a/src/modules/quickaccess/Makefile.am b/src/modules/quickaccess/Makefile.am
new file mode 100644
index 000000000..3e5bde20e
--- /dev/null
+++ b/src/modules/quickaccess/Makefile.am
@@ -0,0 +1,34 @@
+MAINTAINERCLEANFILES = Makefile.in
+MODULE = quickaccess
+
+# data files for the module
+filesdir = $(libdir)/enlightenment/modules/$(MODULE)
+files_DATA = e-module-$(MODULE).edj module.desktop
+
+EXTRA_DIST = $(files_DATA)
+
+# the module .so file
+INCLUDES = -I. \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/modules/$(MODULE) \
+ -I$(top_srcdir)/src/bin \
+ -I$(top_builddir)/src/bin \
+ -I$(top_srcdir)/src/modules \
+ @e_cflags@
+
+pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = e_mod_main.h \
+ e_mod_main.c \
+ e_mod_quickaccess.c \
+ e_quickaccess_bindings.c \
+ e_quickaccess_db.c \
+ e_mod_config.c
+
+module_la_LIBADD = @e_libs@ @dlopen_libs@
+module_la_LDFLAGS = -module -avoid-version
+module_la_DEPENDENCIES = $(top_builddir)/config.h
+
+uninstall:
+ rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE)
diff --git a/src/modules/quickaccess/e-module-quickaccess.edj b/src/modules/quickaccess/e-module-quickaccess.edj
new file mode 100644
index 000000000..300a961d1
Binary files /dev/null and b/src/modules/quickaccess/e-module-quickaccess.edj differ
diff --git a/src/modules/quickaccess/e_mod_config.c b/src/modules/quickaccess/e_mod_config.c
new file mode 100644
index 000000000..10f426a01
--- /dev/null
+++ b/src/modules/quickaccess/e_mod_config.c
@@ -0,0 +1,555 @@
+#include "e_mod_main.h"
+
+typedef struct Config_Entry
+{
+ EINA_INLIST;
+ const char *id;
+ E_Quick_Access_Entry *entry;
+} Config_Entry;
+
+struct _E_Config_Dialog_Data
+{
+ const char *entry;
+ Evas_Object *o_list_entry;
+ Evas_Object *o_list_transient;
+ E_Entry_Dialog *ed;
+
+ Eina_Inlist *entries;
+ Eina_Inlist *transient_entries;
+
+ int autohide;
+ int hide_when_behind;
+ int skip_taskbar;
+ int skip_pager;
+ int dont_bug_me;
+};
+
+/**
+ * in priority order:
+ *
+ * @todo configure match name (to be used by actions)
+ *
+ * @todo configure match icccm match class and name.
+ *
+ * @todo configure show/hide effects:
+ * - fullscreen
+ * - centered
+ * - slide from top, bottom, left or right
+ *
+ * @todo match more than one, doing tabs (my idea is to do another
+ * tabbing module first, experiment with that, maybe use/reuse
+ * it here)
+ */
+
+static Config_Entry *
+_config_entry_new(E_Quick_Access_Entry *entry)
+{
+ Config_Entry *ce;
+
+ ce = E_NEW(Config_Entry, 1);
+ ce->entry = entry;
+ entry->cfg_entry = ce;
+ return ce;
+}
+
+static void
+_config_entry_free(Config_Entry *ce)
+{
+ if (!ce) return;
+ ce->entry->cfg_entry = NULL;
+ eina_stringshare_del(ce->id);
+ if (ce->entry->transient)
+ qa_mod->cfd->cfdata->transient_entries = eina_inlist_remove(qa_mod->cfd->cfdata->transient_entries, EINA_INLIST_GET(ce));
+ else
+ qa_mod->cfd->cfdata->entries = eina_inlist_remove(qa_mod->cfd->cfdata->entries, EINA_INLIST_GET(ce));
+ free(ce);
+}
+
+static void
+_fill_data(E_Config_Dialog_Data *cfdata)
+{
+ Eina_List *l;
+ E_Quick_Access_Entry *entry;
+
+ cfdata->autohide = qa_config->autohide;
+ cfdata->hide_when_behind = qa_config->hide_when_behind;
+ cfdata->skip_taskbar = qa_config->skip_taskbar;
+ cfdata->skip_pager = qa_config->skip_pager;
+
+ EINA_LIST_FOREACH(qa_config->entries, l, entry)
+ cfdata->entries = eina_inlist_append(cfdata->entries, EINA_INLIST_GET(_config_entry_new(entry)));
+
+ EINA_LIST_FOREACH(qa_config->transient_entries, l, entry)
+ cfdata->transient_entries = eina_inlist_append(cfdata->transient_entries, EINA_INLIST_GET(_config_entry_new(entry)));
+}
+
+static void *
+_create_data(E_Config_Dialog *cfd)
+{
+ E_Config_Dialog_Data *cfdata;
+
+ cfdata = E_NEW(E_Config_Dialog_Data, 1);
+ _fill_data(cfdata);
+ qa_mod->cfd = cfd;
+ return cfdata;
+}
+
+static void
+_free_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
+{
+ Eina_Inlist *l;
+ Config_Entry *ce;
+ EINA_INLIST_FOREACH_SAFE(cfdata->entries, l, ce)
+ _config_entry_free(ce);
+ EINA_INLIST_FOREACH_SAFE(cfdata->transient_entries, l, ce)
+ _config_entry_free(ce);
+ free(cfdata);
+ qa_mod->cfd = NULL;
+}
+
+static int
+_advanced_check_changed(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
+{
+ Config_Entry *ce;
+#define CHECK(X) \
+ if (cfdata->X != qa_config->X) return 1
+
+ CHECK(dont_bug_me);
+
+ EINA_INLIST_FOREACH(cfdata->entries, ce)
+ if (ce->id) return 1;
+ EINA_INLIST_FOREACH(cfdata->transient_entries, ce)
+ if (ce->id) return 1;
+
+#undef CHECK
+ return 0;
+}
+
+static int
+_basic_check_changed(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
+{
+#define CHECK(X) \
+ if (cfdata->X != qa_config->X) return 1
+
+ CHECK(autohide);
+ CHECK(skip_pager);
+ CHECK(skip_taskbar);
+ CHECK(hide_when_behind);
+
+#undef CHECK
+ return 0;
+}
+
+static void
+_list_select(void *data)
+{
+ Config_Entry *ce = data;
+}
+
+static void
+_list_fill(E_Config_Dialog_Data *cfdata, Evas_Object *list, Eina_Bool transient)
+{
+ Config_Entry *ce;
+ EINA_INLIST_FOREACH(transient ? cfdata->transient_entries : cfdata->entries, ce)
+ {
+ e_widget_ilist_append(list, NULL, ce->id ?: ce->entry->id, _list_select, ce, ce->entry->id);
+ }
+ e_widget_ilist_selected_set(list, 0);
+}
+
+static void
+_rename_del(void *data)
+{
+ E_Config_Dialog_Data *cfdata = e_object_data_get(data);
+ if (!cfdata) return;
+ cfdata->ed = NULL;
+}
+
+static void
+_rename_ok(char *text, void *data)
+{
+ Config_Entry *ce = data;
+ const char *name;
+ Evas_Object *list;
+
+ name = eina_stringshare_add(text);
+ if (name == ce->id)
+ {
+ eina_stringshare_del(name);
+ return;
+ }
+ if (name == ce->entry->id)
+ {
+ eina_stringshare_del(name);
+ if (!ce->id) return;
+ eina_stringshare_replace(&ce->id, NULL);
+ }
+ else
+ eina_stringshare_replace(&ce->id, text);
+ list = ce->entry->transient ? qa_mod->cfd->cfdata->o_list_transient : qa_mod->cfd->cfdata->o_list_entry;
+ e_widget_ilist_clear(list);
+ _list_fill(qa_mod->cfd->cfdata, list, ce->entry->transient);
+}
+
+static void
+_list_delete(void *data __UNUSED__, void *list)
+{
+ Config_Entry *ce;
+
+ ce = e_widget_ilist_selected_data_get(list);
+ if (!ce) return;
+ e_qa_entry_free(ce->entry);
+}
+
+static void
+_list_rename(void *data, void *list)
+{
+ E_Config_Dialog_Data *cfdata = data;
+ Config_Entry *ce;
+
+ if (cfdata->ed)
+ {
+ e_win_raise(cfdata->ed->dia->win);
+ return;
+ }
+
+ ce = e_widget_ilist_selected_data_get(list);
+ if (!ce) return;
+ cfdata->ed = e_entry_dialog_show(_("Rename"), "edit-rename", _("Enter a unique name for this entry"),
+ ce->id ?: ce->entry->id, NULL, NULL,
+ _rename_ok, NULL, ce);
+ e_object_data_set(E_OBJECT(cfdata->ed), cfdata);
+ e_object_del_attach_func_set(E_OBJECT(cfdata->ed), _rename_del);
+}
+
+static Evas_Object *
+_advanced_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata)
+{
+ Evas_Object *ob, *ol, *otb, *tab;
+ int w, h;
+
+ tab = e_widget_table_add(evas, 0);
+ evas_object_name_set(tab, "dia_table");
+
+ otb = e_widget_toolbook_add(evas, 48 * e_scale, 48 * e_scale);
+
+/////////////////////////////////////////////////////////////////
+ ol = e_widget_list_add(evas, 0, 0);
+ ob = e_widget_check_add(evas, _("Disable Warning Dialogs"), (int*)&(cfdata->dont_bug_me));
+ e_widget_list_object_append(ol, ob, 1, 0, 0.5);
+
+ e_widget_toolbook_page_append(otb, NULL, _("Behavior"), ol, 1, 1, 1, 1, 0.5, 0.5);
+
+/////////////////////////////////////////////////////////////////
+ ol = e_widget_table_add(evas, 0);
+ e_widget_table_freeze(ol);
+
+ cfdata->o_list_entry = ob = e_widget_ilist_add(evas, 0, 0, &cfdata->entry);
+ evas_event_freeze(evas_object_evas_get(ob));
+ edje_freeze();
+ e_widget_ilist_freeze(ob);
+
+ _list_fill(cfdata, ob, EINA_FALSE);
+
+ e_widget_size_min_get(ob, &w, &h);
+ e_widget_size_min_set(ob, MIN(w, 200), MIN(h, 100));
+ e_widget_ilist_go(ob);
+ e_widget_ilist_thaw(ob);
+ edje_thaw();
+ evas_event_thaw(evas_object_evas_get(ol));
+
+ e_widget_table_object_append(ol, ob, 0, 0, 2, 1, 1, 1, 1, 1);
+
+ ob = e_widget_button_add(evas, _("Rename"), "edit-rename", _list_rename, cfdata, cfdata->o_list_entry);
+ e_widget_table_object_append(ol, ob, 0, 1, 1, 1, 1, 1, 0, 0);
+
+ ob = e_widget_button_add(evas, _("Delete"), "edit-delete", _list_delete, cfdata, cfdata->o_list_entry);
+ e_widget_table_object_append(ol, ob, 1, 1, 1, 1, 1, 1, 0, 0);
+
+
+ e_widget_table_thaw(ol);
+
+ e_widget_toolbook_page_append(otb, NULL, _("Entries"), ol, 1, 1, 1, 1, 0.5, 0.5);
+/////////////////////////////////////////////////////////////////
+ ol = e_widget_table_add(evas, 0);
+ e_widget_table_freeze(ol);
+
+ cfdata->o_list_transient = ob = e_widget_ilist_add(evas, 0, 0, &cfdata->entry);
+ evas_event_freeze(evas_object_evas_get(ob));
+ edje_freeze();
+ e_widget_ilist_freeze(ob);
+
+ _list_fill(cfdata, ob, EINA_TRUE);
+
+ e_widget_size_min_get(ob, &w, &h);
+ e_widget_size_min_set(ob, MIN(w, 200), MIN(h, 100));
+ e_widget_ilist_go(ob);
+ e_widget_ilist_thaw(ob);
+ edje_thaw();
+ evas_event_thaw(evas_object_evas_get(ol));
+
+ e_widget_table_object_append(ol, ob, 0, 0, 2, 1, 1, 1, 1, 1);
+
+ ob = e_widget_button_add(evas, _("Rename"), "edit-rename", _list_rename, cfdata, cfdata->o_list_transient);
+ e_widget_table_object_append(ol, ob, 0, 1, 1, 1, 1, 1, 0, 0);
+
+ ob = e_widget_button_add(evas, _("Delete"), "edit-delete", _list_delete, cfdata, cfdata->o_list_transient);
+ e_widget_table_object_append(ol, ob, 1, 1, 1, 1, 1, 1, 0, 0);
+
+ e_widget_table_thaw(ol);
+
+ e_widget_toolbook_page_append(otb, NULL, _("Transients"), ol, 1, 1, 1, 1, 0.5, 0.5);
+/////////////////////////////////////////////////////////////////
+ e_widget_toolbook_page_show(otb, 0);
+
+ e_dialog_resizable_set(cfd->dia, 1);
+
+ e_widget_table_object_append(tab, otb, 0, 0, 1, 1, 1, 1, 1, 1);
+ return tab;
+}
+
+static Evas_Object *
+_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata)
+{
+ Evas_Object *ob, *ol, *otb, *tab;
+
+ cfdata->o_list_entry = cfdata->o_list_transient = NULL;
+
+ tab = e_widget_table_add(evas, 0);
+ evas_object_name_set(tab, "dia_table");
+
+ otb = e_widget_toolbook_add(evas, 48 * e_scale, 48 * e_scale);
+
+ ol = e_widget_list_add(evas, 0, 0);
+
+ ob = e_widget_check_add(evas, _("Hide Instead Of Raising"), &cfdata->hide_when_behind);
+ e_widget_list_object_append(ol, ob, 1, 0, 0.5);
+
+ ob = e_widget_check_add(evas, _("Hide If Focus Lost"), &cfdata->autohide);
+ e_widget_list_object_append(ol, ob, 1, 0, 0.5);
+
+ ob = e_widget_check_add(evas, _("Skip Taskbar"), &cfdata->skip_taskbar);
+ e_widget_list_object_append(ol, ob, 1, 0, 0.5);
+
+ ob = e_widget_check_add(evas, _("Skip Pager"), &cfdata->skip_pager);
+ e_widget_list_object_append(ol, ob, 1, 0, 0.5);
+
+ e_widget_toolbook_page_append(otb, NULL, _("Behavior"), ol, 1, 1, 1, 1, 0.5, 0.5);
+
+ e_widget_toolbook_page_show(otb, 0);
+
+ e_dialog_resizable_set(cfd->dia, 1);
+
+ e_widget_table_object_append(tab, otb, 0, 0, 1, 1, 1, 1, 1, 1);
+ return tab;
+}
+
+
+static int
+_advanced_apply_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
+{
+ Config_Entry *ce;
+ Eina_Bool entry_changed = EINA_FALSE, transient_changed = EINA_FALSE;
+#define SET(X) qa_config->X = cfdata->X
+
+ SET(dont_bug_me);
+
+ EINA_INLIST_FOREACH(cfdata->entries, ce)
+ {
+ if (!ce->id) continue;
+ if (!e_qa_entry_rename(ce->entry, ce->id))
+ entry_changed = EINA_TRUE;
+ eina_stringshare_replace(&ce->id, NULL);
+ }
+ EINA_INLIST_FOREACH(cfdata->transient_entries, ce)
+ {
+ if (!ce->id) continue;
+ if (!e_qa_entry_rename(ce->entry, ce->id))
+ transient_changed = EINA_TRUE;
+ eina_stringshare_replace(&ce->id, NULL);
+ }
+ if (entry_changed)
+ {
+ e_widget_ilist_clear(cfdata->o_list_entry);
+ _list_fill(qa_mod->cfd->cfdata, cfdata->o_list_entry, EINA_FALSE);
+ }
+ if (transient_changed)
+ {
+ e_widget_ilist_clear(cfdata->o_list_transient);
+ _list_fill(qa_mod->cfd->cfdata, cfdata->o_list_transient, EINA_TRUE);
+ }
+ e_config_save_queue();
+ return 1;
+}
+
+static int
+_basic_apply_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
+{
+#define SET(X) qa_config->X = cfdata->X
+ SET(autohide);
+ SET(hide_when_behind);
+ SET(skip_taskbar);
+ SET(skip_pager);
+ e_qa_entries_update();
+ e_config_save_queue();
+ return 1;
+}
+
+static void
+_list_item_add(E_Quick_Access_Entry *entry)
+{
+ Evas_Object *list;
+ Config_Entry *ce = entry->cfg_entry;
+
+ list = ce->entry->transient ? qa_mod->cfd->cfdata->o_list_transient : qa_mod->cfd->cfdata->o_list_entry;
+ if (!list) return;
+ e_widget_ilist_append(list, NULL, ce->id ?: ce->entry->id, _list_select, ce, ce->entry->id);
+ if (e_widget_ilist_selected_get(list) == -1) e_widget_ilist_selected_set(list, 0);
+}
+
+static void
+_list_item_delete(E_Quick_Access_Entry *entry)
+{
+ Eina_List *l, *ll;
+ E_Ilist_Item *ili;
+ Evas_Object *list;
+ unsigned int x = 0;
+
+ list = entry->transient ? qa_mod->cfd->cfdata->o_list_transient : qa_mod->cfd->cfdata->o_list_entry;
+ if (!list) return;
+ l = e_widget_ilist_items_get(list);
+ EINA_LIST_FOREACH(l, ll, ili)
+ {
+ if (e_widget_ilist_item_data_get(ili) == entry->cfg_entry)
+ {
+ e_widget_ilist_remove_num(list, x);
+ break;
+ }
+ x++;
+ }
+ if (e_widget_ilist_selected_get(list) == -1) e_widget_ilist_selected_set(list, 0);
+}
+//////////////////////////////////////////////////////////////////////////////
+E_Config_DD *
+e_qa_config_dd_new(void)
+{
+ E_Config_DD *conf_edd, *entry_edd;
+
+ conf_edd = E_CONFIG_DD_NEW("Quickaccess_Config", Config);
+ entry_edd = E_CONFIG_DD_NEW("E_Quick_Access_Entry", E_Quick_Access_Entry);
+
+#undef T
+#undef D
+#define T E_Quick_Access_Entry
+#define D entry_edd
+ E_CONFIG_VAL(D, T, id, STR);
+ E_CONFIG_VAL(D, T, name, STR);
+ E_CONFIG_VAL(D, T, class, STR);
+ E_CONFIG_VAL(D, T, cmd, STR);
+ E_CONFIG_VAL(D, T, win, UINT);
+ E_CONFIG_VAL(D, T, config.autohide, UCHAR);
+ E_CONFIG_VAL(D, T, config.relaunch, UCHAR);
+ E_CONFIG_VAL(D, T, config.hidden, UCHAR);
+ E_CONFIG_VAL(D, T, transient, UCHAR);
+#undef T
+#undef D
+#define T Config
+#define D conf_edd
+ E_CONFIG_VAL(D, T, config_version, UINT);
+ E_CONFIG_LIST(D, T, entries, entry_edd);
+ E_CONFIG_LIST(D, T, transient_entries, entry_edd);
+ E_CONFIG_VAL(D, T, autohide, UCHAR);
+ E_CONFIG_VAL(D, T, hide_when_behind, UCHAR);
+ E_CONFIG_VAL(D, T, skip_taskbar, UCHAR);
+ E_CONFIG_VAL(D, T, skip_pager, UCHAR);
+ E_CONFIG_VAL(D, T, dont_bug_me, UCHAR);
+ return conf_edd;
+}
+
+void *
+e_qa_config_dd_free(E_Config_DD *conf_dd)
+{
+ free(conf_dd);
+ return NULL;
+}
+
+void
+e_qa_config_free(Config *conf)
+{
+ if (!conf) return;
+ E_FREE_LIST(conf->entries, e_qa_entry_free);
+ E_FREE_LIST(conf->transient_entries, e_qa_entry_free);
+ free(conf);
+}
+
+Config *
+e_qa_config_new(void)
+{
+ Config *conf;
+
+ conf = E_NEW(Config, 1);
+ conf->skip_taskbar = 1;
+ conf->skip_pager = 1;
+ return conf;
+}
+
+void
+e_qa_config_entry_transient_convert(E_Quick_Access_Entry *entry)
+{
+ if (!entry) return;
+ if (!entry->cfg_entry) return;
+ _list_item_delete(entry);
+ entry->transient = !entry->transient;
+ _list_item_add(entry);
+ entry->transient = !entry->transient;
+}
+
+void
+e_qa_config_entry_free(E_Quick_Access_Entry *entry)
+{
+ if (!entry) return;
+ if (!entry->cfg_entry) return;
+ _list_item_delete(entry);
+ _config_entry_free(entry->cfg_entry);
+ entry->cfg_entry = NULL;
+}
+
+void
+e_qa_config_entry_add(E_Quick_Access_Entry *entry)
+{
+ Config_Entry *ce;
+
+ if (!entry) return;
+ if (!qa_mod->cfd) return;
+ ce = _config_entry_new(entry);
+ if (entry->transient)
+ qa_mod->cfd->cfdata->transient_entries = eina_inlist_append(qa_mod->cfd->cfdata->transient_entries, EINA_INLIST_GET(ce));
+ else
+ qa_mod->cfd->cfdata->entries = eina_inlist_append(qa_mod->cfd->cfdata->entries, EINA_INLIST_GET(ce));
+ _list_item_add(entry);
+}
+
+E_Config_Dialog *
+e_int_config_qa_module(E_Container *con, const char *params __UNUSED__)
+{
+ E_Config_Dialog *cfd;
+ E_Config_Dialog_View *v;
+ char buf[PATH_MAX];
+
+ if (qa_mod->cfd) return NULL;
+ v = E_NEW(E_Config_Dialog_View, 1);
+
+ v->create_cfdata = _create_data;
+ v->free_cfdata = _free_data;
+ v->basic.apply_cfdata = _basic_apply_data;
+ v->basic.create_widgets = _basic_create_widgets;
+ v->basic.check_changed = _basic_check_changed;
+ v->advanced.apply_cfdata = _advanced_apply_data;
+ v->advanced.create_widgets = _advanced_create_widgets;
+ v->advanced.check_changed = _advanced_check_changed;
+
+ snprintf(buf, sizeof(buf), "%s/e-module-quickaccess.edj", e_module_dir_get(qa_mod->module));
+ cfd = e_config_dialog_new(con, _("Quickaccess Settings"),
+ "E", "launcher/quickaccess", buf, 32, v, NULL);
+ return cfd;
+}
diff --git a/src/modules/quickaccess/e_mod_main.c b/src/modules/quickaccess/e_mod_main.c
new file mode 100644
index 000000000..6cdcd8a2e
--- /dev/null
+++ b/src/modules/quickaccess/e_mod_main.c
@@ -0,0 +1,119 @@
+#include "e_mod_main.h"
+
+EINTERN int _e_quick_access_log_dom = -1;
+static E_Config_DD *conf_edd = NULL;
+Mod *qa_mod = NULL;
+Config *qa_config = NULL;
+
+
+/**
+ * in priority order:
+ *
+ * @todo config (see e_mod_config.c)
+ *
+ * @todo custom border based on E_Quick_Access_Entry_Mode/E_Gadcon_Orient
+ *
+ * @todo show/hide effects:
+ * - fullscreen
+ * - centered
+ * - slide from top, bottom, left or right
+ *
+ * @todo match more than one, doing tabs (my idea is to do another
+ * tabbing module first, experiment with that, maybe use/reuse
+ * it here)
+ */
+
+EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Quickaccess"};
+
+static Eina_Bool
+_e_mod_cb_config_timer(void *data)
+{
+ e_util_dialog_show(_("Quickaccess Settings Updated"), "%s", (char *)data);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+//////////////////////////////
+EAPI void *
+e_modapi_init(E_Module *m)
+{
+ char buf[PATH_MAX];
+
+ snprintf(buf, sizeof(buf), "%s/e-module-quickaccess.edj", e_module_dir_get(m));
+ e_configure_registry_category_add("launcher", 80, _("Launcher"), NULL,
+ "preferences-extensions");
+ e_configure_registry_item_add("launcher/quickaccess", 1, _("Quickaccess"), NULL,
+ buf, e_int_config_qa_module);
+
+ qa_mod = E_NEW(Mod, 1);
+ qa_mod->module = m;
+ m->data = qa_mod;
+ conf_edd = e_qa_config_dd_new();
+ qa_config = e_config_domain_load("module.quickaccess", conf_edd);
+ if (qa_config)
+ {
+ if ((qa_config->config_version >> 16) < MOD_CONFIG_FILE_EPOCH)
+ {
+ e_qa_config_free(qa_config);
+ qa_config = NULL;
+ ecore_timer_add(1.0, _e_mod_cb_config_timer,
+ _("Quickaccess module settings data needed upgrading. Your old configuration
"
+ "has been wiped and a new set of defaults initialized. This
"
+ "will happen regularly during development, so don't report a
"
+ "bug. This means Quickaccess module needs new configuration
"
+ "data by default for usable functionality that your old
"
+ "configuration lacked. This new set of defaults will fix
"
+ "that by adding it in. You can re-configure things now to your
"
+ "liking. Sorry for the hiccup in your configuration.
"));
+ }
+ else if (qa_config->config_version > MOD_CONFIG_FILE_VERSION)
+ {
+ e_qa_config_free(qa_config);
+ qa_config = NULL;
+ ecore_timer_add(1.0, _e_mod_cb_config_timer,
+ _("Your Quickaccess module configuration is NEWER than Quickaccess module version. This is very
"
+ "strange. This should not happen unless you downgraded
"
+ "the Quickaccess Module or copied the configuration from a place where
"
+ "a newer version of the Quickaccess Module was running. This is bad and
"
+ "as a precaution your configuration has been now restored to
"
+ "defaults. Sorry for the inconvenience.
"));
+ }
+ }
+
+ if (!qa_config) qa_config = e_qa_config_new();
+ qa_config->config_version = MOD_CONFIG_FILE_VERSION;
+
+ _e_quick_access_log_dom = eina_log_domain_register("quickaccess", EINA_COLOR_ORANGE);
+ eina_log_domain_level_set("quickaccess", EINA_LOG_LEVEL_DBG);
+
+ if (!e_qa_init())
+ {
+ eina_log_domain_unregister(_e_quick_access_log_dom);
+ _e_quick_access_log_dom = -1;
+ return NULL;
+ }
+
+ return m;
+}
+
+EAPI int
+e_modapi_shutdown(E_Module *m __UNUSED__)
+{
+ e_qa_shutdown();
+
+ conf_edd = e_qa_config_dd_free(conf_edd);
+ eina_log_domain_unregister(_e_quick_access_log_dom);
+ _e_quick_access_log_dom = -1;
+ e_qa_config_free(qa_config);
+ free(qa_mod);
+ qa_config = NULL;
+ qa_mod = NULL;
+ return 1;
+}
+
+EAPI int
+e_modapi_save(E_Module *m __UNUSED__)
+{
+ e_config_domain_save("module.quickaccess", conf_edd, qa_config);
+ return 1;
+}
+
diff --git a/src/modules/quickaccess/e_mod_main.h b/src/modules/quickaccess/e_mod_main.h
new file mode 100644
index 000000000..dc17de655
--- /dev/null
+++ b/src/modules/quickaccess/e_mod_main.h
@@ -0,0 +1,93 @@
+#ifndef E_MOD_MAIN_H
+#define E_MOD_MAIN_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "e.h"
+
+/* Increment for Major Changes */
+#define MOD_CONFIG_FILE_EPOCH 0x0001
+/* Increment for Minor Changes (ie: user doesn't need a new config) */
+#define MOD_CONFIG_FILE_GENERATION 0x0001
+#define MOD_CONFIG_FILE_VERSION ((MOD_CONFIG_FILE_EPOCH << 16) | MOD_CONFIG_FILE_GENERATION)
+
+typedef struct E_Quick_Access_Entry
+{
+ const char *id; /* entry identifier (config, actions...), stringshared */
+ const char *name; /* icccm name, stringshared */
+ const char *class; /* icccm class, stringshared */
+ const char *cmd; /* stringshared */
+ Ecore_X_Window win; /* current window */
+ E_Border *border; /* associated border, if any */
+ Ecore_Event_Handler *exe_handler; /* for catching exe delete */
+ Ecore_Exe *exe; /* if executed cmd but still no border associated */
+ E_Dialog *dia; // used for option handling
+ void *cfg_entry; // created by config dialog
+
+ struct
+ {
+ Eina_Bool autohide; // hide when focus lost
+ Eina_Bool hide_when_behind; // hide when window is not focused instead of raising
+ Eina_Bool hidden; // FIXME: used for tracking current state to restore on restart
+ Eina_Bool relaunch; // reopen on exit
+ } config;
+ Eina_Bool transient;
+} E_Quick_Access_Entry;
+
+typedef struct Config
+{
+ unsigned int config_version;
+ Eina_List *entries;
+ Eina_List *transient_entries;
+
+ Eina_Bool autohide;
+ Eina_Bool hide_when_behind;
+ Eina_Bool skip_taskbar;
+ Eina_Bool skip_pager;
+ Eina_Bool dont_bug_me;
+} Config;
+
+typedef struct Mod
+{
+ E_Module *module;
+ E_Config_Dialog *cfd;
+} Mod;
+
+extern Config *qa_config;
+extern Mod *qa_mod;
+extern int _e_quick_access_log_dom;
+extern const char *_act_toggle;
+#undef DBG
+#undef INF
+#undef WRN
+#undef ERR
+#undef CRIT
+#define DBG(...) EINA_LOG_DOM_DBG(_e_quick_access_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_e_quick_access_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_e_quick_access_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_e_quick_access_log_dom, __VA_ARGS__)
+#define CRIT(...) EINA_LOG_DOM_CRIT(_e_quick_access_log_dom, __VA_ARGS__)
+
+Eina_Bool e_qa_init(void);
+void e_qa_shutdown(void);
+void e_qa_entry_free(E_Quick_Access_Entry *entry);
+E_Quick_Access_Entry *e_qa_entry_new(const char *id, Eina_Bool transient);
+void e_qa_entries_update(void);
+Eina_Bool e_qa_entry_rename(E_Quick_Access_Entry *entry, const char *name);
+
+E_Config_DD *e_qa_config_dd_new(void);
+void e_qa_config_free(Config *conf);
+Config *e_qa_config_new(void);
+void *e_qa_config_dd_free(E_Config_DD *conf_dd);
+void e_qa_config_entry_free(E_Quick_Access_Entry *entry);
+void e_qa_config_entry_add(E_Quick_Access_Entry *entry);
+void e_qa_config_entry_transient_convert(E_Quick_Access_Entry *entry);
+E_Config_Dialog *e_int_config_qa_module(E_Container *con, const char *params __UNUSED__);
+
+char *e_qa_db_class_lookup(const char *class);
+
+void e_qa_entry_bindings_cleanup(E_Quick_Access_Entry *entry);
+void e_qa_entry_bindings_rename(E_Quick_Access_Entry *entry, const char *name);
+#endif
diff --git a/src/modules/quickaccess/e_mod_quickaccess.c b/src/modules/quickaccess/e_mod_quickaccess.c
new file mode 100644
index 000000000..1dd85ac81
--- /dev/null
+++ b/src/modules/quickaccess/e_mod_quickaccess.c
@@ -0,0 +1,955 @@
+#include "e_mod_main.h"
+
+EINTERN int _e_qa_log_dom = -1;
+static E_Action *_e_qa_toggle = NULL;
+static E_Action *_e_qa_add = NULL;
+static E_Action *_e_qa_del = NULL;
+static const char _e_qa_name[] = "Quickaccess";
+static const char _lbl_toggle[] = "Toggle Visibility";
+static const char _lbl_add[] = "Add Quickaccess For Current Window";
+static const char _lbl_del[] = "Remove Quickaccess From Current Window";
+const char *_act_toggle = NULL;
+static const char _act_add[] = "qa_add";
+static const char _act_del[] = "qa_del";
+static E_Grab_Dialog *eg = NULL;
+static Eina_List *_e_qa_border_hooks = NULL;
+static Eina_List *_e_qa_event_handlers = NULL;
+
+static E_Border_Menu_Hook *border_hook = NULL;
+
+static Eina_Bool qa_running = EINA_FALSE;
+
+
+static void _e_qa_bd_menu_add(void *data, E_Menu *m, E_Menu_Item *mi);
+static void _e_qa_bd_menu_del(void *data, E_Menu *m, E_Menu_Item *mi);
+static void _e_qa_entry_transient_convert(E_Quick_Access_Entry *entry);
+
+/**
+ * in priority order:
+ *
+ * @todo config (see e_mod_config.c)
+ *
+ * @todo custom border based on E_Quick_Access_Entry_Mode/E_Gadcon_Orient
+ *
+ * @todo show/hide effects:
+ * - fullscreen
+ * - centered
+ * - slide from top, bottom, left or right
+ *
+ * @todo match more than one, doing tabs (my idea is to do another
+ * tabbing module first, experiment with that, maybe use/reuse
+ * it here)
+ */
+
+static void
+_e_qa_entry_dia_hide(void *data)
+{
+ E_Quick_Access_Entry *entry;
+ entry = e_object_data_get(data);
+ if (entry) entry->dia = NULL;
+}
+
+/* note: id must be stringshared! */
+static E_Quick_Access_Entry *
+_e_qa_entry_find(const char *id)
+{
+ E_Quick_Access_Entry *entry;
+ const Eina_List *n;
+ EINA_LIST_FOREACH(qa_config->transient_entries, n, entry)
+ if (entry->id == id)
+ return entry;
+ EINA_LIST_FOREACH(qa_config->entries, n, entry)
+ if (entry->id == id)
+ return entry;
+ return NULL;
+}
+
+static E_Quick_Access_Entry *
+_e_qa_entry_find_exe(const Ecore_Exe *exe)
+{
+ E_Quick_Access_Entry *entry;
+ const Eina_List *n;
+ EINA_LIST_FOREACH(qa_config->transient_entries, n, entry)
+ if (entry->exe == exe)
+ return entry;
+ EINA_LIST_FOREACH(qa_config->entries, n, entry)
+ if (entry->exe == exe)
+ return entry;
+ return NULL;
+}
+
+static E_Quick_Access_Entry *
+_e_qa_entry_find_border(const E_Border *bd)
+{
+ E_Quick_Access_Entry *entry;
+ const Eina_List *n;
+ EINA_LIST_FOREACH(qa_config->transient_entries, n, entry)
+ if ((entry->win == bd->client.win) || (entry->border == bd))
+ return entry;
+ EINA_LIST_FOREACH(qa_config->entries, n, entry)
+ if (entry->border == bd)
+ return entry;
+ return NULL;
+}
+
+static E_Quick_Access_Entry *
+_e_qa_entry_find_match_stringshared(const char *name, const char *class)
+{
+ E_Quick_Access_Entry *entry;
+ const Eina_List *n;
+ EINA_LIST_FOREACH(qa_config->transient_entries, n, entry)
+ {
+ if (entry->win) continue;
+ if (entry->class != class) continue;
+ /* no entry name matches all */
+ if ((entry->name) && (entry->name != name)) continue;
+
+ return entry;
+ }
+ EINA_LIST_FOREACH(qa_config->entries, n, entry)
+ {
+ if (entry->win) continue;
+ if (entry->class != class) continue;
+ /* no entry name matches all */
+ if ((entry->name) && (entry->name != name)) continue;
+
+ return entry;
+ }
+
+ return NULL;
+}
+
+static E_Quick_Access_Entry *
+_e_qa_entry_find_match(const E_Border *bd)
+{
+ const char *name, *class;
+ E_Quick_Access_Entry *entry;
+
+ name = bd->client.icccm.name;
+ class = bd->client.icccm.class;
+ entry = _e_qa_entry_find_match_stringshared(name, class);
+
+ return entry;
+}
+
+static Eina_Bool
+_e_qa_event_exe_del_cb(void *data, int type __UNUSED__, Ecore_Exe_Event_Del *ev)
+{
+ E_Quick_Access_Entry *entry;
+
+ if (!data) return ECORE_CALLBACK_RENEW;
+
+ entry = _e_qa_entry_find_exe(ev->exe);
+ if (!entry) return ECORE_CALLBACK_RENEW;
+ entry->exe = NULL; /* not waiting/running anymore */
+ if (entry->exe_handler) ecore_event_handler_del(entry->exe_handler);
+ entry->exe_handler = NULL;
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_e_qa_entry_border_props_restore(E_Quick_Access_Entry *entry __UNUSED__, E_Border *bd)
+{
+#undef SET
+#define SET(X) \
+ bd->X = 0
+
+ SET(lock_user_iconify);
+ SET(lock_client_iconify);
+ SET(lock_user_sticky);
+ SET(lock_client_sticky);
+ SET(user_skip_winlist);
+ SET(sticky);
+#undef SET
+
+ bd->client.netwm.state.skip_taskbar = 0;
+ bd->client.netwm.state.skip_pager = 0;
+ bd->changed = 1;
+}
+
+static void
+_e_qa_border_activate(E_Quick_Access_Entry *entry)
+{
+ entry->config.hidden = 0;
+ if (!entry->border) return;
+ e_border_raise(entry->border);
+ e_border_show(entry->border);
+ e_border_focus_set(entry->border, 1, 1);
+
+}
+
+static void
+_e_qa_border_deactivate(E_Quick_Access_Entry *entry)
+{
+ entry->config.hidden = 1;
+ if (!entry->border) return;
+ e_border_hide(entry->border, 1);
+}
+
+static void
+_e_qa_entry_border_props_apply(E_Quick_Access_Entry *entry)
+{
+ if (!entry->border) return;
+
+ if (entry->config.autohide && (!entry->border->focused))
+ _e_qa_border_deactivate(entry);
+ if (qa_config->skip_taskbar)
+ entry->border->client.netwm.state.skip_taskbar = 1;
+ if (qa_config->skip_pager)
+ entry->border->client.netwm.state.skip_pager = 1;
+}
+
+static void
+_e_qa_entry_border_associate(E_Quick_Access_Entry *entry, E_Border *bd)
+{
+ if (entry->exe) entry->exe = NULL; /* not waiting anymore */
+
+ if (!entry->border)
+ {
+ entry->border = bd;
+
+#define SET(X) \
+ bd->X = 1
+
+ SET(lock_user_iconify);
+ SET(lock_client_iconify);
+ SET(lock_user_sticky);
+ SET(lock_client_sticky);
+ SET(user_skip_winlist);
+ SET(sticky);
+#undef SET
+
+ //bd->client.e.state.centered = 1;
+ }
+ /* FIXME: doesn't work, causes window to flicker on associate
+ if (entry->config.hidden)
+ _e_qa_border_deactivate(entry);
+ else
+ */
+ _e_qa_entry_border_props_apply(entry);
+}
+
+static void
+_e_qa_entry_relaunch_setup_continue(void *data, E_Dialog *dia)
+{
+ E_Quick_Access_Entry *entry = data;
+ char buf[8192];
+ int i;
+
+ if (dia) e_object_del(E_OBJECT(dia));
+ entry->dia = NULL;
+ if (!entry->border->client.icccm.command.argv)
+ {
+ e_util_dialog_show(_("Quickaccess Error"), _("Could not determine command for starting this application!"));
+ /* FIXME: e_entry_dialog? */
+ return;
+ }
+ entry->config.relaunch = 1;
+ buf[0] = 0;
+ for (i = 0; i < entry->border->client.icccm.command.argc; i++)
+ {
+ if ((sizeof(buf) - strlen(buf)) <
+ (strlen(entry->border->client.icccm.command.argv[i]) - 2))
+ break;
+ strcat(buf, entry->border->client.icccm.command.argv[i]);
+ strcat(buf, " ");
+ }
+ entry->cmd = eina_stringshare_add(buf);
+ if (entry->transient)
+ _e_qa_entry_transient_convert(entry);
+}
+
+static void
+_e_qa_entry_relaunch_setup_cancel(void *data, E_Dialog *dia)
+{
+ E_Quick_Access_Entry *entry = data;
+
+ e_object_del(E_OBJECT(dia));
+ entry->config.relaunch = 0;
+}
+
+static void
+_e_qa_entry_relaunch_setup_help(void *data, E_Dialog *dia)
+{
+ E_Quick_Access_Entry *entry = data;
+ char buf[8192];
+
+ e_object_del(E_OBJECT(dia));
+ entry->dia = NULL;
+ entry->dia = dia = e_dialog_new(NULL, "E", "_quickaccess_cmd_help_dialog");
+
+ snprintf(buf, sizeof(buf), "%s
%s/e-module-quickaccess.edj
%s
"
+ "data.item: \"%s\" \"--OPT\";", _("The reopen option is meant to be used
"
+ "with terminal applications to create a persistent
"
+ "terminal which reopens when closed, generally seen
"
+ "in quake-style drop-down terminals.
"
+ "Either the selected application is not a terminal
"
+ "or the cmdline flag for changing the terminal's window
"
+ "name is not known. Feel free to submit a bug report if this
"
+ "is a terminal which can change its window name.
"
+ "Alternatively, you can add a data.item to"),
+ e_module_dir_get(qa_mod->module),
+ _("Like so:"), entry->class);
+
+ e_dialog_title_set(dia, _("Quickaccess Help"));
+ e_dialog_icon_set(dia, "enlightenment", 64);
+ e_dialog_text_set(dia, buf);
+ e_dialog_button_add(dia, _("Cancel"), NULL, _e_qa_entry_relaunch_setup_cancel, entry);
+ e_win_centered_set(dia->win, 1);
+ e_dialog_show(dia);
+ e_object_data_set(E_OBJECT(dia), entry);
+ e_object_del_attach_func_set(E_OBJECT(dia), _e_qa_entry_dia_hide);
+}
+
+static void
+_e_qa_entry_relaunch_setup(E_Quick_Access_Entry *entry)
+{
+ char *opt;
+ const char *name;
+ int i;
+ char buf[4096];
+ Eina_List *l;
+ E_Quick_Access_Entry *e;
+
+ if (entry->dia)
+ {
+ e_win_raise(entry->dia->win);
+ return;
+ }
+ if ((!entry->class) || (!entry->name))
+ {
+ e_util_dialog_show(_("Quickaccess Error"), _("Cannot set relaunch for window without name and class!"));
+ entry->config.relaunch = 0;
+ return;
+ }
+ if (!strcmp(entry->name, "E"))
+ {
+ /* can't set relaunch for internal E dialogs; safety #2 */
+ e_util_dialog_show(_("Quickaccess Error"), _("Cannot set relaunch for internal E dialog!"));
+ entry->config.relaunch = 0;
+ return;
+ }
+ opt = e_qa_db_class_lookup(entry->class);
+ if ((!opt) || (!opt[0]))
+ {
+ E_Dialog *dia;
+
+ free(opt);
+ if (qa_config->dont_bug_me)
+ {
+ _e_qa_entry_relaunch_setup_continue(entry, NULL);
+ return;
+ }
+ entry->dia = dia = e_dialog_new(NULL, "E", "_quickaccess_cmd_dialog");
+
+ snprintf(buf, sizeof(buf), "%s
%s
%s
%s
%s", _("The selected window created with name:"),
+ entry->name, _("and class:"), entry->class, _("could not be found in the quicklaunch app database
"
+ "or it is not intended for use with this option.
"
+ "Please choose an action to take:"));
+
+ e_dialog_title_set(dia, _("Quickaccess Error"));
+ e_dialog_icon_set(dia, "enlightenment", 64);
+ e_dialog_text_set(dia, buf);
+ e_dialog_button_add(dia, _("Continue"), NULL, _e_qa_entry_relaunch_setup_continue, entry);
+ e_dialog_button_add(dia, _("More Help"), NULL, _e_qa_entry_relaunch_setup_help, entry);
+ e_dialog_button_add(dia, _("Cancel"), NULL, _e_qa_entry_relaunch_setup_cancel, entry);
+ e_win_centered_set(dia->win, 1);
+ e_dialog_show(dia);
+ e_object_data_set(E_OBJECT(dia), entry);
+ e_object_del_attach_func_set(E_OBJECT(dia), _e_qa_entry_dia_hide);
+ entry->config.relaunch = 0;
+ return;
+ }
+ if (!entry->border->client.icccm.command.argv)
+ {
+ free(opt);
+ e_util_dialog_show(_("Quickaccess Error"), _("Could not determine command for starting this application!"));
+ /* FIXME: e_entry_dialog? */
+ return;
+ }
+
+ buf[0] = 0;
+ for (i = 0; i < entry->border->client.icccm.command.argc; i++)
+ {
+ if ((sizeof(buf) - strlen(buf)) <
+ (strlen(entry->border->client.icccm.command.argv[i]) - 2))
+ break;
+ strcat(buf, entry->border->client.icccm.command.argv[i]);
+ strcat(buf, " ");
+ }
+ name = entry->name;
+ entry->name = eina_stringshare_printf("e-%s-%u", entry->name, entry->border->client.netwm.pid);
+ while (i)
+ {
+ i = 0;
+ EINA_LIST_FOREACH(qa_config->entries, l, e)
+ {
+ if (e == entry) continue;
+ if (e->class != entry->class) continue;
+ if ((e->name == entry->name) || (e->id == entry->name))
+ {
+ eina_stringshare_del(entry->name);
+ entry->name = eina_stringshare_printf("e-%s-%u%d", entry->name, entry->border->client.netwm.pid, i);
+ i++;
+ break;
+ }
+ }
+ }
+ eina_stringshare_del(name);
+ entry->cmd = eina_stringshare_printf("%s %s \"%s\"", buf, opt, entry->name);
+ entry->config.relaunch = 1;
+ if (entry->transient)
+ _e_qa_entry_transient_convert(entry);
+ free(opt);
+}
+
+static void
+_e_qa_border_new(E_Quick_Access_Entry *entry)
+{
+ E_Exec_Instance *ei;
+
+ if (!entry->cmd) return;
+ if (entry->exe)
+ {
+ INF("already waiting '%s' to start for '%s' (name=%s, class=%s), "
+ "run request ignored.", entry->cmd, entry->id, entry->name, entry->class);
+ return;
+ }
+
+ INF("start quick access '%s' (name=%s, class=%s), "
+ "run command '%s'", entry->id, entry->name, entry->class, entry->cmd);
+
+ ei = e_exec(NULL, NULL, entry->cmd, NULL, NULL);
+ if ((!ei) || (!ei->exe))
+ {
+ ERR("could not execute '%s'", entry->cmd);
+ return;
+ }
+
+ entry->exe = ei->exe;
+ entry->exe_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, (Ecore_Event_Handler_Cb)_e_qa_event_exe_del_cb, entry);
+}
+
+static void
+_e_qa_del_cb(E_Object *obj __UNUSED__, const char *params __UNUSED__)
+{
+ _e_qa_bd_menu_del(_e_qa_entry_find_border(e_border_focused_get()), NULL, NULL);
+}
+
+static void
+_e_qa_add_cb(E_Object *obj __UNUSED__, const char *params __UNUSED__)
+{
+ _e_qa_bd_menu_del(e_border_focused_get(), NULL, NULL);
+}
+
+static void
+_e_qa_toggle_cb(E_Object *obj __UNUSED__, const char *params)
+{
+ E_Quick_Access_Entry *entry;
+
+ if (!params)
+ {
+ ERR("%s got params == NULL", _act_toggle);
+ return;
+ }
+ /* params is stringshared according to e_bindings.c */
+ DBG("%s %s (stringshared=%p)", _act_toggle, params, params);
+
+ entry = _e_qa_entry_find(params);
+ if (!entry)
+ {
+ e_util_dialog_show(_("Quickaccess Error"), _("The requested Quickaccess entry does not exist!"));
+ return;
+ }
+
+ if (entry->border)
+ {
+ if (entry->border->focused || entry->config.hide_when_behind)
+ {
+ _e_qa_border_deactivate(entry);
+ return;
+ }
+
+ DBG("activate border for identifier '%s' (name=%s, class=%s).",
+ entry->id, entry->name, entry->class);
+ _e_qa_border_activate(entry);
+ }
+ else
+ {
+ DBG("no border known for identifier '%s' (name=%s, class=%s).",
+ entry->id, entry->name, entry->class);
+ _e_qa_border_new(entry);
+ }
+}
+
+static void
+_e_qa_border_eval_pre_post_fetch_cb(void *data __UNUSED__, void *border)
+{
+ E_Border *bd = border;
+ E_Quick_Access_Entry *entry;
+
+ if ((!bd->new_client) || (bd->internal)) return;
+ if ((!bd->client.icccm.class) || (!bd->client.icccm.class[0])) return;
+ if ((!bd->client.icccm.name) || (!bd->client.icccm.name[0])) return;
+
+ entry = _e_qa_entry_find_match(bd);
+ if (!entry) return;
+ DBG("border=%p matches entry %s", bd, entry->id);
+ _e_qa_entry_border_associate(entry, bd);
+}
+
+static Eina_Bool
+_e_qa_event_border_focus_out_cb(void *data __UNUSED__, int type __UNUSED__, E_Event_Border_Focus_Out *ev)
+{
+ E_Quick_Access_Entry *entry;
+
+ entry = _e_qa_entry_find_border(ev->border);
+ if (entry && entry->config.autohide) _e_qa_border_deactivate(entry);
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_e_qa_event_module_init_end_cb(void *data __UNUSED__, int type __UNUSED__, void *ev __UNUSED__)
+{
+ Eina_List *l, *ll;
+ E_Quick_Access_Entry *entry;
+ unsigned int count;
+ /* assume that by now, e has successfully placed all windows */
+ count = eina_list_count(qa_config->transient_entries);
+ EINA_LIST_FOREACH_SAFE(qa_config->transient_entries, l, ll, entry)
+ {
+ if (entry->border) continue;
+ entry->border = e_border_find_by_client_window(entry->win);
+ if (entry->border)
+ {
+ DBG("qa window for %u:transient:%s still exists; restoring", entry->win, entry->id);
+ _e_qa_entry_border_associate(entry, entry->border);
+ continue;
+ }
+ DBG("qa window for %u:transient:%s no longer exists; deleting", entry->win, entry->id);
+ e_qa_entry_free(entry);
+ }
+ if (count != eina_list_count(qa_config->transient_entries)) e_bindings_reset();
+ qa_running = EINA_TRUE;
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_e_qa_event_border_remove_cb(void *data __UNUSED__, int type __UNUSED__, E_Event_Border_Remove *ev)
+{
+ E_Quick_Access_Entry *entry;
+
+ entry = _e_qa_entry_find_border(ev->border);
+ if (!entry) return ECORE_CALLBACK_RENEW;
+ if (entry->transient)
+ {
+ DBG("closed transient qa border: deleting keybind and entry");
+ e_qa_entry_free(entry);
+ }
+ else if (entry->config.relaunch) _e_qa_border_new(entry);
+ entry->border = NULL;
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_e_qa_entry_transient_convert(E_Quick_Access_Entry *entry)
+{
+ e_qa_config_entry_transient_convert(entry);
+ if (entry->transient)
+ {
+ entry->transient = EINA_FALSE;
+ entry->win = 0;
+ eina_list_move(&qa_config->entries, &qa_config->transient_entries, entry);
+ return;
+ }
+ entry->transient = EINA_TRUE;
+ entry->win = entry->border->client.win;
+ eina_list_move(&qa_config->transient_entries, &qa_config->entries, entry);
+ eina_stringshare_replace(&entry->cmd, NULL);
+ entry->config.relaunch = 0;
+}
+
+static E_Quick_Access_Entry *
+_e_qa_entry_transient_new(E_Border *bd)
+{
+ E_Quick_Access_Entry *entry;
+ char buf[8192];
+
+ snprintf(buf, sizeof(buf), "%s:%u:%s", bd->client.icccm.name, bd->client.win, bd->client.icccm.class);
+
+ entry = e_qa_entry_new(buf, EINA_TRUE);
+ entry->win = bd->client.win;
+ entry->name = eina_stringshare_ref(bd->client.icccm.name);
+ entry->class = eina_stringshare_ref(bd->client.icccm.class);
+ _e_qa_entry_border_associate(entry, bd);
+ qa_config->transient_entries = eina_list_append(qa_config->transient_entries, entry);
+ e_config_save_queue();
+ return entry;
+}
+
+static Eina_Bool
+_grab_key_down_cb(void *data, int type __UNUSED__, void *event)
+{
+ Ecore_Event_Key *ev = event;
+ E_Border *bd = data;
+ E_Config_Binding_Key *bi;
+ E_Quick_Access_Entry *entry;
+ unsigned int mod = E_BINDING_MODIFIER_NONE;
+
+ if (!strcmp(ev->keyname, "Control_L") || !strcmp(ev->keyname, "Control_R") ||
+ !strcmp(ev->keyname, "Shift_L") || !strcmp(ev->keyname, "Shift_R") ||
+ !strcmp(ev->keyname, "Alt_L") || !strcmp(ev->keyname, "Alt_R") ||
+ !strcmp(ev->keyname, "Super_L") || !strcmp(ev->keyname, "Super_R"))
+ return ECORE_CALLBACK_RENEW;
+
+ if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)
+ mod |= E_BINDING_MODIFIER_SHIFT;
+ if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
+ mod |= E_BINDING_MODIFIER_CTRL;
+ if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT)
+ mod |= E_BINDING_MODIFIER_ALT;
+ if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN)
+ mod |= E_BINDING_MODIFIER_WIN;
+
+ if (e_util_binding_match(NULL, ev, NULL, NULL))
+ {
+ e_util_dialog_show("Keybind Error", "The keybinding you have entered is already in use!");
+ e_object_del(E_OBJECT(eg));
+ return ECORE_CALLBACK_RENEW;
+ }
+ entry = _e_qa_entry_transient_new(bd);
+
+ bi = E_NEW(E_Config_Binding_Key, 1);
+
+ bi->context = E_BINDING_CONTEXT_ANY;
+ bi->modifiers = mod;
+ bi->key = eina_stringshare_add(ev->keyname);
+ bi->action = eina_stringshare_ref(_act_toggle);
+ bi->params = eina_stringshare_ref(entry->id);
+
+ e_managers_keys_ungrab();
+ e_config->key_bindings = eina_list_append(e_config->key_bindings, bi);
+ e_bindings_key_add(bi->context, bi->key, bi->modifiers, bi->any_mod, bi->action, bi->params);
+ e_managers_keys_grab();
+ e_config_save_queue();
+ e_object_del(E_OBJECT(eg));
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_grab_wnd_hide(void *data __UNUSED__)
+{
+ eg = NULL;
+}
+
+static void
+_e_qa_bd_menu_transient(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
+{
+ E_Quick_Access_Entry *entry = data;
+ _e_qa_entry_transient_convert(entry);
+}
+
+static void
+_e_qa_bd_menu_relaunch(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
+{
+ E_Quick_Access_Entry *entry = data;
+
+ entry->config.relaunch = !entry->config.relaunch;
+ if (!entry->config.relaunch) return;
+ _e_qa_entry_relaunch_setup(entry);
+ if (!entry->config.relaunch) return;
+ /* a relaunchable entry cannot be transient */
+ if (entry->transient) _e_qa_entry_transient_convert(entry);
+}
+
+static void
+_e_qa_bd_menu_hideraise(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
+{
+ E_Quick_Access_Entry *entry = data;
+
+ entry->config.hide_when_behind = !entry->config.hide_when_behind;
+}
+
+static void
+_e_qa_bd_menu_autohide(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
+{
+ E_Quick_Access_Entry *entry = data;
+
+ entry->config.autohide = !entry->config.autohide;
+ _e_qa_entry_border_props_apply(entry);
+}
+
+static void
+_e_qa_bd_menu_del(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
+{
+ E_Quick_Access_Entry *entry = data;
+
+ if (!entry) return;
+
+ e_qa_entry_free(entry);
+}
+
+static void
+_e_qa_bd_menu_config(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
+{
+ e_configure_registry_call("launcher/quickaccess", NULL, NULL);
+}
+
+static void
+_e_qa_bd_menu_add(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
+{
+ E_Border *bd = data;
+ if (!bd) return;
+ if (eg) return;
+ eg = e_grab_dialog_show(NULL, EINA_FALSE, _grab_key_down_cb, NULL, NULL, bd);
+ e_object_data_set(E_OBJECT(eg), bd);
+ e_object_del_attach_func_set(E_OBJECT(eg), _grab_wnd_hide);
+}
+
+static void
+_e_qa_bd_menu_pre(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi)
+{
+ E_Quick_Access_Entry *entry = data;
+ E_Menu *subm;
+
+ subm = e_menu_new();
+ e_menu_title_set(subm, entry->id);
+ e_object_data_set(E_OBJECT(subm), entry);
+ e_menu_item_submenu_set(mi, subm);
+
+ mi = e_menu_item_new(subm);
+ e_menu_item_check_set(mi, 1);
+ e_menu_item_toggle_set(mi, entry->config.autohide);
+ e_menu_item_label_set(mi, _("Autohide"));
+ e_menu_item_callback_set(mi, _e_qa_bd_menu_autohide, entry);
+
+ mi = e_menu_item_new(subm);
+ e_menu_item_check_set(mi, 1);
+ e_menu_item_toggle_set(mi, entry->config.hide_when_behind);
+ e_menu_item_label_set(mi, _("Hide Instead Of Raise"));
+ e_menu_item_callback_set(mi, _e_qa_bd_menu_hideraise, entry);
+
+ /* can't set relaunch for internal E dialogs; safety #1 */
+ if (strcmp(entry->name, "E"))
+ {
+ mi = e_menu_item_new(subm);
+ e_menu_item_check_set(mi, 1);
+ e_menu_item_toggle_set(mi, entry->config.relaunch);
+ e_menu_item_label_set(mi, _("Automatically Reopen When Closed"));
+ e_menu_item_callback_set(mi, _e_qa_bd_menu_relaunch, entry);
+ }
+
+ mi = e_menu_item_new(subm);
+ e_menu_item_check_set(mi, 1);
+ e_menu_item_toggle_set(mi, entry->transient);
+ e_menu_item_label_set(mi, _("Transient"));
+ e_menu_item_callback_set(mi, _e_qa_bd_menu_transient, entry);
+
+ mi = e_menu_item_new(subm);
+ e_menu_item_separator_set(mi, 1);
+
+ mi = e_menu_item_new(subm);
+ e_menu_item_label_set(mi, _("Remove Quickaccess"));
+ e_menu_item_callback_set(mi, _e_qa_bd_menu_del, entry);
+}
+
+static void
+_e_qa_bd_menu_hook(void *d __UNUSED__, E_Border *bd)
+{
+ E_Menu_Item *mi;
+ E_Menu *m;
+ E_Quick_Access_Entry *entry;
+ char buf[PATH_MAX];
+
+ if (!bd->border_menu) return;
+ m = bd->border_menu;
+
+ /* position menu item just before first separator */
+ mi = m->items->next->data;
+ mi = e_menu_item_new_relative(m, mi);
+ entry = _e_qa_entry_find_border(bd);
+ if (entry)
+ {
+ e_menu_item_label_set(mi, _("Quickaccess..."));
+ e_menu_item_submenu_pre_callback_set(mi, _e_qa_bd_menu_pre, entry);
+ e_menu_item_callback_set(mi, _e_qa_bd_menu_config, NULL);
+ }
+ else
+ {
+ e_menu_item_label_set(mi, _("Add Quickaccess"));
+ e_menu_item_callback_set(mi, _e_qa_bd_menu_add, bd);
+ }
+ snprintf(buf, sizeof(buf), "%s/e-module-quickaccess.edj", e_module_dir_get(qa_mod->module));
+ e_menu_item_icon_edje_set(mi, buf, "icon");
+}
+
+static void
+_e_qa_entry_config_apply(E_Quick_Access_Entry *entry)
+{
+#define SET(X) entry->config.X = qa_config->X
+ SET(autohide);
+ SET(hide_when_behind);
+#undef SET
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Eina_Bool
+e_qa_init(void)
+{
+ Ecore_Event_Handler *eh;
+ E_Border_Hook *h;
+
+ _act_toggle = eina_stringshare_add("qa_toggle");
+ _e_qa_toggle = e_action_add(_act_toggle);
+ _e_qa_add = e_action_add(_act_add);
+ _e_qa_del = e_action_add(_act_del);
+ if ((!_e_qa_toggle) || (!_e_qa_add) || (!_e_qa_del))
+ {
+ CRIT("could not register %s E_Action", _act_toggle);
+ e_action_del(_act_toggle);
+ e_action_del(_act_add);
+ e_action_del(_act_del);
+ _e_qa_add = _e_qa_del = _e_qa_toggle = NULL;
+ eina_stringshare_replace(&_act_toggle, NULL);
+ return EINA_FALSE;
+ }
+#define CB(id, func) \
+ h = e_border_hook_add(E_BORDER_HOOK_##id, _e_qa_border_##func##_cb, NULL); \
+ _e_qa_border_hooks = eina_list_append(_e_qa_border_hooks, h)
+
+ CB(EVAL_PRE_POST_FETCH, eval_pre_post_fetch);
+#undef CB
+
+#define CB(id, func) \
+ eh = ecore_event_handler_add(id, (Ecore_Event_Handler_Cb)_e_qa_event_##func##_cb, NULL); \
+ _e_qa_event_handlers = eina_list_append(_e_qa_event_handlers, eh)
+
+ CB(E_EVENT_BORDER_FOCUS_OUT, border_focus_out);
+ CB(E_EVENT_BORDER_REMOVE, border_remove);
+ CB(E_EVENT_MODULE_INIT_END, module_init_end);
+ CB(ECORE_EXE_EVENT_DEL, exe_del);
+#undef CB
+
+ _e_qa_toggle->func.go = _e_qa_toggle_cb;
+ e_action_predef_name_set(_(_e_qa_name), _(_lbl_toggle), _act_toggle, NULL, _("quick access name/identifier"), 1);
+ _e_qa_add->func.go = _e_qa_add_cb;
+ e_action_predef_name_set(_(_e_qa_name), _(_lbl_add), _act_add, NULL, NULL, 0);
+ _e_qa_del->func.go = _e_qa_del_cb;
+ e_action_predef_name_set(_(_e_qa_name), _(_lbl_del), _act_del, NULL, NULL, 0);
+ INF("loaded qa module, registered %s action.", _act_toggle);
+
+ border_hook = e_int_border_menu_hook_add(_e_qa_bd_menu_hook, NULL);
+ // TODO: on first usage (ie: no config), show instructions that user
+ // should set a match and keybinding
+
+ return EINA_TRUE;
+}
+
+void
+e_qa_shutdown(void)
+{
+ if (_e_qa_toggle)
+ {
+ e_action_predef_name_del(_(_e_qa_name), _(_lbl_toggle));
+
+ e_action_del(_act_toggle);
+ _e_qa_toggle = NULL;
+ }
+ if (_e_qa_add)
+ {
+ e_action_predef_name_del(_(_e_qa_name), _(_lbl_add));
+
+ e_action_del(_act_add);
+ _e_qa_add = NULL;
+ }
+ if (_e_qa_del)
+ {
+ e_action_predef_name_del(_(_e_qa_name), _(_lbl_del));
+
+ e_action_del(_act_del);
+ _e_qa_del = NULL;
+ }
+
+ E_FREE_LIST(_e_qa_event_handlers, ecore_event_handler_del);
+ E_FREE_LIST(_e_qa_border_hooks, e_border_hook_del);
+
+ e_int_border_menu_hook_del(border_hook);
+ border_hook = NULL;
+ INF("unloaded quickaccess module, unregistered %s action.", _act_toggle);
+ eina_stringshare_del(_act_toggle);
+ _act_toggle = NULL;
+ qa_running = EINA_FALSE;
+}
+
+void
+e_qa_entry_free(E_Quick_Access_Entry *entry)
+{
+ if (entry->exe_handler) ecore_event_handler_del(entry->exe_handler);
+ if (entry->border) _e_qa_entry_border_props_restore(entry, entry->border);
+ if (entry->cfg_entry) e_qa_config_entry_free(entry);
+ e_qa_entry_bindings_cleanup(entry);
+ e_bindings_reset();
+ eina_stringshare_del(entry->id);
+ eina_stringshare_del(entry->name);
+ eina_stringshare_del(entry->class);
+ eina_stringshare_del(entry->cmd);
+ if (entry->transient)
+ qa_config->transient_entries = eina_list_remove(qa_config->transient_entries, entry);
+ else
+ qa_config->entries = eina_list_remove(qa_config->entries, entry);
+ free(entry);
+ e_config_save_queue();
+}
+
+E_Quick_Access_Entry *
+e_qa_entry_new(const char *id, Eina_Bool transient)
+{
+ E_Quick_Access_Entry *entry;
+
+ entry = E_NEW(E_Quick_Access_Entry, 1);
+ entry->id = eina_stringshare_add(id);
+ entry->transient = !!transient;
+ entry->config.autohide = qa_config->autohide;
+ entry->config.hide_when_behind = qa_config->hide_when_behind;
+ if (qa_mod->cfd) e_qa_config_entry_add(entry);
+ return entry;
+}
+
+Eina_Bool
+e_qa_entry_rename(E_Quick_Access_Entry *entry, const char *name)
+{
+ Eina_List *l;
+ E_Quick_Access_Entry *e;
+
+ /* ensure we don't get duplicates as a result of rename */
+ EINA_LIST_FOREACH(qa_config->entries, l, e)
+ if (e->id == name) return EINA_FALSE;
+ EINA_LIST_FOREACH(qa_config->transient_entries, l, e)
+ if (e->id == name) return EINA_FALSE;
+ e_qa_entry_bindings_rename(entry, name);
+ eina_stringshare_replace(&entry->id, name);
+ e_config_save_queue();
+ return EINA_TRUE;
+}
+
+void
+e_qa_entries_update(void)
+{
+ E_Quick_Access_Entry *entry;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(qa_config->entries, l, entry)
+ {
+ _e_qa_entry_config_apply(entry);
+ _e_qa_entry_border_props_apply(entry);
+ }
+ EINA_LIST_FOREACH(qa_config->transient_entries, l, entry)
+ {
+ _e_qa_entry_config_apply(entry);
+ _e_qa_entry_border_props_apply(entry);
+ }
+}
diff --git a/src/modules/quickaccess/e_quickaccess_bindings.c b/src/modules/quickaccess/e_quickaccess_bindings.c
new file mode 100644
index 000000000..8ec767423
--- /dev/null
+++ b/src/modules/quickaccess/e_quickaccess_bindings.c
@@ -0,0 +1,112 @@
+#include "e_mod_main.h"
+
+
+void
+e_qa_entry_bindings_cleanup(E_Quick_Access_Entry *entry)
+{
+ Eina_List *l, *ll;
+ E_Config_Binding_Key *kbi;
+ E_Config_Binding_Mouse *mbi;
+ E_Config_Binding_Edge *ebi;
+ E_Config_Binding_Wheel *wbi;
+ E_Config_Binding_Acpi *abi;
+ E_Config_Binding_Signal *sbi;
+
+ EINA_LIST_FOREACH_SAFE(e_config->key_bindings, l, ll, kbi)
+ {
+ if ((kbi->action == _act_toggle) && (kbi->params == entry->id))
+ {
+ DBG("removed keybind for %s", entry->id);
+ e_config->key_bindings = eina_list_remove_list(e_config->key_bindings, l);
+ eina_stringshare_del(kbi->key);
+ eina_stringshare_del(kbi->action);
+ eina_stringshare_del(kbi->params);
+ free(kbi);
+ }
+ }
+ EINA_LIST_FOREACH_SAFE(e_config->mouse_bindings, l, ll, mbi)
+ {
+ if ((mbi->action == _act_toggle) && (mbi->params == entry->id))
+ {
+ DBG("removed mousebind for %s", entry->id);
+ e_config->mouse_bindings = eina_list_remove_list(e_config->mouse_bindings, l);
+ eina_stringshare_del(mbi->action);
+ eina_stringshare_del(mbi->params);
+ free(mbi);
+ }
+ }
+ EINA_LIST_FOREACH_SAFE(e_config->edge_bindings, l, ll, ebi)
+ {
+ if ((ebi->action == _act_toggle) && (ebi->params == entry->id))
+ {
+ DBG("removed edgebind for %s", entry->id);
+ e_config->edge_bindings = eina_list_remove_list(e_config->edge_bindings, l);
+ eina_stringshare_del(ebi->action);
+ eina_stringshare_del(ebi->params);
+ free(ebi);
+ }
+ }
+ EINA_LIST_FOREACH_SAFE(e_config->wheel_bindings, l, ll, wbi)
+ {
+ if ((wbi->action == _act_toggle) && (wbi->params == entry->id))
+ {
+ DBG("removed wheelbind for %s", entry->id);
+ e_config->wheel_bindings = eina_list_remove_list(e_config->wheel_bindings, l);
+ eina_stringshare_del(wbi->action);
+ eina_stringshare_del(wbi->params);
+ free(wbi);
+ }
+ }
+ EINA_LIST_FOREACH_SAFE(e_config->acpi_bindings, l, ll, abi)
+ {
+ if ((abi->action == _act_toggle) && (abi->params == entry->id))
+ {
+ DBG("removed acpibind for %s", entry->id);
+ e_config->acpi_bindings = eina_list_remove_list(e_config->acpi_bindings, l);
+ eina_stringshare_del(abi->action);
+ eina_stringshare_del(abi->params);
+ free(abi);
+ }
+ }
+ EINA_LIST_FOREACH_SAFE(e_config->signal_bindings, l, ll, sbi)
+ {
+ if ((sbi->action == _act_toggle) && (sbi->params == entry->id))
+ {
+ DBG("removed signalbind for %s", entry->id);
+ e_config->signal_bindings = eina_list_remove_list(e_config->signal_bindings, l);
+ eina_stringshare_del(sbi->action);
+ eina_stringshare_del(sbi->params);
+ free(sbi);
+ }
+ }
+}
+
+void
+e_qa_entry_bindings_rename(E_Quick_Access_Entry *entry, const char *name)
+{
+ Eina_List *l;
+ E_Config_Binding_Key *kbi;
+ E_Config_Binding_Mouse *mbi;
+ E_Config_Binding_Edge *ebi;
+ E_Config_Binding_Wheel *wbi;
+ E_Config_Binding_Acpi *abi;
+ E_Config_Binding_Signal *sbi;
+
+#define RENAME(TYPE, VAR) do {\
+ EINA_LIST_FOREACH(e_config->TYPE##_bindings, l, VAR) \
+ { \
+ if ((VAR->action == _act_toggle) && (VAR->params == entry->id)) \
+ { \
+ DBG("removed %sbind for %s", #TYPE, entry->id); \
+ eina_stringshare_replace(&VAR->params, name); \
+ } \
+ } \
+ } while (0)
+ RENAME(key, kbi);
+ RENAME(mouse, mbi);
+ RENAME(edge, ebi);
+ RENAME(wheel, wbi);
+ RENAME(acpi, abi);
+ RENAME(signal, sbi);
+ e_bindings_reset();
+}
diff --git a/src/modules/quickaccess/e_quickaccess_db.c b/src/modules/quickaccess/e_quickaccess_db.c
new file mode 100644
index 000000000..7f07ff996
--- /dev/null
+++ b/src/modules/quickaccess/e_quickaccess_db.c
@@ -0,0 +1,34 @@
+#include "e_mod_main.h"
+
+static const char *_e_qa_db[] =
+{
+ "XTerm",
+ "URxvt",
+ "terminology",
+ NULL
+};
+
+static const char *_e_qa_arg_db[] =
+{
+ "-name",
+ "-name",
+ "--name",
+ NULL
+};
+
+char *
+e_qa_db_class_lookup(const char *class)
+{
+ int x;
+ char buf[PATH_MAX];
+
+ if (!class) return NULL;
+ for (x = 0; _e_qa_db[x]; x++)
+ {
+ if (!strcmp(_e_qa_db[x], class))
+ return strdup(_e_qa_arg_db[x]);
+ }
+ /* allows user-added name options for weird/obscure terminals */
+ snprintf(buf, sizeof(buf), "%s/e-module-quickaccess.edj", e_module_dir_get(qa_mod->module));
+ return edje_file_data_get(buf, class);
+}
diff --git a/src/modules/quickaccess/module.desktop.in b/src/modules/quickaccess/module.desktop.in
new file mode 100644
index 000000000..cd76405dc
--- /dev/null
+++ b/src/modules/quickaccess/module.desktop.in
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=Link
+Name=Quickaccess
+Icon=e-module-quickaccess
+Comment=Enlightenment Quickaccess Launcher
+X-Enlightenment-ModuleType=launcher