]> icculus.org git repositories - dana/openbox.git/blob - src/openbox.cc
starting openbox without an rc file now works. it makes an empty Xrm db instead of...
[dana/openbox.git] / src / openbox.cc
1 // openbox.cc for Openbox
2 // Copyright (c) 2001 Sean 'Shaleh' Perry <shaleh@debian.org>
3 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22
23 // stupid macros needed to access some functions in version 2 of the GNU C
24 // library
25 #ifndef   _GNU_SOURCE
26 #define   _GNU_SOURCE
27 #endif // _GNU_SOURCE
28
29 #ifdef    HAVE_CONFIG_H
30 #  include "../config.h"
31 #endif // HAVE_CONFIG_H
32
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
35 #include <X11/Xresource.h>
36 #include <X11/Xatom.h>
37 #include <X11/keysym.h>
38
39 #ifdef    SHAPE
40 #include <X11/extensions/shape.h>
41 #endif // SHAPE
42
43 #include "i18n.h"
44 #include "openbox.h"
45 #include "Basemenu.h"
46 #include "Clientmenu.h"
47 #include "Rootmenu.h"
48 #include "Screen.h"
49
50 #ifdef    SLIT
51 #include "Slit.h"
52 #endif // SLIT
53
54 #include "Toolbar.h"
55 #include "Window.h"
56 #include "Workspace.h"
57 #include "Workspacemenu.h"
58 #include "Util.h"
59
60 #include <string>
61 #include <algorithm>
62
63 #ifdef    HAVE_STDIO_H
64 #  include <stdio.h>
65 #endif // HAVE_STDIO_H
66
67 #ifdef    HAVE_STDLIB_H
68 #  include <stdlib.h>
69 #endif // HAVE_STDLIB_H
70
71 #ifdef    HAVE_STRING_H
72 #  include <string.h>
73 #endif // HAVE_STRING_H
74
75 #ifdef    HAVE_UNISTD_H
76 #  include <sys/types.h>
77 #  include <unistd.h>
78 #endif // HAVE_UNISTD_H
79
80 #ifdef    HAVE_SYS_PARAM_H
81 #  include <sys/param.h>
82 #endif // HAVE_SYS_PARAM_H
83
84 #ifndef   MAXPATHLEN
85 #define   MAXPATHLEN 255
86 #endif // MAXPATHLEN
87
88 #ifdef    HAVE_SYS_SELECT_H
89 #  include <sys/select.h>
90 #endif // HAVE_SYS_SELECT_H
91
92 #ifdef    HAVE_SIGNAL_H
93 #  include <signal.h>
94 #endif // HAVE_SIGNAL_H
95
96 #ifdef    HAVE_SYS_SIGNAL_H
97 #  include <sys/signal.h>
98 #endif // HAVE_SYS_SIGNAL_H
99
100 #ifdef    HAVE_SYS_STAT_H
101 #  include <sys/types.h>
102 #  include <sys/stat.h>
103 #endif // HAVE_SYS_STAT_H
104
105 #ifdef    TIME_WITH_SYS_TIME
106 #  include <sys/time.h>
107 #  include <time.h>
108 #else // !TIME_WITH_SYS_TIME
109 #  ifdef    HAVE_SYS_TIME_H
110 #    include <sys/time.h>
111 #  else // !HAVE_SYS_TIME_H
112 #    include <time.h>
113 #  endif // HAVE_SYS_TIME_H
114 #endif // TIME_WITH_SYS_TIME
115
116 #ifdef    HAVE_LIBGEN_H
117 #  include <libgen.h>
118 #endif // HAVE_LIBGEN_H
119
120 #ifndef   HAVE_BASENAME
121 static inline char *basename (char *s) {
122   char *save = s;
123
124   while (*s) if (*s++ == '/') save = s;
125
126   return save;
127 }
128 #endif // HAVE_BASENAME
129
130
131 // X event scanner for enter/leave notifies - adapted from twm
132 typedef struct scanargs {
133   Window w;
134   Bool leave, inferior, enter;
135 } scanargs;
136
137 static Bool queueScanner(Display *, XEvent *e, char *args) {
138   if ((e->type == LeaveNotify) &&
139       (e->xcrossing.window == ((scanargs *) args)->w) &&
140       (e->xcrossing.mode == NotifyNormal)) {
141     ((scanargs *) args)->leave = True;
142     ((scanargs *) args)->inferior = (e->xcrossing.detail == NotifyInferior);
143   } else if ((e->type == EnterNotify) &&
144              (e->xcrossing.mode == NotifyUngrab)) {
145     ((scanargs *) args)->enter = True;
146   }
147
148   return False;
149 }
150
151 Openbox *openbox;
152
153
154 Openbox::Openbox(int m_argc, char **m_argv, char *dpy_name, char *rc)
155   : BaseDisplay(m_argv[0], dpy_name) {
156   grab();
157
158   if (! XSupportsLocale())
159     fprintf(stderr, "X server does not support locale\n");
160
161   if (XSetLocaleModifiers("") == NULL)
162     fprintf(stderr, "cannot set locale modifiers\n");
163
164   ::openbox = this;
165   argc = m_argc;
166   argv = m_argv;
167   if (rc == NULL) {
168     char *homedir = getenv("HOME");
169
170     rc_file = new char[strlen(homedir) + strlen("/.openbox/rc") + 1];
171     sprintf(rc_file, "%s/.openbox", homedir);
172
173     // try to make sure the ~/.openbox directory exists
174     mkdir(rc_file, S_IREAD | S_IWRITE | S_IEXEC | S_IRGRP | S_IWGRP | S_IXGRP |
175           S_IROTH | S_IWOTH | S_IXOTH);
176     
177     sprintf(rc_file, "%s/.openbox/rc", homedir);
178   } else {
179     rc_file = bstrdup(rc);
180   }
181   config.setFile(rc_file);
182
183   no_focus = False;
184
185   resource.menu_file = resource.style_file = (char *) 0;
186   resource.titlebar_layout = (char *) NULL;
187   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
188
189   focused_window = masked_window = (OpenboxWindow *) 0;
190   masked = None;
191
192   windowSearchList = new LinkedList<WindowSearch>;
193   menuSearchList = new LinkedList<MenuSearch>;
194
195 #ifdef    SLIT
196   slitSearchList = new LinkedList<SlitSearch>;
197 #endif // SLIT
198
199   toolbarSearchList = new LinkedList<ToolbarSearch>;
200   groupSearchList = new LinkedList<WindowSearch>;
201
202   menuTimestamps = new LinkedList<MenuTimestamp>;
203
204   load();
205
206 #ifdef    HAVE_GETPID
207   openbox_pid = XInternAtom(getXDisplay(), "_BLACKBOX_PID", False);
208 #endif // HAVE_GETPID
209
210   screenList = new LinkedList<BScreen>;
211   for (int i = 0; i < getNumberOfScreens(); i++) {
212     BScreen *screen = new BScreen(*this, i, config);
213
214     if (! screen->isScreenManaged()) {
215       delete screen;
216       continue;
217     }
218
219     screenList->insert(screen);
220   }
221
222   if (! screenList->count()) {
223     fprintf(stderr,
224             i18n->getMessage(openboxSet, openboxNoManagableScreens,
225                "Openbox::Openbox: no managable screens found, aborting.\n"));
226     ::exit(3);
227   }
228
229   // save current settings and default values
230   save();
231   
232   XSynchronize(getXDisplay(), False);
233   XSync(getXDisplay(), False);
234
235   reconfigure_wait = reread_menu_wait = False;
236
237   timer = new BTimer(*this, *this);
238   timer->setTimeout(0);
239   timer->fireOnce(True);
240
241   ungrab();
242 }
243
244
245 Openbox::~Openbox() {
246   while (screenList->count())
247     delete screenList->remove(0);
248
249   while (menuTimestamps->count()) {
250     MenuTimestamp *ts = menuTimestamps->remove(0);
251
252     if (ts->filename)
253       delete [] ts->filename;
254
255     delete ts;
256   }
257
258   if (resource.menu_file)
259     delete [] resource.menu_file;
260
261   if (resource.style_file)
262     delete [] resource.style_file;
263
264   delete timer;
265
266   delete screenList;
267   delete menuTimestamps;
268
269   delete windowSearchList;
270   delete menuSearchList;
271   delete toolbarSearchList;
272   delete groupSearchList;
273
274   delete [] rc_file;
275
276 #ifdef    SLIT
277   delete slitSearchList;
278 #endif // SLIT
279 }
280
281
282 void Openbox::process_event(XEvent *e) {
283   if ((masked == e->xany.window) && masked_window &&
284       (e->type == MotionNotify)) {
285     last_time = e->xmotion.time;
286     masked_window->motionNotifyEvent(&e->xmotion);
287
288     return;
289   }
290
291   switch (e->type) {
292   case ButtonPress: {
293     // strip the lock key modifiers
294     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
295
296     last_time = e->xbutton.time;
297
298     OpenboxWindow *win = (OpenboxWindow *) 0;
299     Basemenu *menu = (Basemenu *) 0;
300
301 #ifdef    SLIT
302     Slit *slit = (Slit *) 0;
303 #endif // SLIT
304
305     Toolbar *tbar = (Toolbar *) 0;
306
307     if ((win = searchWindow(e->xbutton.window))) {
308       win->buttonPressEvent(&e->xbutton);
309
310       if (e->xbutton.button == 1)
311         win->installColormap(True);
312     } else if ((menu = searchMenu(e->xbutton.window))) {
313       menu->buttonPressEvent(&e->xbutton);
314
315 #ifdef    SLIT
316     } else if ((slit = searchSlit(e->xbutton.window))) {
317       slit->buttonPressEvent(&e->xbutton);
318 #endif // SLIT
319
320     } else if ((tbar = searchToolbar(e->xbutton.window))) {
321       tbar->buttonPressEvent(&e->xbutton);
322     } else {
323       LinkedListIterator<BScreen> it(screenList);
324       BScreen *screen = it.current();
325       for (; screen; it++, screen = it.current()) {
326         if (e->xbutton.window == screen->getRootWindow()) {
327           if (e->xbutton.button == 1) {
328             if (! screen->isRootColormapInstalled())
329               screen->getImageControl()->installRootColormap();
330
331             if (screen->getWorkspacemenu()->isVisible())
332               screen->getWorkspacemenu()->hide();
333
334             if (screen->getRootmenu()->isVisible())
335               screen->getRootmenu()->hide();
336           } else if (e->xbutton.button == 2) {
337             int mx = e->xbutton.x_root -
338               (screen->getWorkspacemenu()->getWidth() / 2);
339             int my = e->xbutton.y_root -
340               (screen->getWorkspacemenu()->getTitleHeight() / 2);
341
342             if (mx < 0) mx = 0;
343             if (my < 0) my = 0;
344
345             if (mx + screen->getWorkspacemenu()->getWidth() >
346                 screen->size().w())
347               mx = screen->size().w() -
348                 screen->getWorkspacemenu()->getWidth() -
349                 screen->getBorderWidth();
350
351             if (my + screen->getWorkspacemenu()->getHeight() >
352                 screen->size().h())
353               my = screen->size().h() -
354                 screen->getWorkspacemenu()->getHeight() -
355                 screen->getBorderWidth();
356
357             screen->getWorkspacemenu()->move(mx, my);
358
359             if (! screen->getWorkspacemenu()->isVisible()) {
360               screen->getWorkspacemenu()->removeParent();
361               screen->getWorkspacemenu()->show();
362             }
363           } else if (e->xbutton.button == 3) {
364             int mx = e->xbutton.x_root -
365               (screen->getRootmenu()->getWidth() / 2);
366             int my = e->xbutton.y_root -
367               (screen->getRootmenu()->getTitleHeight() / 2);
368
369             if (mx < 0) mx = 0;
370             if (my < 0) my = 0;
371
372             if (mx + screen->getRootmenu()->getWidth() > screen->size().w())
373               mx = screen->size().w() -
374                 screen->getRootmenu()->getWidth() -
375                 screen->getBorderWidth();
376
377             if (my + screen->getRootmenu()->getHeight() > screen->size().h())
378                 my = screen->size().h() -
379                   screen->getRootmenu()->getHeight() -
380                   screen->getBorderWidth();
381
382             screen->getRootmenu()->move(mx, my);
383
384             if (! screen->getRootmenu()->isVisible()) {
385               checkMenu();
386               screen->getRootmenu()->show();
387             }
388           } else if (e->xbutton.button == 4) {
389             if ((screen->getCurrentWorkspaceID() + 1) >
390                 screen->getWorkspaceCount() - 1)
391               screen->changeWorkspaceID(0);
392             else
393               screen->changeWorkspaceID(screen->getCurrentWorkspaceID() + 1);
394           } else if (e->xbutton.button == 5) {
395             if ((screen->getCurrentWorkspaceID() - 1) < 0)
396               screen->changeWorkspaceID(screen->getWorkspaceCount() - 1);
397             else
398               screen->changeWorkspaceID(screen->getCurrentWorkspaceID() - 1);
399           }
400         }
401       }
402     }
403
404     break;
405   }
406
407   case ButtonRelease: {
408     // strip the lock key modifiers
409     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
410
411     last_time = e->xbutton.time;
412
413     OpenboxWindow *win = (OpenboxWindow *) 0;
414     Basemenu *menu = (Basemenu *) 0;
415     Toolbar *tbar = (Toolbar *) 0;
416
417     if ((win = searchWindow(e->xbutton.window)))
418       win->buttonReleaseEvent(&e->xbutton);
419     else if ((menu = searchMenu(e->xbutton.window)))
420       menu->buttonReleaseEvent(&e->xbutton);
421     else if ((tbar = searchToolbar(e->xbutton.window)))
422       tbar->buttonReleaseEvent(&e->xbutton);
423
424     break;
425   }
426
427   case ConfigureRequest: {
428     OpenboxWindow *win = (OpenboxWindow *) 0;
429
430 #ifdef    SLIT
431     Slit *slit = (Slit *) 0;
432 #endif // SLIT
433
434     if ((win = searchWindow(e->xconfigurerequest.window))) {
435       win->configureRequestEvent(&e->xconfigurerequest);
436
437 #ifdef    SLIT
438     } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
439       slit->configureRequestEvent(&e->xconfigurerequest);
440 #endif // SLIT
441
442     } else {
443       grab();
444
445       if (validateWindow(e->xconfigurerequest.window)) {
446         XWindowChanges xwc;
447
448         xwc.x = e->xconfigurerequest.x;
449         xwc.y = e->xconfigurerequest.y;
450         xwc.width = e->xconfigurerequest.width;
451         xwc.height = e->xconfigurerequest.height;
452         xwc.border_width = e->xconfigurerequest.border_width;
453         xwc.sibling = e->xconfigurerequest.above;
454         xwc.stack_mode = e->xconfigurerequest.detail;
455
456         XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
457                          e->xconfigurerequest.value_mask, &xwc);
458       }
459
460       ungrab();
461     }
462
463     break;
464   }
465
466   case MapRequest: {
467 #ifdef    DEBUG
468     fprintf(stderr,
469             i18n->getMessage(openboxSet, openboxMapRequest,
470                  "Openbox::process_event(): MapRequest for 0x%lx\n"),
471             e->xmaprequest.window);
472 #endif // DEBUG
473
474     OpenboxWindow *win = searchWindow(e->xmaprequest.window);
475
476     if (! win)
477       win = new OpenboxWindow(*this, e->xmaprequest.window);
478
479     if ((win = searchWindow(e->xmaprequest.window)))
480       win->mapRequestEvent(&e->xmaprequest);
481
482     break;
483   }
484
485   case MapNotify: {
486     OpenboxWindow *win = searchWindow(e->xmap.window);
487
488     if (win)
489       win->mapNotifyEvent(&e->xmap);
490
491       break;
492   }
493
494   case UnmapNotify: {
495     OpenboxWindow *win = (OpenboxWindow *) 0;
496
497 #ifdef    SLIT
498     Slit *slit = (Slit *) 0;
499 #endif // SLIT
500
501     if ((win = searchWindow(e->xunmap.window))) {
502       win->unmapNotifyEvent(&e->xunmap);
503       if (focused_window == win)
504         focused_window = (OpenboxWindow *) 0;
505 #ifdef    SLIT
506     } else if ((slit = searchSlit(e->xunmap.window))) {
507       slit->removeClient(e->xunmap.window);
508 #endif // SLIT
509
510     }
511
512     break;
513   }
514
515   case DestroyNotify: {
516     OpenboxWindow *win = (OpenboxWindow *) 0;
517
518 #ifdef    SLIT
519     Slit *slit = (Slit *) 0;
520 #endif // SLIT
521
522     if ((win = searchWindow(e->xdestroywindow.window))) {
523       win->destroyNotifyEvent(&e->xdestroywindow);
524       if (focused_window == win)
525         focused_window = (OpenboxWindow *) 0;
526 #ifdef    SLIT
527     } else if ((slit = searchSlit(e->xdestroywindow.window))) {
528       slit->removeClient(e->xdestroywindow.window, False);
529 #endif // SLIT
530     }
531
532     break;
533   }
534
535   case MotionNotify: {
536     // strip the lock key modifiers
537     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
538     
539     last_time = e->xmotion.time;
540
541     OpenboxWindow *win = (OpenboxWindow *) 0;
542     Basemenu *menu = (Basemenu *) 0;
543
544     if ((win = searchWindow(e->xmotion.window)))
545       win->motionNotifyEvent(&e->xmotion);
546     else if ((menu = searchMenu(e->xmotion.window)))
547       menu->motionNotifyEvent(&e->xmotion);
548
549     break;
550   }
551
552   case PropertyNotify: {
553     last_time = e->xproperty.time;
554
555     if (e->xproperty.state != PropertyDelete) {
556       OpenboxWindow *win = searchWindow(e->xproperty.window);
557
558       if (win)
559         win->propertyNotifyEvent(e->xproperty.atom);
560     }
561
562     break;
563   }
564
565   case EnterNotify: {
566     last_time = e->xcrossing.time;
567
568     BScreen *screen = (BScreen *) 0;
569     OpenboxWindow *win = (OpenboxWindow *) 0;
570     Basemenu *menu = (Basemenu *) 0;
571     Toolbar *tbar = (Toolbar *) 0;
572
573 #ifdef    SLIT
574     Slit *slit = (Slit *) 0;
575 #endif // SLIT
576
577     if (e->xcrossing.mode == NotifyGrab) break;
578
579     XEvent dummy;
580     scanargs sa;
581     sa.w = e->xcrossing.window;
582     sa.enter = sa.leave = False;
583     XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
584
585     if ((e->xcrossing.window == e->xcrossing.root) &&
586         (screen = searchScreen(e->xcrossing.window))) {
587       screen->getImageControl()->installRootColormap();
588     } else if ((win = searchWindow(e->xcrossing.window))) {
589       if (win->getScreen()->sloppyFocus() &&
590           (! win->isFocused()) && (! no_focus)) {
591         grab();
592
593         if (((! sa.leave) || sa.inferior) && win->isVisible() &&
594             win->setInputFocus())
595           win->installColormap(True);
596
597         ungrab();
598       }
599     } else if ((menu = searchMenu(e->xcrossing.window))) {
600       menu->enterNotifyEvent(&e->xcrossing);
601     } else if ((tbar = searchToolbar(e->xcrossing.window))) {
602       tbar->enterNotifyEvent(&e->xcrossing);
603 #ifdef    SLIT
604     } else if ((slit = searchSlit(e->xcrossing.window))) {
605       slit->enterNotifyEvent(&e->xcrossing);
606 #endif // SLIT
607     }
608     break;
609   }
610
611   case LeaveNotify: {
612     last_time = e->xcrossing.time;
613
614     OpenboxWindow *win = (OpenboxWindow *) 0;
615     Basemenu *menu = (Basemenu *) 0;
616     Toolbar *tbar = (Toolbar *) 0;
617
618 #ifdef    SLIT
619     Slit *slit = (Slit *) 0;
620 #endif // SLIT
621
622     if ((menu = searchMenu(e->xcrossing.window)))
623       menu->leaveNotifyEvent(&e->xcrossing);
624     else if ((win = searchWindow(e->xcrossing.window)))
625       win->installColormap(False);
626     else if ((tbar = searchToolbar(e->xcrossing.window)))
627       tbar->leaveNotifyEvent(&e->xcrossing);
628 #ifdef    SLIT
629     else if ((slit = searchSlit(e->xcrossing.window)))
630       slit->leaveNotifyEvent(&e->xcrossing);
631 #endif // SLIT
632
633     break;
634   }
635
636   case Expose: {
637     OpenboxWindow *win = (OpenboxWindow *) 0;
638     Basemenu *menu = (Basemenu *) 0;
639     Toolbar *tbar = (Toolbar *) 0;
640
641     if ((win = searchWindow(e->xexpose.window)))
642       win->exposeEvent(&e->xexpose);
643     else if ((menu = searchMenu(e->xexpose.window)))
644       menu->exposeEvent(&e->xexpose);
645     else if ((tbar = searchToolbar(e->xexpose.window)))
646       tbar->exposeEvent(&e->xexpose);
647
648     break;
649   }
650
651   case KeyPress: {
652     Toolbar *tbar = searchToolbar(e->xkey.window);
653
654     if (tbar && tbar->isEditing())
655       tbar->keyPressEvent(&e->xkey);
656
657     break;
658   }
659
660   case ColormapNotify: {
661     BScreen *screen = searchScreen(e->xcolormap.window);
662
663     if (screen)
664       screen->setRootColormapInstalled((e->xcolormap.state ==
665                                         ColormapInstalled) ? True : False);
666
667     break;
668   }
669
670   case FocusIn: {
671     if (e->xfocus.mode == NotifyUngrab || e->xfocus.detail == NotifyPointer)
672       break;
673
674     OpenboxWindow *win = searchWindow(e->xfocus.window);
675     if (win && ! win->isFocused())
676       setFocusedWindow(win);
677
678     break;
679   }
680
681   case FocusOut:
682     break;
683
684   case ClientMessage: {
685     if (e->xclient.format == 32) {
686       if (e->xclient.message_type == getWMChangeStateAtom()) {
687         OpenboxWindow *win = searchWindow(e->xclient.window);
688         if (! win || ! win->validateClient()) return;
689
690         if (e->xclient.data.l[0] == IconicState)
691           win->iconify();
692         if (e->xclient.data.l[0] == NormalState)
693           win->deiconify();
694       } else if (e->xclient.message_type == getOpenboxChangeWorkspaceAtom()) {
695         BScreen *screen = searchScreen(e->xclient.window);
696
697         if (screen && e->xclient.data.l[0] >= 0 &&
698             e->xclient.data.l[0] < screen->getWorkspaceCount())
699           screen->changeWorkspaceID(e->xclient.data.l[0]);
700       } else if (e->xclient.message_type == getOpenboxChangeWindowFocusAtom()) {
701         OpenboxWindow *win = searchWindow(e->xclient.window);
702
703         if (win && win->isVisible() && win->setInputFocus())
704           win->installColormap(True);
705       } else if (e->xclient.message_type == getOpenboxCycleWindowFocusAtom()) {
706         BScreen *screen = searchScreen(e->xclient.window);
707
708         if (screen) {
709           if (! e->xclient.data.l[0])
710             screen->prevFocus();
711           else
712             screen->nextFocus();
713         }
714       } else if (e->xclient.message_type == getOpenboxChangeAttributesAtom()) {
715         OpenboxWindow *win = searchWindow(e->xclient.window);
716
717         if (win && win->validateClient()) {
718           OpenboxHints net;
719           net.flags = e->xclient.data.l[0];
720           net.attrib = e->xclient.data.l[1];
721           net.workspace = e->xclient.data.l[2];
722           net.stack = e->xclient.data.l[3];
723           net.decoration = e->xclient.data.l[4];
724
725           win->changeOpenboxHints(&net);
726         }
727       }
728     }
729
730     break;
731   }
732
733
734   default: {
735 #ifdef    SHAPE
736     if (e->type == getShapeEventBase()) {
737       XShapeEvent *shape_event = (XShapeEvent *) e;
738       OpenboxWindow *win = (OpenboxWindow *) 0;
739
740       if ((win = searchWindow(e->xany.window)) ||
741           (shape_event->kind != ShapeBounding))
742         win->shapeEvent(shape_event);
743     }
744 #endif // SHAPE
745
746   }
747   } // switch
748 }
749
750
751 Bool Openbox::handleSignal(int sig) {
752   switch (sig) {
753   case SIGHUP:
754   case SIGUSR1:
755     reconfigure();
756     break;
757
758   case SIGUSR2:
759     rereadMenu();
760     break;
761
762   case SIGPIPE:
763   case SIGSEGV:
764   case SIGFPE:
765   case SIGINT:
766   case SIGTERM:
767     shutdown();
768
769   default:
770     return False;
771   }
772
773   return True;
774 }
775
776
777 BScreen *Openbox::searchScreen(Window window) {
778   LinkedListIterator<BScreen> it(screenList);
779
780   for (BScreen *curr = it.current(); curr; it++, curr = it.current()) {
781     if (curr->getRootWindow() == window) {
782       return curr;
783     }
784   }
785
786   return (BScreen *) 0;
787 }
788
789
790 OpenboxWindow *Openbox::searchWindow(Window window) {
791   LinkedListIterator<WindowSearch> it(windowSearchList);
792
793   for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
794       if (tmp->getWindow() == window) {
795         return tmp->getData();
796       }
797   }
798
799   return (OpenboxWindow *) 0;
800 }
801
802
803 OpenboxWindow *Openbox::searchGroup(Window window, OpenboxWindow *win) {
804   OpenboxWindow *w = (OpenboxWindow *) 0;
805   LinkedListIterator<WindowSearch> it(groupSearchList);
806
807   for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
808     if (tmp->getWindow() == window) {
809       w = tmp->getData();
810       if (w->getClientWindow() != win->getClientWindow())
811         return win;
812     }
813   }
814
815   return (OpenboxWindow *) 0;
816 }
817
818
819 Basemenu *Openbox::searchMenu(Window window) {
820   LinkedListIterator<MenuSearch> it(menuSearchList);
821
822   for (MenuSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
823     if (tmp->getWindow() == window)
824       return tmp->getData();
825   }
826
827   return (Basemenu *) 0;
828 }
829
830
831 Toolbar *Openbox::searchToolbar(Window window) {
832   LinkedListIterator<ToolbarSearch> it(toolbarSearchList);
833
834   for (ToolbarSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
835     if (tmp->getWindow() == window)
836       return tmp->getData();
837   }
838
839   return (Toolbar *) 0;
840 }
841
842
843 #ifdef    SLIT
844 Slit *Openbox::searchSlit(Window window) {
845   LinkedListIterator<SlitSearch> it(slitSearchList);
846
847   for (SlitSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
848     if (tmp->getWindow() == window)
849       return tmp->getData();
850   }
851
852   return (Slit *) 0;
853 }
854 #endif // SLIT
855
856
857 void Openbox::saveWindowSearch(Window window, OpenboxWindow *data) {
858   windowSearchList->insert(new WindowSearch(window, data));
859 }
860
861
862 void Openbox::saveGroupSearch(Window window, OpenboxWindow *data) {
863   groupSearchList->insert(new WindowSearch(window, data));
864 }
865
866
867 void Openbox::saveMenuSearch(Window window, Basemenu *data) {
868   menuSearchList->insert(new MenuSearch(window, data));
869 }
870
871
872 void Openbox::saveToolbarSearch(Window window, Toolbar *data) {
873   toolbarSearchList->insert(new ToolbarSearch(window, data));
874 }
875
876
877 #ifdef    SLIT
878 void Openbox::saveSlitSearch(Window window, Slit *data) {
879   slitSearchList->insert(new SlitSearch(window, data));
880 }
881 #endif // SLIT
882
883
884 void Openbox::removeWindowSearch(Window window) {
885   LinkedListIterator<WindowSearch> it(windowSearchList);
886   for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
887     if (tmp->getWindow() == window) {
888       windowSearchList->remove(tmp);
889       delete tmp;
890       break;
891     }
892   }
893 }
894
895
896 void Openbox::removeGroupSearch(Window window) {
897   LinkedListIterator<WindowSearch> it(groupSearchList);
898   for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
899     if (tmp->getWindow() == window) {
900       groupSearchList->remove(tmp);
901       delete tmp;
902       break;
903     }
904   }
905 }
906
907
908 void Openbox::removeMenuSearch(Window window) {
909   LinkedListIterator<MenuSearch> it(menuSearchList);
910   for (MenuSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
911     if (tmp->getWindow() == window) {
912       menuSearchList->remove(tmp);
913       delete tmp;
914       break;
915     }
916   }
917 }
918
919
920 void Openbox::removeToolbarSearch(Window window) {
921   LinkedListIterator<ToolbarSearch> it(toolbarSearchList);
922   for (ToolbarSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
923     if (tmp->getWindow() == window) {
924       toolbarSearchList->remove(tmp);
925       delete tmp;
926       break;
927     }
928   }
929 }
930
931
932 #ifdef    SLIT
933 void Openbox::removeSlitSearch(Window window) {
934   LinkedListIterator<SlitSearch> it(slitSearchList);
935   for (SlitSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
936     if (tmp->getWindow() == window) {
937       slitSearchList->remove(tmp);
938       delete tmp;
939       break;
940     }
941   }
942 }
943 #endif // SLIT
944
945
946 void Openbox::restart(const char *prog) {
947   shutdown();
948
949   if (prog) {
950     execlp(prog, prog, NULL);
951     perror(prog);
952   }
953
954   // fall back in case the above execlp doesn't work
955   execvp(argv[0], argv);
956   execvp(basename(argv[0]), argv);
957 }
958
959
960 void Openbox::shutdown() {
961   BaseDisplay::shutdown();
962
963   XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
964
965   LinkedListIterator<BScreen> it(screenList);
966   for (BScreen *s = it.current(); s; it++, s = it.current())
967     s->shutdown();
968
969   XSync(getXDisplay(), False);
970 }
971
972
973 void Openbox::save() {
974   config.setAutoSave(false);
975   
976   // save all values as they are so that the defaults will be written to the rc
977   // file
978   
979   config.setValue("session.menuFile", getMenuFilename());
980   config.setValue("session.colorsPerChannel",
981                   resource.colors_per_channel);
982   config.setValue("session.doubleClickInterval",
983                   (long)resource.double_click_interval);
984   config.setValue("session.autoRaiseDelay",
985           ((resource.auto_raise_delay.tv_sec * 1000) +
986            (resource.auto_raise_delay.tv_usec / 1000)));
987   config.setValue("session.cacheLife", (long)resource.cache_life / 60000);
988   config.setValue("session.cacheMax", (long)resource.cache_max);
989   config.setValue("session.styleFile", resource.style_file);
990
991   LinkedListIterator<BScreen> it(screenList);
992   for (BScreen *s = it.current(); s != NULL; it++, s = it.current()) {
993     s->save();
994     s->getToolbar()->save();
995     s->getSlit()->save();
996   }
997
998   config.setAutoSave(true);
999   config.save();
1000 }
1001
1002 void Openbox::load() {
1003   if (!config.load())
1004     config.create();
1005
1006   std::string s;
1007   long l;
1008   
1009   if (resource.menu_file)
1010     delete [] resource.menu_file;
1011   if (config.getValue("session.menuFile", "Session.MenuFile", s))
1012     resource.menu_file = bstrdup(s.c_str());
1013   else
1014     resource.menu_file = bstrdup(DEFAULTMENU);
1015
1016   if (config.getValue("session.colorsPerChannel", "Session.ColorsPerChannel",
1017                       l))
1018     resource.colors_per_channel = (l < 2 ? 2 : (l > 6 ? 6 : l)); // >= 2, <= 6
1019   else
1020     resource.colors_per_channel = 4;
1021
1022   if (resource.style_file)
1023     delete [] resource.style_file;
1024   if (config.getValue("session.styleFile", "Session.StyleFile", s))
1025     resource.style_file = bstrdup(s.c_str());
1026   else
1027     resource.style_file = bstrdup(DEFAULTSTYLE);
1028
1029   if (resource.titlebar_layout)
1030     delete [] resource.titlebar_layout;
1031   if (config.getValue("session.titlebarLayout", "Session.TitlebarLayout", s))
1032     resource.titlebar_layout = bstrdup(s.c_str());
1033   else
1034     resource.titlebar_layout = bstrdup("ILMC");
1035
1036   if (config.getValue("session.doubleClickInterval",
1037                       "Session.DoubleClickInterval", l))
1038     resource.double_click_interval = l;
1039   else
1040     resource.double_click_interval = 250;
1041
1042   if (!config.getValue("session.autoRaiseDelay", "Session.AutoRaiseDelay", l))
1043     resource.auto_raise_delay.tv_usec = l;
1044   else
1045     resource.auto_raise_delay.tv_usec = 400;
1046   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1047   resource.auto_raise_delay.tv_usec -=
1048     (resource.auto_raise_delay.tv_sec * 1000);
1049   resource.auto_raise_delay.tv_usec *= 1000;
1050
1051   if (config.getValue("session.cacheLife", "Session.CacheLife", l))
1052     resource.cache_life = l;
1053   else
1054     resource.cache_life = 51;
1055   resource.cache_life *= 60000;
1056
1057   if (config.getValue("session.cacheMax", "Session.CacheMax", l))
1058     resource.cache_max = l;
1059   else
1060     resource.cache_max = 200;
1061 }
1062
1063
1064 void Openbox::reconfigure() {
1065   reconfigure_wait = True;
1066
1067   if (! timer->isTiming()) timer->start();
1068 }
1069
1070
1071 void Openbox::real_reconfigure() {
1072   grab();
1073
1074   load();
1075   
1076   for (int i = 0, n = menuTimestamps->count(); i < n; i++) {
1077     MenuTimestamp *ts = menuTimestamps->remove(0);
1078
1079     if (ts) {
1080       if (ts->filename)
1081         delete [] ts->filename;
1082
1083       delete ts;
1084     }
1085   }
1086
1087   LinkedListIterator<BScreen> it(screenList);
1088   for (BScreen *screen = it.current(); screen; it++, screen = it.current()) {
1089     screen->reconfigure();
1090   }
1091
1092   ungrab();
1093 }
1094
1095
1096 void Openbox::checkMenu() {
1097   Bool reread = False;
1098   LinkedListIterator<MenuTimestamp> it(menuTimestamps);
1099   for (MenuTimestamp *tmp = it.current(); tmp && (! reread);
1100        it++, tmp = it.current()) {
1101     struct stat buf;
1102
1103     if (! stat(tmp->filename, &buf)) {
1104       if (tmp->timestamp != buf.st_ctime)
1105         reread = True;
1106     } else {
1107       reread = True;
1108     }
1109   }
1110
1111   if (reread) rereadMenu();
1112 }
1113
1114
1115 void Openbox::rereadMenu() {
1116   reread_menu_wait = True;
1117
1118   if (! timer->isTiming()) timer->start();
1119 }
1120
1121
1122 void Openbox::real_rereadMenu() {
1123   for (int i = 0, n = menuTimestamps->count(); i < n; i++) {
1124     MenuTimestamp *ts = menuTimestamps->remove(0);
1125
1126     if (ts) {
1127       if (ts->filename)
1128         delete [] ts->filename;
1129
1130       delete ts;
1131     }
1132   }
1133
1134   LinkedListIterator<BScreen> it(screenList);
1135   for (BScreen *screen = it.current(); screen; it++, screen = it.current())
1136     screen->rereadMenu();
1137 }
1138
1139
1140 void Openbox::setStyleFilename(const char *filename) {
1141   if (resource.style_file)
1142     delete [] resource.style_file;
1143
1144   resource.style_file = bstrdup(filename);
1145   config.setValue("session.styleFile", resource.style_file);
1146 }
1147
1148
1149 void Openbox::setMenuFilename(const char *filename) {
1150   Bool found = False;
1151
1152   LinkedListIterator<MenuTimestamp> it(menuTimestamps);
1153   for (MenuTimestamp *tmp = it.current(); tmp && (! found);
1154        it++, tmp = it.current()) {
1155     if (! strcmp(tmp->filename, filename)) found = True;
1156   }
1157   if (! found) {
1158     struct stat buf;
1159
1160     if (! stat(filename, &buf)) {
1161       MenuTimestamp *ts = new MenuTimestamp;
1162
1163       ts->filename = bstrdup(filename);
1164       ts->timestamp = buf.st_ctime;
1165
1166       menuTimestamps->insert(ts);
1167     }
1168   }
1169 }
1170
1171
1172 void Openbox::timeout() {
1173   if (reconfigure_wait)
1174     real_reconfigure();
1175
1176   if (reread_menu_wait)
1177     real_rereadMenu();
1178
1179   reconfigure_wait = reread_menu_wait = False;
1180 }
1181
1182
1183 void Openbox::setFocusedWindow(OpenboxWindow *win) {
1184   BScreen *old_screen = (BScreen *) 0, *screen = (BScreen *) 0;
1185   OpenboxWindow *old_win = (OpenboxWindow *) 0;
1186   Toolbar *old_tbar = (Toolbar *) 0, *tbar = (Toolbar *) 0;
1187   Workspace *old_wkspc = (Workspace *) 0, *wkspc = (Workspace *) 0;
1188
1189   if (focused_window) {
1190     old_win = focused_window;
1191     old_screen = old_win->getScreen();
1192     old_tbar = old_screen->getToolbar();
1193     old_wkspc = old_screen->getWorkspace(old_win->getWorkspaceNumber());
1194
1195     old_win->setFocusFlag(False);
1196     old_wkspc->getMenu()->setItemSelected(old_win->getWindowNumber(), False);
1197   }
1198
1199   if (win && ! win->isIconic()) {
1200     screen = win->getScreen();
1201     tbar = screen->getToolbar();
1202     wkspc = screen->getWorkspace(win->getWorkspaceNumber());
1203
1204     focused_window = win;
1205
1206     win->setFocusFlag(True);
1207     wkspc->getMenu()->setItemSelected(win->getWindowNumber(), True);
1208   } else {
1209     focused_window = (OpenboxWindow *) 0;
1210   }
1211
1212   if (tbar)
1213     tbar->redrawWindowLabel(True);
1214   if (screen)
1215     screen->updateNetizenWindowFocus();
1216
1217   if (old_tbar && old_tbar != tbar)
1218     old_tbar->redrawWindowLabel(True);
1219   if (old_screen && old_screen != screen)
1220     old_screen->updateNetizenWindowFocus();
1221 }