e744ff4de0e4bfc205ab4887eee52bd2e9a759cf
[framework/uifw/e17.git] / src / bin / e_module.c
1 #include "e.h"
2
3 /* TODO List:
4  * 
5  * * add module types/classes
6  * * add list of exclusions that a module can't work withApi
7  * 
8  */
9
10 /* local subsystem functions */
11 static void _e_module_free(E_Module *m);
12 static void _e_module_dialog_disable_show(const char *title, const char *body, E_Module *m);
13 static void _e_module_cb_dialog_disable(void *data, E_Dialog *dia);
14 static void _e_module_event_update_free(void *data, void *event);
15 static Eina_Bool _e_module_cb_idler(void *data);
16 static int _e_module_sort_priority(const void *d1, const void *d2);
17
18 /* local subsystem globals */
19 static Eina_List *_e_modules = NULL;
20 static Ecore_Idler *_e_module_idler = NULL;
21 static Eina_List *_e_modules_delayed = NULL;
22
23 EAPI int E_EVENT_MODULE_UPDATE = 0;
24 EAPI int E_EVENT_MODULE_INIT_END = 0;
25
26 /* externally accessible functions */
27 EINTERN int
28 e_module_init(void)
29 {
30    E_EVENT_MODULE_UPDATE = ecore_event_type_new();
31    E_EVENT_MODULE_INIT_END = ecore_event_type_new();
32    return 1;
33 }
34
35 EINTERN int
36 e_module_shutdown(void)
37 {
38    E_Module *m;
39    
40 #ifdef HAVE_VALGRIND
41    /* do a leak check now before we dlclose() all those plugins, cause
42     * that means we won't get a decent backtrace to leaks in there
43     */
44    VALGRIND_DO_LEAK_CHECK
45 #endif
46
47    /* do not use EINA_LIST_FREE! e_object_del modifies list */
48    if (x_fatal)
49      {
50         e_module_save_all();
51      }
52    else
53      {
54         while (_e_modules)
55           {
56              m = _e_modules->data;
57              if ((m) && (m->enabled) && !(m->error))
58                {
59                   m->func.save(m);
60                   m->func.shutdown(m);
61                   m->enabled = 0;
62                }
63              e_object_del(E_OBJECT(m));
64           }
65      }
66
67    return 1;
68 }
69
70 EAPI void
71 e_module_all_load(void)
72 {
73    Eina_List *l;
74    E_Config_Module *em;
75    char buf[128];
76
77    e_config->modules = 
78      eina_list_sort(e_config->modules, 0, _e_module_sort_priority);
79
80    EINA_LIST_FOREACH(e_config->modules, l, em)
81      {
82         if (!em) continue;
83
84        printf ("[E17_MODULE_INFO] NAME:%s,   ENABLE:%d,  DELAYED:%d\n", em->name, em->enabled, em->delayed);
85
86         if ((em->delayed) && (em->enabled))
87           {
88              if (!_e_module_idler)
89                _e_module_idler = ecore_idler_add(_e_module_cb_idler, NULL);
90              _e_modules_delayed = 
91                eina_list_append(_e_modules_delayed,
92                                 eina_stringshare_add(em->name));
93           }
94         else if (em->enabled)
95           {
96              E_Module *m;
97
98              if (!em->name) continue;
99
100              setenv("E_MODULE_LOAD", em->name, 1);
101              snprintf (buf, sizeof(buf), _("Loading Module: %s"), em->name);
102              e_init_status_set(em->name);
103
104              m = e_module_new(em->name);
105              if (m) e_module_enable(m);
106           }
107      }
108
109    if (!_e_modules_delayed)
110      ecore_event_add(E_EVENT_MODULE_INIT_END, NULL, NULL, NULL);
111
112    unsetenv("E_MODULE_LOAD");
113 }
114
115 EAPI E_Module *
116 e_module_new(const char *name)
117 {
118    E_Module *m;
119    char buf[PATH_MAX];
120    char body[PATH_MAX], title[1024];
121    const char *modpath;
122    char *s;
123    Eina_List *l;
124    E_Config_Module *em;
125    int in_list = 0;
126
127    if (!name) return NULL;
128    m = E_OBJECT_ALLOC(E_Module, E_MODULE_TYPE, _e_module_free);
129    if (name[0] != '/')
130      {
131         snprintf(buf, sizeof(buf), "%s/%s/module.so", name, MODULE_ARCH);
132         modpath = e_path_find(path_modules, buf);
133      }
134    else
135      modpath = eina_stringshare_add(name);
136    if (!modpath)
137      {
138         snprintf(body, sizeof(body), 
139                  _("There was an error loading module named: %s<br>"
140                    "No module named %s could be found in the<br>"
141                    "module search directories.<br>"), name, buf);
142         _e_module_dialog_disable_show(_("Error loading Module"), body, m);
143         m->error = 1;
144         goto init_done;
145      }
146    m->handle = dlopen(modpath, RTLD_NOW | RTLD_GLOBAL);
147    if (!m->handle)
148      {
149         snprintf(body, sizeof(body), 
150                  _("There was an error loading module named: %s<br>"
151                    "The full path to this module is:<br>"
152                    "%s<br>"
153                    "The error reported was:<br>"
154                    "%s<br>"), name, buf, dlerror());
155         _e_module_dialog_disable_show(_("Error loading Module"), body, m);
156         m->error = 1;
157         goto init_done;
158      }
159    m->api = dlsym(m->handle, "e_modapi");
160    m->func.init = dlsym(m->handle, "e_modapi_init");
161    m->func.shutdown = dlsym(m->handle, "e_modapi_shutdown");
162    m->func.save = dlsym(m->handle, "e_modapi_save");
163
164    if ((!m->func.init) || (!m->func.shutdown) || (!m->func.save) || (!m->api))
165      {
166         snprintf(body, sizeof(body), 
167                  _("There was an error loading module named: %s<br>"
168                    "The full path to this module is:<br>"
169                    "%s<br>"
170                    "The error reported was:<br>"
171                    "%s<br>"),
172                  name, buf, _("Module does not contain all needed functions"));
173         _e_module_dialog_disable_show(_("Error loading Module"), body, m);
174         m->api = NULL;
175         m->func.init = NULL;
176         m->func.shutdown = NULL;
177         m->func.save = NULL;
178
179         dlclose(m->handle);
180         m->handle = NULL;
181         m->error = 1;
182         goto init_done;
183      }
184    if (m->api->version < E_MODULE_API_VERSION)
185      {
186         snprintf(body, sizeof(body), 
187                  _("Module API Error<br>Error initializing Module: %s<br>"
188                    "It requires a minimum module API version of: %i.<br>"
189                    "The module API advertized by Enlightenment is: %i.<br>"), 
190                  _(m->api->name), m->api->version, E_MODULE_API_VERSION);
191
192         snprintf(title, sizeof(title), _("Enlightenment %s Module"), 
193                  _(m->api->name));
194
195         _e_module_dialog_disable_show(title, body, m);
196         m->api = NULL;
197         m->func.init = NULL;
198         m->func.shutdown = NULL;
199         m->func.save = NULL;
200         dlclose(m->handle);
201         m->handle = NULL;
202         m->error = 1;
203         goto init_done;
204      }
205
206 init_done:
207
208    _e_modules = eina_list_append(_e_modules, m);
209    m->name = eina_stringshare_add(name);
210    if (modpath)
211      {
212         s =  ecore_file_dir_get(modpath);
213         if (s)
214           {
215              char *s2;
216
217              s2 = ecore_file_dir_get(s);
218              free(s);
219              if (s2)
220                {
221                   m->dir = eina_stringshare_add(s2);
222                   free(s2);
223                }
224           }
225      }
226    EINA_LIST_FOREACH(e_config->modules, l, em)
227      {
228         if (!em) continue;
229         if (!e_util_strcmp(em->name, m->name))
230           {
231              in_list = 1;
232              break;
233           }
234      }
235    if (!in_list)
236      {
237         E_Config_Module *em;
238
239         em = E_NEW(E_Config_Module, 1);
240         em->name = eina_stringshare_add(m->name);
241         em->enabled = 0;
242         e_config->modules = eina_list_append(e_config->modules, em);
243         e_config_save_queue();
244      }
245    if (modpath) eina_stringshare_del(modpath);
246    return m;
247 }
248
249 EAPI int
250 e_module_save(E_Module *m)
251 {
252    E_OBJECT_CHECK_RETURN(m, 0);
253    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
254    if ((!m->enabled) || (m->error)) return 0;
255    return m->func.save(m);
256 }
257
258 EAPI const char *
259 e_module_dir_get(E_Module *m)
260 {
261    E_OBJECT_CHECK_RETURN(m, NULL);
262    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
263    return m->dir;
264 }
265
266 EAPI int
267 e_module_enable(E_Module *m)
268 {
269    Eina_List *l;
270    E_Event_Module_Update *ev;
271    E_Config_Module *em;
272
273    E_OBJECT_CHECK_RETURN(m, 0);
274    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
275    if ((m->enabled) || (m->error)) return 0;
276    m->data = m->func.init(m);
277    if (m->data)
278      {
279         m->enabled = 1;
280         EINA_LIST_FOREACH(e_config->modules, l, em)
281           {
282              if (!em) continue;
283              if (!e_util_strcmp(em->name, m->name))
284                {
285                   em->enabled = 1;
286                   e_config_save_queue();
287
288                   ev = E_NEW(E_Event_Module_Update, 1);
289                   ev->name = strdup(em->name);
290                   ev->enabled = 1;
291                   ecore_event_add(E_EVENT_MODULE_UPDATE, ev,
292                                   _e_module_event_update_free, NULL);
293                   break;
294                }
295           }
296         return 1;
297      }
298    return 0;
299 }
300
301 EAPI int
302 e_module_disable(E_Module *m)
303 {
304    E_Event_Module_Update *ev;
305    Eina_List *l;
306    E_Config_Module *em;
307    int ret;
308
309    E_OBJECT_CHECK_RETURN(m, 0);
310    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
311    if ((!m->enabled) || (m->error)) return 0;
312    ret = m->func.shutdown(m);
313    m->data = NULL;
314    m->enabled = 0;
315    EINA_LIST_FOREACH(e_config->modules, l, em)
316      {
317         if (!em) continue;
318         if (!e_util_strcmp(em->name, m->name))
319           {
320              em->enabled = 0;
321              e_config_save_queue();
322
323              ev = E_NEW(E_Event_Module_Update, 1);
324              ev->name = strdup(em->name);
325              ev->enabled = 0;
326              ecore_event_add(E_EVENT_MODULE_UPDATE, ev,
327                              _e_module_event_update_free, NULL);
328              break;
329           }
330      }
331    return ret;
332 }
333
334 EAPI int
335 e_module_enabled_get(E_Module *m)
336 {
337    E_OBJECT_CHECK_RETURN(m, 0);
338    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
339    return m->enabled;
340 }
341
342 EAPI int
343 e_module_save_all(void)
344 {
345    Eina_List *l;
346    E_Module *m;
347    int ret = 1;
348
349    EINA_LIST_FOREACH(_e_modules, l, m)
350      e_object_ref(E_OBJECT(m));
351    EINA_LIST_FOREACH(_e_modules, l, m)
352      if ((m->enabled) && (!m->error))
353        {
354           if (!m->func.save(m)) ret = 0;
355        }
356    EINA_LIST_FOREACH(_e_modules, l, m)
357      e_object_unref(E_OBJECT(m));
358    return ret;
359 }
360
361 EAPI E_Module *
362 e_module_find(const char *name)
363 {
364    Eina_List *l;
365    E_Module *m;
366
367    if (!name) return NULL;
368    EINA_LIST_FOREACH(_e_modules, l, m)
369      if (!e_util_strcmp(name, m->name)) return m;
370    return NULL;
371 }
372
373 EAPI Eina_List *
374 e_module_list(void)
375 {
376    return _e_modules;
377 }
378
379 EAPI void
380 e_module_dialog_show(E_Module *m, const char *title, const char *body)
381 {
382    E_Dialog *dia;
383    E_Border *bd;
384    char buf[PATH_MAX];
385    const char *icon = NULL;
386
387    dia = e_dialog_new(e_container_current_get(e_manager_current_get()), 
388                       "E", "_module_dialog");
389    if (!dia) return;
390
391    e_dialog_title_set(dia, title);
392    if (m)
393      {
394         Efreet_Desktop *desktop;
395
396         snprintf(buf, sizeof(buf), "%s/module.desktop", e_module_dir_get(m));
397
398         desktop = efreet_desktop_new(buf);
399         if ((desktop) && (desktop->icon))
400           {
401              icon = efreet_icon_path_find(e_config->icon_theme, desktop->icon, 64);
402              if (!icon)
403                {
404                   snprintf(buf, sizeof(buf), "%s/%s.edj",
405                            e_module_dir_get(m), desktop->icon);
406                   dia->icon_object = e_util_icon_add(buf, e_win_evas_get(dia->win));
407                }
408              else
409                dia->icon_object = e_util_icon_add(icon, e_win_evas_get(dia->win));
410              edje_extern_object_min_size_set(dia->icon_object, 64, 64);
411              edje_object_part_swallow(dia->bg_object, "e.swallow.icon", dia->icon_object);
412              evas_object_show(dia->icon_object);
413           }
414         if (desktop) efreet_desktop_free(desktop);
415      }
416    else
417      e_dialog_icon_set(dia, "preferences-plugin", 64);
418
419    e_dialog_text_set(dia, body);
420    e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
421    e_dialog_button_focus_num(dia, 0);
422    e_win_centered_set(dia->win, 1);
423    e_dialog_show(dia);
424    if (!m) return;
425    bd = dia->win->border;
426    if (!bd) return;
427    bd->internal_icon = eina_stringshare_add(icon);
428 }
429
430 EAPI void
431 e_module_delayed_set(E_Module *m, int delayed)
432 {
433    Eina_List *l;
434    E_Config_Module *em;
435
436    EINA_LIST_FOREACH(e_config->modules, l, em)
437      {
438         if (!em) continue;
439         if (!e_util_strcmp(m->name, em->name))
440           {
441              if (em->delayed != delayed)
442                {
443                   em->delayed = delayed;
444                   e_config_save_queue();
445                }
446              break;
447           }
448      }
449 }
450
451 EAPI void
452 e_module_priority_set(E_Module *m, int priority)
453 {
454    /* Set the loading order for a module.
455       More priority means load earlier */
456    Eina_List *l;
457    E_Config_Module *em;
458
459    EINA_LIST_FOREACH(e_config->modules, l, em)
460      {
461         if (!em) continue;
462         if (!e_util_strcmp(m->name, em->name))
463           {
464              if (em->priority != priority)
465                {
466                   em->priority = priority;
467                   e_config_save_queue();
468                }
469              break;
470           }
471      }
472 }
473
474 /* local subsystem functions */
475
476 static void
477 _e_module_free(E_Module *m)
478 {
479    E_Config_Module *em;
480    Eina_List *l;
481
482    EINA_LIST_FOREACH(e_config->modules, l, em)
483      {
484         if (!em) continue;
485         if (!e_util_strcmp(em->name, m->name))
486           {
487              e_config->modules = eina_list_remove(e_config->modules, em);
488              if (em->name) eina_stringshare_del(em->name);
489              E_FREE(em);
490              break;
491           }
492      }
493
494    if ((m->enabled) && (!m->error))
495      {
496         m->func.save(m);
497         m->func.shutdown(m);
498      }
499    if (m->name) eina_stringshare_del(m->name);
500    if (m->dir) eina_stringshare_del(m->dir);
501 //   if (m->handle) dlclose(m->handle); DONT dlclose! causes problems with deferred callbacks for free etc. - when their code goes away!
502    _e_modules = eina_list_remove(_e_modules, m);
503    free(m);
504 }
505
506 static void
507 _e_module_dialog_disable_show(const char *title, const char *body, E_Module *m)
508 {
509    E_Dialog *dia;
510    char buf[PATH_MAX];
511
512    printf("MODULE ERR:\n%s\n", body);
513    dia = e_dialog_new(e_container_current_get(e_manager_current_get()), 
514                       "E", "_module_unload_dialog");
515    if (!dia) return;
516
517    snprintf(buf, sizeof(buf), "%s<br>%s", body,
518             _("Would you like to unload this module?<br>"));
519
520    e_dialog_title_set(dia, title);
521    e_dialog_icon_set(dia, "enlightenment", 64);
522    e_dialog_text_set(dia, buf);
523    e_dialog_button_add(dia, _("Yes"), NULL, _e_module_cb_dialog_disable, m);
524    e_dialog_button_add(dia, _("No"), NULL, NULL, NULL);
525    e_win_centered_set(dia->win, 1);
526    e_dialog_show(dia);
527 }
528
529 static void
530 _e_module_cb_dialog_disable(void *data, E_Dialog *dia)
531 {
532    E_Module *m;
533
534    m = data;
535    e_module_disable(m);
536    e_object_del(E_OBJECT(m));
537    e_object_del(E_OBJECT(dia));
538    e_config_save_queue();
539 }
540
541 static Eina_Bool
542 _e_module_cb_idler(void *data __UNUSED__)
543 {
544    if (_e_modules_delayed)
545      {
546         const char *name;
547         E_Module *m;
548
549         name = eina_list_data_get(_e_modules_delayed);
550         _e_modules_delayed = 
551           eina_list_remove_list(_e_modules_delayed, _e_modules_delayed);
552         m = NULL;
553         if (name) m = e_module_new(name);
554         if (m) e_module_enable(m);
555         eina_stringshare_del(name);
556      }
557    if (_e_modules_delayed)
558      {
559         e_util_wakeup();
560         return ECORE_CALLBACK_RENEW;
561      }
562
563    ecore_event_add(E_EVENT_MODULE_INIT_END, NULL, NULL, NULL);
564
565    _e_module_idler = NULL;
566    return ECORE_CALLBACK_CANCEL;
567 }
568
569 static int
570 _e_module_sort_priority(const void *d1, const void *d2)
571 {
572    const E_Config_Module *m1, *m2;
573
574    m1 = d1;
575    m2 = d2;
576    return (m2->priority - m1->priority);
577 }
578
579
580 static void 
581 _e_module_event_update_free(void *data __UNUSED__, void *event) 
582 {
583    E_Event_Module_Update *ev;
584
585    if (!(ev = event)) return;
586    E_FREE(ev->name);
587    E_FREE(ev);
588 }