e_security: 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 #include "e_utils_intern.h"
6 #include "e_theme_intern.h"
7 #include "e_signals_intern.h"
8 #include "e_security_intern.h"
9
10 #ifdef __linux__
11 # include <sys/prctl.h>
12 #endif
13 #ifdef HAVE_SYSTEMD
14 # include <systemd/sd-daemon.h>
15 #endif
16
17 #define MAX_LEVEL 80
18
19 #define TS_DO
20 #ifdef TS_DO
21 # define TS(x)                                                    \
22   {                                                               \
23      t1 = ecore_time_unix_get();                                  \
24      printf("ESTART: %1.5f [%1.5f] - %s\n", t1 - t0, t1 - t2, x); \
25      t2 = t1;                                                     \
26   }
27
28 # define TSB(x)                                                  \
29   do {                                                           \
30      TRACE_DS_BEGIN(ESTART: %s, x);                              \
31      TS(x);                                                      \
32   } while (0)
33 # define TSE(x)                                                  \
34   do {                                                           \
35      TRACE_DS_END();                                             \
36      TS(x);                                                      \
37   } while (0)
38 # define TSM(x)                                                  \
39   do {                                                           \
40      TRACE_DS_MARK(ESTART: %s, x);                               \
41      TS(x);                                                      \
42   } while (0)
43 static double t0, t1, t2;
44 #else
45 # define TS(x)
46 # define TSB(x)
47 # define TSE(x)
48 # define TSM(x)
49 #endif
50 /*
51  * i need to make more use of these when i'm baffled as to when something is
52  * up. other hooks:
53  *
54  *      void *(*__malloc_hook)(size_t size, const void *caller);
55  *
56  *      void *(*__realloc_hook)(void *ptr, size_t size, const void *caller);
57  *
58  *      void *(*__memalign_hook)(size_t alignment, size_t size,
59  *                               const void *caller);
60  *
61  *      void (*__free_hook)(void *ptr, const void *caller);
62  *
63  *      void (*__malloc_initialize_hook)(void);
64  *
65  *      void (*__after_morecore_hook)(void);
66  *
67
68    static void my_init_hook(void);
69    static void my_free_hook(void *p, const void *caller);
70
71    static void (*old_free_hook)(void *ptr, const void *caller) = NULL;
72    void (*__free_hook)(void *ptr, const void *caller);
73
74    void (*__malloc_initialize_hook) (void) = my_init_hook;
75    static void
76    my_init_hook(void)
77    {
78    old_free_hook = __free_hook;
79    __free_hook = my_free_hook;
80    }
81
82    //void *magicfree = NULL;
83
84    static void
85    my_free_hook(void *p, const void *caller)
86    {
87    __free_hook = old_free_hook;
88    //   if ((p) && (p == magicfree))
89    //     {
90    //   printf("CAUGHT!!!!! %p ...\n", p);
91    //   abort();
92    //     }
93    free(p);
94    __free_hook = my_free_hook;
95    }
96  */
97
98 /* local function prototypes */
99 static void      _e_main_shutdown(int errcode);
100 static void      _e_main_shutdown_push(int (*func)(void));
101 static void      _e_main_parse_arguments(int argc, char **argv);
102 static Eina_Bool _e_main_cb_signal_exit(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED);
103 static Eina_Bool _e_main_cb_signal_hup(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED);
104 static int       _e_main_dirs_init(void);
105 static int       _e_main_dirs_shutdown(void);
106 static int       _e_main_path_init(void);
107 static int       _e_main_path_shutdown(void);
108 static int       _e_main_screens_init(void);
109 static int       _e_main_screens_shutdown(void);
110 static void      _e_main_desk_save(void);
111 static void      _e_main_desk_restore(void);
112 static Eina_Bool _e_main_cb_idle_before(void *data EINA_UNUSED);
113 static Eina_Bool _e_main_cb_idle_after(void *data EINA_UNUSED);
114 static void      _e_main_create_wm_ready(void);
115 static void      _e_main_hooks_clean(void);
116 static void      _e_main_hook_call(E_Main_Hook_Point hookpoint, void *data EINA_UNUSED);
117
118 /* local variables */
119 static int _e_main_lvl = 0;
120 static int(*_e_main_shutdown_func[MAX_LEVEL]) (void);
121
122 static Ecore_Idle_Enterer *_idle_before = NULL;
123 static Ecore_Idle_Enterer *_idle_after = NULL;
124
125 static Eina_List *hooks = NULL;
126
127 static int _e_main_hooks_delete = 0;
128 static int _e_main_hooks_walking = 0;
129
130 static Eina_Inlist *_e_main_hooks[] =
131 {
132    [E_MAIN_HOOK_MODULE_LOAD_DONE] = NULL,
133    [E_MAIN_HOOK_E_INFO_READY] = NULL,
134    [E_MAIN_HOOK_POST_CLIENT_IDLER_BEFORE] = NULL
135 };
136
137 /* external variables */
138 E_API Eina_Bool starting = EINA_TRUE;
139 E_API Eina_Bool stopping = EINA_FALSE;
140
141 static Eina_Bool
142 _xdg_check_str(const char *env, const char *str)
143 {
144    const char *p;
145    size_t len;
146
147    len = strlen(str);
148    for (p = strstr(env, str); p; p++, p = strstr(p, str))
149      {
150         if ((!p[len]) || (p[len] == ':')) return EINA_TRUE;
151      }
152    return EINA_FALSE;
153 }
154
155 static void
156 _xdg_data_dirs_augment(void)
157 {
158    char *s;
159    const char *p = e_prefix_get();
160    char newpath[PATH_MAX], buf[PATH_MAX + PATH_MAX + 200];
161
162    if (!p) return;
163
164    s = e_util_env_get("XDG_DATA_DIRS");
165    if (s)
166      {
167         Eina_Bool pfxdata, pfx;
168
169         pfxdata = !_xdg_check_str(s, e_prefix_data_get());
170         snprintf(newpath, sizeof(newpath), "%s/share", p);
171         pfx = !_xdg_check_str(s, newpath);
172         if (pfxdata || pfx)
173           {
174              snprintf(buf, sizeof(buf), "%s%s%s%s%s",
175                pfxdata ? e_prefix_data_get() : "",
176                pfxdata ? ":" : "",
177                pfx ? newpath : "",
178                pfx ? ":" : "",
179                s);
180              e_util_env_set("XDG_DATA_DIRS", buf);
181           }
182         E_FREE(s);
183      }
184    else
185      {
186         snprintf(buf, sizeof(buf), "%s:%s/share:/usr/local/share:/usr/share", e_prefix_data_get(), p);
187         e_util_env_set("XDG_DATA_DIRS", buf);
188      }
189
190    s = e_util_env_get("XDG_CONFIG_DIRS");
191    snprintf(newpath, sizeof(newpath), "%s/etc/xdg", p);
192    if (s)
193      {
194         if (!_xdg_check_str(s, newpath))
195           {
196              snprintf(buf, sizeof(buf), "%s:%s", newpath, s);
197              e_util_env_set("XDG_CONFIG_DIRS", buf);
198           }
199         E_FREE(s);
200      }
201    else
202      {
203         snprintf(buf, sizeof(buf), "%s:/etc/xdg", newpath);
204         e_util_env_set("XDG_CONFIG_DIRS", buf);
205      }
206
207    s = e_util_env_get("XDG_RUNTIME_DIR");
208    if (s)
209      E_FREE(s);
210    else
211      {
212         const char *dir;
213
214         snprintf(buf, sizeof(buf), "/tmp/xdg-XXXXXX");
215         dir = mkdtemp(buf);
216         if (!dir) dir = "/tmp";
217         else
218           {
219              e_util_env_set("XDG_RUNTIME_DIR", dir);
220              snprintf(buf, sizeof(buf), "%s/.e-deleteme", dir);
221              ecore_file_mkdir(buf);
222           }
223      }
224
225    /* set menu prefix so we get our e menu */
226    s = e_util_env_get("XDG_MENU_PREFIX");
227    if (s)
228      E_FREE(s);
229    else
230      e_util_env_set("XDG_MENU_PREFIX", "e-");
231 }
232
233 static Eina_Bool
234 _e_main_subsystem_defer(void *data EINA_UNUSED)
235 {
236    TRACE_DS_BEGIN(MAIN:SUBSYSTEMS DEFER);
237
238    /* try to init delayed subsystems */
239
240    TRACE_DS_BEGIN(MAIN:DEFERRED INTERNAL SUBSYSTEMS INIT);
241
242    TSB("[DEFERRED] DPMS Init");
243    if (!e_dpms_init())
244      {
245         e_error_message_show(_("Enlightenment cannot set up dpms.\n"));
246         goto failed;
247      }
248    TSE("[DEFERRED] DPMS Init Done");
249    _e_main_shutdown_push(e_dpms_shutdown);
250
251    TSB("[DEFERRED] E_Dnd Init");
252    if (!e_dnd_init())
253      {
254         e_error_message_show(_("Enlightenment cannot set up its dnd system.\n"));
255         goto failed;
256      }
257    TSE("[DEFERRED] E_Dnd Init Done");
258    _e_main_shutdown_push(e_dnd_shutdown);
259
260    TSB("[DEFERRED] E_Scale Init");
261    if (!e_scale_init())
262      {
263         e_error_message_show(_("Enlightenment cannot set up its scale system.\n"));
264         goto failed;
265      }
266    TSE("[DEFERRED] E_Scale Init Done");
267    _e_main_shutdown_push(e_scale_shutdown);
268
269    TSB("[DEFERRED] E_Test_Helper Init");
270    e_test_helper_init();
271    _e_main_shutdown_push(e_test_helper_shutdown);
272    TSE("[DEFERRED] E_Test_Helper Done");
273
274    TSB("[DEFERRED] E_INFO_SERVER Init");
275    e_info_server_init();
276    _e_main_shutdown_push(e_info_server_shutdown);
277    TSE("[DEFERRED] E_INFO_SERVER Done");
278
279    TRACE_DS_END();
280    TRACE_DS_BEGIN(MAIN:DEFERRED COMP JOB);
281
282    /* try to do deferred job of any subsystems*/
283    TSB("[DEFERRED] Compositor's deferred job");
284    e_comp_deferred_job();
285    TSE("[DEFERRED] Compositor's deferred job Done");
286
287    if (e_config->use_e_policy)
288      {
289         TSB("[DEFERRED] E_Policy's deferred job");
290         e_policy_deferred_job();
291         TSE("[DEFERRED] E_Policy's deferred job Done");
292      }
293
294    TSB("[DEFERRED] E_Module's deferred job");
295    e_module_deferred_job();
296    TSE("[DEFERRED] E_Module's deferred job Done");
297
298    TRACE_DS_END();
299    TRACE_DS_END();
300    return ECORE_CALLBACK_DONE;
301
302 failed:
303    TSE("INIT FAILED");
304    TRACE_DS_END();
305    TRACE_DS_END();
306    _e_main_shutdown(-1);
307    return ECORE_CALLBACK_DONE;
308 }
309
310 static Eina_Bool
311 _e_main_deferred_job_schedule(void *d EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
312 {
313    PRCTL("[Winsys] all modules loaded");
314    ecore_idler_add(_e_main_subsystem_defer, NULL);
315    return ECORE_CALLBACK_DONE;
316 }
317
318 /* externally accessible functions */
319 int
320 main(int argc, char **argv)
321 {
322    char *s = NULL;
323    struct sigaction action;
324
325 #ifdef __linux__
326 # ifdef PR_SET_PTRACER
327 #  ifdef PR_SET_PTRACER_ANY
328    prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
329 #  endif
330 # endif
331 #endif
332
333 #ifdef TIZEN_TEST_GCOV
334    setenv("GCOV_PREFIX", "/tmp", 1);
335 #endif
336
337    /* for debugging by redirecting stdout & stderr of e to a log file to tail */
338    setvbuf(stdout, NULL, _IONBF, 0);
339    setvbuf(stderr, NULL, _IONBF, 0);
340
341 #ifdef TS_DO
342    t0 = t1 = t2 = ecore_time_unix_get();
343    printf("ESTART(main) %1.5f\n", t0);
344 #endif
345    TRACE_DS_BEGIN(MAIN:BEGIN STARTUP);
346    TSB("Begin Startup");
347    PRCTL("[Winsys] start of main");
348
349    /* trap deadly bug signals and allow some form of sane recovery */
350    /* or ability to gdb attach and debug at this point - better than your */
351    /* wm/desktop vanishing and not knowing what happened */
352
353    /* don't install SIGBUS handler */
354    /* Wayland shm sets up a sigbus handler for catching invalid shm region */
355    /* access. If we setup our sigbus handler here, then the wl-shm sigbus */
356    /* handler will not function properly */
357    s = e_util_env_get("NOTIFY_SOCKET");
358    if (s)
359      E_FREE(s);
360    else
361      {
362         TSB("Signal Trap");
363         action.sa_sigaction = e_sigseg_act;
364         action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
365         sigemptyset(&action.sa_mask);
366         sigaction(SIGSEGV, &action, NULL);
367
368         action.sa_sigaction = e_sigill_act;
369         action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
370         sigemptyset(&action.sa_mask);
371         sigaction(SIGILL, &action, NULL);
372
373         action.sa_sigaction = e_sigfpe_act;
374         action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
375         sigemptyset(&action.sa_mask);
376         sigaction(SIGFPE, &action, NULL);
377
378         action.sa_sigaction = e_sigabrt_act;
379         action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
380         sigemptyset(&action.sa_mask);
381         sigaction(SIGABRT, &action, NULL);
382         TSE("Signal Trap Done");
383      }
384
385    TSB("Eina Init");
386    if (!eina_init())
387      {
388         e_error_message_show(_("Enlightenment cannot initialize Eina!\n"));
389         goto failed;
390      }
391    TSE("Eina Init Done");
392    _e_main_shutdown_push(eina_shutdown);
393
394 #ifdef OBJECT_HASH_CHECK
395    TSB("E_Object Hash Init");
396    e_object_hash_init();
397    TSE("E_Object Hash Init Done");
398 #endif
399
400    TSB("E_Log Init");
401    if (!e_log_init())
402      {
403         e_error_message_show(_("Enlightenment could not create a logging domain!\n"));
404         goto failed;
405      }
406    TSE("E_Log Init Done");
407    _e_main_shutdown_push(e_log_shutdown);
408
409    TSB("Determine Prefix");
410    if (!e_prefix_determine(argv[0]))
411      {
412         fprintf(stderr,
413                 "ERROR: Enlightenment cannot determine it's installed\n"
414                 "       prefix from the system or argv[0].\n"
415                 "       This is because it is not on Linux AND has been\n"
416                 "       executed strangely. This is unusual.\n");
417      }
418    TSE("Determine Prefix Done");
419
420    TSB("Parse Arguments");
421    _e_main_parse_arguments(argc, argv);
422    TSE("Parse Arguments Done");
423
424    /*** Initialize Core EFL Libraries We Need ***/
425
426    TSB("Eet Init");
427    if (!eet_init())
428      {
429         e_error_message_show(_("Enlightenment cannot initialize Eet!\n"));
430         goto failed;
431      }
432    TSE("Eet Init Done");
433    _e_main_shutdown_push(eet_shutdown);
434
435    /* Allow ecore to not load system modules.
436     * Without it ecore_init will block until dbus authentication
437     * and registration are complete.
438     */
439    ecore_app_no_system_modules();
440
441    TSB("Ecore Init");
442    if (!ecore_init())
443      {
444         e_error_message_show(_("Enlightenment cannot initialize Ecore!\n"));
445         goto failed;
446      }
447    TSE("Ecore Init Done");
448    _e_main_shutdown_push(ecore_shutdown);
449
450    TSB("EIO Init");
451    if (!eio_init())
452      {
453         e_error_message_show(_("Enlightenment cannot initialize EIO!\n"));
454         goto failed;
455      }
456    TSE("EIO Init Done");
457    _e_main_shutdown_push(eio_shutdown);
458
459    TSB("Ecore Event Handlers");
460    if (!ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT,
461                                 _e_main_cb_signal_exit, NULL))
462      {
463         e_error_message_show(_("Enlightenment cannot set up an exit signal handler.\n"
464                                "Perhaps you are out of memory?"));
465         goto failed;
466      }
467    if (!ecore_event_handler_add(ECORE_EVENT_SIGNAL_HUP,
468                                 _e_main_cb_signal_hup, NULL))
469      {
470         e_error_message_show(_("Enlightenment cannot set up a HUP signal handler.\n"
471                                "Perhaps you are out of memory?"));
472         goto failed;
473      }
474    TSE("Ecore Event Handlers Done");
475
476    TSB("Ecore_File Init");
477    if (!ecore_file_init())
478      {
479         e_error_message_show(_("Enlightenment cannot initialize Ecore_File!\n"));
480         goto failed;
481      }
482    TSE("Ecore_File Init Done");
483    _e_main_shutdown_push(ecore_file_shutdown);
484
485    TSB("E_Util_File_Monitor Init");
486    e_util_file_monitor_init();
487    TSE("E_Util_File_Monitor Init Done");
488    _e_main_shutdown_push(e_util_file_monitor_shutdown);
489
490    _idle_before = ecore_idle_enterer_before_add(_e_main_cb_idle_before, NULL);
491
492    TSB("XDG_DATA_DIRS Init");
493    _xdg_data_dirs_augment();
494    TSE("XDG_DATA_DIRS Init Done");
495
496    TSB("Ecore_Evas Init");
497    if (!ecore_evas_init())
498      {
499         e_error_message_show(_("Enlightenment cannot initialize Ecore_Evas!\n"));
500         goto failed;
501      }
502    TSE("Ecore_Evas Init Done");
503
504    TSB("Edje Init");
505    if (!edje_init())
506      {
507         e_error_message_show(_("Enlightenment cannot initialize Edje!\n"));
508         goto failed;
509      }
510    TSE("Edje Init Done");
511    _e_main_shutdown_push(edje_shutdown);
512
513    /*** Initialize E Subsystems We Need ***/
514
515    TSB("E User Init");
516    if (!e_user_init())
517      {
518         e_error_message_show(_("Enlightenment cannot set up user home path\n"));
519         goto failed;
520      }
521    TSE("E User Init Done");
522    _e_main_shutdown_push(e_user_shutdown);
523
524    TSB("E Directories Init");
525    /* setup directories we will be using for configurations storage etc. */
526    if (!_e_main_dirs_init())
527      {
528         e_error_message_show(_("Enlightenment cannot create directories in your home directory.\n"
529                                "Perhaps you have no home directory or the disk is full?"));
530         goto failed;
531      }
532    TSE("E Directories Init Done");
533    _e_main_shutdown_push(_e_main_dirs_shutdown);
534
535    TSB("E_Config Init");
536    if (!e_config_init())
537      {
538         e_error_message_show(_("Enlightenment cannot set up its config system.\n"));
539         goto failed;
540      }
541    TSE("E_Config Init Done");
542    _e_main_shutdown_push(e_config_shutdown);
543
544    TSB("E_Env Init");
545    if (!e_env_init())
546      {
547         e_error_message_show(_("Enlightenment cannot set up its environment.\n"));
548         goto failed;
549      }
550    TSE("E_Env Init Done");
551    _e_main_shutdown_push(e_env_shutdown);
552
553    ecore_exe_run_priority_set(e_config->priority);
554
555    TSB("E Paths Init");
556    if (!_e_main_path_init())
557      {
558         e_error_message_show(_("Enlightenment cannot set up paths for finding files.\n"
559                                "Perhaps you are out of memory?"));
560         goto failed;
561      }
562    TSE("E Paths Init Done");
563    _e_main_shutdown_push(_e_main_path_shutdown);
564
565    ecore_animator_frametime_set(1.0 / e_config->framerate);
566
567    TSB("E_Theme Init");
568    if (!e_theme_init())
569      {
570         e_error_message_show(_("Enlightenment cannot set up its theme system.\n"));
571         goto failed;
572      }
573    TSE("E_Theme Init Done");
574    _e_main_shutdown_push(e_theme_shutdown);
575
576    TSB("E_Actions Init");
577    if (!e_actions_init())
578      {
579         e_error_message_show(_("Enlightenment cannot set up its actions system.\n"));
580         goto failed;
581      }
582    TSE("E_Actions Init Done");
583    _e_main_shutdown_push(e_actions_shutdown);
584
585    /* these just add event handlers and can't fail
586     * timestamping them is dumb.
587     */
588    e_screensaver_preinit();
589    e_zone_init();
590    e_desk_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_comp_shutdown();
1129    e_client_shutdown();
1130
1131    e_magnifier_shutdown();
1132    e_desk_shutdown();
1133    e_zone_shutdown();
1134    return 1;
1135 }
1136
1137 static void
1138 _e_main_desk_save(void)
1139 {
1140    const Eina_List *l;
1141    char env[1024], name[1024];
1142    E_Zone *zone;
1143
1144    EINA_LIST_FOREACH(e_comp->zones, l, zone)
1145      {
1146         snprintf(name, sizeof(name), "DESK_%d_%d", 0, zone->num);
1147         snprintf(env, sizeof(env), "%d,%d", zone->desk_x_current, zone->desk_y_current);
1148         e_util_env_set(name, env);
1149      }
1150 }
1151
1152 static void
1153 _e_main_desk_restore(void)
1154 {
1155    E_Client *ec;
1156    E_Zone *zone;
1157
1158    E_CLIENT_REVERSE_FOREACH(ec)
1159      {
1160         zone = e_comp_zone_find_by_ec(ec);
1161         if ((!e_client_util_ignored_get(ec)) && e_desk_has_ec(e_desk_current_get(zone), ec))
1162           {
1163              ec->want_focus = ec->take_focus = 1;
1164              break;
1165           }
1166      }
1167 }
1168
1169 static Eina_Bool
1170 _e_main_cb_idle_before(void *data EINA_UNUSED)
1171 {
1172    e_comp_idler_before();
1173    _e_main_hook_call(E_MAIN_HOOK_POST_CLIENT_IDLER_BEFORE, NULL);
1174    edje_thaw();
1175
1176    return ECORE_CALLBACK_RENEW;
1177 }
1178
1179 static Eina_Bool
1180 _e_main_cb_idle_after(void *data EINA_UNUSED)
1181 {
1182    static int first_idle = 1;
1183
1184    eet_clearcache();
1185    edje_freeze();
1186
1187    if (first_idle)
1188      {
1189         TSM("SLEEP");
1190         first_idle = 0;
1191      }
1192
1193    return ECORE_CALLBACK_RENEW;
1194 }
1195
1196 static void
1197 _e_main_create_wm_ready(void)
1198 {
1199    FILE *_wmready_checker = NULL;
1200    const char *path_wm_ready = "/run/.wm_ready";
1201
1202    if (!e_util_file_realpath_check(path_wm_ready, EINA_TRUE))
1203      {
1204         WRN("%s is maybe link, so delete it\n", path_wm_ready);
1205      }
1206
1207    _wmready_checker = fopen(path_wm_ready, "wb");
1208    if (_wmready_checker)
1209      {
1210         TSM("[WM] WINDOW MANAGER is READY!!!");
1211         PRCTL("[Winsys] WINDOW MANAGER is READY!!!");
1212         fclose(_wmready_checker);
1213
1214         /*TODO: Next lines should be removed. */
1215         FILE *_tmp_wm_ready_checker;
1216
1217         _tmp_wm_ready_checker = fopen(path_wm_ready, "wb");
1218
1219         if (_tmp_wm_ready_checker)
1220           {
1221              TSM("[WM] temporary wm_ready path is created.");
1222              PRCTL("[Winsys] temporary wm_ready path is created.");
1223              fclose(_tmp_wm_ready_checker);
1224           }
1225         else
1226           {
1227              TSM("[WM] temporary wm_ready path create failed.");
1228              PRCTL("[Winsys] temporary wm_ready path create failed.");
1229           }
1230      }
1231    else
1232      {
1233         TSM("[WM] WINDOW MANAGER is READY. BUT, failed to create .wm_ready file.");
1234         PRCTL("[Winsys] WINDOW MANAGER is READY. BUT, failed to create .wm_ready file.");
1235      }
1236 }
1237
1238 static void
1239 _e_main_hooks_clean(void)
1240 {
1241    Eina_Inlist *l;
1242    E_Main_Hook *mh;
1243    unsigned int x;
1244
1245    for (x = 0; x < E_MAIN_HOOK_LAST; x++)
1246      EINA_INLIST_FOREACH_SAFE(_e_main_hooks[x], l, mh)
1247        {
1248           if (!mh->delete_me) continue;
1249           _e_main_hooks[x] = eina_inlist_remove(_e_main_hooks[x],
1250                                                 EINA_INLIST_GET(mh));
1251           free(mh);
1252        }
1253 }
1254
1255 static void
1256 _e_main_hook_call(E_Main_Hook_Point hookpoint, void *data EINA_UNUSED)
1257 {
1258    E_Main_Hook *mh;
1259
1260    _e_main_hooks_walking++;
1261    EINA_INLIST_FOREACH(_e_main_hooks[hookpoint], mh)
1262      {
1263         if (mh->delete_me) continue;
1264         mh->func(mh->data);
1265      }
1266    _e_main_hooks_walking--;
1267    if ((_e_main_hooks_walking == 0) && (_e_main_hooks_delete > 0))
1268      _e_main_hooks_clean();
1269 }
1270
1271 E_API E_Main_Hook *
1272 e_main_hook_add(E_Main_Hook_Point hookpoint, E_Main_Hook_Cb func, const void *data)
1273 {
1274    E_Main_Hook *mh;
1275
1276    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_MAIN_HOOK_LAST, NULL);
1277    mh = E_NEW(E_Main_Hook, 1);
1278    EINA_SAFETY_ON_NULL_RETURN_VAL(mh, NULL);
1279    mh->hookpoint = hookpoint;
1280    mh->func = func;
1281    mh->data = (void*)data;
1282    _e_main_hooks[hookpoint] = eina_inlist_append(_e_main_hooks[hookpoint],
1283                                                  EINA_INLIST_GET(mh));
1284    return mh;
1285 }
1286
1287 E_API void
1288 e_main_hook_del(E_Main_Hook *mh)
1289 {
1290    mh->delete_me = 1;
1291    if (_e_main_hooks_walking == 0)
1292      {
1293         _e_main_hooks[mh->hookpoint] = eina_inlist_remove(_e_main_hooks[mh->hookpoint],
1294                                                           EINA_INLIST_GET(mh));
1295         free(mh);
1296      }
1297    else
1298      _e_main_hooks_delete++;
1299 }
1300
1301 E_API void
1302 e_main_hook_call(E_Main_Hook_Point hookpoint)
1303 {
1304    if ((hookpoint < 0) || (hookpoint >= E_MAIN_HOOK_LAST)) return;
1305
1306    _e_main_hook_call(hookpoint, NULL);
1307 }