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