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