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