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