add code to check stopping flag
[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 static double t0, t1, t2;
20 #else
21 # define TS(x)
22 #endif
23 /*
24  * i need to make more use of these when i'm baffled as to when something is
25  * up. other hooks:
26  *
27  *      void *(*__malloc_hook)(size_t size, const void *caller);
28  *
29  *      void *(*__realloc_hook)(void *ptr, size_t size, const void *caller);
30  *
31  *      void *(*__memalign_hook)(size_t alignment, size_t size,
32  *                               const void *caller);
33  *
34  *      void (*__free_hook)(void *ptr, const void *caller);
35  *
36  *      void (*__malloc_initialize_hook)(void);
37  *
38  *      void (*__after_morecore_hook)(void);
39  *
40
41    static void my_init_hook(void);
42    static void my_free_hook(void *p, const void *caller);
43
44    static void (*old_free_hook)(void *ptr, const void *caller) = NULL;
45    void (*__free_hook)(void *ptr, const void *caller);
46
47    void (*__malloc_initialize_hook) (void) = my_init_hook;
48    static void
49    my_init_hook(void)
50    {
51    old_free_hook = __free_hook;
52    __free_hook = my_free_hook;
53    }
54
55    //void *magicfree = NULL;
56
57    static void
58    my_free_hook(void *p, const void *caller)
59    {
60    __free_hook = old_free_hook;
61    //   if ((p) && (p == magicfree))
62    //     {
63    //   printf("CAUGHT!!!!! %p ...\n", p);
64    //   abort();
65    //     }
66    free(p);
67    __free_hook = my_free_hook;
68    }
69  */
70
71 /* local function prototypes */
72 static void      _e_main_shutdown(int errcode);
73 static void      _e_main_shutdown_push(int (*func)(void));
74 static void      _e_main_parse_arguments(int argc, char **argv);
75 static Eina_Bool _e_main_cb_signal_exit(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED);
76 static Eina_Bool _e_main_cb_signal_hup(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED);
77 static Eina_Bool _e_main_cb_signal_user(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev);
78 static int       _e_main_dirs_init(void);
79 static int       _e_main_dirs_shutdown(void);
80 static int       _e_main_path_init(void);
81 static int       _e_main_path_shutdown(void);
82 static int       _e_main_screens_init(void);
83 static int       _e_main_screens_shutdown(void);
84 static void      _e_main_desk_save(void);
85 static void      _e_main_desk_restore(void);
86 static void      _e_main_modules_load(Eina_Bool safe_mode);
87 static Eina_Bool _e_main_cb_idle_before(void *data EINA_UNUSED);
88 static Eina_Bool _e_main_cb_idle_after(void *data EINA_UNUSED);
89 static void      _e_main_create_wm_ready(void);
90 static void      _e_main_hooks_clean(void);
91 static void      _e_main_hook_call(E_Main_Hook_Point hookpoint, void *data EINA_UNUSED);
92
93 /* local variables */
94 static Eina_Bool really_know = EINA_FALSE;
95 static Eina_Bool inloop = EINA_FALSE;
96
97 static int _e_main_lvl = 0;
98 static int(*_e_main_shutdown_func[MAX_LEVEL]) (void);
99
100 static Ecore_Idle_Enterer *_idle_before = NULL;
101 static Ecore_Idle_Enterer *_idle_after = NULL;
102
103 static Ecore_Event_Handler *mod_init_end = NULL;
104
105 static Eina_List *hooks = NULL;
106
107 static int _e_main_hooks_delete = 0;
108 static int _e_main_hooks_walking = 0;
109
110 static Eina_Inlist *_e_main_hooks[] =
111 {
112    [E_MAIN_HOOK_MODULE_LOAD_DONE] = NULL,
113    [E_MAIN_HOOK_E_INFO_READY] = NULL
114 };
115
116 /* external variables */
117 E_API Eina_Bool e_precache_end = EINA_FALSE;
118 E_API Eina_Bool good = EINA_FALSE;
119 E_API Eina_Bool evil = EINA_FALSE;
120 E_API Eina_Bool starting = EINA_TRUE;
121 E_API Eina_Bool stopping = EINA_FALSE;
122 E_API Eina_Bool restart = EINA_FALSE;
123 E_API Eina_Bool e_nopause = EINA_FALSE;
124 EINTERN const char *e_first_frame = NULL;
125 EINTERN double e_first_frame_start_time = -1;
126
127 static Eina_Bool
128 _xdg_check_str(const char *env, const char *str)
129 {
130    const char *p;
131    size_t len;
132
133    len = strlen(str);
134    for (p = strstr(env, str); p; p++, p = strstr(p, str))
135      {
136         if ((!p[len]) || (p[len] == ':')) return EINA_TRUE;
137      }
138    return EINA_FALSE;
139 }
140
141 static void
142 _xdg_data_dirs_augment(void)
143 {
144    const char *s;
145    const char *p = e_prefix_get();
146    char newpath[4096], buf[4096];
147
148    if (!p) return;
149
150    s = getenv("XDG_DATA_DIRS");
151    if (s)
152      {
153         Eina_Bool pfxdata, pfx;
154
155         pfxdata = !_xdg_check_str(s, e_prefix_data_get());
156         snprintf(newpath, sizeof(newpath), "%s/share", p);
157         pfx = !_xdg_check_str(s, newpath);
158         if (pfxdata || pfx)
159           {
160              snprintf(buf, sizeof(buf), "%s%s%s%s%s",
161                pfxdata ? e_prefix_data_get() : "",
162                pfxdata ? ":" : "",
163                pfx ? newpath : "",
164                pfx ? ":" : "",
165                s);
166              e_util_env_set("XDG_DATA_DIRS", buf);
167           }
168      }
169    else
170      {
171         snprintf(buf, sizeof(buf), "%s:%s/share:/usr/local/share:/usr/share", e_prefix_data_get(), p);
172         e_util_env_set("XDG_DATA_DIRS", buf);
173      }
174
175    s = getenv("XDG_CONFIG_DIRS");
176    snprintf(newpath, sizeof(newpath), "%s/etc/xdg", p);
177    if (s)
178      {
179         if (!_xdg_check_str(s, newpath))
180           {
181              snprintf(buf, sizeof(buf), "%s:%s", newpath, s);
182              e_util_env_set("XDG_CONFIG_DIRS", buf);
183           }
184      }
185    else
186      {
187         snprintf(buf, sizeof(buf), "%s:/etc/xdg", newpath);
188         e_util_env_set("XDG_CONFIG_DIRS", buf);
189      }
190
191    if (!getenv("XDG_RUNTIME_DIR"))
192      {
193         const char *dir;
194
195         snprintf(buf, sizeof(buf), "/tmp/xdg-XXXXXX");
196         dir = mkdtemp(buf);
197         if (!dir) dir = "/tmp";
198         else
199           {
200              e_util_env_set("XDG_RUNTIME_DIR", dir);
201              snprintf(buf, sizeof(buf), "%s/.e-deleteme", dir);
202              ecore_file_mkdir(buf);
203           }
204      }
205
206    /* set menu prefix so we get our e menu */
207    if (!getenv("XDG_MENU_PREFIX"))
208      {
209         e_util_env_set("XDG_MENU_PREFIX", "e-");
210      }
211 }
212
213 static Eina_Bool
214 _e_main_subsystem_defer(void *data EINA_UNUSED)
215 {
216    int argc;
217    char **argv;
218
219    TRACE_DS_BEGIN(MAIN:SUBSYSTEMS DEFER);
220
221    ecore_app_args_get(&argc, &argv);
222
223    /* try to init delayed subsystems */
224
225    TRACE_DS_BEGIN(MAIN:DEFERRED INTERNAL SUBSYSTEMS INIT);
226
227    TS("[DEFERRED] Screens Init: win");
228    if (!e_win_init())
229      {
230         e_error_message_show(_("Enlightenment cannot setup elementary trap!\n"));
231         TRACE_DS_END();
232         _e_main_shutdown(-1);
233      }
234    TS("[DEFERRED] Screens Init: win Done");
235
236    TS("[DEFERRED] E_Dnd Init");
237    if (!e_dnd_init())
238      {
239         e_error_message_show(_("Enlightenment cannot set up its dnd system.\n"));
240         _e_main_shutdown(-1);
241      }
242    TS("[DEFERRED] E_Dnd Init Done");
243    _e_main_shutdown_push(e_dnd_shutdown);
244
245    TS("[DEFERRED] E_Scale Init");
246    if (!e_scale_init())
247      {
248         e_error_message_show(_("Enlightenment cannot set up its scale system.\n"));
249         TRACE_DS_END();
250         _e_main_shutdown(-1);
251      }
252    TS("[DEFERRED] E_Scale Init Done");
253    _e_main_shutdown_push(e_scale_shutdown);
254
255    TS("[DEFERRED] E_Test_Helper Init");
256    e_test_helper_init();
257    _e_main_shutdown_push(e_test_helper_shutdown);
258    TS("[DEFERRED] E_Test_Helper Done");
259
260    TS("[DEFERRED] E_INFO_SERVER Init");
261    e_info_server_init();
262    _e_main_shutdown_push(e_info_server_shutdown);
263    TS("[DEFERRED] E_INFO_SERVER Done");
264
265    TRACE_DS_END();
266    TRACE_DS_BEGIN(MAIN:DEFERRED COMP JOB);
267
268    /* try to do deferred job of any subsystems*/
269    TS("[DEFERRED] Compositor's deferred job");
270    e_comp_deferred_job();
271    TS("[DEFERRED] Compositor's deferred job Done");
272
273    TRACE_DS_END();
274    if (e_config->use_e_policy)
275      {
276         TRACE_DS_BEGIN(MAIN:DEFERRED POLICY JOB);
277
278         TS("[DEFERRED] E_Policy's deferred job");
279         e_policy_deferred_job();
280         TS("[DEFERRED] E_Policy's deferred job Done");
281
282         TRACE_DS_END();
283      }
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    TS("Edje Init");
510    if (!edje_init())
511      {
512         e_error_message_show(_("Enlightenment cannot initialize Edje!\n"));
513         _e_main_shutdown(-1);
514      }
515    TS("Edje Init Done");
516    _e_main_shutdown_push(edje_shutdown);
517
518    /*** Initialize E Subsystems We Need ***/
519
520    TS("E Directories Init");
521    /* setup directories we will be using for configurations storage etc. */
522    if (!_e_main_dirs_init())
523      {
524         e_error_message_show(_("Enlightenment cannot create directories in your home directory.\n"
525                                "Perhaps you have no home directory or the disk is full?"));
526         _e_main_shutdown(-1);
527      }
528    TS("E Directories Init Done");
529    _e_main_shutdown_push(_e_main_dirs_shutdown);
530
531    TS("E_Config Init");
532    if (!e_config_init())
533      {
534         e_error_message_show(_("Enlightenment cannot set up its config system.\n"));
535         _e_main_shutdown(-1);
536      }
537    TS("E_Config Init Done");
538    _e_main_shutdown_push(e_config_shutdown);
539
540    TS("E_Env Init");
541    if (!e_env_init())
542      {
543         e_error_message_show(_("Enlightenment cannot set up its environment.\n"));
544         _e_main_shutdown(-1);
545      }
546    TS("E_Env Init Done");
547    _e_main_shutdown_push(e_env_shutdown);
548
549    ecore_exe_run_priority_set(e_config->priority);
550
551    TS("E Paths Init");
552    if (!_e_main_path_init())
553      {
554         e_error_message_show(_("Enlightenment cannot set up paths for finding files.\n"
555                                "Perhaps you are out of memory?"));
556         _e_main_shutdown(-1);
557      }
558    TS("E Paths Init Done");
559    _e_main_shutdown_push(_e_main_path_shutdown);
560
561    ecore_animator_frametime_set(1.0 / e_config->framerate);
562
563    TS("E_Theme Init");
564    if (!e_theme_init())
565      {
566         e_error_message_show(_("Enlightenment cannot set up its theme system.\n"));
567         _e_main_shutdown(-1);
568      }
569    TS("E_Theme Init Done");
570    _e_main_shutdown_push(e_theme_shutdown);
571
572    TS("E_Actions Init");
573    if (!e_actions_init())
574      {
575         e_error_message_show(_("Enlightenment cannot set up its actions system.\n"));
576         _e_main_shutdown(-1);
577      }
578    TS("E_Actions Init Done");
579    _e_main_shutdown_push(e_actions_shutdown);
580
581    /* these just add event handlers and can't fail
582     * timestamping them is dumb.
583     */
584    e_screensaver_preinit();
585    e_zone_init();
586    e_desk_init();
587    e_slot_init();
588
589    TRACE_DS_BEGIN(MAIN:WAIT /dev/dri/card0);
590    if (e_config->sleep_for_dri)
591      {
592         while(access("/dev/dri/card0", F_OK) != 0)
593           {
594              struct timespec req, rem;
595              req.tv_sec = 0;
596              req.tv_nsec = 50000000L;
597              nanosleep(&req, &rem);
598           }
599      }
600    TRACE_DS_END();
601
602    TS("E_Pointer Init");
603    if (!e_pointer_init())
604      {
605         e_error_message_show(_("Enlightenment cannot set up its pointer system.\n"));
606         _e_main_shutdown(-1);
607      }
608    TS("E_Pointer Init Done");
609    _e_main_shutdown_push(e_pointer_shutdown);
610
611    TS("Dpms Init");
612    if (!e_dpms_init())
613      {
614         e_error_message_show(_("Enlightenment cannot set up dpms.\n"));
615         _e_main_shutdown(-1);
616      }
617    TS("Dpms Init Done");
618    _e_main_shutdown_push(e_dpms_shutdown);
619
620    TRACE_DS_BEGIN(MAIN:SCREEN INIT);
621    TS("Screens Init");
622    if (!_e_main_screens_init())
623      {
624         e_error_message_show(_("Enlightenment set up window management for all the screens on your system\n"
625                                "failed. Perhaps another window manager is running?\n"));
626         _e_main_shutdown(-1);
627      }
628    TS("Screens Init Done");
629    _e_main_shutdown_push(_e_main_screens_shutdown);
630    TRACE_DS_END();
631
632    if (e_config->eom_enable)
633      {
634         TS("Eom Init");
635         if (!e_eom_init())
636           {
637              e_error_message_show(_("Enlightenment cannot set up eom.\n"));
638              _e_main_shutdown(-1);
639           }
640         TS("Eom Init Done");
641         _e_main_shutdown_push(e_eom_shutdown);
642      }
643
644    TS("E_Screensaver Init");
645    if (!e_screensaver_init())
646      {
647         e_error_message_show(_("Enlightenment cannot configure the X screensaver.\n"));
648         _e_main_shutdown(-1);
649      }
650    TS("E_Screensaver Init Done");
651    _e_main_shutdown_push(e_screensaver_shutdown);
652
653    TS("E_Comp Freeze");
654    e_comp_all_freeze();
655    TS("E_Comp Freeze Done");
656
657    TS("E_Grabinput Init");
658    if (!e_grabinput_init())
659      {
660         e_error_message_show(_("Enlightenment cannot set up its grab input handling system.\n"));
661         _e_main_shutdown(-1);
662      }
663    TS("E_Grabinput Init Done");
664    _e_main_shutdown_push(e_grabinput_shutdown);
665
666    ecore_event_handler_add(E_EVENT_MODULE_INIT_END, _e_main_deferred_job_schedule, NULL);
667
668    TS("E_Module Init");
669    if (!e_module_init())
670      {
671         e_error_message_show(_("Enlightenment cannot set up its module system.\n"));
672         _e_main_shutdown(-1);
673      }
674    TS("E_Module Init Done");
675    _e_main_shutdown_push(e_module_shutdown);
676
677    TS("E_Mouse Init");
678    if (!e_mouse_update())
679      {
680         e_error_message_show(_("Enlightenment cannot configure the mouse settings.\n"));
681         _e_main_shutdown(-1);
682      }
683    TS("E_Mouse Init Done");
684
685    TS("E_Icon Init");
686    if (!e_icon_init())
687      {
688         e_error_message_show(_("Enlightenment cannot initialize the Icon Cache system.\n"));
689         _e_main_shutdown(-1);
690      }
691    TS("E_Icon Init Done");
692    _e_main_shutdown_push(e_icon_shutdown);
693
694    if (e_config->use_e_policy)
695      {
696         TS("E_Policy Init");
697         if (!e_policy_init())
698           {
699              e_error_message_show(_("Enlightenment cannot setup policy system!\n"));
700              _e_main_shutdown(-1);
701           }
702         TS("E_Policy Init Done");
703         _e_main_shutdown_push(e_policy_shutdown);
704      }
705
706    TS("E_Process Init");
707    if (!e_process_init())
708      {
709         e_error_message_show(_("Enlightenment cannot setup process managing system!\n"));
710         _e_main_shutdown(-1);
711      }
712    TS("E_Process Init Done");
713    _e_main_shutdown_push(e_process_shutdown);
714
715    TS("E_Security Init");
716    if (!e_security_init())
717      {
718         e_error_message_show(_("Enlightenment cannot setup security system!\n"));
719         _e_main_shutdown(-1);
720      }
721    TS("E_Security Init Done");
722    _e_main_shutdown_push(e_security_shutdown);
723
724    TS("Load Modules");
725    _e_main_modules_load(safe_mode);
726    TS("Load Modules Done");
727
728    TS("E_Comp Thaw");
729    e_comp_all_thaw();
730    TS("E_Comp Thaw Done");
731
732    _idle_after = ecore_idle_enterer_add(_e_main_cb_idle_after, NULL);
733
734    starting = EINA_FALSE;
735    inloop = EINA_TRUE;
736
737    e_util_env_set("E_RESTART", "1");
738
739    TS("MAIN LOOP AT LAST");
740
741    if (e_config->create_wm_ready)
742      _e_main_create_wm_ready();
743
744    TRACE_DS_END();
745
746 #ifdef HAVE_SYSTEMD
747    TS("[WM] Send start-up completion");
748    sd_notify(0, "READY=1");
749 #else
750    TS("[WM] Skip sending start-up completion. (no systemd)");
751 #endif
752    ecore_main_loop_begin();
753
754    inloop = EINA_FALSE;
755
756    ELOGF("COMP", "STOPPING enlightenment...", NULL, NULL);
757    stopping = EINA_TRUE;
758
759    _e_main_desk_save();
760    e_comp_internal_save();
761
762    _e_main_shutdown(0);
763
764    if (restart)
765      {
766         e_util_env_set("E_RESTART_OK", "1");
767         if (getenv("E_START_MTRACK"))
768           e_util_env_set("MTRACK", "track");
769         ecore_app_restart();
770      }
771
772    e_prefix_shutdown();
773
774    return 0;
775 }
776
777 E_API double
778 e_main_ts(const char *str)
779 {
780    double ret;
781    t1 = ecore_time_unix_get();
782    printf("ESTART: %1.5f [%1.5f] - %s\n", t1 - t0, t1 - t2, str);
783    ret = t1 - t2;
784    t2 = t1;
785    return ret;
786 }
787
788 /* local functions */
789 static void
790 _e_main_shutdown(int errcode)
791 {
792    int i = 0;
793    char buf[PATH_MAX];
794    const char *dir;
795
796    printf("E: Begin Shutdown Procedure!\n");
797
798    E_FREE_LIST(hooks, e_main_hook_del);
799
800    if (_idle_before) ecore_idle_enterer_del(_idle_before);
801    _idle_before = NULL;
802    if (_idle_after) ecore_idle_enterer_del(_idle_after);
803    _idle_after = NULL;
804
805    dir = getenv("XDG_RUNTIME_DIR");
806    if (dir)
807      {
808         char buf_env[PATH_MAX];
809         snprintf(buf_env, sizeof(buf_env), "%s", dir);
810         snprintf(buf, sizeof(buf), "%s/.e-deleteme", buf_env);
811         if (ecore_file_exists(buf)) ecore_file_recursive_rm(buf_env);
812      }
813    for (i = (_e_main_lvl - 1); i >= 0; i--)
814      (*_e_main_shutdown_func[i])();
815 #ifdef OBJECT_HASH_CHECK
816    e_object_hash_shutdown();
817 #endif
818    if (errcode < 0) exit(errcode);
819 }
820
821 static void
822 _e_main_shutdown_push(int (*func)(void))
823 {
824    _e_main_lvl++;
825    if (_e_main_lvl > MAX_LEVEL)
826      {
827         _e_main_lvl--;
828         e_error_message_show("WARNING: too many init levels. MAX = %i\n",
829                              MAX_LEVEL);
830         return;
831      }
832    _e_main_shutdown_func[_e_main_lvl - 1] = func;
833 }
834
835 static void
836 _e_main_parse_arguments(int argc, char **argv)
837 {
838    int i = 0;
839
840    /* handle some command-line parameters */
841    for (i = 1; i < argc; i++)
842      {
843         if (!strcmp(argv[i], "-good"))
844           {
845              good = EINA_TRUE;
846              evil = EINA_FALSE;
847              printf("LA LA LA\n");
848           }
849         else if (!strcmp(argv[i], "-evil"))
850           {
851              good = EINA_FALSE;
852              evil = EINA_TRUE;
853              printf("MUHAHAHAHHAHAHAHAHA\n");
854           }
855         else if (!strcmp(argv[i], "-psychotic"))
856           {
857              good = EINA_TRUE;
858              evil = EINA_TRUE;
859              printf("MUHAHALALALALALALALA\n");
860           }
861         else if ((!strcmp(argv[i], "-profile")) && (i < (argc - 1)))
862           {
863              i++;
864              if (!getenv("E_CONF_PROFILE"))
865                e_util_env_set("E_CONF_PROFILE", argv[i]);
866           }
867         else if (!strcmp(argv[i], "-i-really-know-what-i-am-doing-and-accept-full-responsibility-for-it"))
868           really_know = EINA_TRUE;
869         else if (!strcmp(argv[i], "-nopause"))
870           e_nopause = EINA_TRUE;
871         else if ((!strcmp(argv[i], "-version")) ||
872                  (!strcmp(argv[i], "--version")))
873           {
874              printf(_("Version: %s\n"), PACKAGE_VERSION);
875              _e_main_shutdown(-1);
876           }
877         else if ((!strcmp(argv[i], "-h")) ||
878                  (!strcmp(argv[i], "-help")) ||
879                  (!strcmp(argv[i], "--help")))
880           {
881              printf
882                (_(
883                  "Options:\n"
884                  "\t-display DISPLAY\n"
885                  "\t\tConnect to display named DISPLAY.\n"
886                  "\t\tEG: -display :1.0\n"
887                  "\t-fake-xinerama-screen WxH+X+Y\n"
888                  "\t\tAdd a FAKE xinerama screen (instead of the real ones)\n"
889                  "\t\tgiven the geometry. Add as many as you like. They all\n"
890                  "\t\treplace the real xinerama screens, if any. This can\n"
891                  "\t\tbe used to simulate xinerama.\n"
892                  "\t\tEG: -fake-xinerama-screen 800x600+0+0 -fake-xinerama-screen 800x600+800+0\n"
893                  "\t-profile CONF_PROFILE\n"
894                  "\t\tUse the configuration profile CONF_PROFILE instead of the user selected default or just \"default\".\n"
895                  "\t-good\n"
896                  "\t\tBe good.\n"
897                  "\t-evil\n"
898                  "\t\tBe evil.\n"
899                  "\t-psychotic\n"
900                  "\t\tBe psychotic.\n"
901                  "\t-i-really-know-what-i-am-doing-and-accept-full-responsibility-for-it\n"
902                  "\t\tIf you need this help, you don't need this option.\n"
903                  "\t-version\n"
904                  )
905                );
906              _e_main_shutdown(-1);
907           }
908      }
909 }
910
911 static Eina_Bool
912 _e_main_cb_signal_exit(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED)
913 {
914    /* called on ctrl-c, kill (pid) (also SIGINT, SIGTERM and SIGQIT) */
915    ecore_main_loop_quit();
916    return ECORE_CALLBACK_RENEW;
917 }
918
919 static Eina_Bool
920 _e_main_cb_signal_hup(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED)
921 {
922    restart = 1;
923    ecore_main_loop_quit();
924    return ECORE_CALLBACK_RENEW;
925 }
926
927 static Eina_Bool
928 _e_main_cb_signal_user(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev)
929 {
930    Ecore_Event_Signal_User *e = ev;
931
932    if (e->number == 1)
933      {
934 //        E_Action *a = e_action_find("configuration");
935 //        if ((a) && (a->func.go)) a->func.go(NULL, NULL);
936      }
937    else if (e->number == 2)
938      {
939         // comp module has its own handler for this for enabling/disabling fps debug
940      }
941    return ECORE_CALLBACK_RENEW;
942
943 }
944
945 static int
946 _e_main_dirs_init(void)
947 {
948    if(getenv("E_CONF_RO"))
949      {
950         return 1;
951      }
952
953    const char *base;
954    const char *dirs[] =
955    {
956       "backgrounds",
957       "config",
958       "themes",
959       NULL
960    };
961
962    base = e_user_dir_get();
963    if (ecore_file_mksubdirs(base, dirs) != sizeof(dirs) / sizeof(dirs[0]) - 1)
964      {
965         e_error_message_show("Could not create one of the required "
966                              "subdirectories of '%s'\n", base);
967         return 0;
968      }
969
970    return 1;
971 }
972
973 static int
974 _e_main_dirs_shutdown(void)
975 {
976    return 1;
977 }
978
979 static int
980 _e_main_path_init(void)
981 {
982    char buf[PATH_MAX];
983
984    /* setup data paths */
985    path_data = e_path_new();
986    if (!path_data)
987      {
988         e_error_message_show("Cannot allocate path for path_data\n");
989         return 0;
990      }
991    e_prefix_data_concat_static(buf, "data");
992    e_path_default_path_append(path_data, buf);
993
994    /* setup image paths */
995    path_images = e_path_new();
996    if (!path_images)
997      {
998         e_error_message_show("Cannot allocate path for path_images\n");
999         return 0;
1000      }
1001    e_user_dir_concat_static(buf, "/images");
1002    e_path_default_path_append(path_images, buf);
1003    e_prefix_data_concat_static(buf, "data/images");
1004    e_path_default_path_append(path_images, buf);
1005
1006    /* setup font paths */
1007    path_fonts = e_path_new();
1008    if (!path_fonts)
1009      {
1010         e_error_message_show("Cannot allocate path for path_fonts\n");
1011         return 0;
1012      }
1013    e_user_dir_concat_static(buf, "/fonts");
1014    e_path_default_path_append(path_fonts, buf);
1015    e_prefix_data_concat_static(buf, "data/fonts");
1016    e_path_default_path_append(path_fonts, buf);
1017
1018    /* setup icon paths */
1019    path_icons = e_path_new();
1020    if (!path_icons)
1021      {
1022         e_error_message_show("Cannot allocate path for path_icons\n");
1023         return 0;
1024      }
1025    e_user_dir_concat_static(buf, "/icons");
1026    e_path_default_path_append(path_icons, buf);
1027    e_prefix_data_concat_static(buf, "data/icons");
1028    e_path_default_path_append(path_icons, buf);
1029
1030    /* setup module paths */
1031    path_modules = e_path_new();
1032    if (!path_modules)
1033      {
1034         e_error_message_show("Cannot allocate path for path_modules\n");
1035         return 0;
1036      }
1037    e_user_dir_concat_static(buf, "/modules");
1038    e_path_default_path_append(path_modules, buf);
1039    snprintf(buf, sizeof(buf), "%s/enlightenment/modules", e_prefix_lib_get());
1040    e_path_default_path_append(path_modules, buf);
1041    /* FIXME: eventually this has to go - moduels should have installers that
1042     * add appropriate install paths (if not installed to user homedir) to
1043     * e's module search dirs
1044     */
1045    snprintf(buf, sizeof(buf), "%s/enlightenment/modules_extra", e_prefix_lib_get());
1046    e_path_default_path_append(path_modules, buf);
1047
1048    /* setup background paths */
1049    path_backgrounds = e_path_new();
1050    if (!path_backgrounds)
1051      {
1052         e_error_message_show("Cannot allocate path for path_backgrounds\n");
1053         return 0;
1054      }
1055    e_user_dir_concat_static(buf, "/backgrounds");
1056    e_path_default_path_append(path_backgrounds, buf);
1057    e_prefix_data_concat_static(buf, "data/backgrounds");
1058    e_path_default_path_append(path_backgrounds, buf);
1059
1060    path_messages = e_path_new();
1061    if (!path_messages)
1062      {
1063         e_error_message_show("Cannot allocate path for path_messages\n");
1064         return 0;
1065      }
1066    e_user_dir_concat_static(buf, "/locale");
1067    e_path_default_path_append(path_messages, buf);
1068    e_path_default_path_append(path_messages, e_prefix_locale_get());
1069
1070    return 1;
1071 }
1072
1073 static int
1074 _e_main_path_shutdown(void)
1075 {
1076    if (path_data)
1077      {
1078         e_object_del(E_OBJECT(path_data));
1079         path_data = NULL;
1080      }
1081    if (path_images)
1082      {
1083         e_object_del(E_OBJECT(path_images));
1084         path_images = NULL;
1085      }
1086    if (path_fonts)
1087      {
1088         e_object_del(E_OBJECT(path_fonts));
1089         path_fonts = NULL;
1090      }
1091    if (path_icons)
1092      {
1093         e_object_del(E_OBJECT(path_icons));
1094         path_icons = NULL;
1095      }
1096    if (path_modules)
1097      {
1098         e_object_del(E_OBJECT(path_modules));
1099         path_modules = NULL;
1100      }
1101    if (path_backgrounds)
1102      {
1103         e_object_del(E_OBJECT(path_backgrounds));
1104         path_backgrounds = NULL;
1105      }
1106    if (path_messages)
1107      {
1108         e_object_del(E_OBJECT(path_messages));
1109         path_messages = NULL;
1110      }
1111    return 1;
1112 }
1113
1114 static int
1115 _e_main_screens_init(void)
1116 {
1117    TS("\tscreens: client");
1118    if (!e_client_init()) return 0;
1119
1120    TS("Compositor Init");
1121    PRCTL("[Winsys] start of compositor init");
1122    if (!e_comp_init())
1123      {
1124         e_error_message_show(_("Enlightenment cannot create a compositor.\n"));
1125         _e_main_shutdown(-1);
1126      }
1127
1128    PRCTL("[Winsys] end of compositor init");
1129    _e_main_desk_restore();
1130
1131    return 1;
1132 }
1133
1134 static int
1135 _e_main_screens_shutdown(void)
1136 {
1137    e_win_shutdown();
1138    e_comp_shutdown();
1139    e_client_shutdown();
1140
1141    e_slot_shutdown();
1142    e_desk_shutdown();
1143    e_zone_shutdown();
1144    return 1;
1145 }
1146
1147 static void
1148 _e_main_desk_save(void)
1149 {
1150    const Eina_List *l;
1151    char env[1024], name[1024];
1152    E_Zone *zone;
1153
1154    EINA_LIST_FOREACH(e_comp->zones, l, zone)
1155      {
1156         snprintf(name, sizeof(name), "DESK_%d_%d", 0, zone->num);
1157         snprintf(env, sizeof(env), "%d,%d", zone->desk_x_current, zone->desk_y_current);
1158         e_util_env_set(name, env);
1159      }
1160 }
1161
1162 static void
1163 _e_main_desk_restore(void)
1164 {
1165    E_Client *ec;
1166
1167    E_CLIENT_REVERSE_FOREACH(ec)
1168      if ((!e_client_util_ignored_get(ec)) && e_client_util_desk_visible(ec, e_desk_current_get(ec->zone)))
1169        {
1170           ec->want_focus = ec->take_focus = 1;
1171           break;
1172        }
1173 }
1174
1175 static Eina_Bool
1176 _e_main_modules_load_after(void *d EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
1177 {
1178    E_FREE_FUNC(mod_init_end, ecore_event_handler_del);
1179    return ECORE_CALLBACK_RENEW;
1180 }
1181
1182 static void
1183 _e_main_modules_load(Eina_Bool safe_mode)
1184 {
1185    if (!safe_mode)
1186      e_module_all_load();
1187    else
1188      {
1189         E_Module *m;
1190         char *crashmodule;
1191
1192         crashmodule = getenv("E_MODULE_LOAD");
1193         if (crashmodule) m = e_module_new(crashmodule);
1194
1195         if ((crashmodule) && (m))
1196           {
1197              e_module_disable(m);
1198              e_object_del(E_OBJECT(m));
1199
1200              e_error_message_show
1201                (_("Enlightenment crashed early on start and has<br>"
1202                   "been restarted. There was an error loading the<br>"
1203                   "module named: %s. This module has been disabled<br>"
1204                   "and will not be loaded."), crashmodule);
1205              e_util_dialog_show
1206                (_("Enlightenment crashed early on start and has been restarted"),
1207                _("Enlightenment crashed early on start and has been restarted.<br>"
1208                  "There was an error loading the module named: %s<br><br>"
1209                  "This module has been disabled and will not be loaded."), crashmodule);
1210              e_module_all_load();
1211           }
1212         else
1213           {
1214              e_error_message_show
1215                (_("Enlightenment crashed early on start and has<br>"
1216                   "been restarted. All modules have been disabled<br>"
1217                   "and will not be loaded to help remove any problem<br>"
1218                   "modules from your configuration. The module<br>"
1219                   "configuration dialog should let you select your<br>"
1220                   "modules again.\n"));
1221              e_util_dialog_show
1222                (_("Enlightenment crashed early on start and has been restarted"),
1223                _("Enlightenment crashed early on start and has been restarted.<br>"
1224                  "All modules have been disabled and will not be loaded to help<br>"
1225                  "remove any problem modules from your configuration.<br><br>"
1226                  "The module configuration dialog should let you select your<br>"
1227                  "modules again."));
1228           }
1229         mod_init_end = ecore_event_handler_add(E_EVENT_MODULE_INIT_END, _e_main_modules_load_after, NULL);
1230      }
1231 }
1232
1233 static Eina_Bool
1234 _e_main_cb_idle_before(void *data EINA_UNUSED)
1235 {
1236    e_client_idler_before();
1237    edje_thaw();
1238    return ECORE_CALLBACK_RENEW;
1239 }
1240
1241 static Eina_Bool
1242 _e_main_cb_idle_after(void *data EINA_UNUSED)
1243 {
1244    static int first_idle = 1;
1245
1246    eet_clearcache();
1247    edje_freeze();
1248
1249 #ifdef E_RELEASE_BUILD
1250    if (first_idle)
1251      {
1252         TS("SLEEP");
1253         first_idle = 0;
1254         e_precache_end = EINA_TRUE;
1255      }
1256 #else
1257    if (first_idle++ < 60)
1258      {
1259         TS("SLEEP");
1260         if (!first_idle)
1261           e_precache_end = EINA_TRUE;
1262      }
1263 #endif
1264
1265    return ECORE_CALLBACK_RENEW;
1266 }
1267
1268 static void
1269 _e_main_create_wm_ready(void)
1270 {
1271    FILE *_wmready_checker = NULL;
1272    const char *path_wm_ready = "/run/.wm_ready";
1273
1274    if (!e_util_file_realpath_check(path_wm_ready, EINA_TRUE))
1275      {
1276         WRN("%s is maybe link, so delete it\n", path_wm_ready);
1277      }
1278
1279    _wmready_checker = fopen(path_wm_ready, "wb");
1280    if (_wmready_checker)
1281      {
1282         TS("[WM] WINDOW MANAGER is READY!!!");
1283         PRCTL("[Winsys] WINDOW MANAGER is READY!!!");
1284         fclose(_wmready_checker);
1285
1286         /*TODO: Next lines should be removed. */
1287         FILE *_tmp_wm_ready_checker;
1288
1289         _tmp_wm_ready_checker = fopen(path_wm_ready, "wb");
1290
1291         if (_tmp_wm_ready_checker)
1292           {
1293              TS("[WM] temporary wm_ready path is created.");
1294              PRCTL("[Winsys] temporary wm_ready path is created.");
1295              fclose(_tmp_wm_ready_checker);
1296           }
1297         else
1298           {
1299              TS("[WM] temporary wm_ready path create failed.");
1300              PRCTL("[Winsys] temporary wm_ready path create failed.");
1301           }
1302      }
1303    else
1304      {
1305         TS("[WM] WINDOW MANAGER is READY. BUT, failed to create .wm_ready file.");
1306         PRCTL("[Winsys] WINDOW MANAGER is READY. BUT, failed to create .wm_ready file.");
1307      }
1308 }
1309
1310 static void
1311 _e_main_hooks_clean(void)
1312 {
1313    Eina_Inlist *l;
1314    E_Main_Hook *mh;
1315    unsigned int x;
1316
1317    for (x = 0; x < E_MAIN_HOOK_LAST; x++)
1318      EINA_INLIST_FOREACH_SAFE(_e_main_hooks[x], l, mh)
1319        {
1320           if (!mh->delete_me) continue;
1321           _e_main_hooks[x] = eina_inlist_remove(_e_main_hooks[x],
1322                                                 EINA_INLIST_GET(mh));
1323           free(mh);
1324        }
1325 }
1326
1327 static void
1328 _e_main_hook_call(E_Main_Hook_Point hookpoint, void *data EINA_UNUSED)
1329 {
1330    E_Main_Hook *mh;
1331
1332    _e_main_hooks_walking++;
1333    EINA_INLIST_FOREACH(_e_main_hooks[hookpoint], mh)
1334      {
1335         if (mh->delete_me) continue;
1336         mh->func(mh->data);
1337      }
1338    _e_main_hooks_walking--;
1339    if ((_e_main_hooks_walking == 0) && (_e_main_hooks_delete > 0))
1340      _e_main_hooks_clean();
1341 }
1342
1343 E_API E_Main_Hook *
1344 e_main_hook_add(E_Main_Hook_Point hookpoint, E_Main_Hook_Cb func, const void *data)
1345 {
1346    E_Main_Hook *mh;
1347
1348    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_MAIN_HOOK_LAST, NULL);
1349    mh = E_NEW(E_Main_Hook, 1);
1350    EINA_SAFETY_ON_NULL_RETURN_VAL(mh, NULL);
1351    mh->hookpoint = hookpoint;
1352    mh->func = func;
1353    mh->data = (void*)data;
1354    _e_main_hooks[hookpoint] = eina_inlist_append(_e_main_hooks[hookpoint],
1355                                                  EINA_INLIST_GET(mh));
1356    return mh;
1357 }
1358
1359 E_API void
1360 e_main_hook_del(E_Main_Hook *mh)
1361 {
1362    mh->delete_me = 1;
1363    if (_e_main_hooks_walking == 0)
1364      {
1365         _e_main_hooks[mh->hookpoint] = eina_inlist_remove(_e_main_hooks[mh->hookpoint],
1366                                                           EINA_INLIST_GET(mh));
1367         free(mh);
1368      }
1369    else
1370      _e_main_hooks_delete++;
1371 }
1372
1373 E_API void
1374 e_main_hook_call(E_Main_Hook_Point hookpoint)
1375 {
1376    if ((hookpoint < 0) || (hookpoint >= E_MAIN_HOOK_LAST)) return;
1377
1378    _e_main_hook_call(hookpoint, NULL);
1379 }