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