chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / main.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2009 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "comms.h"
26 #include "cursors.h"
27 #include "desktops.h"
28 #include "dialog.h"
29 #include "edbus.h"
30 #include "eimage.h"
31 #include "emodule.h"
32 #include "events.h"
33 #include "ewins.h"
34 #include "file.h"
35 #include "grabs.h"
36 #include "hints.h"
37 #include "session.h"
38 #include "snaps.h"
39 #include "user.h"
40 #include "xwin.h"
41 #include <sys/utsname.h>
42 #include <signal.h>
43 #include <time.h>
44
45 const char          e_wm_name[] = "e16";
46 const char          e_wm_version[] = VERSION;
47
48 EConf               Conf;
49 EMode               Mode;
50
51 static int          EoptGet(int argc, char **argv);
52 static void         EoptHelp(void);
53 static void         ECheckEprog(const char *name);
54 static void         EDirUserSet(const char *dir);
55 static void         EConfNameSet(const char *dir);
56 static void         EDirUserCacheSet(const char *dir);
57 static void         EDirsSetup(void);
58 static void         RunInitPrograms(void);
59
60 static int          eoptind = 0;
61 const char         *eoptarg = NULL;
62
63 typedef struct {
64    char                sopt;
65    char                arg;
66    const char         *lopt;
67    const char         *oarg;
68    const char         *desc;
69 } EOpt;
70
71 static const EOpt   Eopts[] = {
72    {'d', 1, "display", "display", "Set display"},
73    {'f', 0, "fast", NULL, "Fast startup"},
74    {'h', 0, "help", NULL, "Show help"},
75    {'m', 1, NULL, NULL, NULL},
76    {'p', 1, "config-prefix", "prefix", "Configuration file name prefix"},
77    {'P', 1, "econfdir", "path", "Set user configuration directory"},
78    {'Q', 1, "ecachedir", "path", "Set user cache directory"},
79    {'s', 1, "single", "screen", "Run only on given screen"},
80    {'S', 1, "sm-client-id", "session id", "Set session manager ID"},
81    {'t', 1, "theme", "name", "Select theme"},
82    {'v', 0, "verbose", NULL, "Show additional info"},
83    {'V', 0, "version", NULL, "Show version"},
84    {'w', 1, "window", "WxH", "Run in window"},
85    {'X', 1, NULL, NULL, NULL},
86 };
87
88 int
89 main(int argc, char **argv)
90 {
91    int                 ch, i, loop;
92    struct utsname      ubuf;
93    const char         *str, *dstr;
94
95    /* This function runs all the setup for startup, and then 
96     * proceeds into the primary event loop at the end.
97     */
98
99    /* Init state variable struct */
100    memset(&Mode, 0, sizeof(EMode));
101
102    Mode.wm.master = 1;
103    Mode.wm.pid = getpid();
104    Mode.wm.exec_name = argv[0];
105    Mode.wm.startup = 1;
106
107    Mode.mode = MODE_NONE;
108    Mode.move.check = 1;
109
110    EXInit();
111    Dpy.screen = -1;
112
113    str = getenv("EDEBUG");
114    if (str)
115       EDebugInit(str);
116    str = getenv("EDEBUG_COREDUMP");
117    if (str)
118       Mode.wm.coredump = 1;
119    str = getenv("EDEBUG_EXIT");
120    if (str)
121       Mode.debug_exit = atoi(str);
122
123    str = getenv("ECONFNAME");
124    if (str)
125       EConfNameSet(str);
126    str = getenv("ECONFDIR");
127    if (str)
128       EDirUserSet(str);
129    str = getenv("ECACHEDIR");
130    if (str)
131       EDirUserCacheSet(str);
132
133    srand((unsigned int)time(NULL));
134
135    if (!uname(&ubuf))
136       Mode.wm.machine_name = Estrdup(ubuf.nodename);
137    if (!Mode.wm.machine_name)
138       Mode.wm.machine_name = Estrdup("localhost");
139
140    /* Now we're going to interpret any of the commandline parameters
141     * that are passed to it -- Well, at least the ones that we
142     * understand.
143     */
144
145    Mode.theme.path = NULL;
146    dstr = NULL;
147
148    for (loop = 1; loop;)
149      {
150         ch = EoptGet(argc, argv);
151         if (ch <= 0)
152            break;
153 #if 0
154         Eprintf("Opt: %c: %d - %s\n", ch, eoptind, eoptarg);
155 #endif
156         switch (ch)
157           {
158           default:
159           case '?':
160              printf("e16: Ignoring: ");
161              for (i = eoptind; i < argc; i++)
162                 printf("%s ", argv[i]);
163              printf("\n");
164              loop = 0;
165              break;
166           case 'h':
167              EoptHelp();
168              exit(0);
169              break;
170           case 'd':
171              dstr = eoptarg;
172              break;
173           case 'f':
174              Mode.wm.restart = 1;
175              break;
176           case 'p':
177              EConfNameSet(eoptarg);
178              break;
179           case 'P':
180              EDirUserSet(eoptarg);
181              break;
182           case 'Q':
183              EDirUserCacheSet(eoptarg);
184              break;
185           case 's':
186              Mode.wm.single = 1;
187              Dpy.screen = strtoul(eoptarg, NULL, 10);
188              break;
189           case 'S':
190              SetSMID(eoptarg);
191              break;
192           case 't':
193              Mode.theme.path = Estrdup(eoptarg);
194              break;
195           case 'V':
196              printf("%s %s\n", e_wm_name, e_wm_version);
197              exit(0);
198              break;
199           case 'v':
200              EDebugSet(EDBUG_TYPE_VERBOSE, 1);
201              break;
202           case 'w':
203              sscanf(eoptarg, "%dx%d", &Mode.wm.win_w, &Mode.wm.win_h);
204              Mode.wm.window = 1;
205              Mode.wm.single = 1;
206              Mode.wm.master = 0;
207              break;
208 #ifdef USE_EXT_INIT_WIN
209           case 'X':
210              ExtInitWinSet(strtoul(eoptarg, NULL, 0));
211              Mode.wm.restart = 1;
212              break;
213 #endif
214           case 'm':
215              Mode.wm.master = 0;
216              Mode.wm.master_screen = strtoul(eoptarg, NULL, 10);
217              break;
218           }
219      }
220
221    SignalsSetup();              /* Install signal handlers */
222
223    SetupX(dstr);                /* This is where the we fork per screen */
224    /* X is now running, and we have forked per screen */
225
226    /* So far nothing should rely on a selected settings or theme. */
227    ConfigurationLoad();         /* Load settings */
228
229    /* Initialise internationalisation */
230    LangInit();
231
232    ECheckEprog("epp");
233    ECheckEprog("eesh");
234    EDirsSetup();
235
236    /* The theme path must now be available for config file loading. */
237    ThemePathFind();
238
239    /* Set the Environment variables */
240    Esetenv("EVERSION", e_wm_version);
241    Esetenv("EROOT", EDirRoot());
242    Esetenv("EBIN", EDirBin());
243    Esetenv("ECONFDIR", EDirUser());
244    Esetenv("ECACHEDIR", EDirUserCache());
245    Esetenv("ETHEME", Mode.theme.path);
246
247    /* Move elsewhere? */
248    EImageInit();
249    HintsInit();
250    CommsInit();
251    SessionInit();
252    SnapshotsLoad();
253
254 #if USE_DBUS
255    DbusInit();
256 #endif
257
258    if (Mode.wm.window)
259       EMapWindow(VROOT);
260
261    ModulesSignal(ESIGNAL_INIT, NULL);
262
263    /* Load the theme */
264    ThemeConfigLoad();
265
266    if (Mode.debug_exit)
267       return 0;
268
269    /* Do initial configuration */
270    ModulesSignal(ESIGNAL_CONFIGURE, NULL);
271
272    /* Set root window cursor */
273    ECsrApply(ECSR_ROOT, WinGetXwin(VROOT));
274
275 #ifdef USE_EXT_INIT_WIN
276    /* Kill the E process owning the "init window" */
277    ExtInitWinKill();
278 #endif
279
280    /* let's make sure we set this up and go to our desk anyways */
281    DeskGoto(DesksGetCurrent());
282    ESync(ESYNC_MAIN);
283
284 #ifdef SIGCONT
285    for (i = 0; i < Mode.wm.child_count; i++)
286       kill(Mode.wm.children[i], SIGCONT);
287 #endif
288
289    ModulesSignal(ESIGNAL_START, NULL);
290 #if ENABLE_DIALOGS
291    DialogsInit();
292 #endif
293    EwinsManage();
294
295    RunInitPrograms();
296    SnapshotsSpawn();
297
298    if (!Mode.wm.restart)
299       StartupWindowsOpen();
300
301    Conf.startup.firsttime = 0;
302    Mode.wm.save_ok = Conf.autosave;
303    Mode.wm.startup = 0;
304    autosave();
305
306    /* The primary event loop */
307    EventsMain();
308
309    SessionExit(EEXIT_QUIT, NULL);
310
311    return 0;
312 }
313
314 void
315 EExit(int exitcode)
316 {
317    int                 i;
318
319    if (EDebug(EDBUG_TYPE_SESSION))
320       Eprintf("EExit(%d)\n", exitcode);
321
322    if (disp)
323      {
324         EUngrabServer();
325         GrabPointerRelease();
326         XAllowEvents(disp, AsyncBoth, CurrentTime);
327
328         /* XSetInputFocus(disp, None, RevertToParent, CurrentTime); */
329         /* I think this is a better way to release the grabs: (felix) */
330         XSetInputFocus(disp, PointerRoot, RevertToPointerRoot, CurrentTime);
331         ESelectInput(VROOT, 0);
332         EDisplayClose();
333      }
334
335    if (Mode.wm.master)
336      {
337         for (i = 0; i < Mode.wm.child_count; i++)
338            kill(Mode.wm.children[i], SIGINT);
339      }
340    else
341      {
342         exitcode = 0;
343      }
344
345    exit(exitcode);
346 }
347
348 /*
349  * Command line parsing.
350  * Not entirely standard compliant, but close enough.
351  */
352 static int
353 EoptGet(int argc, char **argv)
354 {
355    const char         *s;
356    unsigned int        i, len;
357    int                 lopt;
358    const EOpt         *eopt;
359
360    eoptind++;
361    if (eoptind >= argc)
362       return 0;
363
364    s = argv[eoptind];
365    if (*s++ != '-')
366       return 0;
367
368    lopt = 0;
369    if (*s == '-')
370      {
371         lopt = 1;
372         s++;
373      }
374
375    eoptarg = NULL;
376    eopt = NULL;
377    for (i = 0; i < sizeof(Eopts) / sizeof(EOpt); i++)
378      {
379         eopt = &Eopts[i];
380
381         /* Short option */
382         if (!lopt)
383           {
384              if (!eopt->sopt || eopt->sopt != s[0])
385                 continue;
386              if (eopt->arg)
387                {
388                   if (s[1])
389                     {
390                        eoptarg = s + 1;
391                        goto found;
392                     }
393                   goto found;
394                }
395              if (s[1])
396                 break;
397              goto found;
398           }
399
400         if (!eopt->lopt)
401            continue;
402
403         /* Long option */
404         len = strlen(eopt->lopt);
405         if (strncmp(eopt->lopt, s, len))
406            continue;
407         if (eopt->arg)
408           {
409              if (s[len] == '\0')
410                 goto found;
411              if (s[len] != '=')
412                 break;
413              eoptarg = s + len + 1;
414           }
415         goto found;
416      }
417    return '?';
418
419  found:
420    if (!eopt->arg || eoptarg)
421       return eopt->sopt;
422
423    if (eoptind >= argc - 1)
424       return '?';               /* Missing param */
425
426    eoptind++;
427    eoptarg = argv[eoptind];
428    return eopt->sopt;
429 }
430
431 static void
432 EoptHelp(void)
433 {
434    unsigned int        i;
435    const EOpt         *eopt;
436    char                buf[256];
437
438    printf("e16 options:\n");
439    for (i = 0; i < sizeof(Eopts) / sizeof(EOpt); i++)
440      {
441         eopt = &Eopts[i];
442         if (!eopt->desc)
443            continue;
444         if (eopt->oarg)
445            Esnprintf(buf, sizeof(buf), "--%s <%s>", eopt->lopt, eopt->oarg);
446         else
447            Esnprintf(buf, sizeof(buf), "--%s", eopt->lopt);
448         printf("  -%c  %-30s\t%s\n", eopt->sopt, buf, eopt->desc);
449      }
450 }
451
452 static void
453 RunDocBrowser(void)
454 {
455    char                buf[FILEPATH_LEN_MAX];
456
457    Esnprintf(buf, sizeof(buf), "%s/edox", EDirBin());
458    if (!canexec(buf))
459       return;
460    Esnprintf(buf, sizeof(buf), "%s/E-docs/MAIN", EDirRoot());
461    if (!canread(buf))
462       return;
463
464    Esnprintf(buf, sizeof(buf), "%s/edox %s/E-docs", EDirBin(), EDirRoot());
465    execApplication(buf, 0);
466 }
467
468 static void
469 RunMenuGen(void)
470 {
471    char                buf[FILEPATH_LEN_MAX];
472
473    Esnprintf(buf, sizeof(buf), "%s/scripts/e_gen_menu", EDirRoot());
474    execApplication(buf, EXEC_SET_LANG);
475 }
476
477 static void
478 RunInitPrograms(void)
479 {
480    if (Mode.wm.session_start)
481       SessionHelper(ESESSION_INIT);
482
483    SessionHelper(ESESSION_START);
484
485    if (Mode.firsttime && Mode.wm.master)
486      {
487         RunMenuGen();
488         RunDocBrowser();
489      }
490 }
491
492 const char         *
493 EDirBin(void)
494 {
495    return ENLIGHTENMENT_BIN;
496 }
497
498 const char         *
499 EDirRoot(void)
500 {
501    return ENLIGHTENMENT_ROOT;
502 }
503
504 static void
505 EConfNameSet(const char *name)
506 {
507    Efree(Mode.conf.name);
508    Mode.conf.name = Estrdup(name);
509    Esetenv("ECONFNAME", Mode.conf.name);
510 }
511
512 static void
513 EDirUserSet(const char *dir)
514 {
515    if (!strcmp(dir, EDirUser()))
516       return;
517    Efree(Mode.conf.dir);
518    Mode.conf.dir = Estrdup(dir);
519 }
520
521 static void
522 EDirUserCacheSet(const char *dir)
523 {
524    if (!strcmp(dir, EDirUser()))
525       return;
526    Efree(Mode.conf.cache_dir);
527    Mode.conf.cache_dir = Estrdup(dir);
528 }
529
530 static const char  *
531 EConfNameDefault(void)
532 {
533    return "e_config";
534 }
535
536 static const char  *
537 EConfName(void)
538 {
539    return (Mode.conf.name) ? Mode.conf.name : EConfNameDefault();
540 }
541
542 const char         *
543 EDirUser(void)
544 {
545    static char        *user_dir = NULL;
546    char               *home, buf[4096];
547
548    if (Mode.conf.dir)
549       return Mode.conf.dir;
550
551    if (user_dir)
552       return user_dir;
553
554    home = homedir(getuid());
555    Esnprintf(buf, sizeof(buf), "%s/.e16", home);
556    Efree(home);
557    user_dir = Estrdup(buf);
558
559    return user_dir;
560 }
561
562 const char         *
563 EDirUserCache(void)
564 {
565    if (Mode.conf.cache_dir)
566       return Mode.conf.cache_dir;
567    return EDirUser();
568 }
569
570 void
571 Etmp(char *s)
572 {
573    static unsigned int n_calls = 0;
574
575    Esnprintf(s, 1024, "%s/TMP_%d_%d", EDirUser(), getpid(), n_calls++);
576 }
577
578 static void
579 EDirCheck(const char *dir)
580 {
581    if (file_test(dir, EFILE_DIR | EPERM_RWX))
582       return;
583
584    Alert(_("%s must be a directory in which you have\n"
585            "read, write, and execute permission.\n"), dir);
586    EExit(1);
587 }
588
589 void
590 EDirMake(const char *base, const char *name)
591 {
592    char                s[1024];
593
594    Esnprintf(s, sizeof(s), "%s/%s", base, name);
595    if (!exists(s))
596       E_md(s);
597    else
598       EDirCheck(s);
599 }
600
601 static void
602 EDirsSetup(void)
603 {
604    char                s[1024], ss[1024], *home;
605
606    home = homedir(getuid());
607    if (home)
608      {
609         EDirCheck(home);
610         Efree(home);
611      }
612
613    Esnprintf(s, sizeof(s), "%s", EDirUser());
614    if (exists(s))
615      {
616         if (!isdir(s))
617           {
618              Esnprintf(ss, sizeof(ss), "%s.old", EDirUser());
619              E_mv(s, ss);
620              E_md(s);
621           }
622         else
623            EDirCheck(s);
624      }
625    else
626       E_md(s);
627
628    Esnprintf(s, sizeof(s), "%s/menus", EDirUser());
629    Mode.firsttime = !exists(s);
630
631    EDirMake(EDirUser(), "themes");
632    EDirMake(EDirUser(), "backgrounds");
633    EDirMake(EDirUser(), "menus");
634
635    EDirMake(EDirUserCache(), "cached");
636    EDirMake(EDirUserCache(), "cached/cfg");
637 }
638
639 /*
640  * The user control config is called "~/.e16/e_config-$DISPLAY"
641  * The client data appends ".clients" onto this filename and the snapshot data
642  * appends ".snapshots".
643  */
644 const char         *
645 EGetSavePrefix(void)
646 {
647    static char        *def_prefix = NULL;
648    char               *s, buf[1024];
649
650    if (def_prefix)
651       return def_prefix;
652
653    if (Mode.conf.name)
654       Esnprintf(buf, sizeof(buf), "%s/%s-%d", EDirUser(), EConfName(),
655                 Dpy.screen);
656    else if (Mode.wm.window)
657       Esnprintf(buf, sizeof(buf), "%s/%s-window", EDirUser(),
658                 EConfNameDefault());
659    else
660       Esnprintf(buf, sizeof(buf), "%s/%s-%s", EDirUser(), EConfNameDefault(),
661                 Dpy.name);
662    def_prefix = Estrdup(buf);
663
664    for (s = def_prefix; (s = strchr(s, ':')) != NULL; *s = '-')
665       ;
666
667    return def_prefix;
668 }
669
670 static void
671 ECheckEprog(const char *name)
672 {
673    char                s[1024];
674
675    Esnprintf(s, sizeof(s), "%s/%s", EDirBin(), name);
676
677    if (!exists(s))
678      {
679         Alert(_("!!!!!!!! ERROR ERROR ERROR ERROR !!!!!!!!\n" "\n"
680                 "Enlightenment's utility executable cannot be found at:\n"
681                 "\n" "%s\n"
682                 "This is a fatal error and Enlightenment will cease to run.\n"
683                 "Please rectify this situation and ensure it is installed\n"
684                 "correctly.\n" "\n"
685                 "The reason this could be missing is due to badly created\n"
686                 "packages, someone manually deleting that program or perhaps\n"
687                 "an error in installing Enlightenment.\n"), s);
688         EExit(0);
689      }
690
691    if (!canexec(s))
692      {
693         Alert(_("!!!!!!!! ERROR ERROR ERROR ERROR !!!!!!!!\n" "\n"
694                 "Enlightenment's utility executable is not able to be executed:\n"
695                 "\n" "%s\n"
696                 "This is a fatal error and Enlightenment will cease to run.\n"
697                 "Please rectify this situation and ensure it is installed\n"
698                 "correctly.\n"), s);
699         EExit(0);
700      }
701 }