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 with Api
7  *
8  */
9 
10 /* local subsystem functions */
11 static void      _e_module_free(E_Module *m);
12 static void      _e_module_dialog_disable_create(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 int       _e_module_sort_name(const void *d1, const void *d2);
16 static void      _e_module_whitelist_check(void);
17 
18 /* local subsystem globals */
19 static Eina_List *_e_modules = NULL;
20 static Eina_Hash *_e_modules_hash = NULL;
21 static Eina_Bool _e_modules_initting = EINA_FALSE;
22 static Eina_Bool _e_modules_init_end = EINA_FALSE;
23 
24 static Eina_Hash *_e_module_path_hash = NULL;
25 
26 E_API int E_EVENT_MODULE_UPDATE = 0;
27 E_API int E_EVENT_MODULE_INIT_END = 0;
28 
29 static Eina_Bool
_module_is_nosave(const char * name)30 _module_is_nosave(const char *name)
31 {
32    const char *blacklist[] =
33    {
34       "comp",
35       "conf_comp",
36       "xwayland",
37    };
38    unsigned int i;
39 
40    for (i = 0; i < EINA_C_ARRAY_LENGTH(blacklist); i++)
41      if (eina_streq(name, blacklist[i])) return EINA_TRUE;
42    return !strncmp(name, "wl_", 3); //block wl_* modules from being saved
43 }
44 
45 static Eina_Bool
_module_is_important(const char * name)46 _module_is_important(const char *name)
47 {
48    const char *list[] =
49    {
50       "xwayland",
51       "wl_buffer",
52       "wl_desktop_shell",
53       "wl_drm",
54       "wl_fb",
55       "wl_text_input",
56       "wl_weekeyboard",
57       "wl_wl",
58       "wl_x11",
59    };
60    unsigned int i;
61 
62    for (i = 0; i < EINA_C_ARRAY_LENGTH(list); i++)
63      if (eina_streq(name, list[i])) return EINA_TRUE;
64    return EINA_FALSE;
65 }
66 
67 /* externally accessible functions */
68 EINTERN int
e_module_init(void)69 e_module_init(void)
70 {
71    if (_e_modules_hash) return 1;
72    E_EVENT_MODULE_UPDATE = ecore_event_type_new();
73    E_EVENT_MODULE_INIT_END = ecore_event_type_new();
74    _e_modules_hash = eina_hash_string_superfast_new(NULL);
75 
76    return 1;
77 }
78 
79 EINTERN int
e_module_shutdown(void)80 e_module_shutdown(void)
81 {
82    E_Module *m;
83 
84 #ifdef HAVE_VALGRIND
85    /* do a leak check now before we dlclose() all those plugins, cause
86     * that means we won't get a decent backtrace to leaks in there
87     */
88    VALGRIND_DO_LEAK_CHECK
89 #endif
90 
91    /* do not use EINA_LIST_FREE! e_object_del modifies list */
92    if (x_fatal)
93      e_module_save_all();
94    else
95      {
96         while (_e_modules)
97           {
98              m = _e_modules->data;
99              if ((m) && (m->enabled) && !(m->error))
100                {
101                   if (m->func.save) m->func.save(m);
102                   if (m->func.shutdown) m->func.shutdown(m);
103                   m->enabled = 0;
104                }
105              e_object_del(E_OBJECT(m));
106           }
107      }
108 
109    E_FREE_FUNC(_e_module_path_hash, eina_hash_free);
110    E_FREE_FUNC(_e_modules_hash, eina_hash_free);
111 
112    return 1;
113 }
114 
115 E_API void
e_module_all_load(void)116 e_module_all_load(void)
117 {
118    Eina_List *l, *ll;
119    E_Config_Module *em, *em2;
120    char buf[128];
121 
122    _e_modules_initting = EINA_TRUE;
123 
124    // remove duplicate modules in load
125    e_config->modules =
126      eina_list_sort(e_config->modules, 0, _e_module_sort_name);
127    EINA_LIST_FOREACH_SAFE(e_config->modules, l, ll, em)
128      {
129         if ((!em) || (!ll)) continue;
130         em2 = ll->data;
131         if (!em2) continue;
132 
133         if (!strcmp(em->name, em2->name))
134           {
135              eina_stringshare_del(em->name);
136              e_config->modules = eina_list_remove_list(e_config->modules, l);
137              free(em);
138           }
139      }
140 
141    EINA_LIST_FOREACH_SAFE(e_config->modules, l, ll, em)
142      {
143         if ((!em) || (!em->name)) continue;
144 
145         if (_module_is_nosave(em->name))
146           {
147              eina_stringshare_del(em->name);
148              e_config->modules = eina_list_remove_list(e_config->modules, l);
149              free(em);
150              continue;
151           }
152         if (em->enabled)
153           {
154              E_Module *m;
155 
156              if (eina_hash_find(_e_modules_hash, em->name)) continue;
157 
158              e_util_env_set("E_MODULE_LOAD", em->name);
159              snprintf(buf, sizeof(buf), _("Loading Module: %s"), em->name);
160 
161              m = e_module_new(em->name);
162              if (m) e_module_enable(m);
163           }
164      }
165    ecore_event_add(E_EVENT_MODULE_INIT_END, NULL, NULL, NULL);
166    _e_modules_init_end = EINA_TRUE;
167    _e_modules_initting = EINA_FALSE;
168    _e_module_whitelist_check();
169 
170    unsetenv("E_MODULE_LOAD");
171 }
172 
173 E_API Eina_Bool
e_module_loading_get(void)174 e_module_loading_get(void)
175 {
176    return !_e_modules_init_end;
177 }
178 
179 E_API E_Module *
e_module_new(const char * name)180 e_module_new(const char *name)
181 {
182    E_Module *m;
183    char buf[PATH_MAX];
184    char body[4096], title[1024];
185    const char *modpath = NULL;
186    char *s;
187    int in_list = 0;
188 
189    if (!name) return NULL;
190    if (eina_hash_find(_e_modules_hash, name)) return NULL;
191 
192    m = E_OBJECT_ALLOC(E_Module, E_MODULE_TYPE, _e_module_free);
193    if (name[0] != '/')
194      {
195         snprintf(buf, sizeof(buf), "%s/%s/module.so", name, MODULE_ARCH);
196         modpath = e_path_find(path_modules, buf);
197      }
198    else if (eina_str_has_extension(name, ".so"))
199      modpath = eina_stringshare_add(name);
200    if (!modpath)
201      {
202         snprintf(body, sizeof(body),
203                  _("There was an error loading the module named: %s<ps/>"
204                    "No module named %s could be found in the<ps/>"
205                    "module search directories.<ps/>"), name, buf);
206         _e_module_dialog_disable_create(_("Error loading Module"), body, m);
207         m->error = 1;
208         goto init_done;
209      }
210    m->handle = dlopen(modpath, (RTLD_NOW | RTLD_LOCAL));
211    if (!m->handle)
212      {
213         snprintf(body, sizeof(body),
214                  _("There was an error loading the module named: %s<ps/>"
215                    "The full path to this module is:<ps/>"
216                    "%s<ps/>"
217                    "The error reported was:<ps/>"
218                    "%s<ps/>"), name, buf, dlerror());
219         _e_module_dialog_disable_create(_("Error loading Module"), body, m);
220         m->error = 1;
221         goto init_done;
222      }
223    m->file = eina_stringshare_ref(modpath);
224    m->api = dlsym(m->handle, "e_modapi");
225    m->func.init = dlsym(m->handle, "e_modapi_init");
226    m->func.shutdown = dlsym(m->handle, "e_modapi_shutdown");
227    m->func.save = dlsym(m->handle, "e_modapi_save");
228 
229    if ((!m->func.init) || (!m->api))
230      {
231         snprintf(body, sizeof(body),
232                  _("There was an error loading the module named: %s<ps/>"
233                    "The full path to this module is:<ps/>"
234                    "%s<ps/>"
235                    "The error reported was:<ps/>"
236                    "%s<ps/>"),
237                  name, buf, _("Module does not contain all needed functions"));
238         _e_module_dialog_disable_create(_("Error loading Module"), body, m);
239         m->api = NULL;
240         m->func.init = NULL;
241         m->func.shutdown = NULL;
242         m->func.save = NULL;
243 
244         dlclose(m->handle);
245         m->handle = NULL;
246         m->error = 1;
247         goto init_done;
248      }
249    if (m->api->version != E_MODULE_API_VERSION)
250      {
251         snprintf(body, sizeof(body),
252                  _("Module API Error<ps/>Error initializing Module: %s<ps/>"
253                    "It requires a module API version of: %i.<ps/>"
254                    "The module API advertized by Enlightenment is: %i.<ps/>"),
255                  _(m->api->name), m->api->version, E_MODULE_API_VERSION);
256 
257         snprintf(title, sizeof(title), _("Enlightenment %s Module"),
258                  _(m->api->name));
259 
260         _e_module_dialog_disable_create(title, body, m);
261         m->api = NULL;
262         m->func.init = NULL;
263         m->func.shutdown = NULL;
264         m->func.save = NULL;
265         dlclose(m->handle);
266         m->handle = NULL;
267         m->error = 1;
268         goto init_done;
269      }
270 
271 init_done:
272 
273    _e_modules = eina_list_append(_e_modules, m);
274    if (!_e_modules_hash)
275      {
276         /* wayland module preloading */
277         if (!e_module_init())
278           CRI("WTFFFFF");
279      }
280    eina_hash_add(_e_modules_hash, name, m);
281    m->name = eina_stringshare_add(name);
282    if (modpath)
283      {
284         s = ecore_file_dir_get(modpath);
285         if (s)
286           {
287              char *s2;
288 
289              s2 = ecore_file_dir_get(s);
290              free(s);
291              if (s2)
292                {
293                   m->dir = eina_stringshare_add(s2);
294                   free(s2);
295                }
296           }
297      }
298    if (!in_list)
299      {
300         E_Config_Module *module;
301 
302         module = E_NEW(E_Config_Module, 1);
303         module->name = eina_stringshare_add(m->name);
304         module->enabled = 0;
305         e_config->modules = eina_list_append(e_config->modules, module);
306         e_config_save_queue();
307      }
308    if (modpath) eina_stringshare_del(modpath);
309    return m;
310 }
311 
312 E_API int
e_module_save(E_Module * m)313 e_module_save(E_Module *m)
314 {
315    E_OBJECT_CHECK_RETURN(m, 0);
316    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
317    if ((!m->enabled) || (m->error)) return 0;
318    return m->func.save ? m->func.save(m) : 1;
319 }
320 
321 E_API const char *
e_module_dir_get(E_Module * m)322 e_module_dir_get(E_Module *m)
323 {
324    E_OBJECT_CHECK_RETURN(m, NULL);
325    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
326    return m->dir;
327 }
328 
329 E_API int
e_module_enable(E_Module * m)330 e_module_enable(E_Module *m)
331 {
332    Eina_List *l;
333    E_Event_Module_Update *ev;
334    E_Config_Module *em;
335 
336    E_OBJECT_CHECK_RETURN(m, 0);
337    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
338    if ((m->enabled) || (m->error)) return 0;
339    m->data = m->func.init(m);
340    if (m->data)
341      {
342         m->enabled = 1;
343         EINA_LIST_FOREACH(e_config->modules, l, em)
344           {
345              if (!em) continue;
346              if (!e_util_strcmp(em->name, m->name))
347                {
348                   em->enabled = 1;
349                   e_config_save_queue();
350 
351                   ev = E_NEW(E_Event_Module_Update, 1);
352                   ev->name = eina_stringshare_ref(em->name);
353                   ev->enabled = 1;
354                   ecore_event_add(E_EVENT_MODULE_UPDATE, ev,
355                                   _e_module_event_update_free, NULL);
356                   break;
357                }
358           }
359         if (_e_modules_hash && (!_e_modules_initting))
360           _e_module_whitelist_check();
361         return 1;
362      }
363    return 0;
364 }
365 
366 E_API int
e_module_disable(E_Module * m)367 e_module_disable(E_Module *m)
368 {
369    E_Event_Module_Update *ev;
370    Eina_List *l;
371    E_Config_Module *em;
372    int ret;
373 
374    E_OBJECT_CHECK_RETURN(m, 0);
375    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
376    if ((!m->enabled) || (m->error)) return 0;
377    if ((!stopping) && _module_is_important(m->name)) return 0;
378    ret = m->func.shutdown ? m->func.shutdown(m) : 1;
379    m->data = NULL;
380    m->enabled = 0;
381    EINA_LIST_FOREACH(e_config->modules, l, em)
382      {
383         if (!em) continue;
384         if (!e_util_strcmp(em->name, m->name))
385           {
386              em->enabled = 0;
387              e_config_save_queue();
388 
389              ev = E_NEW(E_Event_Module_Update, 1);
390              ev->name = eina_stringshare_ref(em->name);
391              ev->enabled = 0;
392              ecore_event_add(E_EVENT_MODULE_UPDATE, ev,
393                              _e_module_event_update_free, NULL);
394              break;
395           }
396      }
397    return ret;
398 }
399 
400 E_API int
e_module_enabled_get(E_Module * m)401 e_module_enabled_get(E_Module *m)
402 {
403    E_OBJECT_CHECK_RETURN(m, 0);
404    E_OBJECT_TYPE_CHECK_RETURN(m, E_MODULE_TYPE, 0);
405    return m->enabled;
406 }
407 
408 E_API int
e_module_save_all(void)409 e_module_save_all(void)
410 {
411    Eina_List *l;
412    E_Module *m;
413    int ret = 1;
414 
415    EINA_LIST_FOREACH(_e_modules, l, m)
416      {
417         e_object_ref(E_OBJECT(m));
418         if ((m->enabled) && (!m->error))
419           {
420              if (m->func.save && (!m->func.save(m))) ret = 0;
421           }
422         e_object_unref(E_OBJECT(m));
423      }
424    return ret;
425 }
426 
427 E_API E_Module *
e_module_find(const char * name)428 e_module_find(const char *name)
429 {
430    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
431    return eina_hash_find(_e_modules_hash, name);
432 }
433 
434 E_API Eina_List *
e_module_list(void)435 e_module_list(void)
436 {
437    return _e_modules;
438 }
439 
440 E_API void
e_module_dialog_show(E_Module * m,const char * title,const char * body)441 e_module_dialog_show(E_Module *m, const char *title, const char *body)
442 {
443    E_Dialog *dia;
444    char buf[PATH_MAX];
445    const char *icon = NULL;
446 
447    dia = e_dialog_new(NULL,
448                       "E", "_module_dialog");
449    if (!dia) return;
450 
451    e_dialog_title_set(dia, title);
452    if (m)
453      {
454         Efreet_Desktop *desktop;
455 
456         snprintf(buf, sizeof(buf), "%s/module.desktop", e_module_dir_get(m));
457 
458         desktop = efreet_desktop_new(buf);
459         if ((desktop) && (desktop->icon))
460           {
461              icon = efreet_icon_path_find(e_config->icon_theme, desktop->icon, 64);
462              if (!icon)
463                {
464                   snprintf(buf, sizeof(buf), "%s/%s.edj",
465                            e_module_dir_get(m), desktop->icon);
466                   dia->icon_object = e_util_icon_add(buf, evas_object_evas_get(dia->win));
467                }
468              else
469                dia->icon_object = e_util_icon_add(icon, evas_object_evas_get(dia->win));
470              evas_object_size_hint_min_set(dia->icon_object, 64, 64);
471              edje_object_part_swallow(dia->bg_object, "e.swallow.icon", dia->icon_object);
472              evas_object_show(dia->icon_object);
473           }
474         if (desktop) efreet_desktop_free(desktop);
475      }
476    else
477      e_dialog_icon_set(dia, "preferences-plugin", 64);
478 
479    e_dialog_text_set(dia, body);
480    e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
481    e_dialog_button_focus_num(dia, 0);
482    elm_win_center(dia->win, 1, 1);
483    e_dialog_show(dia);
484    if (!m) return;
485    e_win_client_icon_set(dia->win, icon);
486 }
487 
488 static Eina_List *
_e_module_desktop_list(Eina_List * modules,const char * dir)489 _e_module_desktop_list(Eina_List *modules, const char *dir)
490 {
491    Eina_List *l, *files;
492    Efreet_Desktop *desktop;
493    char buf[PATH_MAX], *f;
494    E_Module_Desktop *md;
495 
496    files = ecore_file_ls(dir);
497    EINA_LIST_FOREACH(files, l, f)
498      {
499         snprintf(buf, sizeof(buf), "%s/%s/module.desktop", dir, f);
500         desktop = efreet_desktop_new(buf);
501         if (desktop)
502           {
503              md = E_NEW(E_Module_Desktop, 1);
504              md->desktop = desktop;
505              snprintf(buf, sizeof(buf), "%s/%s", dir, f);
506              md->dir = eina_stringshare_add(buf);
507              modules = eina_list_append(modules, md);
508           }
509      }
510    return modules;
511 }
512 
513 E_API Eina_List *
e_module_desktop_list(void)514 e_module_desktop_list(void)
515 {
516    Eina_List *modules = NULL, *l;
517    E_Path_Dir *epd;
518 
519    EINA_LIST_FOREACH(path_modules->default_dir_list, l, epd)
520      {
521         modules = _e_module_desktop_list(modules, epd->dir);
522      }
523    EINA_LIST_FOREACH(*(path_modules->user_dir_list), l, epd)
524      {
525         modules = _e_module_desktop_list(modules, epd->dir);
526      }
527    return modules;
528 }
529 
530 E_API void
e_module_desktop_free(E_Module_Desktop * md)531 e_module_desktop_free(E_Module_Desktop *md)
532 {
533    if (!md) return;
534    eina_stringshare_del(md->dir);
535    efreet_desktop_free(md->desktop);
536    free(md);
537 }
538 
539 /* local subsystem functions */
540 
541 static void
_e_module_free(E_Module * m)542 _e_module_free(E_Module *m)
543 {
544    E_Config_Module *em;
545    Eina_List *l;
546 
547    EINA_LIST_FOREACH(e_config->modules, l, em)
548      {
549         if (!em) continue;
550         if (!e_util_strcmp(em->name, m->name))
551           {
552              e_config->modules = eina_list_remove(e_config->modules, em);
553              if (em->name) eina_stringshare_del(em->name);
554              E_FREE(em);
555              break;
556           }
557      }
558 
559    if ((m->enabled) && (!m->error))
560      {
561         if (m->func.save) m->func.save(m);
562         if (m->func.shutdown) m->func.shutdown(m);
563      }
564    if (m->name) eina_stringshare_del(m->name);
565    if (m->dir) eina_stringshare_del(m->dir);
566 //   if (m->handle) dlclose(m->handle); DONT dlclose! causes problems with deferred callbacks for free etc. - when their code goes away!
567    _e_modules = eina_list_remove(_e_modules, m);
568    free(m);
569 }
570 
571 typedef struct Disable_Dialog
572 {
573    char *title;
574    char *body;
575    E_Module *m;
576 } Disable_Dialog;
577 
578 static void
_e_module_dialog_disable_show(const char * title,const char * body,E_Module * m)579 _e_module_dialog_disable_show(const char *title, const char *body, E_Module *m)
580 {
581    E_Dialog *dia;
582    char buf[4096];
583 
584    dia = e_dialog_new(NULL, "E", "_module_unload_dialog");
585 
586    snprintf(buf, sizeof(buf), "%s<ps/>%s", body,
587             _("What action should be taken with this module?<ps/>"));
588 
589    e_dialog_title_set(dia, title);
590    e_dialog_icon_set(dia, "enlightenment", 64);
591    e_dialog_text_set(dia, buf);
592    e_dialog_button_add(dia, _("Unload"), NULL, _e_module_cb_dialog_disable, m);
593    e_dialog_button_add(dia, _("Keep"), NULL, NULL, NULL);
594    elm_win_center(dia->win, 1, 1);
595    e_win_no_remember_set(dia->win, 1);
596    e_dialog_show(dia);
597 }
598 
599 static Eina_Bool
_e_module_dialog_disable_timer(Disable_Dialog * dd)600 _e_module_dialog_disable_timer(Disable_Dialog *dd)
601 {
602    _e_module_dialog_disable_show(dd->title, dd->body, dd->m);
603    free(dd->title);
604    free(dd->body);
605    free(dd);
606    return EINA_FALSE;
607 }
608 
609 static void
_e_module_dialog_disable_create(const char * title,const char * body,E_Module * m)610 _e_module_dialog_disable_create(const char *title, const char *body, E_Module *m)
611 {
612    Disable_Dialog *dd;
613 
614    dd = E_NEW(Disable_Dialog, 1);
615    dd->title = strdup(title);
616    dd->body = strdup(body);
617    dd->m = m;
618    ecore_timer_loop_add(1.5, (Ecore_Task_Cb)_e_module_dialog_disable_timer, dd);
619    fprintf(stderr, "MODULE ERR: [%s]\n%s\n", title, body);
620 }
621 
622 static void
_e_module_cb_dialog_disable(void * data,E_Dialog * dia)623 _e_module_cb_dialog_disable(void *data, E_Dialog *dia)
624 {
625    E_Module *m;
626 
627    m = data;
628    e_module_disable(m);
629    e_object_del(E_OBJECT(m));
630    e_object_del(E_OBJECT(dia));
631    e_config_save_queue();
632 }
633 
634 static int
_e_module_sort_name(const void * d1,const void * d2)635 _e_module_sort_name(const void *d1, const void *d2)
636 {
637    const E_Config_Module *m1, *m2;
638 
639    m1 = d1;
640    if (!m1->name) return -1;
641    m2 = d2;
642    if (!m2->name) return 1;
643    return strcmp(m1->name, m2->name);
644 }
645 
646 static void
_e_module_event_update_free(void * data EINA_UNUSED,void * event)647 _e_module_event_update_free(void *data EINA_UNUSED, void *event)
648 {
649    E_Event_Module_Update *ev;
650 
651    if (!(ev = event)) return;
652    eina_stringshare_del(ev->name);
653    E_FREE(ev);
654 }
655 
656 static void
_cleanup_cb(void * data,E_Dialog * dialog)657 _cleanup_cb(void *data, E_Dialog *dialog)
658 {
659    Eina_List *badl = data;
660    const char *s;
661 
662    e_object_del(E_OBJECT(dialog));
663    EINA_LIST_FREE(badl, s)
664      eina_stringshare_del(s);
665 }
666 
667 static void
_ignore_cb(void * data,E_Dialog * dialog)668 _ignore_cb(void *data, E_Dialog *dialog)
669 {
670    const char *s;
671 
672    e_object_del(E_OBJECT(dialog));
673 
674    EINA_LIST_FREE(e_config->bad_modules, s)
675      eina_stringshare_del(s);
676    e_config->bad_modules = data;
677    e_config_save_queue();
678 }
679 
680 static Eina_Bool
_e_module_whitelist_dialog_timer(void * badl)681 _e_module_whitelist_dialog_timer(void *badl)
682 {
683    E_Dialog *dia;
684    Eina_Strbuf *sbuf;
685    Eina_List *l;
686    const char *s;
687 
688    dia = e_dialog_new(NULL,
689                       "E", "_module_whitelist_dialog");
690    sbuf = eina_strbuf_new();
691    eina_strbuf_append
692      (sbuf, _("The following modules are not standard ones for<ps/>"
693               "Enlightenment and may cause bugs and crashes.<ps/>"
694               "Please remove them before reporting any bugs.<ps/>"
695               "<ps/>"
696               "The module list is as follows:<ps/>"
697               "<ps/>"));
698    EINA_LIST_FOREACH(badl, l, s)
699      {
700         eina_strbuf_append(sbuf, s);
701         eina_strbuf_append(sbuf, "<ps/>");
702      }
703 
704    e_dialog_title_set(dia, _("Unstable module tainting"));
705    e_dialog_icon_set(dia, "enlightenment", 64);
706    e_dialog_text_set(dia, eina_strbuf_string_get(sbuf));
707    e_dialog_button_add(dia, _("OK"), NULL, _cleanup_cb, badl);
708    e_dialog_button_add(dia, _("I know"), NULL, _ignore_cb, badl);
709    elm_win_center(dia->win, 1, 1);
710    e_dialog_show(dia);
711    eina_strbuf_free(sbuf);
712    return EINA_FALSE;
713 }
714 
715 static void
_e_module_whitelist_check(void)716 _e_module_whitelist_check(void)
717 {
718    Eina_List *l, *badl = NULL;
719    E_Module *m;
720    unsigned int known = 0;
721    int i;
722    const char *s;
723    const char *goodmods[] =
724    {
725       "backlight",
726       "battery",
727       "bluez5",
728       "clock",
729       "conf",
730       "conf_applications",
731       "conf_comp",
732       "conf_dialogs",
733       "conf_display",
734       "conf_interaction",
735       "conf_intl",
736       "conf_bindings",
737       "conf_menus",
738       "conf_paths",
739       "conf_performance",
740       "conf_randr",
741       "conf_shelves",
742       "conf_theme",
743       "conf_window_manipulation",
744       "conf_window_remembers",
745       "connman",
746       "cpufreq",
747       "everything",
748       "fileman",
749       "fileman_opinfo",
750       "gadman",
751       "ibar",
752       "ibox",
753       "layout",
754       "lokker",
755       "polkit",
756       "luncher",
757       "mixer",
758       "msgbus",
759       "notification",
760       "ofono",
761       "pager",
762       "quickaccess",
763       "shot",
764       "start",
765       "syscon",
766       "sysinfo",
767       "systray",
768       "tasks",
769       "teamwork",
770       "temperature",
771       "tiling",
772       "time",
773       "winlist",
774       "wireless",
775       "wizard",
776       "wl_buffer",
777       "wl_desktop_shell",
778       "wl_x11",
779       "wl_wl",
780       "wl_drm",
781       "wl_shell",
782       "wl_desktop_shell",
783       "xkbswitch",
784       "music-control",
785       "appmenu",
786       "packagekit",
787       "policy_mobile",
788       "geolocation",
789       "xwayland",
790       NULL   // end marker
791    };
792 
793    EINA_LIST_FOREACH(_e_modules, l, m)
794      {
795         Eina_Bool ok;
796 
797         if (!m->name) continue;
798         ok = EINA_FALSE;
799         for (i = 0; goodmods[i]; i++)
800           {
801              if (!strcmp(m->name, goodmods[i]))
802                {
803                   ok = EINA_TRUE;
804                   break;
805                }
806           }
807         if (!ok) badl = eina_list_append(badl, eina_stringshare_add(m->name));
808      }
809 
810    EINA_LIST_FOREACH(badl, l, s)
811      {
812         const char *tmp;
813         Eina_List *ll;
814         Eina_Bool found = EINA_FALSE;
815 
816         EINA_LIST_FOREACH(e_config->bad_modules, ll, tmp)
817           {
818              if (!strcmp(s, tmp))
819                {
820                   found = EINA_TRUE;
821                   break;
822                }
823           }
824 
825         if (!found) break;
826         known++;
827      }
828 
829 #ifndef HAVE_WAYLAND_ONLY
830    {
831       const char *state;
832 
833       state = badl ? "YES" : "NO";
834 
835       if (e_comp->comp_type == E_PIXMAP_TYPE_X)
836         {
837            Ecore_X_Atom _x_tainted;
838            unsigned int _e_tainted = badl ? 1 : 0;
839 
840            _x_tainted = ecore_x_atom_get("_E_TAINTED");
841            ecore_x_window_prop_card32_set(ecore_x_window_root_first_get(),
842                                           _x_tainted, &_e_tainted, 1);
843         }
844 
845       e_env_set("E_TAINTED", state);
846    }
847 #endif
848 
849    if (eina_list_count(badl) != known)
850      ecore_timer_loop_add(1.5, _e_module_whitelist_dialog_timer, badl);
851    else
852      {
853         EINA_LIST_FREE(badl, s)
854           eina_stringshare_del(s);
855      }
856 }
857 
858