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