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