465 lines
10 KiB
C
465 lines
10 KiB
C
/*
|
|
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
|
*/
|
|
#include "e.h"
|
|
|
|
/* TODO List:
|
|
*
|
|
* * add module types/classes
|
|
* * add list of exclusions that a module cant work withApi
|
|
*
|
|
*/
|
|
|
|
typedef struct _Module_Menu_Data Module_Menu_Data;
|
|
|
|
struct _Module_Menu_Data
|
|
{
|
|
Evas_List *submenus;
|
|
};
|
|
|
|
/* local subsystem functions */
|
|
static void _e_module_free(E_Module *m);
|
|
static void _e_module_dialog_disable_show(const char *title, const char *body, E_Module *m);
|
|
static void _e_module_cb_dialog_disable(void *data, E_Dialog *dia);
|
|
|
|
/* local subsystem globals */
|
|
static Evas_List *_e_modules = NULL;
|
|
|
|
/* externally accessible functions */
|
|
EAPI int
|
|
e_module_init(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
EAPI int
|
|
e_module_shutdown(void)
|
|
{
|
|
Evas_List *l, *tmp;
|
|
|
|
#ifdef HAVE_VALGRIND
|
|
/* do a leak check now before we dlclose() all those plugins, cause
|
|
* that means we won't get a decent backtrace to leaks in there
|
|
*/
|
|
VALGRIND_DO_LEAK_CHECK
|
|
#endif
|
|
|
|
for (l = _e_modules; l;)
|
|
{
|
|
tmp = l;
|
|
l = l->next;
|
|
e_object_del(E_OBJECT(tmp->data));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
EAPI void
|
|
e_module_all_load(void)
|
|
{
|
|
Evas_List *pl = NULL, *l;
|
|
|
|
for (l = e_config->modules; l;)
|
|
{
|
|
E_Config_Module *em;
|
|
E_Module *m;
|
|
|
|
em = l->data;
|
|
pl = l;
|
|
l = l->next;
|
|
m = NULL;
|
|
if (em->name) m = e_module_new(em->name);
|
|
if (m)
|
|
{
|
|
if (em->enabled) e_module_enable(m);
|
|
}
|
|
else
|
|
{
|
|
if (em->name) evas_stringshare_del(em->name);
|
|
E_FREE(em);
|
|
e_config->modules = evas_list_remove_list(e_config->modules, pl);
|
|
e_config_save_queue();
|
|
}
|
|
}
|
|
}
|
|
|
|
EAPI E_Module *
|
|
e_module_new(const char *name)
|
|
{
|
|
E_Module *m;
|
|
char buf[4096];
|
|
char body[4096], title[1024];
|
|
const char *modpath;
|
|
char *s;
|
|
Evas_List *l;
|
|
int in_list = 0;
|
|
|
|
if (!name) return NULL;
|
|
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);
|
|
}
|
|
else
|
|
modpath = evas_stringshare_add(name);
|
|
if (!modpath)
|
|
{
|
|
snprintf(body, sizeof(body), _("There was an error loading module named: %s<br>"
|
|
"No module named %s could be found in the<br>"
|
|
"module search directories.<br>"),
|
|
name, buf);
|
|
_e_module_dialog_disable_show(_("Error loading Module"), body, m);
|
|
m->error = 1;
|
|
goto init_done;
|
|
}
|
|
m->handle = dlopen(modpath, RTLD_NOW | RTLD_GLOBAL);
|
|
if (!m->handle)
|
|
{
|
|
snprintf(body, sizeof(body), _("There was an error loading module named: %s<br>"
|
|
"The full path to this module is:<br>"
|
|
"%s<br>"
|
|
"The error reported was:<br>"
|
|
"%s<br>"),
|
|
name, buf, dlerror());
|
|
_e_module_dialog_disable_show(_("Error loading Module"), body, m);
|
|
m->error = 1;
|
|
goto init_done;
|
|
}
|
|
m->api = dlsym(m->handle, "e_modapi");
|
|
m->func.init = dlsym(m->handle, "e_modapi_init");
|
|
m->func.shutdown = dlsym(m->handle, "e_modapi_shutdown");
|
|
m->func.save = dlsym(m->handle, "e_modapi_save");
|
|
m->func.about = dlsym(m->handle, "e_modapi_about");
|
|
m->func.config = dlsym(m->handle, "e_modapi_config");
|
|
|
|
if ((!m->func.init) ||
|
|
(!m->func.shutdown) ||
|
|
(!m->func.save) ||
|
|
(!m->func.about) ||
|
|
(!m->api) ||
|
|
|
|
// this is to more forcibly catch old/bad modules. will go - eventually,
|
|
// but for now is a good check to have
|
|
(dlsym(m->handle, "e_modapi_info"))
|
|
|
|
)
|
|
{
|
|
snprintf(body, sizeof(body), _("There was an error loading module named: %s<br>"
|
|
"The full path to this module is:<br>"
|
|
"%s<br>"
|
|
"The error reported was:<br>"
|
|
"%s<br>"),
|
|
name, buf, _("Module does not contain all needed functions"));
|
|
_e_module_dialog_disable_show(_("Error loading Module"), body, m);
|
|
m->api = NULL;
|
|
m->func.init = NULL;
|
|
m->func.shutdown = NULL;
|
|
m->func.save = NULL;
|
|
m->func.about = NULL;
|
|
m->func.config = NULL;
|
|
|
|
dlclose(m->handle);
|
|
m->handle = NULL;
|
|
m->error = 1;
|
|
goto init_done;
|
|
}
|
|
if (m->api->version < E_MODULE_API_VERSION)
|
|
{
|
|
snprintf(body, sizeof(body), _("Module API Error<br>Error initializing Module: %s<br>"
|
|
"It requires a minimum module API version of: %i.<br>"
|
|
"The module API advertized by Enlightenment is: %i.<br>"),
|
|
_(m->api->name), m->api->version, E_MODULE_API_VERSION);
|
|
|
|
snprintf(title, sizeof(title), _("Enlightenment %s Module"), _(m->api->name));
|
|
|
|
_e_module_dialog_disable_show(title, body, m);
|
|
m->api = NULL;
|
|
m->func.init = NULL;
|
|
m->func.shutdown = NULL;
|
|
m->func.save = NULL;
|
|
m->func.about = NULL;
|
|
m->func.config = NULL;
|
|
dlclose(m->handle);
|
|
m->handle = NULL;
|
|
m->error = 1;
|
|
goto init_done;
|
|
}
|
|
|
|
init_done:
|
|
|
|
_e_modules = evas_list_append(_e_modules, m);
|
|
m->name = evas_stringshare_add(name);
|
|
if (modpath)
|
|
{
|
|
s = ecore_file_get_dir(modpath);
|
|
if (s)
|
|
{
|
|
char *s2;
|
|
|
|
s2 = ecore_file_get_dir(s);
|
|
free(s);
|
|
if (s2)
|
|
{
|
|
m->dir = evas_stringshare_add(s2);
|
|
free(s2);
|
|
}
|
|
}
|
|
}
|
|
for (l = e_config->modules; l; l = l->next)
|
|
{
|
|
E_Config_Module *em;
|
|
|
|
em = l->data;
|
|
if (!strcmp(em->name, m->name))
|
|
{
|
|
in_list = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!in_list)
|
|
{
|
|
E_Config_Module *em;
|
|
|
|
em = E_NEW(E_Config_Module, 1);
|
|
em->name = evas_stringshare_add(m->name);
|
|
em->enabled = 0;
|
|
e_config->modules = evas_list_append(e_config->modules, em);
|
|
e_config_save_queue();
|
|
}
|
|
if (modpath) evas_stringshare_del(modpath);
|
|
return m;
|
|
}
|
|
|
|
EAPI int
|
|
e_module_save(E_Module *m)
|
|
{
|
|
E_OBJECT_CHECK_RETURN(m, 0);
|
|
E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
|
|
if ((!m->enabled) || (m->error)) return 0;
|
|
return m->func.save(m);
|
|
}
|
|
|
|
EAPI const char *
|
|
e_module_dir_get(E_Module *m)
|
|
{
|
|
E_OBJECT_CHECK_RETURN(m, NULL);
|
|
E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
|
|
return m->dir;
|
|
}
|
|
|
|
EAPI int
|
|
e_module_enable(E_Module *m)
|
|
{
|
|
Evas_List *l;
|
|
|
|
E_OBJECT_CHECK_RETURN(m, 0);
|
|
E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
|
|
if ((m->enabled) || (m->error)) return 0;
|
|
m->data = m->func.init(m);
|
|
if (m->data)
|
|
{
|
|
m->enabled = 1;
|
|
for (l = e_config->modules; l; l = l->next)
|
|
{
|
|
E_Config_Module *em;
|
|
|
|
em = l->data;
|
|
if (!e_util_strcmp(em->name, m->name))
|
|
{
|
|
em->enabled = 1;
|
|
e_config_save_queue();
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
EAPI int
|
|
e_module_disable(E_Module *m)
|
|
{
|
|
Evas_List *l;
|
|
int ret;
|
|
|
|
E_OBJECT_CHECK_RETURN(m, 0);
|
|
E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
|
|
if ((!m->enabled) || (m->error)) return 0;
|
|
ret = m->func.shutdown(m);
|
|
m->data = NULL;
|
|
m->enabled = 0;
|
|
for (l = e_config->modules; l; l = l->next)
|
|
{
|
|
E_Config_Module *em;
|
|
|
|
em = l->data;
|
|
if (!e_util_strcmp(em->name, m->name))
|
|
{
|
|
em->enabled = 0;
|
|
e_config_save_queue();
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
EAPI int
|
|
e_module_enabled_get(E_Module *m)
|
|
{
|
|
E_OBJECT_CHECK_RETURN(m, 0);
|
|
E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
|
|
return m->enabled;
|
|
}
|
|
|
|
EAPI int
|
|
e_module_save_all(void)
|
|
{
|
|
Evas_List *l;
|
|
int ret = 1;
|
|
|
|
for (l = _e_modules; l; l = l->next) e_object_ref(E_OBJECT(l->data));
|
|
for (l = _e_modules; l; l = l->next)
|
|
{
|
|
E_Module *m;
|
|
|
|
m = l->data;
|
|
if ((m->enabled) && (!m->error))
|
|
{
|
|
if (!m->func.save(m)) ret = 0;
|
|
}
|
|
}
|
|
for (l = _e_modules; l; l = l->next) e_object_unref(E_OBJECT(l->data));
|
|
return ret;
|
|
}
|
|
|
|
EAPI E_Module *
|
|
e_module_find(const char *name)
|
|
{
|
|
Evas_List *l;
|
|
|
|
if (!name) return NULL;
|
|
for (l = _e_modules; l; l = l->next)
|
|
{
|
|
E_Module *m;
|
|
|
|
m = l->data;
|
|
if (!strcmp(name, m->name)) return m;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
EAPI Evas_List *
|
|
e_module_list(void)
|
|
{
|
|
return _e_modules;
|
|
}
|
|
|
|
EAPI void
|
|
e_module_dialog_show(E_Module *m, const char *title, const char *body)
|
|
{
|
|
E_Dialog *dia;
|
|
E_Border *bd;
|
|
char eap[4096];
|
|
|
|
dia = e_dialog_new(e_container_current_get(e_manager_current_get()), "E", "_module_dialog");
|
|
if (!dia) return;
|
|
|
|
e_dialog_title_set(dia, title);
|
|
if (m)
|
|
{
|
|
snprintf(eap, sizeof(eap), "%s/module.desktop", e_module_dir_get(m));
|
|
if (ecore_file_exists(eap))
|
|
{
|
|
E_App *app;
|
|
|
|
app = e_app_new(eap, 0);
|
|
if (app)
|
|
{
|
|
dia->icon_object = e_app_icon_add(app, e_win_evas_get(dia->win));
|
|
edje_extern_object_min_size_set(dia->icon_object, 64, 64);
|
|
edje_object_part_swallow(dia->bg_object, "e.swallow.icon", dia->icon_object);
|
|
evas_object_show(dia->icon_object);
|
|
e_object_unref(E_OBJECT(app));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
e_dialog_icon_set(dia, "enlightenment/modules", 64);
|
|
|
|
e_dialog_text_set(dia, body);
|
|
e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
|
|
e_dialog_button_focus_num(dia, 0);
|
|
e_win_centered_set(dia->win, 1);
|
|
e_dialog_show(dia);
|
|
if (!m) return;
|
|
bd = dia->win->border;
|
|
if (!bd) return;
|
|
bd->internal_icon = evas_stringshare_add(eap);
|
|
}
|
|
|
|
/* local subsystem functions */
|
|
|
|
static void
|
|
_e_module_free(E_Module *m)
|
|
{
|
|
Evas_List *l;
|
|
|
|
for (l = e_config->modules; l; l = l->next)
|
|
{
|
|
E_Config_Module *em;
|
|
|
|
em = l->data;
|
|
if (!strcmp(em->name, m->name))
|
|
{
|
|
e_config->modules = evas_list_remove(e_config->modules, em);
|
|
if (em->name) evas_stringshare_del(em->name);
|
|
E_FREE(em);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((m->enabled) && (!m->error))
|
|
{
|
|
m->func.save(m);
|
|
m->func.shutdown(m);
|
|
}
|
|
if (m->name) evas_stringshare_del(m->name);
|
|
if (m->dir) evas_stringshare_del(m->dir);
|
|
if (m->handle) dlclose(m->handle);
|
|
_e_modules = evas_list_remove(_e_modules, m);
|
|
free(m);
|
|
}
|
|
|
|
static void
|
|
_e_module_dialog_disable_show(const char *title, const char *body, E_Module *m)
|
|
{
|
|
E_Dialog *dia;
|
|
char buf[4096];
|
|
|
|
dia = e_dialog_new(e_container_current_get(e_manager_current_get()), "E", "_module_unload_dialog");
|
|
if (!dia) return;
|
|
|
|
snprintf(buf, sizeof(buf), "%s<br>%s", body,
|
|
_("Would you like to unload this module?<br>"));
|
|
|
|
e_dialog_title_set(dia, title);
|
|
e_dialog_icon_set(dia, "enlightenment/e", 64);
|
|
e_dialog_text_set(dia, buf);
|
|
e_dialog_button_add(dia, _("Yes"), NULL, _e_module_cb_dialog_disable, m);
|
|
e_dialog_button_add(dia, _("No"), NULL, NULL, NULL);
|
|
e_win_centered_set(dia->win, 1);
|
|
e_dialog_show(dia);
|
|
}
|
|
|
|
static void
|
|
_e_module_cb_dialog_disable(void *data, E_Dialog *dia)
|
|
{
|
|
E_Module *m;
|
|
|
|
m = data;
|
|
e_module_disable(m);
|
|
e_object_del(E_OBJECT(m));
|
|
e_object_del(E_OBJECT(dia));
|
|
e_config_save_queue();
|
|
}
|