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