]> icculus.org git repositories - mikachu/openbox.git/blob - src/openbox.cc
fix segfaut from uninitialized focused_screen pointer
[mikachu/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 = NULL;
186   resource.titlebar_layout = NULL;
187   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
188
189   focused_screen = (BScreen *) 0;
190   masked_window = NULL;
191   masked = None;
192
193   load();
194
195 #ifdef    HAVE_GETPID
196   openbox_pid = XInternAtom(getXDisplay(), "_BLACKBOX_PID", False);
197 #endif // HAVE_GETPID
198
199   for (int i = 0; i < getNumberOfScreens(); i++) {
200     BScreen *screen = new BScreen(*this, i, config);
201
202     if (! screen->isScreenManaged()) {
203       delete screen;
204       continue;
205     }
206
207     screenList.push_back(screen);
208   }
209
210   if (screenList.empty()) {
211     fprintf(stderr,
212             i18n->getMessage(openboxSet, openboxNoManagableScreens,
213                "Openbox::Openbox: no managable screens found, aborting.\n"));
214     ::exit(3);
215   }
216   focused_screen = screenList.front();
217
218   // save current settings and default values
219   save();
220   
221   XSynchronize(getXDisplay(), False);
222   XSync(getXDisplay(), False);
223
224   reconfigure_wait = reread_menu_wait = False;
225
226   timer = new BTimer(*this, *this);
227   timer->setTimeout(0);
228   timer->fireOnce(True);
229
230   ungrab();
231
232   focusWindow((OpenboxWindow *) 0);
233 }
234
235
236 Openbox::~Openbox() {
237   for_each(screenList.begin(), screenList.end(),
238            PointerAssassin());
239
240   for_each(menuTimestamps.begin(), menuTimestamps.end(),
241            PointerAssassin());
242
243   if (resource.menu_file)
244     delete [] resource.menu_file;
245
246   if (resource.style_file)
247     delete [] resource.style_file;
248
249   if (resource.titlebar_layout)
250     delete [] resource.titlebar_layout;
251
252   delete timer;
253
254   delete [] rc_file;
255 }
256
257
258 void Openbox::process_event(XEvent *e) {
259   if ((masked == e->xany.window && masked_window) &&
260       (e->type == MotionNotify)) {
261     last_time = e->xmotion.time;
262     masked_window->motionNotifyEvent(&e->xmotion);
263     return;
264   }
265
266   switch (e->type) {
267   case ButtonPress: {
268     // strip the lock key modifiers
269     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
270
271     last_time = e->xbutton.time;
272
273     OpenboxWindow *win = (OpenboxWindow *) 0;
274     Basemenu *menu = (Basemenu *) 0;
275
276 #ifdef    SLIT
277     Slit *slit = (Slit *) 0;
278 #endif // SLIT
279
280     Toolbar *tbar = (Toolbar *) 0;
281
282     if ((win = searchWindow(e->xbutton.window))) {
283       win->buttonPressEvent(&e->xbutton);
284
285       if (e->xbutton.button == 1)
286         win->installColormap(True);
287     } else if ((menu = searchMenu(e->xbutton.window))) {
288       menu->buttonPressEvent(&e->xbutton);
289
290 #ifdef    SLIT
291     } else if ((slit = searchSlit(e->xbutton.window))) {
292       slit->buttonPressEvent(&e->xbutton);
293 #endif // SLIT
294
295     } else if ((tbar = searchToolbar(e->xbutton.window))) {
296       tbar->buttonPressEvent(&e->xbutton);
297     } else {
298       ScreenList::iterator it;
299       for (it = screenList.begin(); it != screenList.end(); ++it) {
300         BScreen *screen = *it;
301         if (e->xbutton.window == screen->getRootWindow()) {
302           if (e->xbutton.button == 1) {
303             if (! screen->isRootColormapInstalled())
304               screen->getImageControl()->installRootColormap();
305
306             if (screen->getWorkspacemenu()->isVisible())
307               screen->getWorkspacemenu()->hide();
308
309             if (screen->getRootmenu()->isVisible())
310               screen->getRootmenu()->hide();
311           } else if (e->xbutton.button == 2) {
312             int mx = e->xbutton.x_root -
313               (screen->getWorkspacemenu()->getWidth() / 2);
314             int my = e->xbutton.y_root -
315               (screen->getWorkspacemenu()->getTitleHeight() / 2);
316
317             if (mx < 0) mx = 0;
318             if (my < 0) my = 0;
319
320             if (mx + screen->getWorkspacemenu()->getWidth() >
321                 screen->size().w())
322               mx = screen->size().w() -
323                 screen->getWorkspacemenu()->getWidth() -
324                 screen->getBorderWidth();
325
326             if (my + screen->getWorkspacemenu()->getHeight() >
327                 screen->size().h())
328               my = screen->size().h() -
329                 screen->getWorkspacemenu()->getHeight() -
330                 screen->getBorderWidth();
331
332             screen->getWorkspacemenu()->move(mx, my);
333
334             if (! screen->getWorkspacemenu()->isVisible()) {
335               screen->getWorkspacemenu()->removeParent();
336               screen->getWorkspacemenu()->show();
337             }
338           } else if (e->xbutton.button == 3) {
339             int mx = e->xbutton.x_root -
340               (screen->getRootmenu()->getWidth() / 2);
341             int my = e->xbutton.y_root -
342               (screen->getRootmenu()->getTitleHeight() / 2);
343
344             if (mx < 0) mx = 0;
345             if (my < 0) my = 0;
346
347             if (mx + screen->getRootmenu()->getWidth() > screen->size().w())
348               mx = screen->size().w() -
349                 screen->getRootmenu()->getWidth() -
350                 screen->getBorderWidth();
351
352             if (my + screen->getRootmenu()->getHeight() > screen->size().h())
353                 my = screen->size().h() -
354                   screen->getRootmenu()->getHeight() -
355                   screen->getBorderWidth();
356
357             screen->getRootmenu()->move(mx, my);
358
359             if (! screen->getRootmenu()->isVisible()) {
360               checkMenu();
361               screen->getRootmenu()->show();
362             }
363           } else if (e->xbutton.button == 4) {
364             if ((screen->getCurrentWorkspaceID() + 1) >
365                 screen->getWorkspaceCount() - 1)
366               screen->changeWorkspaceID(0);
367             else
368               screen->changeWorkspaceID(screen->getCurrentWorkspaceID() + 1);
369           } else if (e->xbutton.button == 5) {
370             if ((screen->getCurrentWorkspaceID() - 1) < 0)
371               screen->changeWorkspaceID(screen->getWorkspaceCount() - 1);
372             else
373               screen->changeWorkspaceID(screen->getCurrentWorkspaceID() - 1);
374           }
375         }
376       }
377     }
378
379     break;
380   }
381
382   case ButtonRelease: {
383     // strip the lock key modifiers
384     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
385
386     last_time = e->xbutton.time;
387
388     OpenboxWindow *win = (OpenboxWindow *) 0;
389     Basemenu *menu = (Basemenu *) 0;
390     Toolbar *tbar = (Toolbar *) 0;
391
392     if ((win = searchWindow(e->xbutton.window)))
393       win->buttonReleaseEvent(&e->xbutton);
394     else if ((menu = searchMenu(e->xbutton.window)))
395       menu->buttonReleaseEvent(&e->xbutton);
396     else if ((tbar = searchToolbar(e->xbutton.window)))
397       tbar->buttonReleaseEvent(&e->xbutton);
398
399     break;
400   }
401
402   case ConfigureRequest: {
403     OpenboxWindow *win = (OpenboxWindow *) 0;
404
405 #ifdef    SLIT
406     Slit *slit = (Slit *) 0;
407 #endif // SLIT
408
409     if ((win = searchWindow(e->xconfigurerequest.window))) {
410       win->configureRequestEvent(&e->xconfigurerequest);
411
412 #ifdef    SLIT
413     } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
414       slit->configureRequestEvent(&e->xconfigurerequest);
415 #endif // SLIT
416
417     } else {
418       grab();
419
420       if (validateWindow(e->xconfigurerequest.window)) {
421         XWindowChanges xwc;
422
423         xwc.x = e->xconfigurerequest.x;
424         xwc.y = e->xconfigurerequest.y;
425         xwc.width = e->xconfigurerequest.width;
426         xwc.height = e->xconfigurerequest.height;
427         xwc.border_width = e->xconfigurerequest.border_width;
428         xwc.sibling = e->xconfigurerequest.above;
429         xwc.stack_mode = e->xconfigurerequest.detail;
430
431         XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
432                          e->xconfigurerequest.value_mask, &xwc);
433       }
434
435       ungrab();
436     }
437
438     break;
439   }
440
441   case MapRequest: {
442 #ifdef    DEBUG
443     fprintf(stderr,
444             i18n->getMessage(openboxSet, openboxMapRequest,
445                  "Openbox::process_event(): MapRequest for 0x%lx\n"),
446             e->xmaprequest.window);
447 #endif // DEBUG
448
449     OpenboxWindow *win = searchWindow(e->xmaprequest.window);
450
451     if (! win)
452       win = new OpenboxWindow(*this, e->xmaprequest.window);
453
454     if ((win = searchWindow(e->xmaprequest.window)))
455       win->mapRequestEvent(&e->xmaprequest);
456
457     break;
458   }
459
460   case MapNotify: {
461     OpenboxWindow *win = searchWindow(e->xmap.window);
462
463     if (win)
464       win->mapNotifyEvent(&e->xmap);
465
466       break;
467   }
468
469   case UnmapNotify: {
470     OpenboxWindow *win = (OpenboxWindow *) 0;
471
472 #ifdef    SLIT
473     Slit *slit = (Slit *) 0;
474 #endif // SLIT
475
476     if ((win = searchWindow(e->xunmap.window))) {
477       win->unmapNotifyEvent(&e->xunmap);
478 #ifdef    SLIT
479     } else if ((slit = searchSlit(e->xunmap.window))) {
480       slit->removeClient(e->xunmap.window);
481 #endif // SLIT
482
483     }
484
485     break;
486   }
487
488   case DestroyNotify: {
489     OpenboxWindow *win = (OpenboxWindow *) 0;
490
491 #ifdef    SLIT
492     Slit *slit = (Slit *) 0;
493 #endif // SLIT
494
495     if ((win = searchWindow(e->xdestroywindow.window))) {
496       win->destroyNotifyEvent(&e->xdestroywindow);
497 #ifdef    SLIT
498     } else if ((slit = searchSlit(e->xdestroywindow.window))) {
499       slit->removeClient(e->xdestroywindow.window, False);
500 #endif // SLIT
501     }
502
503     break;
504   }
505
506   case MotionNotify: {
507     // strip the lock key modifiers
508     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
509     
510     last_time = e->xmotion.time;
511
512     OpenboxWindow *win = (OpenboxWindow *) 0;
513     Basemenu *menu = (Basemenu *) 0;
514
515     if ((win = searchWindow(e->xmotion.window)))
516       win->motionNotifyEvent(&e->xmotion);
517     else if ((menu = searchMenu(e->xmotion.window)))
518       menu->motionNotifyEvent(&e->xmotion);
519
520     break;
521   }
522
523   case PropertyNotify: {
524     last_time = e->xproperty.time;
525
526     if (e->xproperty.state != PropertyDelete) {
527       OpenboxWindow *win = searchWindow(e->xproperty.window);
528
529       if (win)
530         win->propertyNotifyEvent(e->xproperty.atom);
531     }
532
533     break;
534   }
535
536   case EnterNotify: {
537     last_time = e->xcrossing.time;
538
539     BScreen *screen = (BScreen *) 0;
540     OpenboxWindow *win = (OpenboxWindow *) 0;
541     Basemenu *menu = (Basemenu *) 0;
542     Toolbar *tbar = (Toolbar *) 0;
543
544 #ifdef    SLIT
545     Slit *slit = (Slit *) 0;
546 #endif // SLIT
547
548     if (e->xcrossing.mode == NotifyGrab) break;
549
550     XEvent dummy;
551     scanargs sa;
552     sa.w = e->xcrossing.window;
553     sa.enter = sa.leave = False;
554     XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
555
556     if ((e->xcrossing.window == e->xcrossing.root) &&
557         (screen = searchScreen(e->xcrossing.window))) {
558       screen->getImageControl()->installRootColormap();
559     } else if ((win = searchWindow(e->xcrossing.window))) {
560       if (win->getScreen()->sloppyFocus() &&
561           (! win->isFocused()) && (! no_focus)) {
562         grab();
563
564         if (((! sa.leave) || sa.inferior) && win->isVisible() &&
565             win->setInputFocus())
566           win->installColormap(True);
567
568         ungrab();
569       }
570     } else if ((menu = searchMenu(e->xcrossing.window))) {
571       menu->enterNotifyEvent(&e->xcrossing);
572     } else if ((tbar = searchToolbar(e->xcrossing.window))) {
573       tbar->enterNotifyEvent(&e->xcrossing);
574 #ifdef    SLIT
575     } else if ((slit = searchSlit(e->xcrossing.window))) {
576       slit->enterNotifyEvent(&e->xcrossing);
577 #endif // SLIT
578     }
579     break;
580   }
581
582   case LeaveNotify: {
583     last_time = e->xcrossing.time;
584
585     OpenboxWindow *win = (OpenboxWindow *) 0;
586     Basemenu *menu = (Basemenu *) 0;
587     Toolbar *tbar = (Toolbar *) 0;
588
589 #ifdef    SLIT
590     Slit *slit = (Slit *) 0;
591 #endif // SLIT
592
593     if ((menu = searchMenu(e->xcrossing.window)))
594       menu->leaveNotifyEvent(&e->xcrossing);
595     else if ((win = searchWindow(e->xcrossing.window)))
596       win->installColormap(False);
597     else if ((tbar = searchToolbar(e->xcrossing.window)))
598       tbar->leaveNotifyEvent(&e->xcrossing);
599 #ifdef    SLIT
600     else if ((slit = searchSlit(e->xcrossing.window)))
601       slit->leaveNotifyEvent(&e->xcrossing);
602 #endif // SLIT
603
604     break;
605   }
606
607   case Expose: {
608     OpenboxWindow *win = (OpenboxWindow *) 0;
609     Basemenu *menu = (Basemenu *) 0;
610     Toolbar *tbar = (Toolbar *) 0;
611
612     if ((win = searchWindow(e->xexpose.window)))
613       win->exposeEvent(&e->xexpose);
614     else if ((menu = searchMenu(e->xexpose.window)))
615       menu->exposeEvent(&e->xexpose);
616     else if ((tbar = searchToolbar(e->xexpose.window)))
617       tbar->exposeEvent(&e->xexpose);
618
619     break;
620   }
621
622   case KeyPress: {
623     Toolbar *tbar = searchToolbar(e->xkey.window);
624
625     if (tbar && tbar->isEditing())
626       tbar->keyPressEvent(&e->xkey);
627
628     break;
629   }
630
631   case ColormapNotify: {
632     BScreen *screen = searchScreen(e->xcolormap.window);
633
634     if (screen)
635       screen->setRootColormapInstalled((e->xcolormap.state ==
636                                         ColormapInstalled) ? True : False);
637
638     break;
639   }
640
641   case FocusIn: {
642     if (e->xfocus.mode == NotifyUngrab || e->xfocus.detail == NotifyPointer)
643       break;
644
645     OpenboxWindow *win = searchWindow(e->xfocus.window);
646     if (win && !win->isFocused())
647       focusWindow(win);
648
649     break;
650   }
651
652   case FocusOut:
653     break;
654
655   case ClientMessage: {
656     if (e->xclient.format == 32) {
657       if (e->xclient.message_type == getWMChangeStateAtom()) {
658         OpenboxWindow *win = searchWindow(e->xclient.window);
659         if (! win || ! win->validateClient()) return;
660
661         if (e->xclient.data.l[0] == IconicState)
662           win->iconify();
663         if (e->xclient.data.l[0] == NormalState)
664           win->deiconify();
665       } else if (e->xclient.message_type == getOpenboxChangeWorkspaceAtom()) {
666         BScreen *screen = searchScreen(e->xclient.window);
667
668         if (screen && e->xclient.data.l[0] >= 0 &&
669             e->xclient.data.l[0] < screen->getWorkspaceCount())
670           screen->changeWorkspaceID(e->xclient.data.l[0]);
671       } else if (e->xclient.message_type == getOpenboxChangeWindowFocusAtom()) {
672         OpenboxWindow *win = searchWindow(e->xclient.window);
673
674         if (win && win->isVisible() && win->setInputFocus())
675           win->installColormap(True);
676       } else if (e->xclient.message_type == getOpenboxCycleWindowFocusAtom()) {
677         BScreen *screen = searchScreen(e->xclient.window);
678
679         if (screen) {
680           if (! e->xclient.data.l[0])
681             screen->prevFocus();
682           else
683             screen->nextFocus();
684         }
685       } else if (e->xclient.message_type == getOpenboxChangeAttributesAtom()) {
686         OpenboxWindow *win = searchWindow(e->xclient.window);
687
688         if (win && win->validateClient()) {
689           OpenboxHints net;
690           net.flags = e->xclient.data.l[0];
691           net.attrib = e->xclient.data.l[1];
692           net.workspace = e->xclient.data.l[2];
693           net.stack = e->xclient.data.l[3];
694           net.decoration = e->xclient.data.l[4];
695
696           win->changeOpenboxHints(&net);
697         }
698       }
699     }
700
701     break;
702   }
703
704
705   default: {
706 #ifdef    SHAPE
707     if (e->type == getShapeEventBase()) {
708       XShapeEvent *shape_event = (XShapeEvent *) e;
709       OpenboxWindow *win = (OpenboxWindow *) 0;
710
711       if ((win = searchWindow(e->xany.window)) ||
712           (shape_event->kind != ShapeBounding))
713         win->shapeEvent(shape_event);
714     }
715 #endif // SHAPE
716
717   }
718   } // switch
719 }
720
721
722 Bool Openbox::handleSignal(int sig) {
723   switch (sig) {
724   case SIGHUP:
725   case SIGUSR1:
726     reconfigure();
727     break;
728
729   case SIGUSR2:
730     rereadMenu();
731     break;
732
733   case SIGPIPE:
734   case SIGSEGV:
735   case SIGFPE:
736   case SIGINT:
737   case SIGTERM:
738     shutdown();
739
740   default:
741     return False;
742   }
743
744   return True;
745 }
746
747
748 BScreen *Openbox::searchScreen(Window window) {
749   ScreenList::iterator it;
750   for (it = screenList.begin(); it != screenList.end(); ++it)
751     if ((*it)->getRootWindow() == window)
752       return *it;
753   return (BScreen *) 0;
754 }
755
756
757 OpenboxWindow *Openbox::searchWindow(Window window) {
758   WindowLookup::iterator it = windowSearchList.find(window);
759   if (it == windowSearchList.end())
760     return (OpenboxWindow *) 0;
761   return it->second;
762 }
763
764
765 OpenboxWindow *Openbox::searchGroup(Window window, OpenboxWindow *win) {
766   WindowLookup::iterator it = groupSearchList.find(window);
767   if (it != groupSearchList.end())
768     if (it->second->getClientWindow() != win->getClientWindow())
769       return win;
770   return (OpenboxWindow *) 0;
771 }
772
773
774 Basemenu *Openbox::searchMenu(Window window) {
775   MenuLookup::iterator it = menuSearchList.find(window);
776   if (it == menuSearchList.end())
777     return (Basemenu *) 0;
778   return it->second;
779 }
780
781
782 Toolbar *Openbox::searchToolbar(Window window) {
783   ToolbarLookup::iterator it = toolbarSearchList.find(window);
784   if (it == toolbarSearchList.end())
785     return (Toolbar *) 0;
786   return it->second;
787 }
788
789
790 #ifdef    SLIT
791 Slit *Openbox::searchSlit(Window window) {
792   SlitLookup::iterator it = slitSearchList.find(window);
793   if (it == slitSearchList.end())
794     return (Slit *) 0;
795   return it->second;
796 }
797 #endif // SLIT
798
799
800 void Openbox::saveWindowSearch(Window window, OpenboxWindow *data) {
801   windowSearchList.insert(WindowLookupPair(window, data));
802 }
803
804
805 void Openbox::saveGroupSearch(Window window, OpenboxWindow *data) {
806   groupSearchList.insert(WindowLookupPair(window, data));
807 }
808
809
810 void Openbox::saveMenuSearch(Window window, Basemenu *data) {
811   menuSearchList.insert(MenuLookupPair(window, data));
812 }
813
814
815 void Openbox::saveToolbarSearch(Window window, Toolbar *data) {
816   toolbarSearchList.insert(ToolbarLookupPair(window, data));
817 }
818
819
820 #ifdef    SLIT
821 void Openbox::saveSlitSearch(Window window, Slit *data) {
822   slitSearchList.insert(SlitLookupPair(window, data));
823 }
824 #endif // SLIT
825
826
827 void Openbox::removeWindowSearch(Window window) {
828   windowSearchList.erase(window);
829 }
830
831
832 void Openbox::removeGroupSearch(Window window) {
833   groupSearchList.erase(window);
834 }
835
836
837 void Openbox::removeMenuSearch(Window window) {
838   menuSearchList.erase(window);
839 }
840
841
842 void Openbox::removeToolbarSearch(Window window) {
843   toolbarSearchList.erase(window);
844 }
845
846
847 #ifdef    SLIT
848 void Openbox::removeSlitSearch(Window window) {
849   slitSearchList.erase(window);
850 }
851 #endif // SLIT
852
853
854 void Openbox::restart(const char *prog) {
855   shutdown();
856
857   if (prog) {
858     execlp(prog, prog, NULL);
859     perror(prog);
860   }
861
862   // fall back in case the above execlp doesn't work
863   execvp(argv[0], argv);
864   execvp(basename(argv[0]), argv);
865 }
866
867
868 void Openbox::shutdown() {
869   BaseDisplay::shutdown();
870
871   focusWindow((OpenboxWindow *) 0);
872
873   std::for_each(screenList.begin(), screenList.end(),
874                 std::mem_fun(&BScreen::shutdown));
875
876   XSync(getXDisplay(), False);
877 }
878
879
880 void Openbox::save() {
881   config.setAutoSave(false);
882   
883   // save all values as they are so that the defaults will be written to the rc
884   // file
885   
886   config.setValue("session.menuFile", getMenuFilename());
887   config.setValue("session.colorsPerChannel",
888                   resource.colors_per_channel);
889   config.setValue("session.styleFile", resource.style_file);
890   config.setValue("session.titlebarLayout", resource.titlebar_layout);
891   config.setValue("session.doubleClickInterval",
892                   (long)resource.double_click_interval);
893   config.setValue("session.autoRaiseDelay",
894           ((resource.auto_raise_delay.tv_sec * 1000) +
895            (resource.auto_raise_delay.tv_usec / 1000)));
896   config.setValue("session.cacheLife", (long)resource.cache_life / 60000);
897   config.setValue("session.cacheMax", (long)resource.cache_max);
898
899   std::for_each(screenList.begin(), screenList.end(),
900                 std::mem_fun(&BScreen::save));
901
902   config.setAutoSave(true);
903   config.save();
904 }
905
906 void Openbox::load() {
907   if (!config.load())
908     config.create();
909
910   std::string s;
911   long l;
912   
913   if (resource.menu_file)
914     delete [] resource.menu_file;
915   if (config.getValue("session.menuFile", "Session.MenuFile", s))
916     resource.menu_file = bstrdup(s.c_str());
917   else
918     resource.menu_file = bstrdup(DEFAULTMENU);
919
920   if (config.getValue("session.colorsPerChannel", "Session.ColorsPerChannel",
921                       l))
922     resource.colors_per_channel = (l < 2 ? 2 : (l > 6 ? 6 : l)); // >= 2, <= 6
923   else
924     resource.colors_per_channel = 4;
925
926   if (resource.style_file)
927     delete [] resource.style_file;
928   if (config.getValue("session.styleFile", "Session.StyleFile", s))
929     resource.style_file = bstrdup(s.c_str());
930   else
931     resource.style_file = bstrdup(DEFAULTSTYLE);
932
933   if (resource.titlebar_layout)
934     delete [] resource.titlebar_layout;
935   if (config.getValue("session.titlebarLayout", "Session.TitlebarLayout", s))
936     resource.titlebar_layout = bstrdup(s.c_str());
937   else
938     resource.titlebar_layout = bstrdup("ILMC");
939
940   if (config.getValue("session.doubleClickInterval",
941                       "Session.DoubleClickInterval", l))
942     resource.double_click_interval = l;
943   else
944     resource.double_click_interval = 250;
945
946   if (!config.getValue("session.autoRaiseDelay", "Session.AutoRaiseDelay", l))
947     resource.auto_raise_delay.tv_usec = l;
948   else
949     resource.auto_raise_delay.tv_usec = 400;
950   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
951   resource.auto_raise_delay.tv_usec -=
952     (resource.auto_raise_delay.tv_sec * 1000);
953   resource.auto_raise_delay.tv_usec *= 1000;
954
955   if (config.getValue("session.cacheLife", "Session.CacheLife", l))
956     resource.cache_life = l;
957   else
958     resource.cache_life = 51;
959   resource.cache_life *= 60000;
960
961   if (config.getValue("session.cacheMax", "Session.CacheMax", l))
962     resource.cache_max = l;
963   else
964     resource.cache_max = 200;
965 }
966
967
968 void Openbox::reconfigure() {
969   reconfigure_wait = True;
970
971   if (! timer->isTiming()) timer->start();
972 }
973
974
975 void Openbox::real_reconfigure() {
976   grab();
977
978   load();
979   
980   for_each(menuTimestamps.begin(), menuTimestamps.end(),
981            PointerAssassin());
982   menuTimestamps.clear();
983
984   std::for_each(screenList.begin(), screenList.end(),
985                 std::mem_fun(&BScreen::reconfigure));
986
987   ungrab();
988 }
989
990
991 void Openbox::checkMenu() {
992   MenuTimestampList::iterator it;
993   for (it = menuTimestamps.begin(); it != menuTimestamps.end(); ++it) {
994     struct stat buf;
995
996     if (stat((*it)->filename, &buf) || (*it)->timestamp != buf.st_ctime) {
997       rereadMenu();
998       return;
999     }
1000   }
1001 }
1002
1003
1004 void Openbox::rereadMenu() {
1005   reread_menu_wait = True;
1006
1007   if (! timer->isTiming()) timer->start();
1008 }
1009
1010
1011 void Openbox::real_rereadMenu() {
1012   std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1013                 PointerAssassin());
1014   menuTimestamps.clear();
1015
1016   std::for_each(screenList.begin(), screenList.end(),
1017                 std::mem_fun(&BScreen::rereadMenu));
1018 }
1019
1020
1021 void Openbox::setStyleFilename(const char *filename) {
1022   if (resource.style_file)
1023     delete [] resource.style_file;
1024
1025   resource.style_file = bstrdup(filename);
1026   config.setValue("session.styleFile", resource.style_file);
1027 }
1028
1029
1030 void Openbox::setMenuFilename(const char *filename) {
1031   bool found = false;
1032
1033   MenuTimestampList::iterator it;
1034   for (it = menuTimestamps.begin(); it != menuTimestamps.end(); ++it)
1035     if (! strcmp((*it)->filename, filename)) {
1036       found = true;
1037       break;
1038     }
1039   if (!found) {
1040     struct stat buf;
1041
1042     if (! stat(filename, &buf)) {
1043       MenuTimestamp *ts = new MenuTimestamp;
1044
1045       ts->filename = bstrdup(filename);
1046       ts->timestamp = buf.st_ctime;
1047
1048       menuTimestamps.push_back(ts);
1049     }
1050   }
1051 }
1052
1053
1054 void Openbox::timeout() {
1055   if (reconfigure_wait)
1056     real_reconfigure();
1057
1058   if (reread_menu_wait)
1059     real_rereadMenu();
1060
1061   reconfigure_wait = reread_menu_wait = False;
1062 }
1063
1064
1065 OpenboxWindow *Openbox::focusedWindow() {
1066   if (focused_screen == (BScreen *) 0)
1067     return (OpenboxWindow *) 0;
1068   Workspace *w = focused_screen->getCurrentWorkspace();
1069   if (w == (Workspace *) 0)
1070     return (OpenboxWindow *) 0;
1071   return w->focusedWindow();
1072 }
1073
1074
1075 void Openbox::focusWindow(OpenboxWindow *win) {
1076   BScreen *old_screen = (BScreen *) 0;
1077   Toolbar *old_tbar = (Toolbar *) 0, *tbar = (Toolbar *) 0;
1078   Workspace *old_wkspc = (Workspace *) 0, *wkspc = (Workspace *) 0;
1079
1080   OpenboxWindow *old_win = focusedWindow();
1081   if (old_win != (OpenboxWindow *) 0) {
1082     old_screen = old_win->getScreen();
1083     old_wkspc = old_screen->getWorkspace(old_win->getWorkspaceNumber());
1084     old_tbar = old_screen->getToolbar();
1085
1086     old_win->setFocusFlag(False);
1087     old_wkspc->focusWindow((OpenboxWindow *) 0);
1088   }
1089
1090   if (win && !win->isIconic()) {
1091     focused_screen = win->getScreen();
1092     tbar = focused_screen->getToolbar();
1093     wkspc = focused_screen->getWorkspace(win->getWorkspaceNumber());
1094     win->setFocusFlag(true);
1095     wkspc->focusWindow(win);
1096     
1097     if (tbar)
1098       tbar->redrawWindowLabel(true);
1099     focused_screen->updateNetizenWindowFocus();
1100   } else {
1101     ASSERT(focused_screen != (BScreen *) 0);
1102     XSetInputFocus(getXDisplay(), focused_screen->getRootWindow(),
1103                    None, CurrentTime);
1104   }
1105
1106   if (old_tbar && old_tbar != tbar)
1107     old_tbar->redrawWindowLabel(true);
1108   if (old_screen && old_screen != focused_screen)
1109     old_screen->updateNetizenWindowFocus();
1110 }