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