bug fix
[wmaker-crm.git] / src / startup.c
blob117f8c47c35d9016e2c6baed170bb4ae5def7f90
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
5 * Copyright (c) 1998-2003 Dan Pascu
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.
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.
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.
23 #include "wconfig.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <sys/wait.h>
31 #ifdef __FreeBSD__
32 #include <sys/signal.h>
33 #endif
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37 #include <X11/Intrinsic.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
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 #ifdef XDND
62 #include "xdnd.h"
63 #endif
65 #include "xutil.h"
67 #if 0
68 #ifdef SYS_SIGLIST_DECLARED
69 extern const char * const sys_siglist[];
70 #endif
71 #endif
73 /* for SunOS */
74 #ifndef SA_RESTART
75 # define SA_RESTART 0
76 #endif
78 /* Just in case, for weirdo systems */
79 #ifndef SA_NODEFER
80 # define SA_NODEFER 0
81 #endif
83 /****** Global Variables ******/
85 extern WPreferences wPreferences;
87 extern WDDomain *WDWindowMaker;
88 extern WDDomain *WDRootMenu;
89 extern WDDomain *WDWindowAttributes;
91 extern WShortKey wKeyBindings[WKBD_LAST];
93 extern int wScreenCount;
96 #ifdef SHAPE
97 extern Bool wShapeSupported;
98 extern int wShapeEventBase;
99 #endif
101 #ifdef KEEP_XKB_LOCK_STATUS
102 extern Bool wXkbSupported;
103 extern int wXkbEventBase;
104 #endif
106 /* contexts */
107 extern XContext wWinContext;
108 extern XContext wAppWinContext;
109 extern XContext wStackContext;
110 extern XContext wVEdgeContext;
112 /* atoms */
113 extern Atom _XA_WM_STATE;
114 extern Atom _XA_WM_CHANGE_STATE;
115 extern Atom _XA_WM_PROTOCOLS;
116 extern Atom _XA_WM_TAKE_FOCUS;
117 extern Atom _XA_WM_DELETE_WINDOW;
118 extern Atom _XA_WM_SAVE_YOURSELF;
119 extern Atom _XA_WM_CLIENT_LEADER;
120 extern Atom _XA_WM_COLORMAP_WINDOWS;
121 extern Atom _XA_WM_COLORMAP_NOTIFY;
123 extern Atom _XA_GNUSTEP_WM_ATTR;
125 extern Atom _XA_WINDOWMAKER_MENU;
126 extern Atom _XA_WINDOWMAKER_WM_PROTOCOLS;
127 extern Atom _XA_WINDOWMAKER_STATE;
128 extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
129 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
130 extern Atom _XA_WINDOWMAKER_COMMAND;
131 extern Atom _XA_WINDOWMAKER_ICON_SIZE;
132 extern Atom _XA_WINDOWMAKER_ICON_TILE;
134 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
135 extern Atom _XA_GNUSTEP_TITLEBAR_STATE;
138 /* cursors */
139 extern Cursor wCursor[WCUR_LAST];
141 /* special flags */
142 extern char WDelayedActionSet;
144 /***** Local *****/
146 static WScreen **wScreen = NULL;
149 static unsigned int _NumLockMask = 0;
150 static unsigned int _ScrollLockMask = 0;
154 static void manageAllWindows(WScreen *scr, int crashed);
156 extern void NotifyDeadProcess(pid_t pid, unsigned char status);
159 static int
160 catchXError(Display *dpy, XErrorEvent *error)
162 char buffer[MAXLINE];
164 /* ignore some errors */
165 if (error->resourceid != None
166 && ((error->error_code == BadDrawable
167 && error->request_code == X_GetGeometry)
168 || (error->error_code == BadMatch
169 && (error->request_code == X_SetInputFocus))
170 || (error->error_code == BadWindow)
172 && (error->request_code == X_GetWindowAttributes
173 || error->request_code == X_SetInputFocus
174 || error->request_code == X_ChangeWindowAttributes
175 || error->request_code == X_GetProperty
176 || error->request_code == X_ChangeProperty
177 || error->request_code == X_QueryTree
178 || error->request_code == X_GrabButton
179 || error->request_code == X_UngrabButton
180 || error->request_code == X_SendEvent
181 || error->request_code == X_ConfigureWindow))
183 || (error->request_code == X_InstallColormap))) {
184 #ifndef DEBUG
186 return 0;
187 #else
188 printf("got X error %x %x %x\n", error->request_code,
189 error->error_code, (unsigned)error->resourceid);
190 return 0;
191 #endif
193 FormatXError(dpy, error, buffer, MAXLINE);
194 wwarning(_("internal X error: %s\n"), buffer);
195 return -1;
200 *----------------------------------------------------------------------
201 * handleXIO-
202 * Handle X shutdowns and other stuff.
203 *----------------------------------------------------------------------
205 static int
206 handleXIO(Display *xio_dpy)
208 dpy = NULL;
209 Exit(0);
210 return 0;
215 *----------------------------------------------------------------------
216 * delayedAction-
217 * Action to be executed after the signal() handler is exited.
218 *----------------------------------------------------------------------
220 static void
221 delayedAction(void *cdata)
223 if (WDelayedActionSet == 0) {
224 return;
226 WDelayedActionSet--;
228 * Make the event dispatcher do whatever it needs to do,
229 * including handling zombie processes, restart and exit
230 * signals.
232 DispatchEvent(NULL);
237 *----------------------------------------------------------------------
238 * handleExitSig--
239 * User generated exit signal handler.
240 *----------------------------------------------------------------------
242 static RETSIGTYPE
243 handleExitSig(int sig)
245 sigset_t sigs;
247 sigfillset(&sigs);
248 sigprocmask(SIG_BLOCK, &sigs, NULL);
250 if (sig == SIGUSR1) {
251 #ifdef SYS_SIGLIST_DECLARED
252 wwarning("got signal %i (%s) - restarting\n", sig, sys_siglist[sig]);
253 #else
254 wwarning("got signal %i - restarting\n", sig);
255 #endif
257 SIG_WCHANGE_STATE(WSTATE_NEED_RESTART);
258 /* setup idle handler, so that this will be handled when
259 * the select() is returned becaused of the signal, even if
260 * there are no X events in the queue */
261 WDelayedActionSet++;
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
269 SIG_WCHANGE_STATE(WSTATE_NEED_REREAD);
270 /* setup idle handler, so that this will be handled when
271 * the select() is returned becaused of the signal, even if
272 * there are no X events in the queue */
273 WDelayedActionSet++;
274 } else if (sig==SIGTERM || sig==SIGINT || sig==SIGHUP) {
275 #ifdef SYS_SIGLIST_DECLARED
276 wwarning("got signal %i (%s) - exiting...\n", sig, sys_siglist[sig]);
277 #else
278 wwarning("got signal %i - exiting...\n", sig);
279 #endif
281 SIG_WCHANGE_STATE(WSTATE_NEED_EXIT);
283 WDelayedActionSet++;
286 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
289 /* Dummy signal handler */
290 static void
291 dummyHandler(int sig)
297 *----------------------------------------------------------------------
298 * handleSig--
299 * general signal handler. Exits the program gently.
300 *----------------------------------------------------------------------
302 static RETSIGTYPE
303 handleSig(int sig)
305 #ifdef SYS_SIGLIST_DECLARED
306 wfatal("got signal %i (%s)\n", sig, sys_siglist[sig]);
307 #else
308 wfatal("got signal %i\n", sig);
309 #endif
311 /* Setting the signal behaviour back to default and then reraising the
312 * signal is a cleaner way to make program exit and core dump than calling
313 * abort(), since it correctly returns from the signal handler and sets
314 * the flags accordingly. -Dan
316 if (sig==SIGSEGV || sig==SIGFPE || sig==SIGBUS || sig==SIGILL
317 || sig==SIGABRT) {
318 signal(sig, SIG_DFL);
319 kill(getpid(), sig);
320 return;
323 wAbort(0);
327 static RETSIGTYPE
328 buryChild(int foo)
330 pid_t pid;
331 int status;
332 int save_errno = errno;
333 sigset_t sigs;
335 sigfillset(&sigs);
336 /* Block signals so that NotifyDeadProcess() doesn't get fux0red */
337 sigprocmask(SIG_BLOCK, &sigs, NULL);
339 /* R.I.P. */
340 /* If 2 or more kids exit in a small time window, before this handler gets
341 * the chance to get invoked, the SIGCHLD signals will be merged and only
342 * one SIGCHLD signal will be sent to us. We use a while loop to get all
343 * exited child status because we can't count on the number of SIGCHLD
344 * signals to know exactly how many kids have exited. -Dan
346 while ((pid=waitpid(-1, &status, WNOHANG))>0 || (pid<0 && errno==EINTR)) {
347 NotifyDeadProcess(pid, WEXITSTATUS(status));
350 WDelayedActionSet++;
352 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
354 errno = save_errno;
358 static void
359 getOffendingModifiers()
361 int i;
362 XModifierKeymap *modmap;
363 KeyCode nlock, slock;
364 static int mask_table[8] = {
365 ShiftMask,LockMask,ControlMask,Mod1Mask,
366 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
369 nlock = XKeysymToKeycode(dpy, XK_Num_Lock);
370 slock = XKeysymToKeycode(dpy, XK_Scroll_Lock);
373 * Find out the masks for the NumLock and ScrollLock modifiers,
374 * so that we can bind the grabs for when they are enabled too.
376 modmap = XGetModifierMapping(dpy);
378 if (modmap!=NULL && modmap->max_keypermod>0) {
379 for (i=0; i<8*modmap->max_keypermod; i++) {
380 if (modmap->modifiermap[i]==nlock && nlock!=0)
381 _NumLockMask = mask_table[i/modmap->max_keypermod];
382 else if (modmap->modifiermap[i]==slock && slock!=0)
383 _ScrollLockMask = mask_table[i/modmap->max_keypermod];
387 if (modmap)
388 XFreeModifiermap(modmap);
393 #ifdef NUMLOCK_HACK
394 void
395 wHackedGrabKey(int keycode, unsigned int modifiers,
396 Window grab_window, Bool owner_events, int pointer_mode,
397 int keyboard_mode)
399 if (modifiers == AnyModifier)
400 return;
402 /* grab all combinations of the modifier with CapsLock, NumLock and
403 * ScrollLock. How much memory/CPU does such a monstrosity consume
404 * in the server?
406 if (_NumLockMask)
407 XGrabKey(dpy, keycode, modifiers|_NumLockMask,
408 grab_window, owner_events, pointer_mode, keyboard_mode);
409 if (_ScrollLockMask)
410 XGrabKey(dpy, keycode, modifiers|_ScrollLockMask,
411 grab_window, owner_events, pointer_mode, keyboard_mode);
412 if (_NumLockMask && _ScrollLockMask)
413 XGrabKey(dpy, keycode, modifiers|_NumLockMask|_ScrollLockMask,
414 grab_window, owner_events, pointer_mode, keyboard_mode);
415 if (_NumLockMask)
416 XGrabKey(dpy, keycode, modifiers|_NumLockMask|LockMask,
417 grab_window, owner_events, pointer_mode, keyboard_mode);
418 if (_ScrollLockMask)
419 XGrabKey(dpy, keycode, modifiers|_ScrollLockMask|LockMask,
420 grab_window, owner_events, pointer_mode, keyboard_mode);
421 if (_NumLockMask && _ScrollLockMask)
422 XGrabKey(dpy, keycode, modifiers|_NumLockMask|_ScrollLockMask|LockMask,
423 grab_window, owner_events, pointer_mode, keyboard_mode);
424 /* phew, I guess that's all, right? */
426 #endif
428 void
429 wHackedGrabButton(unsigned int button, unsigned int modifiers,
430 Window grab_window, Bool owner_events,
431 unsigned int event_mask, int pointer_mode,
432 int keyboard_mode, Window confine_to, Cursor cursor)
434 XGrabButton(dpy, button, modifiers, grab_window, owner_events,
435 event_mask, pointer_mode, keyboard_mode, confine_to, cursor);
437 if (modifiers==AnyModifier)
438 return;
440 XGrabButton(dpy, button, modifiers|LockMask, grab_window, owner_events,
441 event_mask, pointer_mode, keyboard_mode, confine_to, cursor);
443 #ifdef NUMLOCK_HACK
444 /* same as above, but for mouse buttons */
445 if (_NumLockMask)
446 XGrabButton(dpy, button, modifiers|_NumLockMask,
447 grab_window, owner_events, event_mask, pointer_mode,
448 keyboard_mode, confine_to, cursor);
449 if (_ScrollLockMask)
450 XGrabButton(dpy, button, modifiers|_ScrollLockMask,
451 grab_window, owner_events, event_mask, pointer_mode,
452 keyboard_mode, confine_to, cursor);
453 if (_NumLockMask && _ScrollLockMask)
454 XGrabButton(dpy, button, modifiers|_ScrollLockMask|_NumLockMask,
455 grab_window, owner_events, event_mask, pointer_mode,
456 keyboard_mode, confine_to, cursor);
457 if (_NumLockMask)
458 XGrabButton(dpy, button, modifiers|_NumLockMask|LockMask,
459 grab_window, owner_events, event_mask, pointer_mode,
460 keyboard_mode, confine_to, cursor);
461 if (_ScrollLockMask)
462 XGrabButton(dpy, button, modifiers|_ScrollLockMask|LockMask,
463 grab_window, owner_events, event_mask, pointer_mode,
464 keyboard_mode, confine_to, cursor);
465 if (_NumLockMask && _ScrollLockMask)
466 XGrabButton(dpy, button, modifiers|_ScrollLockMask|_NumLockMask|LockMask,
467 grab_window, owner_events, event_mask, pointer_mode,
468 keyboard_mode, confine_to, cursor);
469 #endif /* NUMLOCK_HACK */
472 #ifdef notused
473 void
474 wHackedUngrabButton(unsigned int button, unsigned int modifiers,
475 Window grab_window)
477 XUngrabButton(dpy, button, modifiers|_NumLockMask,
478 grab_window);
479 XUngrabButton(dpy, button, modifiers|_ScrollLockMask,
480 grab_window);
481 XUngrabButton(dpy, button, modifiers|_NumLockMask|_ScrollLockMask,
482 grab_window);
483 XUngrabButton(dpy, button, modifiers|_NumLockMask|LockMask,
484 grab_window);
485 XUngrabButton(dpy, button, modifiers|_ScrollLockMask|LockMask,
486 grab_window);
487 XUngrabButton(dpy, button, modifiers|_NumLockMask|_ScrollLockMask|LockMask,
488 grab_window);
490 #endif
494 WScreen*
495 wScreenWithNumber(int i)
497 assert(i < wScreenCount);
499 return wScreen[i];
503 WScreen*
504 wScreenForRootWindow(Window window)
506 int i;
508 if (wScreenCount==1)
509 return wScreen[0];
512 * Since the number of heads will probably be small (normally 2),
513 * it should be faster to use this than a hash table, because
514 * of the overhead.
516 for (i=0; i<wScreenCount; i++) {
517 if (wScreen[i]->root_win == window) {
518 return wScreen[i];
522 return wScreenForWindow(window);
526 WScreen*
527 wScreenSearchForRootWindow(Window window)
529 int i;
531 if (wScreenCount==1)
532 return wScreen[0];
535 * Since the number of heads will probably be small (normally 2),
536 * it should be faster to use this than a hash table, because
537 * of the overhead.
539 for (i=0; i<wScreenCount; i++) {
540 if (wScreen[i]->root_win == window) {
541 return wScreen[i];
545 return wScreenForWindow(window);
549 WScreen*
550 wScreenForWindow(Window window)
552 XWindowAttributes attr;
554 if (wScreenCount==1)
555 return wScreen[0];
557 if (XGetWindowAttributes(dpy, window, &attr)) {
558 return wScreenForRootWindow(attr.root);
560 return NULL;
564 static char *atomNames[] = {
565 "WM_STATE",
566 "WM_CHANGE_STATE",
567 "WM_PROTOCOLS",
568 "WM_TAKE_FOCUS",
569 "WM_DELETE_WINDOW",
570 "WM_SAVE_YOURSELF",
571 "WM_CLIENT_LEADER",
572 "WM_COLORMAP_WINDOWS",
573 "WM_COLORMAP_NOTIFY",
575 "_WINDOWMAKER_MENU",
576 "_WINDOWMAKER_STATE",
577 "_WINDOWMAKER_WM_PROTOCOLS",
578 "_WINDOWMAKER_WM_FUNCTION",
579 "_WINDOWMAKER_NOTICEBOARD",
580 "_WINDOWMAKER_COMMAND",
581 "_WINDOWMAKER_ICON_SIZE",
582 "_WINDOWMAKER_ICON_TILE",
584 GNUSTEP_WM_ATTR_NAME,
585 GNUSTEP_WM_MINIATURIZE_WINDOW,
586 GNUSTEP_TITLEBAR_STATE
591 *----------------------------------------------------------
592 * StartUp--
593 * starts the window manager and setup global data.
594 * Called from main() at startup.
596 * Side effects:
597 * global data declared in main.c is initialized
598 *----------------------------------------------------------
600 void
601 StartUp(Bool defaultScreenOnly)
603 struct sigaction sig_action;
604 int j, max;
605 Atom atom[sizeof(atomNames)/sizeof(char*)];
608 * Ignore CapsLock in modifiers
610 ValidModMask = 0xff & ~LockMask;
612 getOffendingModifiers();
614 * Ignore NumLock and ScrollLock too
616 ValidModMask &= ~(_NumLockMask|_ScrollLockMask);
619 memset(&wKeyBindings, 0, sizeof(wKeyBindings));
621 wWinContext = XUniqueContext();
622 wAppWinContext = XUniqueContext();
623 wStackContext = XUniqueContext();
624 wVEdgeContext = XUniqueContext();
626 /* _XA_VERSION = XInternAtom(dpy, "VERSION", False);*/
628 #ifdef HAVE_XINTERNATOMS
629 XInternAtoms(dpy, atomNames, sizeof(atomNames)/sizeof(char*),
630 False, atom);
631 #else
634 int i;
635 for (i = 0; i < sizeof(atomNames)/sizeof(char*); i++) {
636 atom[i] = XInternAtom(dpy, atomNames[i], False);
639 #endif
641 _XA_WM_STATE = atom[0];
642 _XA_WM_CHANGE_STATE = atom[1];
643 _XA_WM_PROTOCOLS = atom[2];
644 _XA_WM_TAKE_FOCUS = atom[3];
645 _XA_WM_DELETE_WINDOW = atom[4];
646 _XA_WM_SAVE_YOURSELF = atom[5];
647 _XA_WM_CLIENT_LEADER = atom[6];
648 _XA_WM_COLORMAP_WINDOWS = atom[7];
649 _XA_WM_COLORMAP_NOTIFY = atom[8];
651 _XA_WINDOWMAKER_MENU = atom[9];
652 _XA_WINDOWMAKER_STATE = atom[10];
653 _XA_WINDOWMAKER_WM_PROTOCOLS = atom[11];
654 _XA_WINDOWMAKER_WM_FUNCTION = atom[12];
655 _XA_WINDOWMAKER_NOTICEBOARD = atom[13];
656 _XA_WINDOWMAKER_COMMAND = atom[14];
657 _XA_WINDOWMAKER_ICON_SIZE = atom[15];
658 _XA_WINDOWMAKER_ICON_TILE = atom[16];
660 _XA_GNUSTEP_WM_ATTR = atom[17];
661 _XA_GNUSTEP_WM_MINIATURIZE_WINDOW = atom[18];
662 _XA_GNUSTEP_TITLEBAR_STATE = atom[19];
664 #ifdef XDND
665 wXDNDInitializeAtoms();
666 #endif
669 /* cursors */
670 wCursor[WCUR_NORMAL] = None; /* inherit from root */
671 wCursor[WCUR_ROOT] = XCreateFontCursor(dpy, XC_left_ptr);
672 wCursor[WCUR_ARROW] = XCreateFontCursor(dpy, XC_top_left_arrow);
673 wCursor[WCUR_MOVE] = XCreateFontCursor(dpy, XC_fleur);
674 wCursor[WCUR_RESIZE] = XCreateFontCursor(dpy, XC_sizing);
675 wCursor[WCUR_TOPLEFTRESIZE] = XCreateFontCursor(dpy, XC_top_left_corner);
676 wCursor[WCUR_TOPRIGHTRESIZE] = XCreateFontCursor(dpy, XC_top_right_corner);
677 wCursor[WCUR_BOTTOMLEFTRESIZE] = XCreateFontCursor(dpy, XC_bottom_left_corner);
678 wCursor[WCUR_BOTTOMRIGHTRESIZE] = XCreateFontCursor(dpy, XC_bottom_right_corner);
679 wCursor[WCUR_VERTICALRESIZE] = XCreateFontCursor(dpy, XC_sb_v_double_arrow);
680 wCursor[WCUR_HORIZONRESIZE] = XCreateFontCursor(dpy, XC_sb_h_double_arrow);
681 wCursor[WCUR_WAIT] = XCreateFontCursor(dpy, XC_watch);
682 wCursor[WCUR_QUESTION] = XCreateFontCursor(dpy, XC_question_arrow);
683 wCursor[WCUR_TEXT] = XCreateFontCursor(dpy, XC_xterm); /* odd name???*/
684 wCursor[WCUR_SELECT] = XCreateFontCursor(dpy, XC_cross);
686 Pixmap cur = XCreatePixmap(dpy, DefaultRootWindow(dpy), 16, 16, 1);
687 GC gc = XCreateGC(dpy, cur, 0, NULL);
688 XColor black;
689 memset(&black, 0, sizeof(XColor));
690 XSetForeground(dpy, gc, 0);
691 XFillRectangle(dpy, cur, gc, 0, 0, 16, 16);
692 XFreeGC(dpy, gc);
693 wCursor[WCUR_EMPTY] = XCreatePixmapCursor(dpy, cur, cur, &black, &black, 0, 0);
694 XFreePixmap(dpy, cur);
697 /* signal handler stuff that gets called when a signal is caught */
698 WMAddPersistentTimerHandler(500, delayedAction, NULL);
700 /* emergency exit... */
701 sig_action.sa_handler = handleSig;
702 sigemptyset(&sig_action.sa_mask);
704 sig_action.sa_flags = SA_RESTART;
705 sigaction(SIGQUIT, &sig_action, NULL);
706 /* instead of catching these, we let the default handler abort the
707 * program. The new monitor process will take appropriate action
708 * when it detects the crash.
709 sigaction(SIGSEGV, &sig_action, NULL);
710 sigaction(SIGBUS, &sig_action, NULL);
711 sigaction(SIGFPE, &sig_action, NULL);
712 sigaction(SIGABRT, &sig_action, NULL);
715 sig_action.sa_handler = handleExitSig;
717 /* Here we set SA_RESTART for safety, because SIGUSR1 may not be handled
718 * immediately. -Dan */
719 sig_action.sa_flags = SA_RESTART;
720 sigaction(SIGTERM, &sig_action, NULL);
721 sigaction(SIGINT, &sig_action, NULL);
722 sigaction(SIGHUP, &sig_action, NULL);
723 sigaction(SIGUSR1, &sig_action, NULL);
724 sigaction(SIGUSR2, &sig_action, NULL);
726 /* ignore dead pipe */
727 /* Because POSIX mandates that only signal with handlers are reset
728 * accross an exec*(), we do not want to propagate ignoring SIGPIPEs
729 * to children. Hence the dummy handler.
730 * Philippe Troin <phil@fifi.org>
732 sig_action.sa_handler = &dummyHandler;
733 sig_action.sa_flags = SA_RESTART;
734 sigaction(SIGPIPE, &sig_action, NULL);
736 /* handle dead children */
737 sig_action.sa_handler = buryChild;
738 sig_action.sa_flags = SA_NOCLDSTOP|SA_RESTART;
739 sigaction(SIGCHLD, &sig_action, NULL);
741 /* Now we unblock all signals, that may have been blocked by the parent
742 * who exec()-ed us. This can happen for example if Window Maker crashes
743 * and restarts itself or another window manager from the signal handler.
744 * In this case, the new proccess inherits the blocked signal mask and
745 * will no longer react to that signal, until unblocked.
746 * This is because the signal handler of the proccess who crashed (parent)
747 * didn't return, and the signal remained blocked. -Dan
749 sigfillset(&sig_action.sa_mask);
750 sigprocmask(SIG_UNBLOCK, &sig_action.sa_mask, NULL);
752 /* handle X shutdowns a such */
753 XSetIOErrorHandler(handleXIO);
755 /* set hook for out event dispatcher in WINGs event dispatcher */
756 WMHookEventHandler(DispatchEvent);
758 /* initialize defaults stuff */
759 WDWindowMaker = wDefaultsInitDomain("WindowMaker", True);
760 if (!WDWindowMaker->dictionary) {
761 wwarning(_("could not read domain \"%s\" from defaults database"),
762 "WindowMaker");
765 /* read defaults that don't change until a restart and are
766 * screen independent */
767 wReadStaticDefaults(WDWindowMaker ? WDWindowMaker->dictionary : NULL);
769 /* check sanity of some values */
770 if (wPreferences.icon_size < 16) {
771 wwarning(_("icon size is configured to %i, but it's too small. Using 16, instead\n"),
772 wPreferences.icon_size);
773 wPreferences.icon_size = 16;
776 /* init other domains */
777 WDRootMenu = wDefaultsInitDomain("WMRootMenu", False);
778 if (!WDRootMenu->dictionary) {
779 wwarning(_("could not read domain \"%s\" from defaults database"),
780 "WMRootMenu");
782 wDefaultsMergeGlobalMenus(WDRootMenu);
784 WDWindowAttributes = wDefaultsInitDomain("WMWindowAttributes", True);
785 if (!WDWindowAttributes->dictionary) {
786 wwarning(_("could not read domain \"%s\" from defaults database"),
787 "WMWindowAttributes");
790 XSetErrorHandler((XErrorHandler)catchXError);
792 #ifdef SHAPE
793 /* ignore j */
794 wShapeSupported = XShapeQueryExtension(dpy, &wShapeEventBase, &j);
795 #endif
797 #ifdef KEEP_XKB_LOCK_STATUS
798 wXkbSupported = XkbQueryExtension(dpy, NULL, &wXkbEventBase, NULL, NULL, NULL);
799 if(wPreferences.modelock && !wXkbSupported) {
800 wwarning(_("XKB is not supported. KbdModeLock is automatically disabled."));
801 wPreferences.modelock = 0;
803 #endif
805 if (defaultScreenOnly) {
806 max = 1;
807 } else {
808 max = ScreenCount(dpy);
810 wScreen = wmalloc(sizeof(WScreen*)*max);
812 wScreenCount = 0;
814 /* manage the screens */
815 for (j = 0; j < max; j++) {
816 if (defaultScreenOnly || max==1) {
817 wScreen[wScreenCount] = wScreenInit(DefaultScreen(dpy));
818 if (!wScreen[wScreenCount]) {
819 wfatal(_("it seems that there is already a window manager running"));
820 Exit(1);
822 } else {
823 wScreen[wScreenCount] = wScreenInit(j);
824 if (!wScreen[wScreenCount]) {
825 wwarning(_("could not manage screen %i"), j);
826 continue;
829 wScreenCount++;
832 #ifndef LITE
833 InitializeSwitchMenu();
834 #endif
836 /* initialize/restore state for the screens */
837 for (j = 0; j < wScreenCount; j++) {
838 int lastDesktop;
840 lastDesktop= wNETWMGetCurrentDesktopFromHint(wScreen[j]);
842 wScreenRestoreState(wScreen[j]);
844 /* manage all windows that were already here before us */
845 if (!wPreferences.flags.nodock && wScreen[j]->dock)
846 wScreen[j]->last_dock = wScreen[j]->dock;
848 manageAllWindows(wScreen[j], wPreferences.flags.restarting==2);
850 /* restore saved menus */
851 wMenuRestoreState(wScreen[j]);
853 /* If we're not restarting, restore session */
854 if (wPreferences.flags.restarting==0 && !wPreferences.flags.norestore)
855 wSessionRestoreState(wScreen[j]);
857 if (!wPreferences.flags.noautolaunch) {
858 /* auto-launch apps */
859 if (!wPreferences.flags.nodock && wScreen[j]->dock) {
860 wScreen[j]->last_dock = wScreen[j]->dock;
861 wDockDoAutoLaunch(wScreen[j]->dock, 0);
863 /* auto-launch apps in clip */
864 if (!wPreferences.flags.noclip) {
865 int i;
866 for(i=0; i<wScreen[j]->workspace_count; i++) {
867 if (wScreen[j]->workspaces[i]->clip) {
868 wScreen[j]->last_dock = wScreen[j]->workspaces[i]->clip;
869 wDockDoAutoLaunch(wScreen[j]->workspaces[i]->clip, i);
875 /* go to workspace where we were before restart */
876 if (lastDesktop >= 0) {
877 wWorkspaceForceChange(wScreen[j], lastDesktop);
878 } else {
879 wSessionRestoreLastWorkspace(wScreen[j]);
883 if (wScreenCount == 0) {
884 wfatal(_("could not manage any screen"));
885 Exit(1);
888 if (!wPreferences.flags.nopolling && !wPreferences.flags.noupdates) {
889 /* setup defaults file polling */
890 WMAddTimerHandler(3000, wDefaultsCheckDomains, NULL);
897 static Bool
898 windowInList(Window window, Window *list, int count)
900 for (; count>=0; count--) {
901 if (window == list[count])
902 return True;
904 return False;
908 *-----------------------------------------------------------------------
909 * manageAllWindows--
910 * Manages all windows in the screen.
912 * Notes:
913 * Called when the wm is being started.
914 * No events can be processed while the windows are being
915 * reparented/managed.
916 *-----------------------------------------------------------------------
918 static void
919 manageAllWindows(WScreen *scr, int crashRecovery)
921 Window root, parent;
922 Window *children;
923 unsigned int nchildren;
924 unsigned int i, j;
925 WWindow *wwin;
927 XGrabServer(dpy);
928 XQueryTree(dpy, scr->root_win, &root, &parent, &children, &nchildren);
930 scr->flags.startup = 1;
932 /* first remove all icon windows */
933 for (i = 0; i < nchildren; i++) {
934 XWMHints *wmhints;
936 if (children[i]==None)
937 continue;
939 wmhints = XGetWMHints(dpy, children[i]);
940 if (wmhints && (wmhints->flags & IconWindowHint)) {
941 for (j = 0; j < nchildren; j++) {
942 if (children[j] == wmhints->icon_window) {
943 XFree(wmhints);
944 wmhints = NULL;
945 children[j] = None;
946 break;
950 if (wmhints) {
951 XFree(wmhints);
956 for (i = 0; i < nchildren; i++) {
957 if (children[i] == None)
958 continue;
960 wwin = wManageWindow(scr, children[i]);
961 if (wwin) {
962 /* apply states got from WSavedState */
963 /* shaded + minimized is not restored correctly */
964 if (wwin->flags.shaded) {
965 wwin->flags.shaded = 0;
966 wShadeWindow(wwin);
968 if (wwin->flags.miniaturized
969 && (wwin->transient_for == None
970 || wwin->transient_for == scr->root_win
971 || !windowInList(wwin->transient_for, children,
972 nchildren))) {
974 wwin->flags.skip_next_animation = 1;
975 wwin->flags.miniaturized = 0;
976 wIconifyWindow(wwin);
977 } else {
978 wClientSetState(wwin, NormalState, None);
980 if (crashRecovery) {
981 int border;
983 border = (!HAS_BORDER(wwin) ? 0 : FRAME_BORDER_WIDTH);
985 wWindowMove(wwin, wwin->frame_x - border,
986 wwin->frame_y - border -
987 (wwin->frame->titlebar ?
988 wwin->frame->titlebar->height : 0));
992 XUngrabServer(dpy);
994 /* hide apps */
995 wwin = scr->focused_window;
996 while (wwin) {
997 if (wwin->flags.hidden) {
998 WApplication *wapp = wApplicationOf(wwin->main_window);
1000 if (wapp) {
1001 wwin->flags.hidden = 0;
1002 wHideApplication(wapp);
1003 } else {
1004 wwin->flags.hidden = 0;
1007 wwin = wwin->prev;
1010 XFree(children);
1011 scr->flags.startup = 0;
1012 scr->flags.startup2 = 1;
1014 while (XPending(dpy)) {
1015 XEvent ev;
1016 WMNextEvent(dpy, &ev);
1017 WMHandleEvent(&ev);
1019 wWorkspaceForceChange(scr, 0);
1020 if (!wPreferences.flags.noclip)
1021 wDockShowIcons(scr->workspaces[scr->current_workspace]->clip);
1022 scr->flags.startup2 = 0;