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