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