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