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