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