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