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