Change to the linux kernel coding style
[wmaker-crm.git] / src / startup.c
1 /*
2  *  Window Maker window manager
3  *
4  *  Copyright (c) 1997-2003 Alfredo K. Kojima
5  *  Copyright (c) 1998-2003 Dan Pascu
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  *  USA.
21  */
22
23 #include "wconfig.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <sys/wait.h>
32 #ifdef __FreeBSD__
33 #include <sys/signal.h>
34 #endif
35
36 #include <X11/Xlib.h>
37 #include <X11/Xresource.h>
38 #include <X11/Xutil.h>
39 #include <X11/cursorfont.h>
40 #include <X11/Xproto.h>
41 #include <X11/keysym.h>
42 #ifdef SHAPE
43 #include <X11/extensions/shape.h>
44 #endif
45
46 #include "WindowMaker.h"
47 #include "GNUstep.h"
48 #include "texture.h"
49 #include "screen.h"
50 #include "window.h"
51 #include "actions.h"
52 #include "client.h"
53 #include "funcs.h"
54 #include "dock.h"
55 #include "workspace.h"
56 #include "keybind.h"
57 #include "framewin.h"
58 #include "session.h"
59 #include "defaults.h"
60 #include "properties.h"
61 #include "dialog.h"
62 #include "wmspec.h"
63 #ifdef XDND
64 #include "xdnd.h"
65 #endif
66
67 #include "xutil.h"
68
69 #if 0
70 #ifdef SYS_SIGLIST_DECLARED
71 extern const char *const sys_siglist[];
72 #endif
73 #endif
74
75 /* for SunOS */
76 #ifndef SA_RESTART
77 # define SA_RESTART 0
78 #endif
79
80 /* Just in case, for weirdo systems */
81 #ifndef SA_NODEFER
82 # define SA_NODEFER 0
83 #endif
84
85 /****** Global Variables ******/
86
87 extern WPreferences wPreferences;
88
89 extern WDDomain *WDWindowMaker;
90 extern WDDomain *WDRootMenu;
91 extern WDDomain *WDWindowAttributes;
92
93 extern WShortKey wKeyBindings[WKBD_LAST];
94
95 extern int wScreenCount;
96
97 #ifdef SHAPE
98 extern Bool wShapeSupported;
99 extern int wShapeEventBase;
100 #endif
101
102 #ifdef KEEP_XKB_LOCK_STATUS
103 extern Bool wXkbSupported;
104 extern int wXkbEventBase;
105 #endif
106
107 /* contexts */
108 extern XContext wWinContext;
109 extern XContext wAppWinContext;
110 extern XContext wStackContext;
111 extern XContext wVEdgeContext;
112
113 /* atoms */
114 extern Atom _XA_WM_STATE;
115 extern Atom _XA_WM_CHANGE_STATE;
116 extern Atom _XA_WM_PROTOCOLS;
117 extern Atom _XA_WM_TAKE_FOCUS;
118 extern Atom _XA_WM_DELETE_WINDOW;
119 extern Atom _XA_WM_SAVE_YOURSELF;
120 extern Atom _XA_WM_CLIENT_LEADER;
121 extern Atom _XA_WM_COLORMAP_WINDOWS;
122 extern Atom _XA_WM_COLORMAP_NOTIFY;
123
124 extern Atom _XA_GNUSTEP_WM_ATTR;
125
126 extern Atom _XA_WINDOWMAKER_MENU;
127 extern Atom _XA_WINDOWMAKER_WM_PROTOCOLS;
128 extern Atom _XA_WINDOWMAKER_STATE;
129 extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
130 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
131 extern Atom _XA_WINDOWMAKER_COMMAND;
132 extern Atom _XA_WINDOWMAKER_ICON_SIZE;
133 extern Atom _XA_WINDOWMAKER_ICON_TILE;
134
135 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
136 extern Atom _XA_GNUSTEP_TITLEBAR_STATE;
137
138 /* cursors */
139 extern Cursor wCursor[WCUR_LAST];
140
141 /* special flags */
142 /*extern char WDelayedActionSet;*/
143
144 /***** Local *****/
145
146 static WScreen **wScreen = NULL;
147
148 static unsigned int _NumLockMask = 0;
149 static unsigned int _ScrollLockMask = 0;
150
151 static void manageAllWindows(WScreen * scr, int crashed);
152
153 extern void NotifyDeadProcess(pid_t pid, unsigned char status);
154
155 static int catchXError(Display * dpy, XErrorEvent * error)
156 {
157         char buffer[MAXLINE];
158
159         /* ignore some errors */
160         if (error->resourceid != None
161             && ((error->error_code == BadDrawable && error->request_code == X_GetGeometry)
162                 || (error->error_code == BadMatch && (error->request_code == X_SetInputFocus))
163                 || (error->error_code == BadWindow)
164                 /*
165                    && (error->request_code == X_GetWindowAttributes
166                    || error->request_code == X_SetInputFocus
167                    || error->request_code == X_ChangeWindowAttributes
168                    || error->request_code == X_GetProperty
169                    || error->request_code == X_ChangeProperty
170                    || error->request_code == X_QueryTree
171                    || error->request_code == X_GrabButton
172                    || error->request_code == X_UngrabButton
173                    || error->request_code == X_SendEvent
174                    || error->request_code == X_ConfigureWindow))
175                  */
176                 || (error->request_code == X_InstallColormap))) {
177 #ifndef DEBUG
178
179                 return 0;
180 #else
181                 printf("got X error %x %x %x\n", error->request_code,
182                        error->error_code, (unsigned)error->resourceid);
183                 return 0;
184 #endif
185         }
186         FormatXError(dpy, error, buffer, MAXLINE);
187         wwarning(_("internal X error: %s\n"), buffer);
188         return -1;
189 }
190
191 /*
192  *----------------------------------------------------------------------
193  * handleXIO-
194  *      Handle X shutdowns and other stuff.
195  *----------------------------------------------------------------------
196  */
197 static int handleXIO(Display * xio_dpy)
198 {
199         dpy = NULL;
200         Exit(0);
201         return 0;
202 }
203
204 /*
205  *----------------------------------------------------------------------
206  * delayedAction-
207  *      Action to be executed after the signal() handler is exited.
208  * This was called every 500ms to 'clean up' signals. Not used now.
209  *----------------------------------------------------------------------
210  */
211 #ifdef notused
212 static void delayedAction(void *cdata)
213 {
214         if (WDelayedActionSet == 0) {
215                 return;
216         }
217         WDelayedActionSet--;
218         /*
219          * Make the event dispatcher do whatever it needs to do,
220          * including handling zombie processes, restart and exit
221          * signals.
222          */
223         DispatchEvent(NULL);
224 }
225 #endif
226
227 /*
228  *----------------------------------------------------------------------
229  * handleExitSig--
230  *      User generated exit signal handler.
231  *----------------------------------------------------------------------
232  */
233 static RETSIGTYPE handleExitSig(int sig)
234 {
235         sigset_t sigs;
236
237         sigfillset(&sigs);
238         sigprocmask(SIG_BLOCK, &sigs, NULL);
239
240         if (sig == SIGUSR1) {
241 #ifdef SYS_SIGLIST_DECLARED
242                 wwarning("got signal %i (%s) - restarting\n", sig, sys_siglist[sig]);
243 #else
244                 wwarning("got signal %i - restarting\n", sig);
245 #endif
246
247                 SIG_WCHANGE_STATE(WSTATE_NEED_RESTART);
248
249         } else if (sig == SIGUSR2) {
250 #ifdef SYS_SIGLIST_DECLARED
251                 wwarning("got signal %i (%s) - rereading defaults\n", sig, sys_siglist[sig]);
252 #else
253                 wwarning("got signal %i - rereading defaults\n", sig);
254 #endif
255
256                 SIG_WCHANGE_STATE(WSTATE_NEED_REREAD);
257
258         } else if (sig == SIGTERM || sig == SIGINT || sig == SIGHUP) {
259 #ifdef SYS_SIGLIST_DECLARED
260                 wwarning("got signal %i (%s) - exiting...\n", sig, sys_siglist[sig]);
261 #else
262                 wwarning("got signal %i - exiting...\n", sig);
263 #endif
264
265                 SIG_WCHANGE_STATE(WSTATE_NEED_EXIT);
266
267         }
268
269         sigprocmask(SIG_UNBLOCK, &sigs, NULL);
270         DispatchEvent(NULL);    /* Dispatch events imediately. */
271 }
272
273 /* Dummy signal handler */
274 static void dummyHandler(int sig)
275 {
276 }
277
278 /*
279  *----------------------------------------------------------------------
280  * handleSig--
281  *      general signal handler. Exits the program gently.
282  *----------------------------------------------------------------------
283  */
284 static RETSIGTYPE handleSig(int sig)
285 {
286 #ifdef SYS_SIGLIST_DECLARED
287         wfatal("got signal %i (%s)\n", sig, sys_siglist[sig]);
288 #else
289         wfatal("got signal %i\n", sig);
290 #endif
291
292         /* Setting the signal behaviour back to default and then reraising the
293          * signal is a cleaner way to make program exit and core dump than calling
294          * abort(), since it correctly returns from the signal handler and sets
295          * the flags accordingly. -Dan
296          */
297         if (sig == SIGSEGV || sig == SIGFPE || sig == SIGBUS || sig == SIGILL || sig == SIGABRT) {
298                 signal(sig, SIG_DFL);
299                 kill(getpid(), sig);
300                 return;
301         }
302
303         wAbort(0);
304 }
305
306 static RETSIGTYPE buryChild(int foo)
307 {
308         pid_t pid;
309         int status;
310         int save_errno = errno;
311         sigset_t sigs;
312
313         sigfillset(&sigs);
314         /* Block signals so that NotifyDeadProcess() doesn't get fux0red */
315         sigprocmask(SIG_BLOCK, &sigs, NULL);
316
317         /* R.I.P. */
318         /* If 2 or more kids exit in a small time window, before this handler gets
319          * the chance to get invoked, the SIGCHLD signals will be merged and only
320          * one SIGCHLD signal will be sent to us. We use a while loop to get all
321          * exited child status because we can't count on the number of SIGCHLD
322          * signals to know exactly how many kids have exited. -Dan
323          */
324         while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || (pid < 0 && errno == EINTR)) {
325                 NotifyDeadProcess(pid, WEXITSTATUS(status));
326         }
327
328         sigprocmask(SIG_UNBLOCK, &sigs, NULL);
329
330         errno = save_errno;
331 }
332
333 static void getOffendingModifiers()
334 {
335         int i;
336         XModifierKeymap *modmap;
337         KeyCode nlock, slock;
338         static int mask_table[8] = {
339                 ShiftMask, LockMask, ControlMask, Mod1Mask,
340                 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
341         };
342
343         nlock = XKeysymToKeycode(dpy, XK_Num_Lock);
344         slock = XKeysymToKeycode(dpy, XK_Scroll_Lock);
345
346         /*
347          * Find out the masks for the NumLock and ScrollLock modifiers,
348          * so that we can bind the grabs for when they are enabled too.
349          */
350         modmap = XGetModifierMapping(dpy);
351
352         if (modmap != NULL && modmap->max_keypermod > 0) {
353                 for (i = 0; i < 8 * modmap->max_keypermod; i++) {
354                         if (modmap->modifiermap[i] == nlock && nlock != 0)
355                                 _NumLockMask = mask_table[i / modmap->max_keypermod];
356                         else if (modmap->modifiermap[i] == slock && slock != 0)
357                                 _ScrollLockMask = mask_table[i / modmap->max_keypermod];
358                 }
359         }
360
361         if (modmap)
362                 XFreeModifiermap(modmap);
363 }
364
365 #ifdef NUMLOCK_HACK
366 void
367 wHackedGrabKey(int keycode, unsigned int modifiers,
368                Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode)
369 {
370         if (modifiers == AnyModifier)
371                 return;
372
373         /* grab all combinations of the modifier with CapsLock, NumLock and
374          * ScrollLock. How much memory/CPU does such a monstrosity consume
375          * in the server?
376          */
377         if (_NumLockMask)
378                 XGrabKey(dpy, keycode, modifiers | _NumLockMask,
379                          grab_window, owner_events, pointer_mode, keyboard_mode);
380         if (_ScrollLockMask)
381                 XGrabKey(dpy, keycode, modifiers | _ScrollLockMask,
382                          grab_window, owner_events, pointer_mode, keyboard_mode);
383         if (_NumLockMask && _ScrollLockMask)
384                 XGrabKey(dpy, keycode, modifiers | _NumLockMask | _ScrollLockMask,
385                          grab_window, owner_events, pointer_mode, keyboard_mode);
386         if (_NumLockMask)
387                 XGrabKey(dpy, keycode, modifiers | _NumLockMask | LockMask,
388                          grab_window, owner_events, pointer_mode, keyboard_mode);
389         if (_ScrollLockMask)
390                 XGrabKey(dpy, keycode, modifiers | _ScrollLockMask | LockMask,
391                          grab_window, owner_events, pointer_mode, keyboard_mode);
392         if (_NumLockMask && _ScrollLockMask)
393                 XGrabKey(dpy, keycode, modifiers | _NumLockMask | _ScrollLockMask | LockMask,
394                          grab_window, owner_events, pointer_mode, keyboard_mode);
395         /* phew, I guess that's all, right? */
396 }
397 #endif
398
399 void
400 wHackedGrabButton(unsigned int button, unsigned int modifiers,
401                   Window grab_window, Bool owner_events,
402                   unsigned int event_mask, int pointer_mode, int keyboard_mode, Window confine_to, Cursor cursor)
403 {
404         XGrabButton(dpy, button, modifiers, grab_window, owner_events,
405                     event_mask, pointer_mode, keyboard_mode, confine_to, cursor);
406
407         if (modifiers == AnyModifier)
408                 return;
409
410         XGrabButton(dpy, button, modifiers | LockMask, grab_window, owner_events,
411                     event_mask, pointer_mode, keyboard_mode, confine_to, cursor);
412
413 #ifdef NUMLOCK_HACK
414         /* same as above, but for mouse buttons */
415         if (_NumLockMask)
416                 XGrabButton(dpy, button, modifiers | _NumLockMask,
417                             grab_window, owner_events, event_mask, pointer_mode,
418                             keyboard_mode, confine_to, cursor);
419         if (_ScrollLockMask)
420                 XGrabButton(dpy, button, modifiers | _ScrollLockMask,
421                             grab_window, owner_events, event_mask, pointer_mode,
422                             keyboard_mode, confine_to, cursor);
423         if (_NumLockMask && _ScrollLockMask)
424                 XGrabButton(dpy, button, modifiers | _ScrollLockMask | _NumLockMask,
425                             grab_window, owner_events, event_mask, pointer_mode,
426                             keyboard_mode, confine_to, cursor);
427         if (_NumLockMask)
428                 XGrabButton(dpy, button, modifiers | _NumLockMask | LockMask,
429                             grab_window, owner_events, event_mask, pointer_mode,
430                             keyboard_mode, confine_to, cursor);
431         if (_ScrollLockMask)
432                 XGrabButton(dpy, button, modifiers | _ScrollLockMask | LockMask,
433                             grab_window, owner_events, event_mask, pointer_mode,
434                             keyboard_mode, confine_to, cursor);
435         if (_NumLockMask && _ScrollLockMask)
436                 XGrabButton(dpy, button, modifiers | _ScrollLockMask | _NumLockMask | LockMask,
437                             grab_window, owner_events, event_mask, pointer_mode,
438                             keyboard_mode, confine_to, cursor);
439 #endif                          /* NUMLOCK_HACK */
440 }
441
442 #ifdef notused
443 void wHackedUngrabButton(unsigned int button, unsigned int modifiers, Window grab_window)
444 {
445         XUngrabButton(dpy, button, modifiers | _NumLockMask, grab_window);
446         XUngrabButton(dpy, button, modifiers | _ScrollLockMask, grab_window);
447         XUngrabButton(dpy, button, modifiers | _NumLockMask | _ScrollLockMask, grab_window);
448         XUngrabButton(dpy, button, modifiers | _NumLockMask | LockMask, grab_window);
449         XUngrabButton(dpy, button, modifiers | _ScrollLockMask | LockMask, grab_window);
450         XUngrabButton(dpy, button, modifiers | _NumLockMask | _ScrollLockMask | LockMask, grab_window);
451 }
452 #endif
453
454 WScreen *wScreenWithNumber(int i)
455 {
456         assert(i < wScreenCount);
457
458         return wScreen[i];
459 }
460
461 WScreen *wScreenForRootWindow(Window window)
462 {
463         int i;
464
465         if (wScreenCount == 1)
466                 return wScreen[0];
467
468         /*
469          * Since the number of heads will probably be small (normally 2),
470          * it should be faster to use this than a hash table, because
471          * of the overhead.
472          */
473         for (i = 0; i < wScreenCount; i++) {
474                 if (wScreen[i]->root_win == window) {
475                         return wScreen[i];
476                 }
477         }
478
479         return wScreenForWindow(window);
480 }
481
482 WScreen *wScreenSearchForRootWindow(Window window)
483 {
484         int i;
485
486         if (wScreenCount == 1)
487                 return wScreen[0];
488
489         /*
490          * Since the number of heads will probably be small (normally 2),
491          * it should be faster to use this than a hash table, because
492          * of the overhead.
493          */
494         for (i = 0; i < wScreenCount; i++) {
495                 if (wScreen[i]->root_win == window) {
496                         return wScreen[i];
497                 }
498         }
499
500         return wScreenForWindow(window);
501 }
502
503 WScreen *wScreenForWindow(Window window)
504 {
505         XWindowAttributes attr;
506
507         if (wScreenCount == 1)
508                 return wScreen[0];
509
510         if (XGetWindowAttributes(dpy, window, &attr)) {
511                 return wScreenForRootWindow(attr.root);
512         }
513         return NULL;
514 }
515
516 static char *atomNames[] = {
517         "WM_STATE",
518         "WM_CHANGE_STATE",
519         "WM_PROTOCOLS",
520         "WM_TAKE_FOCUS",
521         "WM_DELETE_WINDOW",
522         "WM_SAVE_YOURSELF",
523         "WM_CLIENT_LEADER",
524         "WM_COLORMAP_WINDOWS",
525         "WM_COLORMAP_NOTIFY",
526
527         "_WINDOWMAKER_MENU",
528         "_WINDOWMAKER_STATE",
529         "_WINDOWMAKER_WM_PROTOCOLS",
530         "_WINDOWMAKER_WM_FUNCTION",
531         "_WINDOWMAKER_NOTICEBOARD",
532         "_WINDOWMAKER_COMMAND",
533         "_WINDOWMAKER_ICON_SIZE",
534         "_WINDOWMAKER_ICON_TILE",
535
536         GNUSTEP_WM_ATTR_NAME,
537         GNUSTEP_WM_MINIATURIZE_WINDOW,
538         GNUSTEP_TITLEBAR_STATE
539 };
540
541 /*
542  *----------------------------------------------------------
543  * StartUp--
544  *      starts the window manager and setup global data.
545  * Called from main() at startup.
546  *
547  * Side effects:
548  * global data declared in main.c is initialized
549  *----------------------------------------------------------
550  */
551 void StartUp(Bool defaultScreenOnly)
552 {
553         struct sigaction sig_action;
554         int j, max;
555         Atom atom[sizeof(atomNames) / sizeof(char *)];
556
557         /*
558          * Ignore CapsLock in modifiers
559          */
560         ValidModMask = 0xff & ~LockMask;
561
562         getOffendingModifiers();
563         /*
564          * Ignore NumLock and ScrollLock too
565          */
566         ValidModMask &= ~(_NumLockMask | _ScrollLockMask);
567
568         memset(&wKeyBindings, 0, sizeof(wKeyBindings));
569
570         wWinContext = XUniqueContext();
571         wAppWinContext = XUniqueContext();
572         wStackContext = XUniqueContext();
573         wVEdgeContext = XUniqueContext();
574
575         /*    _XA_VERSION = XInternAtom(dpy, "VERSION", False); */
576
577 #ifdef HAVE_XINTERNATOMS
578         XInternAtoms(dpy, atomNames, sizeof(atomNames) / sizeof(char *), False, atom);
579 #else
580
581         {
582                 int i;
583                 for (i = 0; i < sizeof(atomNames) / sizeof(char *); i++) {
584                         atom[i] = XInternAtom(dpy, atomNames[i], False);
585                 }
586         }
587 #endif
588
589         _XA_WM_STATE = atom[0];
590         _XA_WM_CHANGE_STATE = atom[1];
591         _XA_WM_PROTOCOLS = atom[2];
592         _XA_WM_TAKE_FOCUS = atom[3];
593         _XA_WM_DELETE_WINDOW = atom[4];
594         _XA_WM_SAVE_YOURSELF = atom[5];
595         _XA_WM_CLIENT_LEADER = atom[6];
596         _XA_WM_COLORMAP_WINDOWS = atom[7];
597         _XA_WM_COLORMAP_NOTIFY = atom[8];
598
599         _XA_WINDOWMAKER_MENU = atom[9];
600         _XA_WINDOWMAKER_STATE = atom[10];
601         _XA_WINDOWMAKER_WM_PROTOCOLS = atom[11];
602         _XA_WINDOWMAKER_WM_FUNCTION = atom[12];
603         _XA_WINDOWMAKER_NOTICEBOARD = atom[13];
604         _XA_WINDOWMAKER_COMMAND = atom[14];
605         _XA_WINDOWMAKER_ICON_SIZE = atom[15];
606         _XA_WINDOWMAKER_ICON_TILE = atom[16];
607
608         _XA_GNUSTEP_WM_ATTR = atom[17];
609         _XA_GNUSTEP_WM_MINIATURIZE_WINDOW = atom[18];
610         _XA_GNUSTEP_TITLEBAR_STATE = atom[19];
611
612 #ifdef XDND
613         wXDNDInitializeAtoms();
614 #endif
615
616         /* cursors */
617         wCursor[WCUR_NORMAL] = None;    /* inherit from root */
618         wCursor[WCUR_ROOT] = XCreateFontCursor(dpy, XC_left_ptr);
619         wCursor[WCUR_ARROW] = XCreateFontCursor(dpy, XC_top_left_arrow);
620         wCursor[WCUR_MOVE] = XCreateFontCursor(dpy, XC_fleur);
621         wCursor[WCUR_RESIZE] = XCreateFontCursor(dpy, XC_sizing);
622         wCursor[WCUR_TOPLEFTRESIZE] = XCreateFontCursor(dpy, XC_top_left_corner);
623         wCursor[WCUR_TOPRIGHTRESIZE] = XCreateFontCursor(dpy, XC_top_right_corner);
624         wCursor[WCUR_BOTTOMLEFTRESIZE] = XCreateFontCursor(dpy, XC_bottom_left_corner);
625         wCursor[WCUR_BOTTOMRIGHTRESIZE] = XCreateFontCursor(dpy, XC_bottom_right_corner);
626         wCursor[WCUR_VERTICALRESIZE] = XCreateFontCursor(dpy, XC_sb_v_double_arrow);
627         wCursor[WCUR_HORIZONRESIZE] = XCreateFontCursor(dpy, XC_sb_h_double_arrow);
628         wCursor[WCUR_WAIT] = XCreateFontCursor(dpy, XC_watch);
629         wCursor[WCUR_QUESTION] = XCreateFontCursor(dpy, XC_question_arrow);
630         wCursor[WCUR_TEXT] = XCreateFontCursor(dpy, XC_xterm);  /* odd name??? */
631         wCursor[WCUR_SELECT] = XCreateFontCursor(dpy, XC_cross);
632         {
633                 Pixmap cur = XCreatePixmap(dpy, DefaultRootWindow(dpy), 16, 16, 1);
634                 GC gc = XCreateGC(dpy, cur, 0, NULL);
635                 XColor black;
636                 memset(&black, 0, sizeof(XColor));
637                 XSetForeground(dpy, gc, 0);
638                 XFillRectangle(dpy, cur, gc, 0, 0, 16, 16);
639                 XFreeGC(dpy, gc);
640                 wCursor[WCUR_EMPTY] = XCreatePixmapCursor(dpy, cur, cur, &black, &black, 0, 0);
641                 XFreePixmap(dpy, cur);
642         }
643
644         /* emergency exit... */
645         sig_action.sa_handler = handleSig;
646         sigemptyset(&sig_action.sa_mask);
647
648         sig_action.sa_flags = SA_RESTART;
649         sigaction(SIGQUIT, &sig_action, NULL);
650         /* instead of catching these, we let the default handler abort the
651          * program. The new monitor process will take appropriate action
652          * when it detects the crash.
653          sigaction(SIGSEGV, &sig_action, NULL);
654          sigaction(SIGBUS, &sig_action, NULL);
655          sigaction(SIGFPE, &sig_action, NULL);
656          sigaction(SIGABRT, &sig_action, NULL);
657          */
658
659         sig_action.sa_handler = handleExitSig;
660
661         /* Here we set SA_RESTART for safety, because SIGUSR1 may not be handled
662          * immediately. -Dan */
663         sig_action.sa_flags = SA_RESTART;
664         sigaction(SIGTERM, &sig_action, NULL);
665         sigaction(SIGINT, &sig_action, NULL);
666         sigaction(SIGHUP, &sig_action, NULL);
667         sigaction(SIGUSR1, &sig_action, NULL);
668         sigaction(SIGUSR2, &sig_action, NULL);
669
670         /* ignore dead pipe */
671         /* Because POSIX mandates that only signal with handlers are reset
672          * accross an exec*(), we do not want to propagate ignoring SIGPIPEs
673          * to children. Hence the dummy handler.
674          * Philippe Troin <phil@fifi.org>
675          */
676         sig_action.sa_handler = &dummyHandler;
677         sig_action.sa_flags = SA_RESTART;
678         sigaction(SIGPIPE, &sig_action, NULL);
679
680         /* handle dead children */
681         sig_action.sa_handler = buryChild;
682         sig_action.sa_flags = SA_NOCLDSTOP | SA_RESTART;
683         sigaction(SIGCHLD, &sig_action, NULL);
684
685         /* Now we unblock all signals, that may have been blocked by the parent
686          * who exec()-ed us. This can happen for example if Window Maker crashes
687          * and restarts itself or another window manager from the signal handler.
688          * In this case, the new proccess inherits the blocked signal mask and
689          * will no longer react to that signal, until unblocked.
690          * This is because the signal handler of the proccess who crashed (parent)
691          * didn't return, and the signal remained blocked. -Dan
692          */
693         sigfillset(&sig_action.sa_mask);
694         sigprocmask(SIG_UNBLOCK, &sig_action.sa_mask, NULL);
695
696         /* handle X shutdowns a such */
697         XSetIOErrorHandler(handleXIO);
698
699         /* set hook for out event dispatcher in WINGs event dispatcher */
700         WMHookEventHandler(DispatchEvent);
701
702         /* initialize defaults stuff */
703         WDWindowMaker = wDefaultsInitDomain("WindowMaker", True);
704         if (!WDWindowMaker->dictionary) {
705                 wwarning(_("could not read domain \"%s\" from defaults database"), "WindowMaker");
706         }
707
708         /* read defaults that don't change until a restart and are
709          * screen independent */
710         wReadStaticDefaults(WDWindowMaker ? WDWindowMaker->dictionary : NULL);
711
712         /* check sanity of some values */
713         if (wPreferences.icon_size < 16) {
714                 wwarning(_("icon size is configured to %i, but it's too small. Using 16, instead\n"),
715                          wPreferences.icon_size);
716                 wPreferences.icon_size = 16;
717         }
718
719         /* init other domains */
720         WDRootMenu = wDefaultsInitDomain("WMRootMenu", False);
721         if (!WDRootMenu->dictionary) {
722                 wwarning(_("could not read domain \"%s\" from defaults database"), "WMRootMenu");
723         }
724         wDefaultsMergeGlobalMenus(WDRootMenu);
725
726         WDWindowAttributes = wDefaultsInitDomain("WMWindowAttributes", True);
727         if (!WDWindowAttributes->dictionary) {
728                 wwarning(_("could not read domain \"%s\" from defaults database"), "WMWindowAttributes");
729         }
730
731         XSetErrorHandler((XErrorHandler) catchXError);
732
733 #ifdef SHAPE
734         /* ignore j */
735         wShapeSupported = XShapeQueryExtension(dpy, &wShapeEventBase, &j);
736 #endif
737
738 #ifdef KEEP_XKB_LOCK_STATUS
739         wXkbSupported = XkbQueryExtension(dpy, NULL, &wXkbEventBase, NULL, NULL, NULL);
740         if (wPreferences.modelock && !wXkbSupported) {
741                 wwarning(_("XKB is not supported. KbdModeLock is automatically disabled."));
742                 wPreferences.modelock = 0;
743         }
744 #endif
745
746         if (defaultScreenOnly) {
747                 max = 1;
748         } else {
749                 max = ScreenCount(dpy);
750         }
751         wScreen = wmalloc(sizeof(WScreen *) * max);
752
753         wScreenCount = 0;
754
755         /* manage the screens */
756         for (j = 0; j < max; j++) {
757                 if (defaultScreenOnly || max == 1) {
758                         wScreen[wScreenCount] = wScreenInit(DefaultScreen(dpy));
759                         if (!wScreen[wScreenCount]) {
760                                 wfatal(_("it seems that there is already a window manager running"));
761                                 Exit(1);
762                         }
763                 } else {
764                         wScreen[wScreenCount] = wScreenInit(j);
765                         if (!wScreen[wScreenCount]) {
766                                 wwarning(_("could not manage screen %i"), j);
767                                 continue;
768                         }
769                 }
770                 wScreenCount++;
771         }
772
773 #ifndef LITE
774         InitializeSwitchMenu();
775 #endif
776
777         /* initialize/restore state for the screens */
778         for (j = 0; j < wScreenCount; j++) {
779                 int lastDesktop;
780
781                 lastDesktop = wNETWMGetCurrentDesktopFromHint(wScreen[j]);
782
783                 wScreenRestoreState(wScreen[j]);
784
785                 /* manage all windows that were already here before us */
786                 if (!wPreferences.flags.nodock && wScreen[j]->dock)
787                         wScreen[j]->last_dock = wScreen[j]->dock;
788
789                 manageAllWindows(wScreen[j], wPreferences.flags.restarting == 2);
790
791                 /* restore saved menus */
792                 wMenuRestoreState(wScreen[j]);
793
794                 /* If we're not restarting, restore session */
795                 if (wPreferences.flags.restarting == 0 && !wPreferences.flags.norestore)
796                         wSessionRestoreState(wScreen[j]);
797
798                 if (!wPreferences.flags.noautolaunch) {
799                         /* auto-launch apps */
800                         if (!wPreferences.flags.nodock && wScreen[j]->dock) {
801                                 wScreen[j]->last_dock = wScreen[j]->dock;
802                                 wDockDoAutoLaunch(wScreen[j]->dock, 0);
803                         }
804                         /* auto-launch apps in clip */
805                         if (!wPreferences.flags.noclip) {
806                                 int i;
807                                 for (i = 0; i < wScreen[j]->workspace_count; i++) {
808                                         if (wScreen[j]->workspaces[i]->clip) {
809                                                 wScreen[j]->last_dock = wScreen[j]->workspaces[i]->clip;
810                                                 wDockDoAutoLaunch(wScreen[j]->workspaces[i]->clip, i);
811                                         }
812                                 }
813                         }
814                 }
815
816                 /* go to workspace where we were before restart */
817                 if (lastDesktop >= 0) {
818                         wWorkspaceForceChange(wScreen[j], lastDesktop);
819                 } else {
820                         wSessionRestoreLastWorkspace(wScreen[j]);
821                 }
822         }
823
824         if (wScreenCount == 0) {
825                 wfatal(_("could not manage any screen"));
826                 Exit(1);
827         }
828
829 }
830
831 static Bool windowInList(Window window, Window * list, int count)
832 {
833         for (; count >= 0; count--) {
834                 if (window == list[count])
835                         return True;
836         }
837         return False;
838 }
839
840 /*
841  *-----------------------------------------------------------------------
842  * manageAllWindows--
843  *      Manages all windows in the screen.
844  *
845  * Notes:
846  *      Called when the wm is being started.
847  *      No events can be processed while the windows are being
848  * reparented/managed.
849  *-----------------------------------------------------------------------
850  */
851 static void manageAllWindows(WScreen * scr, int crashRecovery)
852 {
853         Window root, parent;
854         Window *children;
855         unsigned int nchildren;
856         unsigned int i, j;
857         WWindow *wwin;
858
859         XGrabServer(dpy);
860         XQueryTree(dpy, scr->root_win, &root, &parent, &children, &nchildren);
861
862         scr->flags.startup = 1;
863
864         /* first remove all icon windows */
865         for (i = 0; i < nchildren; i++) {
866                 XWMHints *wmhints;
867
868                 if (children[i] == None)
869                         continue;
870
871                 wmhints = XGetWMHints(dpy, children[i]);
872                 if (wmhints && (wmhints->flags & IconWindowHint)) {
873                         for (j = 0; j < nchildren; j++) {
874                                 if (children[j] == wmhints->icon_window) {
875                                         XFree(wmhints);
876                                         wmhints = NULL;
877                                         children[j] = None;
878                                         break;
879                                 }
880                         }
881                 }
882                 if (wmhints) {
883                         XFree(wmhints);
884                 }
885         }
886
887         for (i = 0; i < nchildren; i++) {
888                 if (children[i] == None)
889                         continue;
890
891                 wwin = wManageWindow(scr, children[i]);
892                 if (wwin) {
893                         /* apply states got from WSavedState */
894                         /* shaded + minimized is not restored correctly */
895                         if (wwin->flags.shaded) {
896                                 wwin->flags.shaded = 0;
897                                 wShadeWindow(wwin);
898                         }
899                         if (wwin->flags.miniaturized
900                             && (wwin->transient_for == None
901                                 || wwin->transient_for == scr->root_win
902                                 || !windowInList(wwin->transient_for, children, nchildren))) {
903
904                                 wwin->flags.skip_next_animation = 1;
905                                 wwin->flags.miniaturized = 0;
906                                 wIconifyWindow(wwin);
907                         } else {
908                                 wClientSetState(wwin, NormalState, None);
909                         }
910                         if (crashRecovery) {
911                                 int border;
912
913                                 border = (!HAS_BORDER(wwin) ? 0 : FRAME_BORDER_WIDTH);
914
915                                 wWindowMove(wwin, wwin->frame_x - border,
916                                             wwin->frame_y - border -
917                                             (wwin->frame->titlebar ? wwin->frame->titlebar->height : 0));
918                         }
919                 }
920         }
921         XUngrabServer(dpy);
922
923         /* hide apps */
924         wwin = scr->focused_window;
925         while (wwin) {
926                 if (wwin->flags.hidden) {
927                         WApplication *wapp = wApplicationOf(wwin->main_window);
928
929                         if (wapp) {
930                                 wwin->flags.hidden = 0;
931                                 wHideApplication(wapp);
932                         } else {
933                                 wwin->flags.hidden = 0;
934                         }
935                 }
936                 wwin = wwin->prev;
937         }
938
939         XFree(children);
940         scr->flags.startup = 0;
941         scr->flags.startup2 = 1;
942
943         while (XPending(dpy)) {
944                 XEvent ev;
945                 WMNextEvent(dpy, &ev);
946                 WMHandleEvent(&ev);
947         }
948         wWorkspaceForceChange(scr, 0);
949         if (!wPreferences.flags.noclip)
950                 wDockShowIcons(scr->workspaces[scr->current_workspace]->clip);
951         scr->flags.startup2 = 0;
952 }