static Eina_Bool _e_module_cb_idler(void *data);
static int _e_module_sort_priority(const void *d1, const void *d2);
static void _e_module_whitelist_check(void);
+static Eina_Bool _e_module_desktop_list_cb(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata);
/* local subsystem globals */
static Eina_List *_e_modules = NULL;
+static Eina_Hash *_e_modules_hash = NULL;
static Ecore_Idle_Enterer *_e_module_idler = NULL;
static Eina_List *_e_modules_delayed = NULL;
static Eina_Bool _e_modules_initting = EINA_FALSE;
+static Eina_List *_e_module_path_monitors = NULL;
+static Eina_List *_e_module_path_lists = NULL;
+static Eina_List *handlers = NULL;
+static Eina_Hash *_e_module_path_hash = NULL;
+
EAPI int E_EVENT_MODULE_UPDATE = 0;
EAPI int E_EVENT_MODULE_INIT_END = 0;
+static Eina_Bool
+_module_filter_cb(void *d EINA_UNUSED, Eio_File *ls EINA_UNUSED, const Eina_File_Direct_Info *info)
+{
+ struct stat st;
+ char buf[PATH_MAX];
+
+ if (lstat(info->path, &st)) return EINA_FALSE;
+ return (info->path[info->name_start] != '.');
+
+ snprintf(buf, sizeof(buf), "%s/%s/module.so", info->path, MODULE_ARCH);
+ return ecore_file_exists(buf);
+}
+
+static void
+_module_main_cb(void *d EINA_UNUSED, Eio_File *ls EINA_UNUSED, const Eina_File_Direct_Info *info)
+{
+ Eina_Stringshare *s;
+
+ s = eina_hash_set(_e_module_path_hash, info->path + info->name_start, eina_stringshare_add(info->path));
+ if (!s) return;
+ WRN("REPLACING DUPLICATE MODULE PATH: %s -> %s", s, info->path);
+ eina_stringshare_del(s);
+}
+
+static void
+_module_done_cb(void *d EINA_UNUSED, Eio_File *ls)
+{
+ _e_module_path_lists = eina_list_remove(_e_module_path_lists, ls);
+ if (_e_module_path_lists) return;
+ if (_e_modules_initting) e_module_all_load();
+}
+
+static void
+_module_error_cb(void *d EINA_UNUSED, Eio_File *ls, int error EINA_UNUSED)
+{
+ _e_module_path_lists = eina_list_remove(_e_module_path_lists, ls);
+ if (_e_module_path_lists) return;
+ if (_e_modules_initting) e_module_all_load();
+}
+
+static Eina_Bool
+_module_monitor_dir_create(void *d EINA_UNUSED, int type EINA_UNUSED, Eio_Monitor_Event *ev)
+{
+ Eina_Stringshare *s;
+ const char *path;
+
+ path = ecore_file_file_get(ev->filename);
+ s = eina_hash_set(_e_module_path_hash, path, eina_stringshare_ref(ev->filename));
+ if (s && (s != ev->filename))
+ WRN("REPLACING DUPLICATE MODULE PATH: %s -> %s", s, ev->filename);
+ eina_stringshare_del(s);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_module_monitor_dir_del(void *d EINA_UNUSED, int type EINA_UNUSED, Eio_Monitor_Event *ev)
+{
+ Eina_Stringshare *s;
+ const char *path;
+
+ path = ecore_file_file_get(ev->filename);
+ s = eina_hash_find(_e_module_path_hash, path);
+ if (s == ev->filename)
+ eina_hash_del_by_key(_e_module_path_hash, path);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_module_monitor_error(void *d EINA_UNUSED, int type EINA_UNUSED, Eio_Monitor_Error *ev)
+{
+ _e_module_path_monitors = eina_list_remove(_e_module_path_monitors, ev->monitor);
+ eio_monitor_del(ev->monitor);
+ return ECORE_CALLBACK_RENEW;
+}
+
/* externally accessible functions */
EINTERN int
e_module_init(void)
{
+ Eina_List *module_paths;
+ E_Path_Dir *epd;
+
E_EVENT_MODULE_UPDATE = ecore_event_type_new();
E_EVENT_MODULE_INIT_END = ecore_event_type_new();
+ _e_module_path_hash = eina_hash_string_superfast_new((Eina_Free_Cb)eina_stringshare_del);
+ _e_modules_hash = eina_hash_string_superfast_new(NULL);
+
+ E_LIST_HANDLER_APPEND(handlers, EIO_MONITOR_DIRECTORY_CREATED, _module_monitor_dir_create, NULL);
+ E_LIST_HANDLER_APPEND(handlers, EIO_MONITOR_DIRECTORY_DELETED, _module_monitor_dir_del, NULL);
+ E_LIST_HANDLER_APPEND(handlers, EIO_MONITOR_ERROR, _module_monitor_error, NULL);
+
+ module_paths = e_path_dir_list_get(path_modules);
+ EINA_LIST_FREE(module_paths, epd)
+ {
+ Eio_Monitor *mon;
+ Eio_File *ls;
+
+ mon = eio_monitor_stringshared_add(epd->dir);
+ ls = eio_file_direct_ls(epd->dir, _module_filter_cb, _module_main_cb, _module_done_cb, _module_error_cb, NULL);
+ _e_module_path_monitors = eina_list_append(_e_module_path_monitors, mon);
+ _e_module_path_lists = eina_list_append(_e_module_path_lists, ls);
+ eina_stringshare_del(epd->dir);
+ free(epd);
+ }
+
return 1;
}
}
}
+ E_FN_DEL(eina_hash_free, _e_module_path_hash);
+ E_FN_DEL(eina_hash_free, _e_modules_hash);
+ E_FREE_LIST(handlers, ecore_event_handler_del);
+ E_FREE_LIST(_e_module_path_monitors, eio_monitor_del);
+ E_FREE_LIST(_e_module_path_lists, eio_file_cancel);
+
return 1;
}
char buf[128];
_e_modules_initting = EINA_TRUE;
+ if (_e_module_path_lists) return;
e_config->modules =
eina_list_sort(e_config->modules, 0, _e_module_sort_priority);
m = E_OBJECT_ALLOC(E_Module, E_MODULE_TYPE, _e_module_free);
if (name[0] != '/')
{
- snprintf(buf, sizeof(buf), "%s/%s/module.so", name, MODULE_ARCH);
- modpath = e_path_find(path_modules, buf);
+ Eina_Stringshare *path;
+
+ path = eina_hash_find(_e_module_path_hash, name);
+ if (path)
+ {
+ snprintf(buf, sizeof(buf), "%s/%s/module.so", path, MODULE_ARCH);
+ modpath = eina_stringshare_add(buf);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), "%s/%s/module.so", name, MODULE_ARCH);
+ modpath = e_path_find(path_modules, buf);
+ }
}
else if (eina_str_has_extension(name, ".so"))
modpath = eina_stringshare_add(name);
init_done:
_e_modules = eina_list_append(_e_modules, m);
+ eina_hash_add(_e_modules_hash, name, m);
m->name = eina_stringshare_add(name);
if (modpath)
{
int ret = 1;
EINA_LIST_FOREACH(_e_modules, l, m)
- e_object_ref(E_OBJECT(m));
- EINA_LIST_FOREACH(_e_modules, l, m)
- if ((m->enabled) && (!m->error))
- {
- if (m->func.save && (!m->func.save(m))) ret = 0;
- }
- EINA_LIST_FOREACH(_e_modules, l, m)
- e_object_unref(E_OBJECT(m));
+ {
+ e_object_ref(E_OBJECT(m));
+ if ((m->enabled) && (!m->error))
+ {
+ if (m->func.save && (!m->func.save(m))) ret = 0;
+ }
+ e_object_unref(E_OBJECT(m));
+ }
return ret;
}
EAPI E_Module *
e_module_find(const char *name)
{
- Eina_List *l;
- E_Module *m;
-
- if (!name) return NULL;
- EINA_LIST_FOREACH(_e_modules, l, m)
- if (!e_util_strcmp(name, m->name)) return m;
- return NULL;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+ return eina_hash_find(_e_modules_hash, name);
}
EAPI Eina_List *
}
}
+EAPI Eina_List *
+e_module_desktop_list(void)
+{
+ Eina_List *l = NULL;
+
+ eina_hash_foreach(_e_module_path_hash, _e_module_desktop_list_cb, &l);
+ return l;
+}
+
+EAPI void
+e_module_desktop_free(E_Module_Desktop *md)
+{
+ if (!md) return;
+ eina_stringshare_del(md->dir);
+ efreet_desktop_free(md->desktop);
+ free(md);
+}
+
/* local subsystem functions */
static void
free(m);
}
+static Eina_Bool
+_e_module_desktop_list_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
+{
+ char buf[PATH_MAX];
+ Eina_List **l = fdata;
+ Efreet_Desktop *desktop;
+ E_Module_Desktop *md;
+
+ snprintf(buf, sizeof(buf), "%s/module.desktop", (char*)data);
+ desktop = efreet_desktop_new(buf);
+ if (desktop)
+ {
+ md = E_NEW(E_Module_Desktop, 1);
+ md->desktop = desktop;
+ md->dir = eina_stringshare_ref(data);
+ *l = eina_list_append(*l, md);
+ }
+ return EINA_TRUE;
+}
+
static void
_e_module_dialog_disable_show(const char *title, const char *body, E_Module *m)
{