]> icculus.org git repositories - dana/openbox.git/blob - src/openbox.cc
Initial revision
[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
59 #ifdef    HAVE_STDIO_H
60 #  include <stdio.h>
61 #endif // HAVE_STDIO_H
62
63 #ifdef    STDC_HEADERS
64 #  include <stdlib.h>
65 #  include <string.h>
66 #endif // STDC_HEADERS
67
68 #ifdef    HAVE_UNISTD_H
69 #  include <sys/types.h>
70 #  include <unistd.h>
71 #endif // HAVE_UNISTD_H
72
73 #ifdef    HAVE_SYS_PARAM_H
74 #  include <sys/param.h>
75 #endif // HAVE_SYS_PARAM_H
76
77 #ifndef   MAXPATHLEN
78 #define   MAXPATHLEN 255
79 #endif // MAXPATHLEN
80
81 #ifdef    HAVE_SYS_SELECT_H
82 #  include <sys/select.h>
83 #endif // HAVE_SYS_SELECT_H
84
85 #ifdef    HAVE_SIGNAL_H
86 #  include <signal.h>
87 #endif // HAVE_SIGNAL_H
88
89 #ifdef    HAVE_SYS_SIGNAL_H
90 #  include <sys/signal.h>
91 #endif // HAVE_SYS_SIGNAL_H
92
93 #ifdef    HAVE_SYS_STAT_H
94 #  include <sys/types.h>
95 #  include <sys/stat.h>
96 #endif // HAVE_SYS_STAT_H
97
98 #ifdef    TIME_WITH_SYS_TIME
99 #  include <sys/time.h>
100 #  include <time.h>
101 #else // !TIME_WITH_SYS_TIME
102 #  ifdef    HAVE_SYS_TIME_H
103 #    include <sys/time.h>
104 #  else // !HAVE_SYS_TIME_H
105 #    include <time.h>
106 #  endif // HAVE_SYS_TIME_H
107 #endif // TIME_WITH_SYS_TIME
108
109 #ifdef    HAVE_LIBGEN_H
110 #  include <libgen.h>
111 #endif // HAVE_LIBGEN_H
112
113 #ifndef   HAVE_BASENAME
114 static inline char *basename (char *s) {
115   char *save = s;
116
117   while (*s) if (*s++ == '/') save = s;
118
119   return save;
120 }
121 #endif // HAVE_BASENAME
122
123
124 // X event scanner for enter/leave notifies - adapted from twm
125 typedef struct scanargs {
126   Window w;
127   Bool leave, inferior, enter;
128 } scanargs;
129
130 static Bool queueScanner(Display *, XEvent *e, char *args) {
131   if ((e->type == LeaveNotify) &&
132       (e->xcrossing.window == ((scanargs *) args)->w) &&
133       (e->xcrossing.mode == NotifyNormal)) {
134     ((scanargs *) args)->leave = True;
135     ((scanargs *) args)->inferior = (e->xcrossing.detail == NotifyInferior);
136   } else if ((e->type == EnterNotify) &&
137              (e->xcrossing.mode == NotifyUngrab)) {
138     ((scanargs *) args)->enter = True;
139   }
140
141   return False;
142 }
143
144 Openbox *openbox;
145
146
147 Openbox::Openbox(int m_argc, char **m_argv, char *dpy_name, char *rc)
148   : BaseDisplay(m_argv[0], dpy_name) {
149   grab();
150
151   if (! XSupportsLocale())
152     fprintf(stderr, "X server does not support locale\n");
153
154   if (XSetLocaleModifiers("") == NULL)
155     fprintf(stderr, "cannot set locale modifiers\n");
156
157   ::openbox = this;
158   argc = m_argc;
159   argv = m_argv;
160   if (rc == NULL) {
161     char *homedir = getenv("HOME");
162
163     rc_file = new char[strlen(homedir) + strlen("/.openbox/rc") + 1];
164     sprintf(rc_file, "%s/.openbox", homedir);
165
166     // try to make sure the ~/.openbox directory exists
167     mkdir(rc_file, S_IREAD | S_IWRITE | S_IEXEC | S_IRGRP | S_IWGRP | S_IXGRP |
168           S_IROTH | S_IWOTH | S_IXOTH);
169     
170     sprintf(rc_file, "%s/.openbox/rc", homedir);
171   } else {
172     rc_file = bstrdup(rc);
173   }
174
175   no_focus = False;
176
177   resource.menu_file = resource.style_file = (char *) 0;
178   resource.titlebar_layout = (char *) NULL;
179   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
180
181   focused_window = masked_window = (OpenboxWindow *) 0;
182   masked = None;
183
184   windowSearchList = new LinkedList<WindowSearch>;
185   menuSearchList = new LinkedList<MenuSearch>;
186
187 #ifdef    SLIT
188   slitSearchList = new LinkedList<SlitSearch>;
189 #endif // SLIT
190
191   toolbarSearchList = new LinkedList<ToolbarSearch>;
192   groupSearchList = new LinkedList<WindowSearch>;
193
194   menuTimestamps = new LinkedList<MenuTimestamp>;
195
196   XrmInitialize();
197   load_rc();
198
199 #ifdef    HAVE_GETPID
200   openbox_pid = XInternAtom(getXDisplay(), "_BLACKBOX_PID", False);
201 #endif // HAVE_GETPID
202
203   screenList = new LinkedList<BScreen>;
204   for (int i = 0; i < getNumberOfScreens(); i++) {
205     BScreen *screen = new BScreen(this, i);
206
207     if (! screen->isScreenManaged()) {
208       delete screen;
209       continue;
210     }
211
212     screenList->insert(screen);
213   }
214
215   if (! screenList->count()) {
216     fprintf(stderr,
217             i18n->getMessage(openboxSet, openboxNoManagableScreens,
218                "Openbox::Openbox: no managable screens found, aborting.\n"));
219     ::exit(3);
220   }
221
222   XSynchronize(getXDisplay(), False);
223   XSync(getXDisplay(), False);
224
225   reconfigure_wait = reread_menu_wait = False;
226
227   timer = new BTimer(this, this);
228   timer->setTimeout(0);
229   timer->fireOnce(True);
230
231   ungrab();
232 }
233
234
235 Openbox::~Openbox(void) {
236   while (screenList->count())
237     delete screenList->remove(0);
238
239   while (menuTimestamps->count()) {
240     MenuTimestamp *ts = menuTimestamps->remove(0);
241
242     if (ts->filename)
243       delete [] ts->filename;
244
245     delete ts;
246   }
247
248   if (resource.menu_file)
249     delete [] resource.menu_file;
250
251   if (resource.style_file)
252     delete [] resource.style_file;
253
254   delete timer;
255
256   delete screenList;
257   delete menuTimestamps;
258
259   delete windowSearchList;
260   delete menuSearchList;
261   delete toolbarSearchList;
262   delete groupSearchList;
263
264   delete [] rc_file;
265
266 #ifdef    SLIT
267   delete slitSearchList;
268 #endif // SLIT
269 }
270
271
272 void Openbox::process_event(XEvent *e) {
273   if ((masked == e->xany.window) && masked_window &&
274       (e->type == MotionNotify)) {
275     last_time = e->xmotion.time;
276     masked_window->motionNotifyEvent(&e->xmotion);
277
278     return;
279   }
280
281   switch (e->type) {
282   case ButtonPress: {
283     // strip the lock key modifiers
284     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
285
286     last_time = e->xbutton.time;
287
288     OpenboxWindow *win = (OpenboxWindow *) 0;
289     Basemenu *menu = (Basemenu *) 0;
290
291 #ifdef    SLIT
292     Slit *slit = (Slit *) 0;
293 #endif // SLIT
294
295     Toolbar *tbar = (Toolbar *) 0;
296
297     if ((win = searchWindow(e->xbutton.window))) {
298       win->buttonPressEvent(&e->xbutton);
299
300       if (e->xbutton.button == 1)
301         win->installColormap(True);
302     } else if ((menu = searchMenu(e->xbutton.window))) {
303       menu->buttonPressEvent(&e->xbutton);
304
305 #ifdef    SLIT
306     } else if ((slit = searchSlit(e->xbutton.window))) {
307       slit->buttonPressEvent(&e->xbutton);
308 #endif // SLIT
309
310     } else if ((tbar = searchToolbar(e->xbutton.window))) {
311       tbar->buttonPressEvent(&e->xbutton);
312     } else {
313       LinkedListIterator<BScreen> it(screenList);
314       BScreen *screen = it.current();
315       for (; screen; it++, screen = it.current()) {
316         if (e->xbutton.window == screen->getRootWindow()) {
317           if (e->xbutton.button == 1) {
318             if (! screen->isRootColormapInstalled())
319               screen->getImageControl()->installRootColormap();
320
321             if (screen->getWorkspacemenu()->isVisible())
322               screen->getWorkspacemenu()->hide();
323
324             if (screen->getRootmenu()->isVisible())
325               screen->getRootmenu()->hide();
326           } else if (e->xbutton.button == 2) {
327             int mx = e->xbutton.x_root -
328               (screen->getWorkspacemenu()->getWidth() / 2);
329             int my = e->xbutton.y_root -
330               (screen->getWorkspacemenu()->getTitleHeight() / 2);
331
332             if (mx < 0) mx = 0;
333             if (my < 0) my = 0;
334
335             if (mx + screen->getWorkspacemenu()->getWidth() >
336                 screen->getWidth())
337               mx = screen->getWidth() -
338                 screen->getWorkspacemenu()->getWidth() -
339                 screen->getBorderWidth();
340
341             if (my + screen->getWorkspacemenu()->getHeight() >
342                 screen->getHeight())
343               my = screen->getHeight() -
344                 screen->getWorkspacemenu()->getHeight() -
345                 screen->getBorderWidth();
346
347             screen->getWorkspacemenu()->move(mx, my);
348
349             if (! screen->getWorkspacemenu()->isVisible()) {
350               screen->getWorkspacemenu()->removeParent();
351               screen->getWorkspacemenu()->show();
352             }
353           } else if (e->xbutton.button == 3) {
354             int mx = e->xbutton.x_root -
355               (screen->getRootmenu()->getWidth() / 2);
356             int my = e->xbutton.y_root -
357               (screen->getRootmenu()->getTitleHeight() / 2);
358
359             if (mx < 0) mx = 0;
360             if (my < 0) my = 0;
361
362             if (mx + screen->getRootmenu()->getWidth() > screen->getWidth())
363               mx = screen->getWidth() -
364                 screen->getRootmenu()->getWidth() -
365                 screen->getBorderWidth();
366
367             if (my + screen->getRootmenu()->getHeight() > screen->getHeight())
368                 my = screen->getHeight() -
369                   screen->getRootmenu()->getHeight() -
370                   screen->getBorderWidth();
371
372             screen->getRootmenu()->move(mx, my);
373
374             if (! screen->getRootmenu()->isVisible()) {
375               checkMenu();
376               screen->getRootmenu()->show();
377             }
378           } else if (e->xbutton.button == 4) {
379             if ((screen->getCurrentWorkspaceID()-1)<0)
380               screen->changeWorkspaceID(screen->getCount()-1);
381             else
382               screen->changeWorkspaceID(screen->getCurrentWorkspaceID()-1);
383           } else if (e->xbutton.button == 5) {
384             if ((screen->getCurrentWorkspaceID()+1)>screen->getCount()-1)
385               screen->changeWorkspaceID(0);
386             else
387               screen->changeWorkspaceID(screen->getCurrentWorkspaceID()+1);
388           }
389         }
390       }
391     }
392
393     break;
394   }
395
396   case ButtonRelease: {
397     // strip the lock key modifiers
398     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
399
400     last_time = e->xbutton.time;
401
402     OpenboxWindow *win = (OpenboxWindow *) 0;
403     Basemenu *menu = (Basemenu *) 0;
404     Toolbar *tbar = (Toolbar *) 0;
405
406     if ((win = searchWindow(e->xbutton.window)))
407       win->buttonReleaseEvent(&e->xbutton);
408     else if ((menu = searchMenu(e->xbutton.window)))
409       menu->buttonReleaseEvent(&e->xbutton);
410     else if ((tbar = searchToolbar(e->xbutton.window)))
411       tbar->buttonReleaseEvent(&e->xbutton);
412
413     break;
414   }
415
416   case ConfigureRequest: {
417     OpenboxWindow *win = (OpenboxWindow *) 0;
418
419 #ifdef    SLIT
420     Slit *slit = (Slit *) 0;
421 #endif // SLIT
422
423     if ((win = searchWindow(e->xconfigurerequest.window))) {
424       win->configureRequestEvent(&e->xconfigurerequest);
425
426 #ifdef    SLIT
427     } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
428       slit->configureRequestEvent(&e->xconfigurerequest);
429 #endif // SLIT
430
431     } else {
432       grab();
433
434       if (validateWindow(e->xconfigurerequest.window)) {
435         XWindowChanges xwc;
436
437         xwc.x = e->xconfigurerequest.x;
438         xwc.y = e->xconfigurerequest.y;
439         xwc.width = e->xconfigurerequest.width;
440         xwc.height = e->xconfigurerequest.height;
441         xwc.border_width = e->xconfigurerequest.border_width;
442         xwc.sibling = e->xconfigurerequest.above;
443         xwc.stack_mode = e->xconfigurerequest.detail;
444
445         XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
446                          e->xconfigurerequest.value_mask, &xwc);
447       }
448
449       ungrab();
450     }
451
452     break;
453   }
454
455   case MapRequest: {
456 #ifdef    DEBUG
457     fprintf(stderr,
458             i18n->getMessage(openboxSet, openboxMapRequest,
459                  "Openbox::process_event(): MapRequest for 0x%lx\n"),
460             e->xmaprequest.window);
461 #endif // DEBUG
462
463     OpenboxWindow *win = searchWindow(e->xmaprequest.window);
464
465     if (! win)
466       win = new OpenboxWindow(this, e->xmaprequest.window);
467
468     if ((win = searchWindow(e->xmaprequest.window)))
469       win->mapRequestEvent(&e->xmaprequest);
470
471     break;
472   }
473
474   case MapNotify: {
475     OpenboxWindow *win = searchWindow(e->xmap.window);
476
477     if (win)
478       win->mapNotifyEvent(&e->xmap);
479
480       break;
481   }
482
483   case UnmapNotify: {
484     OpenboxWindow *win = (OpenboxWindow *) 0;
485
486 #ifdef    SLIT
487     Slit *slit = (Slit *) 0;
488 #endif // SLIT
489
490     if ((win = searchWindow(e->xunmap.window))) {
491       win->unmapNotifyEvent(&e->xunmap);
492       if (focused_window == win)
493         focused_window = (OpenboxWindow *) 0;
494 #ifdef    SLIT
495     } else if ((slit = searchSlit(e->xunmap.window))) {
496       slit->removeClient(e->xunmap.window);
497 #endif // SLIT
498
499     }
500
501     break;
502   }
503
504   case DestroyNotify: {
505     OpenboxWindow *win = (OpenboxWindow *) 0;
506
507 #ifdef    SLIT
508     Slit *slit = (Slit *) 0;
509 #endif // SLIT
510
511     if ((win = searchWindow(e->xdestroywindow.window))) {
512       win->destroyNotifyEvent(&e->xdestroywindow);
513       if (focused_window == win)
514         focused_window = (OpenboxWindow *) 0;
515 #ifdef    SLIT
516     } else if ((slit = searchSlit(e->xdestroywindow.window))) {
517       slit->removeClient(e->xdestroywindow.window, False);
518 #endif // SLIT
519     }
520
521     break;
522   }
523
524   case MotionNotify: {
525     // strip the lock key modifiers
526     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
527     
528     last_time = e->xmotion.time;
529
530     OpenboxWindow *win = (OpenboxWindow *) 0;
531     Basemenu *menu = (Basemenu *) 0;
532
533     if ((win = searchWindow(e->xmotion.window)))
534       win->motionNotifyEvent(&e->xmotion);
535     else if ((menu = searchMenu(e->xmotion.window)))
536       menu->motionNotifyEvent(&e->xmotion);
537
538     break;
539   }
540
541   case PropertyNotify: {
542     last_time = e->xproperty.time;
543
544     if (e->xproperty.state != PropertyDelete) {
545       OpenboxWindow *win = searchWindow(e->xproperty.window);
546
547       if (win)
548         win->propertyNotifyEvent(e->xproperty.atom);
549     }
550
551     break;
552   }
553
554   case EnterNotify: {
555     last_time = e->xcrossing.time;
556
557     BScreen *screen = (BScreen *) 0;
558     OpenboxWindow *win = (OpenboxWindow *) 0;
559     Basemenu *menu = (Basemenu *) 0;
560     Toolbar *tbar = (Toolbar *) 0;
561
562 #ifdef    SLIT
563     Slit *slit = (Slit *) 0;
564 #endif // SLIT
565
566     if (e->xcrossing.mode == NotifyGrab) break;
567
568     XEvent dummy;
569     scanargs sa;
570     sa.w = e->xcrossing.window;
571     sa.enter = sa.leave = False;
572     XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
573
574     if ((e->xcrossing.window == e->xcrossing.root) &&
575         (screen = searchScreen(e->xcrossing.window))) {
576       screen->getImageControl()->installRootColormap();
577     } else if ((win = searchWindow(e->xcrossing.window))) {
578       if (win->getScreen()->isSloppyFocus() &&
579           (! win->isFocused()) && (! no_focus)) {
580         grab();
581
582         if (((! sa.leave) || sa.inferior) && win->isVisible() &&
583             win->setInputFocus())
584           win->installColormap(True);
585
586         ungrab();
587       }
588     } else if ((menu = searchMenu(e->xcrossing.window))) {
589       menu->enterNotifyEvent(&e->xcrossing);
590     } else if ((tbar = searchToolbar(e->xcrossing.window))) {
591       tbar->enterNotifyEvent(&e->xcrossing);
592 #ifdef    SLIT
593     } else if ((slit = searchSlit(e->xcrossing.window))) {
594       slit->enterNotifyEvent(&e->xcrossing);
595 #endif // SLIT
596     }
597     break;
598   }
599
600   case LeaveNotify: {
601     last_time = e->xcrossing.time;
602
603     OpenboxWindow *win = (OpenboxWindow *) 0;
604     Basemenu *menu = (Basemenu *) 0;
605     Toolbar *tbar = (Toolbar *) 0;
606
607 #ifdef    SLIT
608     Slit *slit = (Slit *) 0;
609 #endif // SLIT
610
611     if ((menu = searchMenu(e->xcrossing.window)))
612       menu->leaveNotifyEvent(&e->xcrossing);
613     else if ((win = searchWindow(e->xcrossing.window)))
614       win->installColormap(False);
615     else if ((tbar = searchToolbar(e->xcrossing.window)))
616       tbar->leaveNotifyEvent(&e->xcrossing);
617 #ifdef    SLIT
618     else if ((slit = searchSlit(e->xcrossing.window)))
619       slit->leaveNotifyEvent(&e->xcrossing);
620 #endif // SLIT
621
622     break;
623   }
624
625   case Expose: {
626     OpenboxWindow *win = (OpenboxWindow *) 0;
627     Basemenu *menu = (Basemenu *) 0;
628     Toolbar *tbar = (Toolbar *) 0;
629
630     if ((win = searchWindow(e->xexpose.window)))
631       win->exposeEvent(&e->xexpose);
632     else if ((menu = searchMenu(e->xexpose.window)))
633       menu->exposeEvent(&e->xexpose);
634     else if ((tbar = searchToolbar(e->xexpose.window)))
635       tbar->exposeEvent(&e->xexpose);
636
637     break;
638   }
639
640   case KeyPress: {
641     Toolbar *tbar = searchToolbar(e->xkey.window);
642
643     if (tbar && tbar->isEditing())
644       tbar->keyPressEvent(&e->xkey);
645
646     break;
647   }
648
649   case ColormapNotify: {
650     BScreen *screen = searchScreen(e->xcolormap.window);
651
652     if (screen)
653       screen->setRootColormapInstalled((e->xcolormap.state ==
654                                         ColormapInstalled) ? True : False);
655
656     break;
657   }
658
659   case FocusIn: {
660     if (e->xfocus.mode == NotifyUngrab || e->xfocus.detail == NotifyPointer)
661       break;
662
663     OpenboxWindow *win = searchWindow(e->xfocus.window);
664     if (win && ! win->isFocused())
665       setFocusedWindow(win);
666
667     break;
668   }
669
670   case FocusOut:
671     break;
672
673   case ClientMessage: {
674     if (e->xclient.format == 32) {
675       if (e->xclient.message_type == getWMChangeStateAtom()) {
676         OpenboxWindow *win = searchWindow(e->xclient.window);
677         if (! win || ! win->validateClient()) return;
678
679         if (e->xclient.data.l[0] == IconicState)
680           win->iconify();
681         if (e->xclient.data.l[0] == NormalState)
682           win->deiconify();
683       } else if (e->xclient.message_type == getOpenboxChangeWorkspaceAtom()) {
684         BScreen *screen = searchScreen(e->xclient.window);
685
686         if (screen && e->xclient.data.l[0] >= 0 &&
687             e->xclient.data.l[0] < screen->getCount())
688           screen->changeWorkspaceID(e->xclient.data.l[0]);
689       } else if (e->xclient.message_type == getOpenboxChangeWindowFocusAtom()) {
690         OpenboxWindow *win = searchWindow(e->xclient.window);
691
692         if (win && win->isVisible() && win->setInputFocus())
693           win->installColormap(True);
694       } else if (e->xclient.message_type == getOpenboxCycleWindowFocusAtom()) {
695         BScreen *screen = searchScreen(e->xclient.window);
696
697         if (screen) {
698           if (! e->xclient.data.l[0])
699             screen->prevFocus();
700           else
701             screen->nextFocus();
702         }
703       } else if (e->xclient.message_type == getOpenboxChangeAttributesAtom()) {
704         OpenboxWindow *win = searchWindow(e->xclient.window);
705
706         if (win && win->validateClient()) {
707           OpenboxHints net;
708           net.flags = e->xclient.data.l[0];
709           net.attrib = e->xclient.data.l[1];
710           net.workspace = e->xclient.data.l[2];
711           net.stack = e->xclient.data.l[3];
712           net.decoration = e->xclient.data.l[4];
713
714           win->changeOpenboxHints(&net);
715         }
716       }
717     }
718
719     break;
720   }
721
722
723   default: {
724 #ifdef    SHAPE
725     if (e->type == getShapeEventBase()) {
726       XShapeEvent *shape_event = (XShapeEvent *) e;
727       OpenboxWindow *win = (OpenboxWindow *) 0;
728
729       if ((win = searchWindow(e->xany.window)) ||
730           (shape_event->kind != ShapeBounding))
731         win->shapeEvent(shape_event);
732     }
733 #endif // SHAPE
734
735   }
736   } // switch
737 }
738
739
740 Bool Openbox::handleSignal(int sig) {
741   switch (sig) {
742   case SIGHUP:
743     reconfigure();
744     break;
745
746   case SIGUSR1:
747     reload_rc();
748     break;
749
750   case SIGUSR2:
751     rereadMenu();
752     break;
753
754   case SIGPIPE:
755   case SIGSEGV:
756   case SIGFPE:
757   case SIGINT:
758   case SIGTERM:
759     shutdown();
760
761   default:
762     return False;
763   }
764
765   return True;
766 }
767
768
769 BScreen *Openbox::searchScreen(Window window) {
770   LinkedListIterator<BScreen> it(screenList);
771
772   for (BScreen *curr = it.current(); curr; it++, curr = it.current()) {
773     if (curr->getRootWindow() == window) {
774       return curr;
775     }
776   }
777
778   return (BScreen *) 0;
779 }
780
781
782 OpenboxWindow *Openbox::searchWindow(Window window) {
783   LinkedListIterator<WindowSearch> it(windowSearchList);
784
785   for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
786       if (tmp->getWindow() == window) {
787         return tmp->getData();
788       }
789   }
790
791   return (OpenboxWindow *) 0;
792 }
793
794
795 OpenboxWindow *Openbox::searchGroup(Window window, OpenboxWindow *win) {
796   OpenboxWindow *w = (OpenboxWindow *) 0;
797   LinkedListIterator<WindowSearch> it(groupSearchList);
798
799   for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
800     if (tmp->getWindow() == window) {
801       w = tmp->getData();
802       if (w->getClientWindow() != win->getClientWindow())
803         return win;
804     }
805   }
806
807   return (OpenboxWindow *) 0;
808 }
809
810
811 Basemenu *Openbox::searchMenu(Window window) {
812   LinkedListIterator<MenuSearch> it(menuSearchList);
813
814   for (MenuSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
815     if (tmp->getWindow() == window)
816       return tmp->getData();
817   }
818
819   return (Basemenu *) 0;
820 }
821
822
823 Toolbar *Openbox::searchToolbar(Window window) {
824   LinkedListIterator<ToolbarSearch> it(toolbarSearchList);
825
826   for (ToolbarSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
827     if (tmp->getWindow() == window)
828       return tmp->getData();
829   }
830
831   return (Toolbar *) 0;
832 }
833
834
835 #ifdef    SLIT
836 Slit *Openbox::searchSlit(Window window) {
837   LinkedListIterator<SlitSearch> it(slitSearchList);
838
839   for (SlitSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
840     if (tmp->getWindow() == window)
841       return tmp->getData();
842   }
843
844   return (Slit *) 0;
845 }
846 #endif // SLIT
847
848
849 void Openbox::saveWindowSearch(Window window, OpenboxWindow *data) {
850   windowSearchList->insert(new WindowSearch(window, data));
851 }
852
853
854 void Openbox::saveGroupSearch(Window window, OpenboxWindow *data) {
855   groupSearchList->insert(new WindowSearch(window, data));
856 }
857
858
859 void Openbox::saveMenuSearch(Window window, Basemenu *data) {
860   menuSearchList->insert(new MenuSearch(window, data));
861 }
862
863
864 void Openbox::saveToolbarSearch(Window window, Toolbar *data) {
865   toolbarSearchList->insert(new ToolbarSearch(window, data));
866 }
867
868
869 #ifdef    SLIT
870 void Openbox::saveSlitSearch(Window window, Slit *data) {
871   slitSearchList->insert(new SlitSearch(window, data));
872 }
873 #endif // SLIT
874
875
876 void Openbox::removeWindowSearch(Window window) {
877   LinkedListIterator<WindowSearch> it(windowSearchList);
878   for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
879     if (tmp->getWindow() == window) {
880       windowSearchList->remove(tmp);
881       delete tmp;
882       break;
883     }
884   }
885 }
886
887
888 void Openbox::removeGroupSearch(Window window) {
889   LinkedListIterator<WindowSearch> it(groupSearchList);
890   for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
891     if (tmp->getWindow() == window) {
892       groupSearchList->remove(tmp);
893       delete tmp;
894       break;
895     }
896   }
897 }
898
899
900 void Openbox::removeMenuSearch(Window window) {
901   LinkedListIterator<MenuSearch> it(menuSearchList);
902   for (MenuSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
903     if (tmp->getWindow() == window) {
904       menuSearchList->remove(tmp);
905       delete tmp;
906       break;
907     }
908   }
909 }
910
911
912 void Openbox::removeToolbarSearch(Window window) {
913   LinkedListIterator<ToolbarSearch> it(toolbarSearchList);
914   for (ToolbarSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
915     if (tmp->getWindow() == window) {
916       toolbarSearchList->remove(tmp);
917       delete tmp;
918       break;
919     }
920   }
921 }
922
923
924 #ifdef    SLIT
925 void Openbox::removeSlitSearch(Window window) {
926   LinkedListIterator<SlitSearch> it(slitSearchList);
927   for (SlitSearch *tmp = it.current(); tmp; it++, tmp = it.current()) {
928     if (tmp->getWindow() == window) {
929       slitSearchList->remove(tmp);
930       delete tmp;
931       break;
932     }
933   }
934 }
935 #endif // SLIT
936
937
938 void Openbox::restart(const char *prog) {
939   shutdown();
940
941   if (prog) {
942     execlp(prog, prog, NULL);
943     perror(prog);
944   }
945
946   // fall back in case the above execlp doesn't work
947   execvp(argv[0], argv);
948   execvp(basename(argv[0]), argv);
949 }
950
951
952 void Openbox::shutdown(void) {
953   BaseDisplay::shutdown();
954
955   XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
956
957   LinkedListIterator<BScreen> it(screenList);
958   for (BScreen *s = it.current(); s; it++, s = it.current())
959     s->shutdown();
960
961   XSync(getXDisplay(), False);
962
963   save_rc();
964 }
965
966
967 void Openbox::save_rc(void) {
968   XrmDatabase new_openboxrc = (XrmDatabase) 0;
969   char rc_string[1024];
970
971   load_rc();
972
973   sprintf(rc_string, "session.menuFile:  %s", resource.menu_file);
974   XrmPutLineResource(&new_openboxrc, rc_string);
975
976   sprintf(rc_string, "session.colorsPerChannel:  %d",
977           resource.colors_per_channel);
978   XrmPutLineResource(&new_openboxrc, rc_string);
979
980   sprintf(rc_string, "session.titlebarLayout:  %s",
981           resource.titlebar_layout);
982   XrmPutLineResource(&new_openboxrc, rc_string);
983
984   sprintf(rc_string, "session.doubleClickInterval:  %lu",
985           resource.double_click_interval);
986   XrmPutLineResource(&new_openboxrc, rc_string);
987
988   sprintf(rc_string, "session.autoRaiseDelay:  %lu",
989           ((resource.auto_raise_delay.tv_sec * 1000) +
990            (resource.auto_raise_delay.tv_usec / 1000)));
991   XrmPutLineResource(&new_openboxrc, rc_string);
992
993   sprintf(rc_string, "session.cacheLife: %lu", resource.cache_life / 60000);
994   XrmPutLineResource(&new_openboxrc, rc_string);
995
996   sprintf(rc_string, "session.cacheMax: %lu", resource.cache_max);
997   XrmPutLineResource(&new_openboxrc, rc_string);
998
999   LinkedListIterator<BScreen> it(screenList);
1000   for (BScreen *screen = it.current(); screen; it++, screen = it.current()) {
1001     int screen_number = screen->getScreenNumber();
1002
1003 #ifdef    SLIT
1004     char *slit_placement = (char *) 0;
1005
1006     switch (screen->getSlitPlacement()) {
1007     case Slit::TopLeft: slit_placement = "TopLeft"; break;
1008     case Slit::CenterLeft: slit_placement = "CenterLeft"; break;
1009     case Slit::BottomLeft: slit_placement = "BottomLeft"; break;
1010     case Slit::TopCenter: slit_placement = "TopCenter"; break;
1011     case Slit::BottomCenter: slit_placement = "BottomCenter"; break;
1012     case Slit::TopRight: slit_placement = "TopRight"; break;
1013     case Slit::BottomRight: slit_placement = "BottomRight"; break;
1014     case Slit::CenterRight: default: slit_placement = "CenterRight"; break;
1015     }
1016
1017     sprintf(rc_string, "session.screen%d.slit.placement: %s", screen_number,
1018             slit_placement);
1019     XrmPutLineResource(&new_openboxrc, rc_string);
1020
1021     sprintf(rc_string, "session.screen%d.slit.direction: %s", screen_number,
1022             ((screen->getSlitDirection() == Slit::Horizontal) ? "Horizontal" :
1023                                                                 "Vertical"));
1024     XrmPutLineResource(&new_openboxrc, rc_string);
1025
1026     const char *rootcmd;
1027     if ((rootcmd = screen->getRootCommand()) != NULL) {
1028       sprintf(rc_string, "session.screen%d.rootCommand: %s", screen_number,
1029               rootcmd);
1030       XrmPutLineResource(&new_openboxrc, rc_string);
1031     }
1032
1033     sprintf(rc_string, "session.screen%d.slit.onTop: %s", screen_number,
1034             ((screen->getSlit()->isOnTop()) ? "True" : "False"));
1035     XrmPutLineResource(&new_openboxrc, rc_string);
1036
1037     sprintf(rc_string, "session.screen%d.slit.autoHide: %s", screen_number,
1038             ((screen->getSlit()->doAutoHide()) ? "True" : "False"));
1039     XrmPutLineResource(&new_openboxrc, rc_string);
1040 #endif // SLIT
1041
1042     sprintf(rc_string, "session.opaqueMove: %s",
1043             ((screen->doOpaqueMove()) ? "True" : "False"));
1044     XrmPutLineResource(&new_openboxrc, rc_string);
1045
1046     sprintf(rc_string, "session.imageDither: %s",
1047             ((screen->getImageControl()->doDither()) ? "True" : "False"));
1048     XrmPutLineResource(&new_openboxrc, rc_string);
1049
1050     sprintf(rc_string, "session.screen%d.fullMaximization: %s", screen_number,
1051             ((screen->doFullMax()) ? "True" : "False"));
1052     XrmPutLineResource(&new_openboxrc, rc_string);
1053
1054     sprintf(rc_string, "session.screen%d.focusNewWindows: %s", screen_number,
1055             ((screen->doFocusNew()) ? "True" : "False"));
1056     XrmPutLineResource(&new_openboxrc, rc_string);
1057
1058     sprintf(rc_string, "session.screen%d.focusLastWindow: %s", screen_number,
1059             ((screen->doFocusLast()) ? "True" : "False"));
1060     XrmPutLineResource(&new_openboxrc, rc_string);
1061
1062     sprintf(rc_string, "session.screen%d.rowPlacementDirection: %s",
1063             screen_number,
1064             ((screen->getRowPlacementDirection() == BScreen::LeftRight) ?
1065              "LeftToRight" : "RightToLeft"));
1066     XrmPutLineResource(&new_openboxrc, rc_string);
1067
1068     sprintf(rc_string, "session.screen%d.colPlacementDirection: %s",
1069             screen_number,
1070             ((screen->getColPlacementDirection() == BScreen::TopBottom) ?
1071              "TopToBottom" : "BottomToTop"));
1072     XrmPutLineResource(&new_openboxrc, rc_string);
1073
1074     char *placement = (char *) 0;
1075     switch (screen->getPlacementPolicy()) {
1076     case BScreen::CascadePlacement:
1077       placement = "CascadePlacement";
1078       break;
1079
1080     case BScreen::ColSmartPlacement:
1081       placement = "ColSmartPlacement";
1082       break;
1083
1084     case BScreen::RowSmartPlacement:
1085     default:
1086       placement = "RowSmartPlacement";
1087       break;
1088     }
1089     sprintf(rc_string, "session.screen%d.windowPlacement:  %s", screen_number,
1090             placement);
1091     XrmPutLineResource(&new_openboxrc, rc_string);
1092
1093     sprintf(rc_string, "session.screen%d.windowZones:  %i", screen_number,
1094             screen->getWindowZones());
1095     XrmPutLineResource(&new_openboxrc, rc_string);
1096
1097     sprintf(rc_string, "session.screen%d.focusModel:  %s", screen_number,
1098             ((screen->isSloppyFocus()) ?
1099              ((screen->doAutoRaise()) ? "AutoRaiseSloppyFocus" :
1100               "SloppyFocus") :
1101              "ClickToFocus"));
1102     XrmPutLineResource(&new_openboxrc, rc_string);
1103
1104     sprintf(rc_string, "session.screen%d.workspaces:  %d", screen_number,
1105             screen->getCount());
1106     XrmPutLineResource(&new_openboxrc, rc_string);
1107
1108     sprintf(rc_string, "session.screen%d.toolbar.onTop:  %s", screen_number,
1109             ((screen->getToolbar()->isOnTop()) ? "True" : "False"));
1110     XrmPutLineResource(&new_openboxrc, rc_string);
1111
1112     sprintf(rc_string, "session.screen%d.toolbar.autoHide:  %s", screen_number,
1113             ((screen->getToolbar()->doAutoHide()) ? "True" : "False"));
1114     XrmPutLineResource(&new_openboxrc, rc_string);
1115
1116     char *toolbar_placement = (char *) 0;
1117
1118     switch (screen->getToolbarPlacement()) {
1119     case Toolbar::TopLeft: toolbar_placement = "TopLeft"; break;
1120     case Toolbar::BottomLeft: toolbar_placement = "BottomLeft"; break;
1121     case Toolbar::TopCenter: toolbar_placement = "TopCenter"; break;
1122     case Toolbar::TopRight: toolbar_placement = "TopRight"; break;
1123     case Toolbar::BottomRight: toolbar_placement = "BottomRight"; break;
1124     case Toolbar::BottomCenter: default:
1125       toolbar_placement = "BottomCenter"; break;
1126     }
1127
1128     sprintf(rc_string, "session.screen%d.toolbar.placement: %s", screen_number,
1129             toolbar_placement);
1130     XrmPutLineResource(&new_openboxrc, rc_string);
1131
1132     load_rc(screen);
1133
1134     // these are static, but may not be saved in the users .openbox/rc,
1135     // writing these resources will allow the user to edit them at a later
1136     // time... but loading the defaults before saving allows us to rewrite the
1137     // users changes...
1138
1139 #ifdef    HAVE_STRFTIME
1140     sprintf(rc_string, "session.screen%d.strftimeFormat: %s", screen_number,
1141             screen->getStrftimeFormat());
1142     XrmPutLineResource(&new_openboxrc, rc_string);
1143 #else // !HAVE_STRFTIME
1144     sprintf(rc_string, "session.screen%d.dateFormat:  %s", screen_number,
1145             ((screen->getDateFormat() == B_EuropeanDate) ?
1146              "European" : "American"));
1147     XrmPutLineResource(&new_openboxrc, rc_string);
1148
1149     sprintf(rc_string, "session.screen%d.clockFormat:  %d", screen_number,
1150             ((screen->isClock24Hour()) ? 24 : 12));
1151     XrmPutLineResource(&new_openboxrc, rc_string);
1152 #endif // HAVE_STRFTIME
1153
1154     sprintf(rc_string, "session.screen%d.edgeSnapThreshold: %d", screen_number,
1155             screen->getEdgeSnapThreshold());
1156     XrmPutLineResource(&new_openboxrc, rc_string);
1157
1158     sprintf(rc_string, "session.screen%d.toolbar.widthPercent:  %d",
1159             screen_number, screen->getToolbarWidthPercent());
1160     XrmPutLineResource(&new_openboxrc, rc_string);
1161
1162     // write out the users workspace names
1163     int i, len = 0;
1164     for (i = 0; i < screen->getCount(); i++)
1165       len += strlen((screen->getWorkspace(i)->getName()) ?
1166                     screen->getWorkspace(i)->getName() : "Null") + 1;
1167
1168     char *resource_string = new char[len + 1024],
1169       *save_string = new char[len], *save_string_pos = save_string,
1170       *name_string_pos;
1171     if (save_string) {
1172       for (i = 0; i < screen->getCount(); i++) {
1173         len = strlen((screen->getWorkspace(i)->getName()) ?
1174                      screen->getWorkspace(i)->getName() : "Null") + 1;
1175         name_string_pos =
1176           (char *) ((screen->getWorkspace(i)->getName()) ?
1177                     screen->getWorkspace(i)->getName() : "Null");
1178
1179         while (--len) *(save_string_pos++) = *(name_string_pos++);
1180         *(save_string_pos++) = ',';
1181       }
1182     }
1183
1184     *(--save_string_pos) = '\0';
1185
1186     sprintf(resource_string, "session.screen%d.workspaceNames:  %s",
1187             screen_number, save_string);
1188     XrmPutLineResource(&new_openboxrc, resource_string);
1189
1190     delete [] resource_string;
1191     delete [] save_string;
1192   }
1193
1194   XrmDatabase old_openboxrc = XrmGetFileDatabase(rc_file);
1195
1196   XrmMergeDatabases(new_openboxrc, &old_openboxrc);
1197   XrmPutFileDatabase(old_openboxrc, rc_file);
1198   XrmDestroyDatabase(old_openboxrc);
1199 }
1200
1201
1202 void Openbox::load_rc(void) {
1203   XrmDatabase database = (XrmDatabase) 0;
1204
1205   database = XrmGetFileDatabase(rc_file);
1206
1207   XrmValue value;
1208   char *value_type;
1209
1210   if (resource.menu_file)
1211     delete [] resource.menu_file;
1212
1213   if (XrmGetResource(database, "session.menuFile", "Session.MenuFile",
1214                      &value_type, &value))
1215     resource.menu_file = bstrdup(value.addr);
1216   else
1217     resource.menu_file = bstrdup(DEFAULTMENU);
1218
1219   if (XrmGetResource(database, "session.colorsPerChannel",
1220                      "Session.ColorsPerChannel", &value_type, &value)) {
1221     if (sscanf(value.addr, "%d", &resource.colors_per_channel) != 1) {
1222       resource.colors_per_channel = 4;
1223     } else {
1224       if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1225       if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1226     }
1227   } else {
1228     resource.colors_per_channel = 4;
1229   }
1230
1231   if (resource.style_file)
1232     delete [] resource.style_file;
1233
1234   if (XrmGetResource(database, "session.styleFile", "Session.StyleFile",
1235                      &value_type, &value))
1236     resource.style_file = bstrdup(value.addr);
1237   else
1238     resource.style_file = bstrdup(DEFAULTSTYLE);
1239
1240   if (XrmGetResource(database, "session.titlebarLayout",
1241                      "Session.TitlebarLayout", &value_type, &value)) {
1242     resource.titlebar_layout = bstrdup(value.addr == NULL ? "ILMC" :
1243                                        value.addr);
1244   } else {
1245     resource.titlebar_layout = bstrdup("ILMC");
1246   }
1247
1248   if (XrmGetResource(database, "session.doubleClickInterval",
1249                      "Session.DoubleClickInterval", &value_type, &value)) {
1250     if (sscanf(value.addr, "%lu", &resource.double_click_interval) != 1)
1251       resource.double_click_interval = 250;
1252   } else {
1253     resource.double_click_interval = 250;
1254   }
1255
1256   if (XrmGetResource(database, "session.autoRaiseDelay",
1257                      "Session.AutoRaiseDelay", &value_type, &value)) {
1258     if (sscanf(value.addr, "%ld", &resource.auto_raise_delay.tv_usec) != 1)
1259       resource.auto_raise_delay.tv_usec = 400;
1260   } else {
1261     resource.auto_raise_delay.tv_usec = 400;
1262   }
1263
1264   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1265   resource.auto_raise_delay.tv_usec -=
1266     (resource.auto_raise_delay.tv_sec * 1000);
1267   resource.auto_raise_delay.tv_usec *= 1000;
1268
1269   if (XrmGetResource(database, "session.cacheLife", "Session.CacheLife",
1270                      &value_type, &value)) {
1271     if (sscanf(value.addr, "%lu", &resource.cache_life) != 1)
1272       resource.cache_life = 5l;
1273   } else {
1274     resource.cache_life = 5l;
1275   }
1276
1277   resource.cache_life *= 60000;
1278
1279   if (XrmGetResource(database, "session.cacheMax", "Session.CacheMax",
1280                      &value_type, &value)) {
1281     if (sscanf(value.addr, "%lu", &resource.cache_max) != 1)
1282       resource.cache_max = 200;
1283   } else {
1284     resource.cache_max = 200;
1285   }
1286 }
1287
1288
1289 void Openbox::load_rc(BScreen *screen) {
1290   XrmDatabase database = (XrmDatabase) 0;
1291
1292   database = XrmGetFileDatabase(rc_file);
1293
1294   XrmValue value;
1295   char *value_type, name_lookup[1024], class_lookup[1024];
1296   int screen_number = screen->getScreenNumber();
1297
1298   sprintf(name_lookup,  "session.screen%d.fullMaximization", screen_number);
1299   sprintf(class_lookup, "Session.Screen%d.FullMaximization", screen_number);
1300   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1301                      &value)) {
1302     if (! strncasecmp(value.addr, "true", value.size))
1303       screen->saveFullMax(True);
1304     else
1305       screen->saveFullMax(False);
1306   } else {
1307     screen->saveFullMax(False);
1308   }
1309   sprintf(name_lookup,  "session.screen%d.focusNewWindows", screen_number);
1310   sprintf(class_lookup, "Session.Screen%d.FocusNewWindows", screen_number);
1311   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1312                      &value)) {
1313     if (! strncasecmp(value.addr, "true", value.size))
1314       screen->saveFocusNew(True);
1315     else
1316       screen->saveFocusNew(False);
1317   } else {
1318     screen->saveFocusNew(False);
1319   }
1320   sprintf(name_lookup,  "session.screen%d.focusLastWindow", screen_number);
1321   sprintf(class_lookup, "Session.Screen%d.focusLastWindow", screen_number);
1322   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1323                      &value)) {
1324     if (! strncasecmp(value.addr, "true", value.size))
1325       screen->saveFocusLast(True);
1326     else
1327       screen->saveFocusLast(False);
1328   } else {
1329     screen->saveFocusLast(False);
1330   }
1331   sprintf(name_lookup,  "session.screen%d.rowPlacementDirection",
1332           screen_number);
1333   sprintf(class_lookup, "Session.Screen%d.RowPlacementDirection",
1334           screen_number);
1335   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1336                      &value)) {
1337     if (! strncasecmp(value.addr, "righttoleft", value.size))
1338       screen->saveRowPlacementDirection(BScreen::RightLeft);
1339     else
1340       screen->saveRowPlacementDirection(BScreen::LeftRight);
1341   } else {
1342     screen->saveRowPlacementDirection(BScreen::LeftRight);
1343   }
1344   sprintf(name_lookup,  "session.screen%d.colPlacementDirection",
1345           screen_number);
1346   sprintf(class_lookup, "Session.Screen%d.ColPlacementDirection",
1347           screen_number);
1348   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1349                      &value)) {
1350     if (! strncasecmp(value.addr, "bottomtotop", value.size))
1351       screen->saveColPlacementDirection(BScreen::BottomTop);
1352     else
1353       screen->saveColPlacementDirection(BScreen::TopBottom);
1354   } else {
1355     screen->saveColPlacementDirection(BScreen::TopBottom);
1356   }
1357   sprintf(name_lookup,  "session.screen%d.workspaces", screen_number);
1358   sprintf(class_lookup, "Session.Screen%d.Workspaces", screen_number);
1359   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1360                      &value)) {
1361     int i;
1362     if (sscanf(value.addr, "%d", &i) != 1) i = 1;
1363     screen->saveWorkspaces(i);
1364   } else {
1365     screen->saveWorkspaces(1);
1366   }
1367   sprintf(name_lookup,  "session.screen%d.toolbar.widthPercent",
1368           screen_number);
1369   sprintf(class_lookup, "Session.Screen%d.Toolbar.WidthPercent",
1370           screen_number);
1371   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1372                      &value)) {
1373     int i;
1374     if (sscanf(value.addr, "%d", &i) != 1) i = 66;
1375
1376     if (i <= 0 || i > 100)
1377       i = 66;
1378
1379     screen->saveToolbarWidthPercent(i);
1380   } else {
1381     screen->saveToolbarWidthPercent(66);
1382   }
1383   sprintf(name_lookup, "session.screen%d.toolbar.placement", screen_number);
1384   sprintf(class_lookup, "Session.Screen%d.Toolbar.Placement", screen_number);
1385   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1386                      &value)) {
1387     if (! strncasecmp(value.addr, "TopLeft", value.size))
1388       screen->saveToolbarPlacement(Toolbar::TopLeft);
1389     else if (! strncasecmp(value.addr, "BottomLeft", value.size))
1390       screen->saveToolbarPlacement(Toolbar::BottomLeft);
1391     else if (! strncasecmp(value.addr, "TopCenter", value.size))
1392       screen->saveToolbarPlacement(Toolbar::TopCenter);
1393     else if (! strncasecmp(value.addr, "TopRight", value.size))
1394       screen->saveToolbarPlacement(Toolbar::TopRight);
1395     else if (! strncasecmp(value.addr, "BottomRight", value.size))
1396       screen->saveToolbarPlacement(Toolbar::BottomRight);
1397     else
1398       screen->saveToolbarPlacement(Toolbar::BottomCenter);
1399   } else {
1400     screen->saveToolbarPlacement(Toolbar::BottomCenter);
1401   }
1402   screen->removeWorkspaceNames();
1403
1404   sprintf(name_lookup,  "session.screen%d.workspaceNames", screen_number);
1405   sprintf(class_lookup, "Session.Screen%d.WorkspaceNames", screen_number);
1406   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1407                      &value)) {
1408     char *search = bstrdup(value.addr);
1409
1410     for (int i = 0; i < screen->getNumberOfWorkspaces(); i++) {
1411       char *nn;
1412
1413       if (! i) nn = strtok(search, ",");
1414       else nn = strtok(NULL, ",");
1415
1416       if (nn) screen->addWorkspaceName(nn);
1417       else break;
1418     }
1419
1420     delete [] search;
1421   }
1422
1423   sprintf(name_lookup,  "session.screen%d.toolbar.onTop", screen_number);
1424   sprintf(class_lookup, "Session.Screen%d.Toolbar.OnTop", screen_number);
1425   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1426                      &value)) {
1427     if (! strncasecmp(value.addr, "true", value.size))
1428       screen->saveToolbarOnTop(True);
1429     else
1430       screen->saveToolbarOnTop(False);
1431   } else {
1432     screen->saveToolbarOnTop(False);
1433   }
1434   sprintf(name_lookup,  "session.screen%d.toolbar.autoHide", screen_number);
1435   sprintf(class_lookup, "Session.Screen%d.Toolbar.autoHide", screen_number);
1436   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1437                      &value)) {
1438     if (! strncasecmp(value.addr, "true", value.size))
1439       screen->saveToolbarAutoHide(True);
1440     else
1441       screen->saveToolbarAutoHide(False);
1442   } else {
1443     screen->saveToolbarAutoHide(False);
1444   }
1445   sprintf(name_lookup,  "session.screen%d.focusModel", screen_number);
1446   sprintf(class_lookup, "Session.Screen%d.FocusModel", screen_number);
1447   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1448                      &value)) {
1449     if (! strncasecmp(value.addr, "clicktofocus", value.size)) {
1450       screen->saveAutoRaise(False);
1451       screen->saveSloppyFocus(False);
1452     } else if (! strncasecmp(value.addr, "autoraisesloppyfocus", value.size)) {
1453       screen->saveSloppyFocus(True);
1454       screen->saveAutoRaise(True);
1455     } else {
1456       screen->saveSloppyFocus(True);
1457       screen->saveAutoRaise(False);
1458     }
1459   } else {
1460     screen->saveSloppyFocus(True);
1461     screen->saveAutoRaise(False);
1462   }
1463
1464   sprintf(name_lookup,  "session.screen%d.windowZones", screen_number);
1465   sprintf(class_lookup, "Session.Screen%d.WindowZones", screen_number);
1466   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1467                      &value)) {
1468     int i = atoi(value.addr);
1469     screen->saveWindowZones((i == 1 || i == 2 || i == 4) ? i : 1);
1470   } else {
1471     screen->saveWindowZones(1);
1472   }
1473   
1474   sprintf(name_lookup,  "session.screen%d.windowPlacement", screen_number);
1475   sprintf(class_lookup, "Session.Screen%d.WindowPlacement", screen_number);
1476   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1477                      &value)) {
1478     if (! strncasecmp(value.addr, "RowSmartPlacement", value.size))
1479       screen->savePlacementPolicy(BScreen::RowSmartPlacement);
1480     else if (! strncasecmp(value.addr, "ColSmartPlacement", value.size))
1481       screen->savePlacementPolicy(BScreen::ColSmartPlacement);
1482     else
1483       screen->savePlacementPolicy(BScreen::CascadePlacement);
1484   } else {
1485     screen->savePlacementPolicy(BScreen::RowSmartPlacement);
1486   }
1487 #ifdef    SLIT
1488   sprintf(name_lookup, "session.screen%d.slit.placement", screen_number);
1489   sprintf(class_lookup, "Session.Screen%d.Slit.Placement", screen_number);
1490   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1491                      &value)) {
1492     if (! strncasecmp(value.addr, "TopLeft", value.size))
1493       screen->saveSlitPlacement(Slit::TopLeft);
1494     else if (! strncasecmp(value.addr, "CenterLeft", value.size))
1495       screen->saveSlitPlacement(Slit::CenterLeft);
1496     else if (! strncasecmp(value.addr, "BottomLeft", value.size))
1497       screen->saveSlitPlacement(Slit::BottomLeft);
1498     else if (! strncasecmp(value.addr, "TopCenter", value.size))
1499       screen->saveSlitPlacement(Slit::TopCenter);
1500     else if (! strncasecmp(value.addr, "BottomCenter", value.size))
1501       screen->saveSlitPlacement(Slit::BottomCenter);
1502     else if (! strncasecmp(value.addr, "TopRight", value.size))
1503       screen->saveSlitPlacement(Slit::TopRight);
1504     else if (! strncasecmp(value.addr, "BottomRight", value.size))
1505       screen->saveSlitPlacement(Slit::BottomRight);
1506     else
1507       screen->saveSlitPlacement(Slit::CenterRight);
1508   } else {
1509     screen->saveSlitPlacement(Slit::CenterRight);
1510   }
1511   sprintf(name_lookup, "session.screen%d.slit.direction", screen_number);
1512   sprintf(class_lookup, "Session.Screen%d.Slit.Direction", screen_number);
1513   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1514                      &value)) {
1515     if (! strncasecmp(value.addr, "Horizontal", value.size))
1516       screen->saveSlitDirection(Slit::Horizontal);
1517     else
1518       screen->saveSlitDirection(Slit::Vertical);
1519   } else {
1520     screen->saveSlitDirection(Slit::Vertical);
1521   }
1522   sprintf(name_lookup, "session.screen%d.slit.onTop", screen_number);
1523   sprintf(class_lookup, "Session.Screen%d.Slit.OnTop", screen_number);
1524   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1525                      &value)) {
1526     if (! strncasecmp(value.addr, "True", value.size))
1527       screen->saveSlitOnTop(True);
1528     else
1529       screen->saveSlitOnTop(False);
1530   } else {
1531     screen->saveSlitOnTop(False);
1532   }
1533   sprintf(name_lookup, "session.screen%d.slit.autoHide", screen_number);
1534   sprintf(class_lookup, "Session.Screen%d.Slit.AutoHide", screen_number);
1535   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1536                      &value)) {
1537     if (! strncasecmp(value.addr, "True", value.size))
1538       screen->saveSlitAutoHide(True);
1539     else
1540       screen->saveSlitAutoHide(False);
1541   } else {
1542     screen->saveSlitAutoHide(False);
1543   }
1544 #endif // SLIT
1545
1546 #ifdef    HAVE_STRFTIME
1547   sprintf(name_lookup,  "session.screen%d.strftimeFormat", screen_number);
1548   sprintf(class_lookup, "Session.Screen%d.StrftimeFormat", screen_number);
1549   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1550                      &value)) {
1551     screen->saveStrftimeFormat(value.addr);
1552   } else {
1553     screen->saveStrftimeFormat("%I:%M %p");
1554   }
1555 #else //  HAVE_STRFTIME
1556   sprintf(name_lookup,  "session.screen%d.dateFormat", screen_number);
1557   sprintf(class_lookup, "Session.Screen%d.DateFormat", screen_number);
1558   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1559                      &value)) {
1560     if (strncasecmp(value.addr, "european", value.size))
1561       screen->saveDateFormat(B_AmericanDate);
1562     else
1563       screen->saveDateFormat(B_EuropeanDate);
1564   } else {
1565     screen->saveDateFormat(B_AmericanDate);
1566   }
1567   sprintf(name_lookup,  "session.screen%d.clockFormat", screen_number);
1568   sprintf(class_lookup, "Session.Screen%d.ClockFormat", screen_number);
1569   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1570                      &value)) {
1571     int clock;
1572     if (sscanf(value.addr, "%d", &clock) != 1) screen->saveClock24Hour(False);
1573     else if (clock == 24) screen->saveClock24Hour(True);
1574     else screen->saveClock24Hour(False);
1575   } else {
1576     screen->saveClock24Hour(False);
1577   }
1578 #endif // HAVE_STRFTIME
1579
1580   sprintf(name_lookup,  "session.screen%d.edgeSnapThreshold", screen_number);
1581   sprintf(class_lookup, "Session.Screen%d.EdgeSnapThreshold", screen_number);
1582   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1583                      &value)) {
1584     int threshold;
1585     if (sscanf(value.addr, "%d", &threshold) != 1)
1586       screen->saveEdgeSnapThreshold(0);
1587     else
1588       screen->saveEdgeSnapThreshold(threshold);
1589   } else {
1590     screen->saveEdgeSnapThreshold(0);
1591   }
1592   sprintf(name_lookup,  "session.screen%d.imageDither", screen_number);
1593   sprintf(class_lookup, "Session.Screen%d.ImageDither", screen_number);
1594   if (XrmGetResource(database, "session.imageDither", "Session.ImageDither",
1595                      &value_type, &value)) {
1596     if (! strncasecmp("true", value.addr, value.size))
1597       screen->saveImageDither(True);
1598     else
1599       screen->saveImageDither(False);
1600   } else {
1601     screen->saveImageDither(True);
1602   }
1603
1604   sprintf(name_lookup, "session.screen%d.rootCommand", screen_number);
1605   sprintf(class_lookup, "Session.Screen%d.RootCommand", screen_number);
1606   if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1607                      &value)) {
1608     screen->saveRootCommand(value.addr);
1609   } else
1610     screen->saveRootCommand(NULL);
1611
1612   if (XrmGetResource(database, "session.opaqueMove", "Session.OpaqueMove",
1613                      &value_type, &value)) {
1614     if (! strncasecmp("true", value.addr, value.size))
1615       screen->saveOpaqueMove(True);
1616     else
1617       screen->saveOpaqueMove(False);
1618   } else {
1619     screen->saveOpaqueMove(False);
1620   }
1621   XrmDestroyDatabase(database);
1622 }
1623
1624
1625 void Openbox::reload_rc(void) {
1626   load_rc();
1627   reconfigure();
1628 }
1629
1630
1631 void Openbox::reconfigure(void) {
1632   reconfigure_wait = True;
1633
1634   if (! timer->isTiming()) timer->start();
1635 }
1636
1637
1638 void Openbox::real_reconfigure(void) {
1639   grab();
1640
1641   XrmDatabase new_openboxrc = (XrmDatabase) 0;
1642   char style[MAXPATHLEN + 64];
1643
1644   sprintf(style, "session.styleFile: %s", resource.style_file);
1645   XrmPutLineResource(&new_openboxrc, style);
1646
1647   XrmDatabase old_openboxrc = XrmGetFileDatabase(rc_file);
1648
1649   XrmMergeDatabases(new_openboxrc, &old_openboxrc);
1650   XrmPutFileDatabase(old_openboxrc, rc_file);
1651   if (old_openboxrc) XrmDestroyDatabase(old_openboxrc);
1652
1653   for (int i = 0, n = menuTimestamps->count(); i < n; i++) {
1654     MenuTimestamp *ts = menuTimestamps->remove(0);
1655
1656     if (ts) {
1657       if (ts->filename)
1658         delete [] ts->filename;
1659
1660       delete ts;
1661     }
1662   }
1663
1664   LinkedListIterator<BScreen> it(screenList);
1665   for (BScreen *screen = it.current(); screen; it++, screen = it.current()) {
1666     screen->reconfigure();
1667   }
1668
1669   ungrab();
1670 }
1671
1672
1673 void Openbox::checkMenu(void) {
1674   Bool reread = False;
1675   LinkedListIterator<MenuTimestamp> it(menuTimestamps);
1676   for (MenuTimestamp *tmp = it.current(); tmp && (! reread);
1677        it++, tmp = it.current()) {
1678     struct stat buf;
1679
1680     if (! stat(tmp->filename, &buf)) {
1681       if (tmp->timestamp != buf.st_ctime)
1682         reread = True;
1683     } else {
1684       reread = True;
1685     }
1686   }
1687
1688   if (reread) rereadMenu();
1689 }
1690
1691
1692 void Openbox::rereadMenu(void) {
1693   reread_menu_wait = True;
1694
1695   if (! timer->isTiming()) timer->start();
1696 }
1697
1698
1699 void Openbox::real_rereadMenu(void) {
1700   for (int i = 0, n = menuTimestamps->count(); i < n; i++) {
1701     MenuTimestamp *ts = menuTimestamps->remove(0);
1702
1703     if (ts) {
1704       if (ts->filename)
1705         delete [] ts->filename;
1706
1707       delete ts;
1708     }
1709   }
1710
1711   LinkedListIterator<BScreen> it(screenList);
1712   for (BScreen *screen = it.current(); screen; it++, screen = it.current())
1713     screen->rereadMenu();
1714 }
1715
1716
1717 void Openbox::saveStyleFilename(const char *filename) {
1718   if (resource.style_file)
1719     delete [] resource.style_file;
1720
1721   resource.style_file = bstrdup(filename);
1722 }
1723
1724
1725 void Openbox::saveMenuFilename(const char *filename) {
1726   Bool found = False;
1727
1728   LinkedListIterator<MenuTimestamp> it(menuTimestamps);
1729   for (MenuTimestamp *tmp = it.current(); tmp && (! found);
1730        it++, tmp = it.current()) {
1731     if (! strcmp(tmp->filename, filename)) found = True;
1732   }
1733   if (! found) {
1734     struct stat buf;
1735
1736     if (! stat(filename, &buf)) {
1737       MenuTimestamp *ts = new MenuTimestamp;
1738
1739       ts->filename = bstrdup(filename);
1740       ts->timestamp = buf.st_ctime;
1741
1742       menuTimestamps->insert(ts);
1743     }
1744   }
1745 }
1746
1747
1748 void Openbox::timeout(void) {
1749   if (reconfigure_wait)
1750     real_reconfigure();
1751
1752   if (reread_menu_wait)
1753     real_rereadMenu();
1754
1755   reconfigure_wait = reread_menu_wait = False;
1756 }
1757
1758
1759 void Openbox::setFocusedWindow(OpenboxWindow *win) {
1760   BScreen *old_screen = (BScreen *) 0, *screen = (BScreen *) 0;
1761   OpenboxWindow *old_win = (OpenboxWindow *) 0;
1762   Toolbar *old_tbar = (Toolbar *) 0, *tbar = (Toolbar *) 0;
1763   Workspace *old_wkspc = (Workspace *) 0, *wkspc = (Workspace *) 0;
1764
1765   if (focused_window) {
1766     old_win = focused_window;
1767     old_screen = old_win->getScreen();
1768     old_tbar = old_screen->getToolbar();
1769     old_wkspc = old_screen->getWorkspace(old_win->getWorkspaceNumber());
1770
1771     old_win->setFocusFlag(False);
1772     old_wkspc->getMenu()->setItemSelected(old_win->getWindowNumber(), False);
1773   }
1774
1775   if (win && ! win->isIconic()) {
1776     screen = win->getScreen();
1777     tbar = screen->getToolbar();
1778     wkspc = screen->getWorkspace(win->getWorkspaceNumber());
1779
1780     focused_window = win;
1781
1782     win->setFocusFlag(True);
1783     wkspc->getMenu()->setItemSelected(win->getWindowNumber(), True);
1784   } else {
1785     focused_window = (OpenboxWindow *) 0;
1786   }
1787
1788   if (tbar)
1789     tbar->redrawWindowLabel(True);
1790   if (screen)
1791     screen->updateNetizenWindowFocus();
1792
1793   if (old_tbar && old_tbar != tbar)
1794     old_tbar->redrawWindowLabel(True);
1795   if (old_screen && old_screen != screen)
1796     old_screen->updateNetizenWindowFocus();
1797 }