Use inotify to check for changes to the defaults database. Workaround for
[wmaker-crm.git] / src / main.c
1 /*
2  *  Window Maker window manager
3  *
4  *  Copyright (c) 1997-2003 Alfredo K. Kojima
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  *  USA.
20  */
21
22 #include <sys/inotify.h>
23
24 #include "wconfig.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <fcntl.h>
33
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36
37
38 /* Xlocale.h and locale.h are the same if X_LOCALE is undefind in wconfig.h,
39  * and if X_LOCALE is defined, X's locale emulating functions will be used.
40  * See Xlocale.h for more information.
41  */
42 #include <X11/Xlocale.h>
43
44 #define MAINFILE
45
46 #include "WindowMaker.h"
47 #include "window.h"
48 #include "funcs.h"
49 #include "menu.h"
50 #include "keybind.h"
51 #include "xmodifier.h"
52 #include "defaults.h"
53 #include "session.h"
54 #include "dialog.h"
55
56 #include <WINGs/WUtil.h>
57
58 /****** Global Variables ******/
59
60 /* general info */
61
62 Display *dpy;
63
64 char *ProgName;
65
66 unsigned int ValidModMask = 0xff;
67
68 int inotifyFD;
69 int inotifyWD;
70 /* locale to use. NULL==POSIX or C */
71 char *Locale=NULL;
72
73 int wScreenCount=0;
74
75 WPreferences wPreferences;
76
77
78 WMPropList *wDomainName;
79 WMPropList *wAttributeDomainName;
80
81 WShortKey wKeyBindings[WKBD_LAST];
82
83 /* defaults domains */
84 WDDomain *WDWindowMaker = NULL;
85 WDDomain *WDWindowAttributes = NULL;
86 WDDomain *WDRootMenu = NULL;
87
88 /* XContexts */
89 XContext wWinContext;
90 XContext wAppWinContext;
91 XContext wStackContext;
92 XContext wVEdgeContext;
93
94 /* Atoms */
95 Atom _XA_WM_STATE;
96 Atom _XA_WM_CHANGE_STATE;
97 Atom _XA_WM_PROTOCOLS;
98 Atom _XA_WM_TAKE_FOCUS;
99 Atom _XA_WM_DELETE_WINDOW;
100 Atom _XA_WM_SAVE_YOURSELF;
101 Atom _XA_WM_CLIENT_LEADER;
102 Atom _XA_WM_COLORMAP_WINDOWS;
103 Atom _XA_WM_COLORMAP_NOTIFY;
104
105 Atom _XA_GNUSTEP_WM_ATTR;
106 Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
107 Atom _XA_GNUSTEP_WM_RESIZEBAR;
108 Atom _XA_GNUSTEP_TITLEBAR_STATE;
109
110 Atom _XA_WINDOWMAKER_MENU;
111 Atom _XA_WINDOWMAKER_WM_PROTOCOLS;
112 Atom _XA_WINDOWMAKER_STATE;
113
114 Atom _XA_WINDOWMAKER_WM_FUNCTION;
115 Atom _XA_WINDOWMAKER_NOTICEBOARD;
116 Atom _XA_WINDOWMAKER_COMMAND;
117
118 Atom _XA_WINDOWMAKER_ICON_SIZE;
119 Atom _XA_WINDOWMAKER_ICON_TILE;
120
121
122 /* cursors */
123 Cursor wCursor[WCUR_LAST];
124
125 /* last event timestamp for XSetInputFocus */
126 Time LastTimestamp = CurrentTime;
127 /* timestamp on the last time we did XSetInputFocus() */
128 Time LastFocusChange = CurrentTime;
129
130 #ifdef SHAPE
131 Bool wShapeSupported;
132 int wShapeEventBase;
133 #endif
134
135 #ifdef KEEP_XKB_LOCK_STATUS
136 Bool wXkbSupported;
137 int wXkbEventBase;
138 #endif
139
140 /* special flags */
141 char WProgramSigState = 0;
142 char WProgramState = WSTATE_NORMAL;
143 char WDelayedActionSet = 0;
144
145
146 /* temporary stuff */
147 int wVisualID = -1;
148
149
150 /* notifications */
151 const char *WMNManaged = "WMNManaged";
152 const char *WMNUnmanaged = "WMNUnmanaged";
153 const char *WMNChangedWorkspace = "WMNChangedWorkspace";
154 const char *WMNChangedState = "WMNChangedState";
155 const char *WMNChangedFocus = "WMNChangedFocus";
156 const char *WMNChangedStacking = "WMNChangedStacking";
157 const char *WMNChangedName = "WMNChangedName";
158
159 const char *WMNWorkspaceCreated = "WMNWorkspaceCreated";
160 const char *WMNWorkspaceDestroyed = "WMNWorkspaceDestroyed";
161 const char *WMNWorkspaceChanged = "WMNWorkspaceChanged";
162 const char *WMNWorkspaceNameChanged = "WMNWorkspaceNameChanged";
163
164 const char *WMNResetStacking = "WMNResetStacking";
165
166 /******** End Global Variables *****/
167
168 static char *DisplayName = NULL;
169
170 static char **Arguments;
171
172 static int ArgCount;
173
174 extern void EventLoop();
175 extern void StartUp();
176 extern int MonitorLoop(int argc, char **argv);
177
178 static Bool multiHead = True;
179
180 /* stdi/o for log shell */
181 static int LogStdIn = -1, LogStdOut = -1, LogStdErr = -1;
182
183
184 static int real_main(int argc, char **argv);
185
186 void
187 Exit(int status)
188 {
189 #ifdef XSMP_ENABLED
190     wSessionDisconnectManager();
191 #endif
192     if (dpy)
193         XCloseDisplay(dpy);
194
195     exit(status);
196 }
197
198
199 void
200 Restart(char *manager, Bool abortOnFailure)
201 {
202     char *prog=NULL;
203     char *argv[MAX_RESTART_ARGS];
204     int i;
205
206     if (manager && manager[0]!=0) {
207         prog = argv[0] = strtok(manager, " ");
208         for (i=1; i<MAX_RESTART_ARGS; i++) {
209             argv[i]=strtok(NULL, " ");
210             if (argv[i]==NULL) {
211                 break;
212             }
213         }
214     }
215     if (dpy) {
216 #ifdef XSMP_ENABLED
217         wSessionDisconnectManager();
218 #endif
219         XCloseDisplay(dpy);
220         dpy = NULL;
221     }
222     if (!prog) {
223         execvp(Arguments[0], Arguments);
224         wfatal(_("failed to restart Window Maker."));
225     } else {
226         execvp(prog, argv);
227         wsyserror(_("could not exec %s"), prog);
228     }
229     if (abortOnFailure)
230         exit(7);
231 }
232
233
234
235 void
236 SetupEnvironment(WScreen *scr)
237 {
238     char *tmp, *ptr;
239     char buf[16];
240
241     if (multiHead) {
242         int len = strlen(DisplayName)+64;
243         tmp = wmalloc(len);
244         snprintf(tmp, len, "DISPLAY=%s", XDisplayName(DisplayName));
245         ptr = strchr(strchr(tmp, ':'), '.');
246         if (ptr)
247             *ptr = 0;
248         snprintf(buf, sizeof(buf), ".%i", scr->screen);
249         strcat(tmp, buf);
250         putenv(tmp);
251     }
252     tmp = wmalloc(60);
253     snprintf(tmp, 60, "WRASTER_COLOR_RESOLUTION%i=%i", scr->screen,
254              scr->rcontext->attribs->colors_per_channel);
255     putenv(tmp);
256 }
257
258
259
260
261 typedef struct {
262     WScreen *scr;
263     char *command;
264 } _tuple;
265
266
267 static void
268 shellCommandHandler(pid_t pid, unsigned char status, _tuple *data)
269 {
270     if (status == 127) {
271         char *buffer;
272
273         buffer = wstrconcat(_("Could not execute command: "), data->command);
274
275         wMessageDialog(data->scr, _("Error"), buffer, _("OK"), NULL, NULL);
276         wfree(buffer);
277     } else if (status != 127) {
278         /*
279          printf("%s: %i\n", data->command, status);
280          */
281     }
282
283     wfree(data->command);
284     wfree(data);
285 }
286
287
288 void
289 ExecuteShellCommand(WScreen *scr, char *command)
290 {
291     static char *shell = NULL;
292     pid_t pid;
293
294     /*
295      * This have a problem: if the shell is tcsh (not sure about others)
296      * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell
297      * will block and the command will not be executed.
298      if (!shell) {
299      shell = getenv("SHELL");
300      if (!shell)
301      shell = "/bin/sh";
302      }
303      */
304     shell = "/bin/sh";
305
306     pid = fork();
307
308     if (pid==0) {
309
310         SetupEnvironment(scr);
311
312 #ifdef HAVE_SETSID
313         setsid();
314 #endif
315         execl(shell, shell, "-c", command, NULL);
316         wsyserror("could not execute %s -c %s", shell, command);
317         Exit(-1);
318     } else if (pid < 0) {
319         wsyserror("cannot fork a new process");
320     } else {
321         _tuple *data = wmalloc(sizeof(_tuple));
322
323         data->scr = scr;
324         data->command = wstrdup(command);
325
326         wAddDeathHandler(pid, (WDeathHandler*)shellCommandHandler, data);
327     }
328 }
329
330
331 /*
332  *---------------------------------------------------------------------------
333  * StartLogShell
334  *      Start a shell that will receive all stdin and stdout from processes
335  * forked by wmaker.
336  *---------------------------------------------------------------------------
337  */
338 void
339 StartLogShell(WScreen *scr)
340 {
341     int in_fd[2];
342     int out_fd[2];
343     int err_fd[2];
344     pid_t pid;
345
346     SetupEnvironment(scr);
347
348     if (pipe(in_fd) < 0) {
349         wsyserror("could not create pipe for log shell\n");
350         return;
351     }
352     if (pipe(out_fd) < 0) {
353         wsyserror("could not create pipe for log shell\n");
354         close(in_fd[0]);
355         close(in_fd[1]);
356         return;
357     }
358     if (pipe(err_fd) < 0) {
359         wsyserror("could not create pipe for log shell\n");
360         close(out_fd[0]);
361         close(out_fd[1]);
362         close(in_fd[0]);
363         close(in_fd[1]);
364         return;
365     }
366
367     pid = fork();
368     if (pid < 0) {
369         wsyserror("could not fork a new process for log shell\n");
370         return;
371     } else if (pid == 0) {
372         close(in_fd[0]);
373         close(out_fd[1]);
374         close(err_fd[1]);
375
376         close(0);
377         close(1);
378         close(2);
379
380         if (dup2(in_fd[1], 0) < 0) {
381             wsyserror("could not redirect stdin for log shell\n");
382             exit(1);
383         }
384         if (dup2(out_fd[1], 1) < 0) {
385             wsyserror("could not redirect stdout for log shell\n");
386             exit(1);
387         }
388         if (dup2(err_fd[1], 2) < 0) {
389             wsyserror("could not redirect stderr for log shell\n");
390             exit(1);
391         }
392
393         close(in_fd[1]);
394         close(out_fd[1]);
395         close(err_fd[1]);
396
397         execl("/bin/sh", "/bin/sh", "-c", wPreferences.logger_shell, NULL);
398         wsyserror("could not execute %s\n", wPreferences.logger_shell);
399         exit(1);
400     } else {
401         close(in_fd[1]);
402         close(out_fd[0]);
403         close(err_fd[0]);
404
405         LogStdIn = in_fd[1];
406         LogStdOut = out_fd[0];
407         LogStdErr = err_fd[0];
408     }
409 }
410
411
412 /*
413  *---------------------------------------------------------------------
414  * wAbort--
415  *      Do a major cleanup and exit the program
416  *
417  *----------------------------------------------------------------------
418  */
419 void
420 wAbort(Bool dumpCore)
421 {
422     int i;
423     WScreen *scr;
424
425     for (i=0; i<wScreenCount; i++) {
426         scr = wScreenWithNumber(i);
427         if (scr)
428             RestoreDesktop(scr);
429     }
430     printf(_("%s aborted.\n"), ProgName);
431     if (dumpCore)
432         abort();
433     else
434         exit(1);
435 }
436
437
438 void
439 print_help()
440 {
441     printf(_("Usage: %s [options]\n"), ProgName);
442     puts(_("The Window Maker window manager for the X window system"));
443     puts("");
444     puts(_(" -display host:dpy  display to use"));
445 #ifdef USECPP
446     puts(_(" --no-cpp           disable preprocessing of configuration files"));
447 #endif
448     puts(_(" --no-dock          do not open the application Dock"));
449     puts(_(" --no-clip          do not open the workspace Clip"));
450     puts(_(" --no-autolaunch    do not autolaunch applications"));
451     puts(_(" --dont-restore             do not restore saved session"));
452
453     puts(_(" --locale locale    locale to use"));
454
455     puts(_(" --create-stdcmap   create the standard colormap hint in PseudoColor visuals"));
456     puts(_(" --visual-id visualid       visual id of visual to use"));
457     puts(_(" --static           do not update or save configurations"));
458 #ifdef DEBUG
459     puts(_(" --synchronous              turn on synchronous display mode"));
460 #endif
461     puts(_(" --version          print version and exit"));
462     puts(_(" --help                     show this message"));
463 }
464
465
466
467 void
468 check_defaults()
469 {
470     char *path;
471
472     path = wdefaultspathfordomain("WindowMaker");
473
474     if (access(path, R_OK)!=0) {
475 #if 0
476         wfatal(_("could not find user GNUstep directory (%s).\n"
477                  "Make sure you have installed Window Maker correctly and run wmaker.inst"),
478                path);
479         exit(1);
480 #else
481         wwarning(_("could not find user GNUstep directory (%s)."), path);
482
483         if (system("wmaker.inst --batch") != 0) {
484             wwarning(_("There was an error while creating GNUstep directory, please "
485                        "make sure you have installed Window Maker correctly and run wmaker.inst"));
486         } else {
487             wwarning(_("%s directory created with default configuration."), path);
488         }
489 #endif
490     }
491
492     wfree(path);
493 }
494
495
496 /*
497  * Add watch here, used to notify if configuration
498  * files have changed, using linux kernel inotify mechanism
499  */
500
501 static void
502 inotifyWatchConfig()
503 {
504     char *watchPath;
505     inotifyFD = inotify_init(); /* Initialise an inotify instance */
506     if (inotifyFD < 0) {
507          wwarning(_("could not initialise an inotify instance."
508                    " Changes to the defaults database will require"
509                    " a restart to take effect. Check your kernel!"));
510     } else {            
511          watchPath = wstrconcat(wusergnusteppath(), "/Defaults");
512          /* Add the watch; really we are only looking for modify events
513          * but we might want more in the future so check all events for now.
514          * The individual events are checked for in event.c.
515          */
516          inotifyWD = inotify_add_watch (inotifyFD, watchPath, IN_ALL_EVENTS);
517          if (inotifyWD < 0) {
518             wwarning(_("could not add an inotify watch on path\n."
519                         "%s\n"
520                         "Changes to the defaults database will require"
521                         " a restart to take effect."),watchPath);
522             close (inotifyFD);
523          }
524     }
525     wfree(watchPath);
526 }
527
528 static void
529 execInitScript()
530 {
531     char *file, *paths;
532
533     paths = wstrconcat(wusergnusteppath(), "/Library/WindowMaker");
534     paths = wstrappend(paths, ":"DEF_CONFIG_PATHS);
535
536     file = wfindfile(paths, DEF_INIT_SCRIPT);
537     wfree(paths);
538
539     if (file) {
540         if (system(file) != 0) {
541             wsyserror(_("%s:could not execute initialization script"), file);
542         }
543 #if 0
544         if (fork()==0) {
545             execl("/bin/sh", "/bin/sh", "-c", file, NULL);
546             wsyserror(_("%s:could not execute initialization script"), file);
547             exit(1);
548         }
549 #endif
550         wfree(file);
551     }
552 }
553
554
555 void
556 ExecExitScript()
557 {
558     char *file, *paths;
559
560     paths = wstrconcat(wusergnusteppath(), "/Library/WindowMaker");
561     paths = wstrappend(paths, ":"DEF_CONFIG_PATHS);
562
563     file = wfindfile(paths, DEF_EXIT_SCRIPT);
564     wfree(paths);
565
566     if (file) {
567         if (system(file) != 0) {
568             wsyserror(_("%s:could not execute exit script"), file);
569         }
570 #if 0
571         if (fork()==0) {
572             execl("/bin/sh", "/bin/sh", "-c", file, NULL);
573             wsyserror(_("%s:could not execute exit script"), file);
574             exit(1);
575         }
576 #endif
577         wfree(file);
578     }
579 }
580
581 #if 0
582 char*
583 getFullPath(char *path)
584 {
585     char buffer[1024];
586     char *tmp;
587     char *basep = (char*)buffer;
588
589     if (*path != '/' && getcwd(buffer, 1023)) {
590
591         for (;;) {
592             if (strncmp(path, "../", 3)==0) {
593                 path += 3;
594                 basep = strchr(basep, '/');
595                 if (!basep || *path==0)
596                     break;
597             }
598         }
599         if (*path == '/' || strncmp(path, "./",2)==0) {
600             tmp =
601         }
602
603         /*
604          * path
605          * ./path
606          * ../path
607          * ../../path
608          */
609
610
611     } else {
612         return wstrconcat(path);
613     }
614
615     return tmp;
616 }
617 #endif
618
619
620 int
621 main(int argc, char **argv)
622 {
623     int i_am_the_monitor, i, len;
624     char *str, *alt;
625
626     /* setup common stuff for the monitor and wmaker itself */
627     WMInitializeApplication("WindowMaker", &argc, argv);
628
629     memset(&wPreferences, 0, sizeof(WPreferences));
630
631     wPreferences.fallbackWMs = WMCreateArray(8);
632     alt = getenv("WINDOWMAKER_ALT_WM");
633     if (alt != NULL)
634         WMAddToArray(wPreferences.fallbackWMs, wstrdup(alt));
635
636     WMAddToArray(wPreferences.fallbackWMs, wstrdup("blackbox"));
637     WMAddToArray(wPreferences.fallbackWMs, wstrdup("metacity"));
638     WMAddToArray(wPreferences.fallbackWMs, wstrdup("fvwm"));
639     WMAddToArray(wPreferences.fallbackWMs, wstrdup("twm"));
640     WMAddToArray(wPreferences.fallbackWMs, NULL);
641     WMAddToArray(wPreferences.fallbackWMs, wstrdup("rxvt"));
642     WMAddToArray(wPreferences.fallbackWMs, wstrdup("xterm"));
643
644     i_am_the_monitor= 1;
645
646     for (i= 1; i < argc; i++)
647     {
648         if (strncmp(argv[i], "--for-real", strlen("--for-real"))==0)
649         {
650             i_am_the_monitor= 0;
651             break;
652         }
653         else if (strcmp(argv[i], "-display")==0 || strcmp(argv[i], "--display")==0)
654         {
655             i++;
656             if (i>=argc) {
657                 wwarning(_("too few arguments for %s"), argv[i-1]);
658                 exit(0);
659             }
660             DisplayName = argv[i];
661         }
662     }
663
664     DisplayName = XDisplayName(DisplayName);
665     len = strlen(DisplayName)+64;
666     str = wmalloc(len);
667     snprintf(str, len, "DISPLAY=%s", DisplayName);
668     putenv(str);
669
670     if (i_am_the_monitor)
671       return MonitorLoop(argc, argv);
672     else
673       return real_main(argc, argv);
674 }
675
676
677 static int
678 real_main(int argc, char **argv)
679 {
680     int i, restart=0;
681     char *str;
682     int d, s;
683     int flag;
684 #ifdef DEBUG
685     Bool doSync = False;
686 #endif
687     setlocale(LC_ALL, "");
688
689     wsetabort(wAbort);
690
691     /* for telling WPrefs what's the name of the wmaker binary being ran */
692
693     str = wstrconcat("WMAKER_BIN_NAME=", argv[0]);
694     putenv(str);
695
696     flag= 0;
697     ArgCount = argc;
698     Arguments = wmalloc(sizeof(char*)*(ArgCount+1));
699     for (i= 0; i < argc; i++)
700     {
701         Arguments[i]= argv[i];
702     }
703     /* add the extra option to signal that we're just restarting wmaker */
704     Arguments[argc-1]= "--for-real=";
705     Arguments[argc]= NULL;
706
707     ProgName = strrchr(argv[0],'/');
708     if (!ProgName)
709         ProgName = argv[0];
710     else
711         ProgName++;
712
713
714     restart = 0;
715
716     if (argc>1) {
717         for (i=1; i<argc; i++) {
718 #ifdef USECPP
719             if (strcmp(argv[i], "-nocpp")==0
720                 || strcmp(argv[i], "--no-cpp")==0) {
721                 wPreferences.flags.nocpp=1;
722             } else
723 #endif
724                 if (strcmp(argv[i], "--for-real")==0) {
725                     wPreferences.flags.restarting = 0;
726                 } else if (strcmp(argv[i], "--for-real=")==0) {
727                     wPreferences.flags.restarting = 1;
728                 } else if (strcmp(argv[i], "--for-real-")==0) {
729                     wPreferences.flags.restarting = 2;
730                 } else if (strcmp(argv[i], "-no-autolaunch")==0
731                     || strcmp(argv[i], "--no-autolaunch")==0) {
732                     wPreferences.flags.noautolaunch = 1;
733                 } else if (strcmp(argv[i], "-dont-restore")==0
734                            || strcmp(argv[i], "--dont-restore")==0) {
735                     wPreferences.flags.norestore = 1;
736                 } else if (strcmp(argv[i], "-nodock")==0
737                            || strcmp(argv[i], "--no-dock")==0) {
738                     wPreferences.flags.nodock=1;
739                 } else if (strcmp(argv[i], "-noclip")==0
740                            || strcmp(argv[i], "--no-clip")==0) {
741                     wPreferences.flags.noclip=1;
742                 } else if (strcmp(argv[i], "-version")==0
743                            || strcmp(argv[i], "--version")==0) {
744                     printf("Window Maker %s\n", VERSION);
745                     exit(0);
746                 } else if (strcmp(argv[i], "--global_defaults_path")==0) {
747                     printf("%s/WindowMaker\n", SYSCONFDIR);
748                     exit(0);
749 #ifdef DEBUG
750                 } else if (strcmp(argv[i], "--synchronous")==0) {
751                     doSync = 1;
752 #endif
753                 } else if (strcmp(argv[i], "-locale")==0
754                            || strcmp(argv[i], "--locale")==0) {
755                     i++;
756                     if (i>=argc) {
757                         wwarning(_("too few arguments for %s"), argv[i-1]);
758                         exit(0);
759                     }
760                     Locale = argv[i];
761                 } else if (strcmp(argv[i], "-display")==0
762                            || strcmp(argv[i], "--display")==0) {
763                     i++;
764                     if (i>=argc) {
765                         wwarning(_("too few arguments for %s"), argv[i-1]);
766                         exit(0);
767                     }
768                     DisplayName = argv[i];
769                 } else if (strcmp(argv[i], "-visualid")==0
770                            || strcmp(argv[i], "--visual-id")==0) {
771                     i++;
772                     if (i>=argc) {
773                         wwarning(_("too few arguments for %s"), argv[i-1]);
774                         exit(0);
775                     }
776                     if (sscanf(argv[i], "%i", &wVisualID)!=1) {
777                         wwarning(_("bad value for visualid: \"%s\""), argv[i]);
778                         exit(0);
779                     }
780                 } else if (strcmp(argv[i], "-static")==0
781                            || strcmp(argv[i], "--static")==0) {
782
783                     wPreferences.flags.noupdates = 1;
784 #ifdef XSMP_ENABLED
785                 } else if (strcmp(argv[i], "-clientid")==0
786                            || strcmp(argv[i], "-restore")==0) {
787                     i++;
788                     if (i>=argc) {
789                         wwarning(_("too few arguments for %s"), argv[i-1]);
790                         exit(0);
791                     }
792 #endif
793                 } else if (strcmp(argv[i], "--help")==0) {
794                     print_help();
795                     exit(0);
796                 } else {
797                     printf(_("%s: invalid argument '%s'\n"), argv[0], argv[i]);
798                     printf(_("Try '%s --help' for more information\n"), argv[0]);
799                     exit(1);
800                 }
801         }
802     }
803
804     if (!wPreferences.flags.noupdates) {
805         /* check existence of Defaults DB directory */
806         check_defaults();
807     }
808
809
810     if (Locale) {
811         /* return of wstrconcat should not be free-ed! read putenv man page */
812         putenv(wstrconcat("LANG=", Locale));
813     } else {
814         Locale = getenv("LC_ALL");
815         if (!Locale) {
816             Locale = getenv("LANG");
817         }
818     }
819
820     setlocale(LC_ALL, "");
821
822     if (!Locale || strcmp(Locale, "C")==0 || strcmp(Locale, "POSIX")==0)
823         Locale = NULL;
824 #ifdef I18N
825     if (getenv("NLSPATH"))
826         bindtextdomain("WindowMaker", getenv("NLSPATH"));
827     else
828         bindtextdomain("WindowMaker", LOCALEDIR);
829     bind_textdomain_codeset("WindowMaker", "UTF-8");
830     textdomain("WindowMaker");
831
832     if (!XSupportsLocale()) {
833         wwarning(_("X server does not support locale"));
834     }
835
836     if (XSetLocaleModifiers("") == NULL) {
837         wwarning(_("cannot set locale modifiers"));
838     }
839 #endif
840
841     if (Locale) {
842         char *ptr;
843
844         Locale = wstrdup(Locale);
845         ptr = strchr(Locale, '.');
846         if (ptr)
847             *ptr = 0;
848     }
849
850     /* open display */
851     dpy = XOpenDisplay(DisplayName);
852     if (dpy == NULL) {
853         wfatal(_("could not open display \"%s\""), XDisplayName(DisplayName));
854         exit(1);
855     }
856
857     if (fcntl(ConnectionNumber(dpy), F_SETFD, FD_CLOEXEC) < 0) {
858         wsyserror("error setting close-on-exec flag for X connection");
859         exit(1);
860     }
861
862     if (wVisualID < 0)
863         /*
864          *   If unspecified, use default visual instead of waiting
865          * for wrlib/context.c:bestContext() that may end up choosing
866          * the "fake" 24 bits added by the Composite extension.
867          *   This is required to avoid all sort of corruptions when
868          * composite is enabled, and at a depth other than 24.
869          */
870         wVisualID = (int)DefaultVisual(dpy, DefaultScreen(dpy))->visualid;
871
872     /* check if the user specified a complete display name (with screen).
873      * If so, only manage the specified screen */
874     if (DisplayName)
875         str = strchr(DisplayName, ':');
876     else
877         str = NULL;
878
879     if (str && sscanf(str, ":%i.%i", &d, &s)==2)
880         multiHead = False;
881
882     DisplayName = XDisplayName(DisplayName);
883     {
884         int len = strlen(DisplayName)+64;
885         str = wmalloc(len);
886         snprintf(str, len, "DISPLAY=%s", DisplayName);
887     }
888     putenv(str);
889
890 #ifdef DEBUG
891     if (doSync)
892         XSynchronize(dpy, True);
893 #endif
894
895     wXModifierInitialize();
896
897 #ifdef XSMP_ENABLED
898     wSessionConnectManager(argv, argc);
899 #endif
900
901     StartUp(!multiHead);
902
903     if (wScreenCount==1)
904         multiHead = False;
905
906     execInitScript();
907     inotifyWatchConfig();
908     EventLoop();
909     return -1;
910 }
911