e_util: replaced getenv by e_util_env_get to avoid copying tainted string
[platform/upstream/enlightenment.git] / src / bin / e_main.c
1 #include "e.h"
2 #ifdef __linux__
3 # include <sys/prctl.h>
4 #endif
5 #ifdef HAVE_SYSTEMD
6 # include <systemd/sd-daemon.h>
7 #endif
8
9 #define MAX_LEVEL 80
10
11 #define TS_DO
12 #ifdef TS_DO
13 # define TS(x)                                                    \
14   {                                                               \
15      t1 = ecore_time_unix_get();                                  \
16      printf("ESTART: %1.5f [%1.5f] - %s\n", t1 - t0, t1 - t2, x); \
17      t2 = t1;                                                     \
18   }
19
20 # define TSB(x)                                                  \
21   do {                                                           \
22      TRACE_DS_BEGIN(ESTART: %s, x);                              \
23      TS(x);                                                      \
24   } while (0)
25 # define TSE(x)                                                  \
26   do {                                                           \
27      TRACE_DS_END();                                             \
28      TS(x);                                                      \
29   } while (0)
30 # define TSM(x)                                                  \
31   do {                                                           \
32      TRACE_DS_MARK(ESTART: %s, x);                               \
33      TS(x);                                                      \
34   } while (0)
35 static double t0, t1, t2;
36 #else
37 # define TS(x)
38 # define TSB(x)
39 # define TSE(x)
40 # define TSM(x)
41 #endif
42 /*
43  * i need to make more use of these when i'm baffled as to when something is
44  * up. other hooks:
45  *
46  *      void *(*__malloc_hook)(size_t size, const void *caller);
47  *
48  *      void *(*__realloc_hook)(void *ptr, size_t size, const void *caller);
49  *
50  *      void *(*__memalign_hook)(size_t alignment, size_t size,
51  *                               const void *caller);
52  *
53  *      void (*__free_hook)(void *ptr, const void *caller);
54  *
55  *      void (*__malloc_initialize_hook)(void);
56  *
57  *      void (*__after_morecore_hook)(void);
58  *
59
60    static void my_init_hook(void);
61    static void my_free_hook(void *p, const void *caller);
62
63    static void (*old_free_hook)(void *ptr, const void *caller) = NULL;
64    void (*__free_hook)(void *ptr, const void *caller);
65
66    void (*__malloc_initialize_hook) (void) = my_init_hook;
67    static void
68    my_init_hook(void)
69    {
70    old_free_hook = __free_hook;
71    __free_hook = my_free_hook;
72    }
73
74    //void *magicfree = NULL;
75
76    static void
77    my_free_hook(void *p, const void *caller)
78    {
79    __free_hook = old_free_hook;
80    //   if ((p) && (p == magicfree))
81    //     {
82    //   printf("CAUGHT!!!!! %p ...\n", p);
83    //   abort();
84    //     }
85    free(p);
86    __free_hook = my_free_hook;
87    }
88  */
89
90 /* local function prototypes */
91 static void      _e_main_shutdown(int errcode);
92 static void      _e_main_shutdown_push(int (*func)(void));
93 static void      _e_main_parse_arguments(int argc, char **argv);
94 static Eina_Bool _e_main_cb_signal_exit(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED);
95 static Eina_Bool _e_main_cb_signal_hup(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED);
96 static Eina_Bool _e_main_cb_signal_user(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev);
97 static int       _e_main_dirs_init(void);
98 static int       _e_main_dirs_shutdown(void);
99 static int       _e_main_path_init(void);
100 static int       _e_main_path_shutdown(void);
101 static int       _e_main_screens_init(void);
102 static int       _e_main_screens_shutdown(void);
103 static void      _e_main_desk_save(void);
104 static void      _e_main_desk_restore(void);
105 static void      _e_main_modules_load(Eina_Bool safe_mode);
106 static Eina_Bool _e_main_cb_idle_before(void *data EINA_UNUSED);
107 static Eina_Bool _e_main_cb_idle_after(void *data EINA_UNUSED);
108 static void      _e_main_create_wm_ready(void);
109 static void      _e_main_hooks_clean(void);
110 static void      _e_main_hook_call(E_Main_Hook_Point hookpoint, void *data EINA_UNUSED);
111
112 /* local variables */
113 static Eina_Bool really_know = EINA_FALSE;
114 static Eina_Bool inloop = EINA_FALSE;
115
116 static int _e_main_lvl = 0;
117 static int(*_e_main_shutdown_func[MAX_LEVEL]) (void);
118
119 static Ecore_Idle_Enterer *_idle_before = NULL;
120 static Ecore_Idle_Enterer *_idle_after = NULL;
121
122 static Ecore_Event_Handler *mod_init_end = NULL;
123
124 static Eina_List *hooks = NULL;
125
126 static int _e_main_hooks_delete = 0;
127 static int _e_main_hooks_walking = 0;
128
129 static Eina_Inlist *_e_main_hooks[] =
130 {
131    [E_MAIN_HOOK_MODULE_LOAD_DONE] = NULL,
132    [E_MAIN_HOOK_E_INFO_READY] = NULL
133 };
134
135 /* external variables */
136 E_API Eina_Bool e_precache_end = EINA_FALSE;
137 E_API Eina_Bool good = EINA_FALSE;
138 E_API Eina_Bool evil = EINA_FALSE;
139 E_API Eina_Bool starting = EINA_TRUE;
140 E_API Eina_Bool stopping = EINA_FALSE;
141 E_API Eina_Bool restart = EINA_FALSE;
142 E_API Eina_Bool e_nopause = EINA_FALSE;
143
144 static Eina_Bool
145 _xdg_check_str(const char *env, const char *str)
146 {
147    const char *p;
148    size_t len;
149
150    len = strlen(str);
151    for (p = strstr(env, str); p; p++, p = strstr(p, str))
152      {
153         if ((!p[len]) || (p[len] == ':')) return EINA_TRUE;
154      }
155    return EINA_FALSE;
156 }
157
158 static void
159 _xdg_data_dirs_augment(void)
160 {
161    char *s;
162    const char *p = e_prefix_get();
163    char newpath[4096], buf[4096];
164
165    if (!p) return;
166
167    s = e_util_env_get("XDG_DATA_DIRS");
168    if (s)
169      {
170         Eina_Bool pfxdata, pfx;
171
172         pfxdata = !_xdg_check_str(s, e_prefix_data_get());
173         snprintf(newpath, sizeof(newpath), "%s/share", p);
174         pfx = !_xdg_check_str(s, newpath);
175         if (pfxdata || pfx)
176           {
177              snprintf(buf, sizeof(buf), "%s%s%s%s%s",
178                pfxdata ? e_prefix_data_get() : "",
179                pfxdata ? ":" : "",
180                pfx ? newpath : "",
181                pfx ? ":" : "",
182                s);
183              e_util_env_set("XDG_DATA_DIRS", buf);
184           }
185         E_FREE(s);
186      }
187    else
188      {
189         snprintf(buf, sizeof(buf), "%s:%s/share:/usr/local/share:/usr/share", e_prefix_data_get(), p);
190         e_util_env_set("XDG_DATA_DIRS", buf);
191      }
192
193    s = e_util_env_get("XDG_CONFIG_DIRS");
194    snprintf(newpath, sizeof(newpath), "%s/etc/xdg", p);
195    if (s)
196      {
197         if (!_xdg_check_str(s, newpath))
198           {
199              snprintf(buf, sizeof(buf), "%s:%s", newpath, s);
200              e_util_env_set("XDG_CONFIG_DIRS", buf);
201           }
202         E_FREE(s);
203      }
204    else
205      {
206         snprintf(buf, sizeof(buf), "%s:/etc/xdg", newpath);
207         e_util_env_set("XDG_CONFIG_DIRS", buf);
208      }
209
210    s = e_util_env_get("XDG_RUNTIME_DIR");
211    if (s)
212      E_FREE(s);
213    else
214      {
215         const char *dir;
216
217         snprintf(buf, sizeof(buf), "/tmp/xdg-XXXXXX");
218         dir = mkdtemp(buf);
219         if (!dir) dir = "/tmp";
220         else
221           {
222              e_util_env_set("XDG_RUNTIME_DIR", dir);
223              snprintf(buf, sizeof(buf), "%s/.e-deleteme", dir);
224              ecore_file_mkdir(buf);
225           }
226      }
227
228    /* set menu prefix so we get our e menu */
229    s = e_util_env_get("XDG_MENU_PREFIX");
230    if (s)
231      E_FREE(s);
232    else
233      e_util_env_set("XDG_MENU_PREFIX", "e-");
234 }
235
236 static Eina_Bool
237 _e_main_subsystem_defer(void *data EINA_UNUSED)
238 {
239    int argc;
240    char **argv;
241
242    TRACE_DS_BEGIN(MAIN:SUBSYSTEMS DEFER);
243
244    ecore_app_args_get(&argc, &argv);
245
246    /* try to init delayed subsystems */
247
248    TRACE_DS_BEGIN(MAIN:DEFERRED INTERNAL SUBSYSTEMS INIT);
249
250    TSB("[DEFERRED] DPMS Init");
251    if (!e_dpms_init())
252      {
253         e_error_message_show(_("Enlightenment cannot set up dpms.\n"));
254         goto failed;
255      }
256    TSE("[DEFERRED] DPMS Init Done");
257    _e_main_shutdown_push(e_dpms_shutdown);
258
259    TSB("[DEFERRED] Screens Init: win");
260    if (!e_win_init())
261      {
262         e_error_message_show(_("Enlightenment cannot setup elementary trap!\n"));
263         goto failed;
264      }
265    TSE("[DEFERRED] Screens Init: win Done");
266
267    TSB("[DEFERRED] E_Dnd Init");
268    if (!e_dnd_init())
269      {
270         e_error_message_show(_("Enlightenment cannot set up its dnd system.\n"));
271         goto failed;
272      }
273    TSE("[DEFERRED] E_Dnd Init Done");
274    _e_main_shutdown_push(e_dnd_shutdown);
275
276    TSB("[DEFERRED] E_Scale Init");
277    if (!e_scale_init())
278      {
279         e_error_message_show(_("Enlightenment cannot set up its scale system.\n"));
280         goto failed;
281      }
282    TSE("[DEFERRED] E_Scale Init Done");
283    _e_main_shutdown_push(e_scale_shutdown);
284
285    TSB("[DEFERRED] E_Test_Helper Init");
286    e_test_helper_init();
287    _e_main_shutdown_push(e_test_helper_shutdown);
288    TSE("[DEFERRED] E_Test_Helper Done");
289
290    TSB("[DEFERRED] E_INFO_SERVER Init");
291    e_info_server_init();
292    _e_main_shutdown_push(e_info_server_shutdown);
293    TSE("[DEFERRED] E_INFO_SERVER Done");
294
295    TRACE_DS_END();
296    TRACE_DS_BEGIN(MAIN:DEFERRED COMP JOB);
297
298    /* try to do deferred job of any subsystems*/
299    TSB("[DEFERRED] Compositor's deferred job");
300    e_comp_deferred_job();
301    TSE("[DEFERRED] Compositor's deferred job Done");
302
303    if (e_config->use_e_policy)
304      {
305         TSB("[DEFERRED] E_Policy's deferred job");
306         e_policy_deferred_job();
307         TSE("[DEFERRED] E_Policy's deferred job Done");
308      }
309
310    TSB("[DEFERRED] E_Module's deferred job");
311    e_module_deferred_job();
312    TSE("[DEFERRED] E_Module's deferred job Done");
313
314    TRACE_DS_END();
315    TRACE_DS_END();
316    return ECORE_CALLBACK_DONE;
317
318 failed:
319    TSE("INIT FAILED");
320    TRACE_DS_END();
321    TRACE_DS_END();
322    _e_main_shutdown(-1);
323    return ECORE_CALLBACK_DONE;
324 }
325
326 static Eina_Bool
327 _e_main_deferred_job_schedule(void *d EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
328 {
329    PRCTL("[Winsys] all modules loaded");
330    ecore_idler_add(_e_main_subsystem_defer, NULL);
331    return ECORE_CALLBACK_DONE;
332 }
333
334 /* externally accessible functions */
335 int
336 main(int argc, char **argv)
337 {
338    Eina_Bool safe_mode = EINA_FALSE;
339    double t = 0.0, tstart = 0.0;
340    char *s = NULL, *s1 = NULL, buff[32];
341    struct sigaction action;
342
343 #ifdef __linux__
344 # ifdef PR_SET_PTRACER
345 #  ifdef PR_SET_PTRACER_ANY
346    prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
347 #  endif
348 # endif
349 #endif
350 #ifdef TS_DO
351    t0 = t1 = t2 = ecore_time_unix_get();
352    printf("ESTART(main) %1.5f\n", t0);
353 #endif
354    TRACE_DS_BEGIN(MAIN:BEGIN STARTUP);
355    TSB("Begin Startup");
356    PRCTL("[Winsys] start of main");
357
358    /* trap deadly bug signals and allow some form of sane recovery */
359    /* or ability to gdb attach and debug at this point - better than your */
360    /* wm/desktop vanishing and not knowing what happened */
361
362    /* don't install SIGBUS handler */
363    /* Wayland shm sets up a sigbus handler for catching invalid shm region */
364    /* access. If we setup our sigbus handler here, then the wl-shm sigbus */
365    /* handler will not function properly */
366    s = e_util_env_get("NOTIFY_SOCKET");
367    if (s)
368      E_FREE(s);
369    else
370      {
371         TSB("Signal Trap");
372         action.sa_sigaction = e_sigseg_act;
373         action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
374         sigemptyset(&action.sa_mask);
375         sigaction(SIGSEGV, &action, NULL);
376
377         action.sa_sigaction = e_sigill_act;
378         action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
379         sigemptyset(&action.sa_mask);
380         sigaction(SIGILL, &action, NULL);
381
382         action.sa_sigaction = e_sigfpe_act;
383         action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
384         sigemptyset(&action.sa_mask);
385         sigaction(SIGFPE, &action, NULL);
386
387         action.sa_sigaction = e_sigabrt_act;
388         action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
389         sigemptyset(&action.sa_mask);
390         sigaction(SIGABRT, &action, NULL);
391         TSE("Signal Trap Done");
392      }
393
394    t = ecore_time_unix_get();
395    s = e_util_env_get("E_START_TIME");
396    if (s)
397      {
398         s1 = e_util_env_get("E_RESTART_OK");
399         if (s1)
400           E_FREE(s1); /* do nothing... */
401         else
402           {
403              /* enable safe mode
404               * 1. E_RESTART_OK is not defined.
405               * 2. the diff time between this and previous start is less than 5 seconds.
406               */
407              tstart = atof(s);
408              if ((t - tstart) < 5.0) safe_mode = EINA_TRUE;
409           }
410         E_FREE(s);
411      }
412
413    /* save start time to environment variable to calculate
414     * diff time at the next restart
415     */
416    tstart = t;
417    snprintf(buff, sizeof(buff), "%1.1f", tstart);
418    e_util_env_set("E_START_TIME", buff);
419
420    s = e_util_env_get("E_START_MTRACK");
421    if (s)
422      {
423         e_util_env_set("MTRACK", NULL);
424         E_FREE(s);
425      }
426    TSB("Eina Init");
427    if (!eina_init())
428      {
429         e_error_message_show(_("Enlightenment cannot initialize Eina!\n"));
430         goto failed;
431      }
432    TSE("Eina Init Done");
433    _e_main_shutdown_push(eina_shutdown);
434
435 #ifdef OBJECT_HASH_CHECK
436    TSB("E_Object Hash Init");
437    e_object_hash_init();
438    TSE("E_Object Hash Init Done");
439 #endif
440
441    TSB("E_Log Init");
442    if (!e_log_init())
443      {
444         e_error_message_show(_("Enlightenment could not create a logging domain!\n"));
445         goto failed;
446      }
447    TSE("E_Log Init Done");
448    _e_main_shutdown_push(e_log_shutdown);
449
450    TSB("Determine Prefix");
451    if (!e_prefix_determine(argv[0]))
452      {
453         fprintf(stderr,
454                 "ERROR: Enlightenment cannot determine it's installed\n"
455                 "       prefix from the system or argv[0].\n"
456                 "       This is because it is not on Linux AND has been\n"
457                 "       executed strangely. This is unusual.\n");
458      }
459    TSE("Determine Prefix Done");
460
461    /* for debugging by redirecting stdout of e to a log file to tail */
462    setvbuf(stdout, NULL, _IONBF, 0);
463
464    TSB("Parse Arguments");
465    _e_main_parse_arguments(argc, argv);
466    TSE("Parse Arguments Done");
467
468    /*** Initialize Core EFL Libraries We Need ***/
469
470    TSB("Eet Init");
471    if (!eet_init())
472      {
473         e_error_message_show(_("Enlightenment cannot initialize Eet!\n"));
474         goto failed;
475      }
476    TSE("Eet Init Done");
477    _e_main_shutdown_push(eet_shutdown);
478
479    /* Allow ecore to not load system modules.
480     * Without it ecore_init will block until dbus authentication
481     * and registration are complete.
482     */
483    ecore_app_no_system_modules();
484
485    TSB("Ecore Init");
486    if (!ecore_init())
487      {
488         e_error_message_show(_("Enlightenment cannot initialize Ecore!\n"));
489         goto failed;
490      }
491    TSE("Ecore Init Done");
492    _e_main_shutdown_push(ecore_shutdown);
493
494    TSB("EIO Init");
495    if (!eio_init())
496      {
497         e_error_message_show(_("Enlightenment cannot initialize EIO!\n"));
498         goto failed;
499      }
500    TSE("EIO Init Done");
501    _e_main_shutdown_push(eio_shutdown);
502
503    ecore_app_args_set(argc, (const char **)argv);
504
505    TSB("Ecore Event Handlers");
506    if (!ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT,
507                                 _e_main_cb_signal_exit, NULL))
508      {
509         e_error_message_show(_("Enlightenment cannot set up an exit signal handler.\n"
510                                "Perhaps you are out of memory?"));
511         goto failed;
512      }
513    if (!ecore_event_handler_add(ECORE_EVENT_SIGNAL_HUP,
514                                 _e_main_cb_signal_hup, NULL))
515      {
516         e_error_message_show(_("Enlightenment cannot set up a HUP signal handler.\n"
517                                "Perhaps you are out of memory?"));
518         goto failed;
519      }
520    if (!ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
521                                 _e_main_cb_signal_user, NULL))
522      {
523         e_error_message_show(_("Enlightenment cannot set up a USER signal handler.\n"
524                                "Perhaps you are out of memory?"));
525         goto failed;
526      }
527    TSE("Ecore Event Handlers Done");
528
529    TSB("Ecore_File Init");
530    if (!ecore_file_init())
531      {
532         e_error_message_show(_("Enlightenment cannot initialize Ecore_File!\n"));
533         goto failed;
534      }
535    TSE("Ecore_File Init Done");
536    _e_main_shutdown_push(ecore_file_shutdown);
537
538    _idle_before = ecore_idle_enterer_before_add(_e_main_cb_idle_before, NULL);
539
540    TSB("XDG_DATA_DIRS Init");
541    _xdg_data_dirs_augment();
542    TSE("XDG_DATA_DIRS Init Done");
543
544    TSB("Ecore_Evas Init");
545    if (!ecore_evas_init())
546      {
547         e_error_message_show(_("Enlightenment cannot initialize Ecore_Evas!\n"));
548         goto failed;
549      }
550    TSE("Ecore_Evas Init Done");
551
552    /* e doesn't sync to compositor - it should be one */
553    ecore_evas_app_comp_sync_set(0);
554
555    TSB("Edje Init");
556    if (!edje_init())
557      {
558         e_error_message_show(_("Enlightenment cannot initialize Edje!\n"));
559         goto failed;
560      }
561    TSE("Edje Init Done");
562    _e_main_shutdown_push(edje_shutdown);
563
564    /*** Initialize E Subsystems We Need ***/
565
566    TSB("E User Init");
567    if (!e_user_init())
568      {
569         e_error_message_show(_("Enlightenment cannot set up user home path\n"));
570         goto failed;
571      }
572    TSE("E User Init Done");
573    _e_main_shutdown_push(e_user_shutdown);
574
575    TSB("E Directories Init");
576    /* setup directories we will be using for configurations storage etc. */
577    if (!_e_main_dirs_init())
578      {
579         e_error_message_show(_("Enlightenment cannot create directories in your home directory.\n"
580                                "Perhaps you have no home directory or the disk is full?"));
581         goto failed;
582      }
583    TSE("E Directories Init Done");
584    _e_main_shutdown_push(_e_main_dirs_shutdown);
585
586    TSB("E_Config Init");
587    if (!e_config_init())
588      {
589         e_error_message_show(_("Enlightenment cannot set up its config system.\n"));
590         goto failed;
591      }
592    TSE("E_Config Init Done");
593    _e_main_shutdown_push(e_config_shutdown);
594
595    TSB("E_Env Init");
596    if (!e_env_init())
597      {
598         e_error_message_show(_("Enlightenment cannot set up its environment.\n"));
599         goto failed;
600      }
601    TSE("E_Env Init Done");
602    _e_main_shutdown_push(e_env_shutdown);
603
604    ecore_exe_run_priority_set(e_config->priority);
605
606    TSB("E Paths Init");
607    if (!_e_main_path_init())
608      {
609         e_error_message_show(_("Enlightenment cannot set up paths for finding files.\n"
610                                "Perhaps you are out of memory?"));
611         goto failed;
612      }
613    TSE("E Paths Init Done");
614    _e_main_shutdown_push(_e_main_path_shutdown);
615
616    ecore_animator_frametime_set(1.0 / e_config->framerate);
617
618    TSB("E_Theme Init");
619    if (!e_theme_init())
620      {
621         e_error_message_show(_("Enlightenment cannot set up its theme system.\n"));
622         goto failed;
623      }
624    TSE("E_Theme Init Done");
625    _e_main_shutdown_push(e_theme_shutdown);
626
627    TSB("E_Actions Init");
628    if (!e_actions_init())
629      {
630         e_error_message_show(_("Enlightenment cannot set up its actions system.\n"));
631         goto failed;
632      }
633    TSE("E_Actions Init Done");
634    _e_main_shutdown_push(e_actions_shutdown);
635
636    /* these just add event handlers and can't fail
637     * timestamping them is dumb.
638     */
639    e_screensaver_preinit();
640    e_zone_init();
641    e_desk_init();
642    e_slot_init();
643
644    TRACE_DS_BEGIN(MAIN:WAIT /dev/dri/card0);
645    if (e_config->sleep_for_dri)
646      {
647         while(access("/dev/dri/card0", F_OK) != 0)
648           {
649              struct timespec req, rem;
650              req.tv_sec = 0;
651              req.tv_nsec = 50000000L;
652              nanosleep(&req, &rem);
653           }
654      }
655    TRACE_DS_END();
656
657    e_module_event_init();
658
659    TSB("E_Pointer Init");
660    if (!e_pointer_init())
661      {
662         e_error_message_show(_("Enlightenment cannot set up its pointer system.\n"));
663         goto failed;
664      }
665    TSE("E_Pointer Init Done");
666    _e_main_shutdown_push(e_pointer_shutdown);
667
668    TRACE_DS_BEGIN(MAIN:SCREEN INIT);
669    TSB("Screens Init");
670    if (!_e_main_screens_init())
671      {
672         e_error_message_show(_("Enlightenment set up window management for all the screens on your system\n"
673                                "failed. Perhaps another window manager is running?\n"));
674         goto failed;
675      }
676    TSE("Screens Init Done");
677    _e_main_shutdown_push(_e_main_screens_shutdown);
678    TRACE_DS_END();
679
680    if (e_config->eom_enable)
681      {
682         TSB("Eom Init");
683         if (!e_eom_init())
684           {
685              e_error_message_show(_("Enlightenment cannot set up eom.\n"));
686              goto failed;
687           }
688         TSE("Eom Init Done");
689         _e_main_shutdown_push(e_eom_shutdown);
690      }
691
692    TSB("E_Screensaver Init");
693    if (!e_screensaver_init())
694      {
695         e_error_message_show(_("Enlightenment cannot configure the X screensaver.\n"));
696         goto failed;
697      }
698    TSE("E_Screensaver Init Done");
699    _e_main_shutdown_push(e_screensaver_shutdown);
700
701    TSB("E_Comp Freeze");
702    e_comp_all_freeze();
703    TSE("E_Comp Freeze Done");
704
705    TSB("E_Grabinput Init");
706    if (!e_grabinput_init())
707      {
708         e_error_message_show(_("Enlightenment cannot set up its grab input handling system.\n"));
709         goto failed;
710      }
711    TSE("E_Grabinput Init Done");
712    _e_main_shutdown_push(e_grabinput_shutdown);
713
714    TS("E_Gesture Init");
715    e_gesture_init();
716    _e_main_shutdown_push(e_gesture_shutdown);
717
718    ecore_event_handler_add(E_EVENT_MODULE_INIT_END, _e_main_deferred_job_schedule, NULL);
719
720    TSB("E_Module Init");
721    if (!e_module_init())
722      {
723         e_error_message_show(_("Enlightenment cannot set up its module system.\n"));
724         goto failed;
725      }
726    TSE("E_Module Init Done");
727    _e_main_shutdown_push(e_module_shutdown);
728
729    TSB("E_Mouse Init");
730    if (!e_mouse_update())
731      {
732         e_error_message_show(_("Enlightenment cannot configure the mouse settings.\n"));
733         goto failed;
734      }
735    TSE("E_Mouse Init Done");
736
737    TSB("E_Icon Init");
738    if (!e_icon_init())
739      {
740         e_error_message_show(_("Enlightenment cannot initialize the Icon Cache system.\n"));
741         goto failed;
742      }
743    TSE("E_Icon Init Done");
744    _e_main_shutdown_push(e_icon_shutdown);
745
746    if (e_config->use_e_policy)
747      {
748         TSB("E_Policy Init");
749         if (!e_policy_init())
750           {
751              e_error_message_show(_("Enlightenment cannot setup policy system!\n"));
752              goto failed;
753           }
754         TSE("E_Policy Init Done");
755         _e_main_shutdown_push(e_policy_shutdown);
756      }
757
758    TSB("E_Process Init");
759    if (!e_process_init())
760      {
761         e_error_message_show(_("Enlightenment cannot setup process managing system!\n"));
762         goto failed;
763      }
764    TSE("E_Process Init Done");
765    _e_main_shutdown_push(e_process_shutdown);
766
767    TSB("E_Security Init");
768    if (!e_security_init())
769      {
770         e_error_message_show(_("Enlightenment cannot setup security system!\n"));
771         goto failed;
772      }
773    TSE("E_Security Init Done");
774    _e_main_shutdown_push(e_security_shutdown);
775
776    TSB("Load Modules");
777    _e_main_modules_load(safe_mode);
778    TSE("Load Modules Done");
779
780    TSB("E_Comp Thaw");
781    e_comp_all_thaw();
782    TSE("E_Comp Thaw Done");
783
784    _idle_after = ecore_idle_enterer_add(_e_main_cb_idle_after, NULL);
785
786    starting = EINA_FALSE;
787    inloop = EINA_TRUE;
788
789    e_util_env_set("E_RESTART", "1");
790
791    TSM("MAIN LOOP AT LAST");
792
793    if (e_config->create_wm_ready)
794      _e_main_create_wm_ready();
795
796    TRACE_DS_END();
797
798 #ifdef HAVE_SYSTEMD
799    TSM("[WM] Send start-up completion");
800    sd_notify(0, "READY=1");
801 #else
802    TSM("[WM] Skip sending start-up completion. (no systemd)");
803 #endif
804    ecore_main_loop_begin();
805
806    inloop = EINA_FALSE;
807
808    ELOGF("COMP", "STOPPING enlightenment...", NULL, NULL);
809    stopping = EINA_TRUE;
810
811    _e_main_desk_save();
812    e_comp_internal_save();
813
814    _e_main_shutdown(0);
815
816    if (restart)
817      {
818         e_util_env_set("E_RESTART_OK", "1");
819         s = e_util_env_get("E_START_MTRACK");
820         if (s)
821           {
822              e_util_env_set("MTRACK", "track");
823              E_FREE(s);
824           }
825         ecore_app_restart();
826      }
827
828    e_prefix_shutdown();
829
830    return 0;
831
832 failed:
833    TSE("INIT FAILED");
834    TRACE_DS_END();
835    _e_main_shutdown(-1);
836 }
837
838 E_API double
839 e_main_ts(const char *str)
840 {
841    double ret;
842    t1 = ecore_time_unix_get();
843    printf("ESTART: %1.5f [%1.5f] - %s\n", t1 - t0, t1 - t2, str);
844    ret = t1 - t2;
845    t2 = t1;
846    return ret;
847 }
848
849 E_API double
850 e_main_ts_begin(const char *str)
851 {
852    TRACE_DS_BEGIN(ESTART: %s, str);
853    return e_main_ts(str);
854 }
855
856 E_API double
857 e_main_ts_end(const char *str)
858 {
859    TRACE_DS_END();
860    return e_main_ts(str);
861 }
862
863 /* local functions */
864 static void
865 _e_main_shutdown(int errcode)
866 {
867    int i = 0;
868    char buf[PATH_MAX];
869    char *dir;
870
871    printf("E: Begin Shutdown Procedure!\n");
872
873    E_FREE_LIST(hooks, e_main_hook_del);
874
875    if (_idle_before) ecore_idle_enterer_del(_idle_before);
876    _idle_before = NULL;
877    if (_idle_after) ecore_idle_enterer_del(_idle_after);
878    _idle_after = NULL;
879
880    dir = e_util_env_get("XDG_RUNTIME_DIR");
881    if (dir)
882      {
883         char buf_env[PATH_MAX];
884         snprintf(buf_env, sizeof(buf_env), "%s", dir);
885         snprintf(buf, sizeof(buf), "%s/.e-deleteme", buf_env);
886         if (ecore_file_exists(buf)) ecore_file_recursive_rm(buf_env);
887         E_FREE(dir);
888      }
889    for (i = (_e_main_lvl - 1); i >= 0; i--)
890      (*_e_main_shutdown_func[i])();
891 #ifdef OBJECT_HASH_CHECK
892    e_object_hash_shutdown();
893 #endif
894    if (errcode < 0) exit(errcode);
895 }
896
897 static void
898 _e_main_shutdown_push(int (*func)(void))
899 {
900    _e_main_lvl++;
901    if (_e_main_lvl > MAX_LEVEL)
902      {
903         _e_main_lvl--;
904         e_error_message_show("WARNING: too many init levels. MAX = %i\n",
905                              MAX_LEVEL);
906         return;
907      }
908    _e_main_shutdown_func[_e_main_lvl - 1] = func;
909 }
910
911 static void
912 _e_main_parse_arguments(int argc, char **argv)
913 {
914    int i = 0;
915
916    /* handle some command-line parameters */
917    for (i = 1; i < argc; i++)
918      {
919         if (!strcmp(argv[i], "-good"))
920           {
921              good = EINA_TRUE;
922              evil = EINA_FALSE;
923              printf("LA LA LA\n");
924           }
925         else if (!strcmp(argv[i], "-evil"))
926           {
927              good = EINA_FALSE;
928              evil = EINA_TRUE;
929              printf("MUHAHAHAHHAHAHAHAHA\n");
930           }
931         else if (!strcmp(argv[i], "-psychotic"))
932           {
933              good = EINA_TRUE;
934              evil = EINA_TRUE;
935              printf("MUHAHALALALALALALALA\n");
936           }
937         else if ((!strcmp(argv[i], "-profile")) && (i < (argc - 1)))
938           {
939              i++;
940              if (!getenv("E_CONF_PROFILE"))
941                e_util_env_set("E_CONF_PROFILE", argv[i]);
942           }
943         else if (!strcmp(argv[i], "-i-really-know-what-i-am-doing-and-accept-full-responsibility-for-it"))
944           really_know = EINA_TRUE;
945         else if (!strcmp(argv[i], "-nopause"))
946           e_nopause = EINA_TRUE;
947         else if ((!strcmp(argv[i], "-version")) ||
948                  (!strcmp(argv[i], "--version")))
949           {
950              printf(_("Version: %s\n"), PACKAGE_VERSION);
951              _e_main_shutdown(-1);
952           }
953         else if ((!strcmp(argv[i], "-h")) ||
954                  (!strcmp(argv[i], "-help")) ||
955                  (!strcmp(argv[i], "--help")))
956           {
957              printf
958                (_(
959                  "Options:\n"
960                  "\t-display DISPLAY\n"
961                  "\t\tConnect to display named DISPLAY.\n"
962                  "\t\tEG: -display :1.0\n"
963                  "\t-fake-xinerama-screen WxH+X+Y\n"
964                  "\t\tAdd a FAKE xinerama screen (instead of the real ones)\n"
965                  "\t\tgiven the geometry. Add as many as you like. They all\n"
966                  "\t\treplace the real xinerama screens, if any. This can\n"
967                  "\t\tbe used to simulate xinerama.\n"
968                  "\t\tEG: -fake-xinerama-screen 800x600+0+0 -fake-xinerama-screen 800x600+800+0\n"
969                  "\t-profile CONF_PROFILE\n"
970                  "\t\tUse the configuration profile CONF_PROFILE instead of the user selected default or just \"default\".\n"
971                  "\t-good\n"
972                  "\t\tBe good.\n"
973                  "\t-evil\n"
974                  "\t\tBe evil.\n"
975                  "\t-psychotic\n"
976                  "\t\tBe psychotic.\n"
977                  "\t-i-really-know-what-i-am-doing-and-accept-full-responsibility-for-it\n"
978                  "\t\tIf you need this help, you don't need this option.\n"
979                  "\t-version\n"
980                  )
981                );
982              _e_main_shutdown(-1);
983           }
984      }
985 }
986
987 static Eina_Bool
988 _e_main_cb_signal_exit(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED)
989 {
990    /* called on ctrl-c, kill (pid) (also SIGINT, SIGTERM and SIGQIT) */
991    ecore_main_loop_quit();
992    return ECORE_CALLBACK_RENEW;
993 }
994
995 static Eina_Bool
996 _e_main_cb_signal_hup(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED)
997 {
998    restart = 1;
999    ecore_main_loop_quit();
1000    return ECORE_CALLBACK_RENEW;
1001 }
1002
1003 static Eina_Bool
1004 _e_main_cb_signal_user(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev)
1005 {
1006    Ecore_Event_Signal_User *e = ev;
1007
1008    if (e->number == 1)
1009      {
1010 //        E_Action *a = e_action_find("configuration");
1011 //        if ((a) && (a->func.go)) a->func.go(NULL, NULL);
1012      }
1013    else if (e->number == 2)
1014      {
1015         // comp module has its own handler for this for enabling/disabling fps debug
1016      }
1017    return ECORE_CALLBACK_RENEW;
1018
1019 }
1020
1021 static int
1022 _e_main_dirs_init(void)
1023 {
1024    if(getenv("E_CONF_RO"))
1025      {
1026         return 1;
1027      }
1028
1029    const char *base;
1030    const char *dirs[] =
1031    {
1032       "backgrounds",
1033       "config",
1034       "themes",
1035       NULL
1036    };
1037
1038    base = e_user_dir_get();
1039    if (ecore_file_mksubdirs(base, dirs) != sizeof(dirs) / sizeof(dirs[0]) - 1)
1040      {
1041         e_error_message_show("Could not create one of the required "
1042                              "subdirectories of '%s'\n", base);
1043         return 0;
1044      }
1045
1046    return 1;
1047 }
1048
1049 static int
1050 _e_main_dirs_shutdown(void)
1051 {
1052    return 1;
1053 }
1054
1055 static int
1056 _e_main_path_init(void)
1057 {
1058    char buf[PATH_MAX];
1059
1060    /* setup data paths */
1061    path_data = e_path_new();
1062    if (!path_data)
1063      {
1064         e_error_message_show("Cannot allocate path for path_data\n");
1065         return 0;
1066      }
1067    e_prefix_data_concat_static(buf, "data");
1068    e_path_default_path_append(path_data, buf);
1069
1070    /* setup image paths */
1071    path_images = e_path_new();
1072    if (!path_images)
1073      {
1074         e_error_message_show("Cannot allocate path for path_images\n");
1075         return 0;
1076      }
1077    e_user_dir_concat_static(buf, "/images");
1078    e_path_default_path_append(path_images, buf);
1079    e_prefix_data_concat_static(buf, "data/images");
1080    e_path_default_path_append(path_images, buf);
1081
1082    /* setup font paths */
1083    path_fonts = e_path_new();
1084    if (!path_fonts)
1085      {
1086         e_error_message_show("Cannot allocate path for path_fonts\n");
1087         return 0;
1088      }
1089    e_user_dir_concat_static(buf, "/fonts");
1090    e_path_default_path_append(path_fonts, buf);
1091    e_prefix_data_concat_static(buf, "data/fonts");
1092    e_path_default_path_append(path_fonts, buf);
1093
1094    /* setup icon paths */
1095    path_icons = e_path_new();
1096    if (!path_icons)
1097      {
1098         e_error_message_show("Cannot allocate path for path_icons\n");
1099         return 0;
1100      }
1101    e_user_dir_concat_static(buf, "/icons");
1102    e_path_default_path_append(path_icons, buf);
1103    e_prefix_data_concat_static(buf, "data/icons");
1104    e_path_default_path_append(path_icons, buf);
1105
1106    /* setup module paths */
1107    path_modules = e_path_new();
1108    if (!path_modules)
1109      {
1110         e_error_message_show("Cannot allocate path for path_modules\n");
1111         return 0;
1112      }
1113    e_user_dir_concat_static(buf, "/modules");
1114    e_path_default_path_append(path_modules, buf);
1115    snprintf(buf, sizeof(buf), "%s/enlightenment/modules", e_prefix_lib_get());
1116    e_path_default_path_append(path_modules, buf);
1117    /* FIXME: eventually this has to go - moduels should have installers that
1118     * add appropriate install paths (if not installed to user homedir) to
1119     * e's module search dirs
1120     */
1121    snprintf(buf, sizeof(buf), "%s/enlightenment/modules_extra", e_prefix_lib_get());
1122    e_path_default_path_append(path_modules, buf);
1123
1124    /* setup background paths */
1125    path_backgrounds = e_path_new();
1126    if (!path_backgrounds)
1127      {
1128         e_error_message_show("Cannot allocate path for path_backgrounds\n");
1129         return 0;
1130      }
1131    e_user_dir_concat_static(buf, "/backgrounds");
1132    e_path_default_path_append(path_backgrounds, buf);
1133    e_prefix_data_concat_static(buf, "data/backgrounds");
1134    e_path_default_path_append(path_backgrounds, buf);
1135
1136    path_messages = e_path_new();
1137    if (!path_messages)
1138      {
1139         e_error_message_show("Cannot allocate path for path_messages\n");
1140         return 0;
1141      }
1142    e_user_dir_concat_static(buf, "/locale");
1143    e_path_default_path_append(path_messages, buf);
1144    e_path_default_path_append(path_messages, e_prefix_locale_get());
1145
1146    return 1;
1147 }
1148
1149 static int
1150 _e_main_path_shutdown(void)
1151 {
1152    if (path_data)
1153      {
1154         e_object_del(E_OBJECT(path_data));
1155         path_data = NULL;
1156      }
1157    if (path_images)
1158      {
1159         e_object_del(E_OBJECT(path_images));
1160         path_images = NULL;
1161      }
1162    if (path_fonts)
1163      {
1164         e_object_del(E_OBJECT(path_fonts));
1165         path_fonts = NULL;
1166      }
1167    if (path_icons)
1168      {
1169         e_object_del(E_OBJECT(path_icons));
1170         path_icons = NULL;
1171      }
1172    if (path_modules)
1173      {
1174         e_object_del(E_OBJECT(path_modules));
1175         path_modules = NULL;
1176      }
1177    if (path_backgrounds)
1178      {
1179         e_object_del(E_OBJECT(path_backgrounds));
1180         path_backgrounds = NULL;
1181      }
1182    if (path_messages)
1183      {
1184         e_object_del(E_OBJECT(path_messages));
1185         path_messages = NULL;
1186      }
1187    return 1;
1188 }
1189
1190 static int
1191 _e_main_screens_init(void)
1192 {
1193    TSB("\tscreens: client");
1194    if (!e_client_init()) return 0;
1195    TSE("\tscreens: client Done");
1196
1197    TSB("Compositor Init");
1198    PRCTL("[Winsys] start of compositor init");
1199    if (!e_comp_init())
1200      {
1201         e_error_message_show(_("Enlightenment cannot create a compositor.\n"));
1202         _e_main_shutdown(-1);
1203      }
1204    TSE("Compositor Init Done");
1205
1206    PRCTL("[Winsys] end of compositor init");
1207    _e_main_desk_restore();
1208
1209    return 1;
1210 }
1211
1212 static int
1213 _e_main_screens_shutdown(void)
1214 {
1215    e_win_shutdown();
1216    e_comp_shutdown();
1217    e_client_shutdown();
1218
1219    e_slot_shutdown();
1220    e_desk_shutdown();
1221    e_zone_shutdown();
1222    return 1;
1223 }
1224
1225 static void
1226 _e_main_desk_save(void)
1227 {
1228    const Eina_List *l;
1229    char env[1024], name[1024];
1230    E_Zone *zone;
1231
1232    EINA_LIST_FOREACH(e_comp->zones, l, zone)
1233      {
1234         snprintf(name, sizeof(name), "DESK_%d_%d", 0, zone->num);
1235         snprintf(env, sizeof(env), "%d,%d", zone->desk_x_current, zone->desk_y_current);
1236         e_util_env_set(name, env);
1237      }
1238 }
1239
1240 static void
1241 _e_main_desk_restore(void)
1242 {
1243    E_Client *ec;
1244
1245    E_CLIENT_REVERSE_FOREACH(ec)
1246      if ((!e_client_util_ignored_get(ec)) && e_client_util_desk_visible(ec, e_desk_current_get(ec->zone)))
1247        {
1248           ec->want_focus = ec->take_focus = 1;
1249           break;
1250        }
1251 }
1252
1253 static Eina_Bool
1254 _e_main_modules_load_after(void *d EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
1255 {
1256    E_FREE_FUNC(mod_init_end, ecore_event_handler_del);
1257    return ECORE_CALLBACK_RENEW;
1258 }
1259
1260 static void
1261 _e_main_modules_load(Eina_Bool safe_mode)
1262 {
1263    if (!safe_mode)
1264      e_module_all_load();
1265    else
1266      {
1267         E_Module *m;
1268         char *crashmodule;
1269
1270         crashmodule = getenv("E_MODULE_LOAD");
1271         if (crashmodule) m = e_module_new(crashmodule);
1272
1273         if ((crashmodule) && (m))
1274           {
1275              e_module_disable(m);
1276              e_object_del(E_OBJECT(m));
1277
1278              e_error_message_show
1279                (_("Enlightenment crashed early on start and has<br>"
1280                   "been restarted. There was an error loading the<br>"
1281                   "module named: %s. This module has been disabled<br>"
1282                   "and will not be loaded."), crashmodule);
1283              e_util_dialog_show
1284                (_("Enlightenment crashed early on start and has been restarted"),
1285                _("Enlightenment crashed early on start and has been restarted.<br>"
1286                  "There was an error loading the module named: %s<br><br>"
1287                  "This module has been disabled and will not be loaded."), crashmodule);
1288              e_module_all_load();
1289           }
1290         else
1291           {
1292              e_error_message_show
1293                (_("Enlightenment crashed early on start and has<br>"
1294                   "been restarted. All modules have been disabled<br>"
1295                   "and will not be loaded to help remove any problem<br>"
1296                   "modules from your configuration. The module<br>"
1297                   "configuration dialog should let you select your<br>"
1298                   "modules again.\n"));
1299              e_util_dialog_show
1300                (_("Enlightenment crashed early on start and has been restarted"),
1301                _("Enlightenment crashed early on start and has been restarted.<br>"
1302                  "All modules have been disabled and will not be loaded to help<br>"
1303                  "remove any problem modules from your configuration.<br><br>"
1304                  "The module configuration dialog should let you select your<br>"
1305                  "modules again."));
1306           }
1307         mod_init_end = ecore_event_handler_add(E_EVENT_MODULE_INIT_END, _e_main_modules_load_after, NULL);
1308      }
1309 }
1310
1311 static Eina_Bool
1312 _e_main_cb_idle_before(void *data EINA_UNUSED)
1313 {
1314    e_client_idler_before();
1315    edje_thaw();
1316    return ECORE_CALLBACK_RENEW;
1317 }
1318
1319 static Eina_Bool
1320 _e_main_cb_idle_after(void *data EINA_UNUSED)
1321 {
1322    static int first_idle = 1;
1323
1324    eet_clearcache();
1325    edje_freeze();
1326
1327 #ifdef E_RELEASE_BUILD
1328    if (first_idle)
1329      {
1330         TSM("SLEEP");
1331         first_idle = 0;
1332         e_precache_end = EINA_TRUE;
1333      }
1334 #else
1335    if (first_idle++ < 60)
1336      {
1337         TSM("SLEEP");
1338         if (!first_idle)
1339           e_precache_end = EINA_TRUE;
1340      }
1341 #endif
1342
1343    return ECORE_CALLBACK_RENEW;
1344 }
1345
1346 static void
1347 _e_main_create_wm_ready(void)
1348 {
1349    FILE *_wmready_checker = NULL;
1350    const char *path_wm_ready = "/run/.wm_ready";
1351
1352    if (!e_util_file_realpath_check(path_wm_ready, EINA_TRUE))
1353      {
1354         WRN("%s is maybe link, so delete it\n", path_wm_ready);
1355      }
1356
1357    _wmready_checker = fopen(path_wm_ready, "wb");
1358    if (_wmready_checker)
1359      {
1360         TSM("[WM] WINDOW MANAGER is READY!!!");
1361         PRCTL("[Winsys] WINDOW MANAGER is READY!!!");
1362         fclose(_wmready_checker);
1363
1364         /*TODO: Next lines should be removed. */
1365         FILE *_tmp_wm_ready_checker;
1366
1367         _tmp_wm_ready_checker = fopen(path_wm_ready, "wb");
1368
1369         if (_tmp_wm_ready_checker)
1370           {
1371              TSM("[WM] temporary wm_ready path is created.");
1372              PRCTL("[Winsys] temporary wm_ready path is created.");
1373              fclose(_tmp_wm_ready_checker);
1374           }
1375         else
1376           {
1377              TSM("[WM] temporary wm_ready path create failed.");
1378              PRCTL("[Winsys] temporary wm_ready path create failed.");
1379           }
1380      }
1381    else
1382      {
1383         TSM("[WM] WINDOW MANAGER is READY. BUT, failed to create .wm_ready file.");
1384         PRCTL("[Winsys] WINDOW MANAGER is READY. BUT, failed to create .wm_ready file.");
1385      }
1386 }
1387
1388 static void
1389 _e_main_hooks_clean(void)
1390 {
1391    Eina_Inlist *l;
1392    E_Main_Hook *mh;
1393    unsigned int x;
1394
1395    for (x = 0; x < E_MAIN_HOOK_LAST; x++)
1396      EINA_INLIST_FOREACH_SAFE(_e_main_hooks[x], l, mh)
1397        {
1398           if (!mh->delete_me) continue;
1399           _e_main_hooks[x] = eina_inlist_remove(_e_main_hooks[x],
1400                                                 EINA_INLIST_GET(mh));
1401           free(mh);
1402        }
1403 }
1404
1405 static void
1406 _e_main_hook_call(E_Main_Hook_Point hookpoint, void *data EINA_UNUSED)
1407 {
1408    E_Main_Hook *mh;
1409
1410    _e_main_hooks_walking++;
1411    EINA_INLIST_FOREACH(_e_main_hooks[hookpoint], mh)
1412      {
1413         if (mh->delete_me) continue;
1414         mh->func(mh->data);
1415      }
1416    _e_main_hooks_walking--;
1417    if ((_e_main_hooks_walking == 0) && (_e_main_hooks_delete > 0))
1418      _e_main_hooks_clean();
1419 }
1420
1421 E_API E_Main_Hook *
1422 e_main_hook_add(E_Main_Hook_Point hookpoint, E_Main_Hook_Cb func, const void *data)
1423 {
1424    E_Main_Hook *mh;
1425
1426    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_MAIN_HOOK_LAST, NULL);
1427    mh = E_NEW(E_Main_Hook, 1);
1428    EINA_SAFETY_ON_NULL_RETURN_VAL(mh, NULL);
1429    mh->hookpoint = hookpoint;
1430    mh->func = func;
1431    mh->data = (void*)data;
1432    _e_main_hooks[hookpoint] = eina_inlist_append(_e_main_hooks[hookpoint],
1433                                                  EINA_INLIST_GET(mh));
1434    return mh;
1435 }
1436
1437 E_API void
1438 e_main_hook_del(E_Main_Hook *mh)
1439 {
1440    mh->delete_me = 1;
1441    if (_e_main_hooks_walking == 0)
1442      {
1443         _e_main_hooks[mh->hookpoint] = eina_inlist_remove(_e_main_hooks[mh->hookpoint],
1444                                                           EINA_INLIST_GET(mh));
1445         free(mh);
1446      }
1447    else
1448      _e_main_hooks_delete++;
1449 }
1450
1451 E_API void
1452 e_main_hook_call(E_Main_Hook_Point hookpoint)
1453 {
1454    if ((hookpoint < 0) || (hookpoint >= E_MAIN_HOOK_LAST)) return;
1455
1456    _e_main_hook_call(hookpoint, NULL);
1457 }