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