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