added BScreen::availableArea() which returns a rect specifying where windows can...
[mikachu/openbox.git] / src / Screen.cc
1 // Screen.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/Xatom.h>
34 #include <X11/keysym.h>
35
36 #include "i18n.h"
37 #include "openbox.h"
38 #include "Clientmenu.h"
39 #include "Iconmenu.h"
40 #include "Image.h"
41 #include "Screen.h"
42
43 #ifdef    SLIT
44 #include "Slit.h"
45 #endif // SLIT
46
47 #include "Rootmenu.h"
48 #include "Toolbar.h"
49 #include "Window.h"
50 #include "Workspace.h"
51 #include "Workspacemenu.h"
52 #include "Util.h"
53
54 #ifdef    HAVE_STDLIB_H
55 #  include <stdlib.h>
56 #endif // HAVE_STDLIB_H
57
58 #ifdef    HAVE_STRING_H
59 #  include <string.h>
60 #endif // HAVE_STRING_H
61
62 #ifdef    HAVE_SYS_TYPES_H
63 #  include <sys/types.h>
64 #endif // HAVE_SYS_TYPES_H
65
66 #ifdef    HAVE_CTYPE_H
67 #  include <ctype.h>
68 #endif // HAVE_CTYPE_H
69
70 #ifdef    HAVE_DIRENT_H
71 #  include <dirent.h>
72 #endif // HAVE_DIRENT_H
73
74 #ifdef    HAVE_LOCALE_H
75 #  include <locale.h>
76 #endif // HAVE_LOCALE_H
77
78 #ifdef    HAVE_UNISTD_H
79 #  include <sys/types.h>
80 #  include <unistd.h>
81 #endif // HAVE_UNISTD_H
82
83 #ifdef    HAVE_SYS_STAT_H
84 #  include <sys/stat.h>
85 #endif // HAVE_SYS_STAT_H
86
87 #ifdef    HAVE_STDARG_H
88 #  include <stdarg.h>
89 #endif // HAVE_STDARG_H
90
91 #ifndef    HAVE_SNPRINTF
92 #  include "bsd-snprintf.h"
93 #endif // !HAVE_SNPRINTF
94
95 #ifndef   MAXPATHLEN
96 #define   MAXPATHLEN 255
97 #endif // MAXPATHLEN
98
99 #ifndef   FONT_ELEMENT_SIZE
100 #define   FONT_ELEMENT_SIZE 50
101 #endif // FONT_ELEMENT_SIZE
102
103 #include <strstream>
104 #include <string>
105 #include <algorithm>
106
107 static Bool running = True;
108
109 static int anotherWMRunning(Display *display, XErrorEvent *) {
110   fprintf(stderr, i18n->getMessage(ScreenSet, ScreenAnotherWMRunning,
111      "BScreen::BScreen: an error occured while querying the X server.\n"
112              "  another window manager already running on display %s.\n"),
113           DisplayString(display));
114
115   running = False;
116
117   return(-1);
118 }
119
120 struct dcmp {
121   bool operator()(const char *one, const char *two) const {
122     return (strcmp(one, two) < 0) ? True : False;
123   }
124 };
125
126 #ifndef    HAVE_STRCASESTR
127 static const char * strcasestr(const char *str, const char *ptn) {
128   const char *s2, *p2;
129   for( ; *str; str++) {
130     for(s2=str,p2=ptn; ; s2++,p2++) {
131       if (!*p2) return str;
132       if (toupper(*s2) != toupper(*p2)) break;
133     }
134   }
135   return NULL;
136 }
137 #endif // HAVE_STRCASESTR
138
139 static const char *getFontElement(const char *pattern, char *buf, int bufsiz, ...) {
140   const char *p, *v;
141   char *p2;
142   va_list va;
143
144   va_start(va, bufsiz);
145   buf[bufsiz-1] = 0;
146   buf[bufsiz-2] = '*';
147   while((v = va_arg(va, char *)) != NULL) {
148     p = strcasestr(pattern, v);
149     if (p) {
150       strncpy(buf, p+1, bufsiz-2);
151       p2 = strchr(buf, '-');
152       if (p2) *p2=0;
153       va_end(va);
154       return p;
155     }
156   }
157   va_end(va);
158   strncpy(buf, "*", bufsiz);
159   return NULL;
160 }
161
162 static const char *getFontSize(const char *pattern, int *size) {
163   const char *p;
164   const char *p2=NULL;
165   int n=0;
166
167   for (p=pattern; 1; p++) {
168     if (!*p) {
169       if (p2!=NULL && n>1 && n<72) {
170         *size = n; return p2+1;
171       } else {
172         *size = 16; return NULL;
173       }
174     } else if (*p=='-') {
175       if (n>1 && n<72 && p2!=NULL) {
176         *size = n;
177         return p2+1;
178       }
179       p2=p; n=0;
180     } else if (*p>='0' && *p<='9' && p2!=NULL) {
181       n *= 10;
182       n += *p-'0';
183     } else {
184       p2=NULL; n=0;
185     }
186   }
187 }
188
189
190 BScreen::BScreen(Openbox &ob, int scrn, Resource &conf) : ScreenInfo(ob, scrn),
191   openbox(ob), config(conf)
192 {
193   event_mask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
194                SubstructureRedirectMask | KeyPressMask | KeyReleaseMask |
195                ButtonPressMask | ButtonReleaseMask;
196
197   XErrorHandler old = XSetErrorHandler((XErrorHandler) anotherWMRunning);
198   XSelectInput(getBaseDisplay().getXDisplay(), getRootWindow(), event_mask);
199   XSync(getBaseDisplay().getXDisplay(), False);
200   XSetErrorHandler((XErrorHandler) old);
201
202   managed = running;
203   if (! managed) return;
204
205   fprintf(stderr, i18n->getMessage(ScreenSet, ScreenManagingScreen,
206                      "BScreen::BScreen: managing screen %d "
207                      "using visual 0x%lx, depth %d\n"),
208           getScreenNumber(), XVisualIDFromVisual(getVisual()),
209           getDepth());
210
211   rootmenu = 0;
212
213   resource.mstyle.t_fontset = resource.mstyle.f_fontset =
214     resource.tstyle.fontset = resource.wstyle.fontset = NULL;
215   resource.mstyle.t_font = resource.mstyle.f_font = resource.tstyle.font =
216     resource.wstyle.font = NULL;
217
218 #ifdef   SLIT
219   slit = NULL;
220 #endif // SLIT
221   toolbar = NULL;
222
223 #ifdef    HAVE_GETPID
224   pid_t bpid = getpid();
225
226   XChangeProperty(getBaseDisplay().getXDisplay(), getRootWindow(),
227                   openbox.getOpenboxPidAtom(), XA_CARDINAL,
228                   sizeof(pid_t) * 8, PropModeReplace,
229                   (unsigned char *) &bpid, 1);
230 #endif // HAVE_GETPID
231
232   XDefineCursor(getBaseDisplay().getXDisplay(), getRootWindow(),
233                 openbox.getSessionCursor());
234
235   workspaceNames = new LinkedList<char>;
236   workspacesList = new LinkedList<Workspace>;
237   rootmenuList = new LinkedList<Rootmenu>;
238   netizenList = new LinkedList<Netizen>;
239   iconList = new LinkedList<OpenboxWindow>;
240
241   image_control =
242     new BImageControl(openbox, *this, True, openbox.getColorsPerChannel(),
243                       openbox.getCacheLife(), openbox.getCacheMax());
244   image_control->installRootColormap();
245   root_colormap_installed = True;
246
247   load();       // load config options from Resources
248   LoadStyle();
249
250   XGCValues gcv;
251   unsigned long gc_value_mask = GCForeground;
252   if (! i18n->multibyte()) gc_value_mask |= GCFont;
253
254   gcv.foreground = WhitePixel(getBaseDisplay().getXDisplay(),
255                               getScreenNumber())
256                  ^ BlackPixel(getBaseDisplay().getXDisplay(),
257                               getScreenNumber());
258   gcv.function = GXxor;
259   gcv.subwindow_mode = IncludeInferiors;
260   opGC = XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
261                    GCForeground | GCFunction | GCSubwindowMode, &gcv);
262
263   gcv.foreground = resource.wstyle.l_text_focus.getPixel();
264   if (resource.wstyle.font)
265     gcv.font = resource.wstyle.font->fid;
266   resource.wstyle.l_text_focus_gc =
267     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
268               gc_value_mask, &gcv);
269
270   gcv.foreground = resource.wstyle.l_text_unfocus.getPixel();
271   if (resource.wstyle.font)
272     gcv.font = resource.wstyle.font->fid;
273   resource.wstyle.l_text_unfocus_gc =
274     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
275               gc_value_mask, &gcv);
276
277   gcv.foreground = resource.wstyle.b_pic_focus.getPixel();
278   resource.wstyle.b_pic_focus_gc =
279     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
280               GCForeground, &gcv);
281
282   gcv.foreground = resource.wstyle.b_pic_unfocus.getPixel();
283   resource.wstyle.b_pic_unfocus_gc =
284     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
285               GCForeground, &gcv);
286
287   gcv.foreground = resource.mstyle.t_text.getPixel();
288   if (resource.mstyle.t_font)
289     gcv.font = resource.mstyle.t_font->fid;
290   resource.mstyle.t_text_gc =
291     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
292               gc_value_mask, &gcv);
293
294   gcv.foreground = resource.mstyle.f_text.getPixel();
295   if (resource.mstyle.f_font)
296     gcv.font = resource.mstyle.f_font->fid;
297   resource.mstyle.f_text_gc =
298     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
299               gc_value_mask, &gcv);
300
301   gcv.foreground = resource.mstyle.h_text.getPixel();
302   resource.mstyle.h_text_gc =
303     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
304               gc_value_mask, &gcv);
305
306   gcv.foreground = resource.mstyle.d_text.getPixel();
307   resource.mstyle.d_text_gc =
308     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
309               gc_value_mask, &gcv);
310
311   gcv.foreground = resource.mstyle.hilite.getColor()->getPixel();
312   resource.mstyle.hilite_gc =
313     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
314               gc_value_mask, &gcv);
315
316   gcv.foreground = resource.tstyle.l_text.getPixel();
317   if (resource.tstyle.font)
318     gcv.font = resource.tstyle.font->fid;
319   resource.tstyle.l_text_gc =
320     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
321               gc_value_mask, &gcv);
322
323   gcv.foreground = resource.tstyle.w_text.getPixel();
324   resource.tstyle.w_text_gc =
325     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
326               gc_value_mask, &gcv);
327
328   gcv.foreground = resource.tstyle.c_text.getPixel();
329   resource.tstyle.c_text_gc =
330     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
331               gc_value_mask, &gcv);
332
333   gcv.foreground = resource.tstyle.b_pic.getPixel();
334   resource.tstyle.b_pic_gc =
335     XCreateGC(getBaseDisplay().getXDisplay(), getRootWindow(),
336               gc_value_mask, &gcv);
337
338   const char *s =  i18n->getMessage(ScreenSet, ScreenPositionLength,
339                                     "0: 0000 x 0: 0000");
340   int l = strlen(s);
341
342   if (i18n->multibyte()) {
343     XRectangle ink, logical;
344     XmbTextExtents(resource.wstyle.fontset, s, l, &ink, &logical);
345     geom_w = logical.width;
346
347     geom_h = resource.wstyle.fontset_extents->max_ink_extent.height;
348   } else {
349     geom_h = resource.wstyle.font->ascent +
350              resource.wstyle.font->descent;
351
352     geom_w = XTextWidth(resource.wstyle.font, s, l);
353   }
354
355   geom_w += (resource.bevel_width * 2);
356   geom_h += (resource.bevel_width * 2);
357
358   XSetWindowAttributes attrib;
359   unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder;
360   attrib.border_pixel = getBorderColor()->getPixel();
361   attrib.colormap = getColormap();
362   attrib.save_under = True;
363
364   geom_window =
365     XCreateWindow(getBaseDisplay().getXDisplay(), getRootWindow(),
366                   0, 0, geom_w, geom_h, resource.border_width, getDepth(),
367                   InputOutput, getVisual(), mask, &attrib);
368   geom_visible = False;
369
370   if (resource.wstyle.l_focus.getTexture() & BImage_ParentRelative) {
371     if (resource.wstyle.t_focus.getTexture() ==
372                                       (BImage_Flat | BImage_Solid)) {
373       geom_pixmap = None;
374       XSetWindowBackground(getBaseDisplay().getXDisplay(), geom_window,
375                            resource.wstyle.t_focus.getColor()->getPixel());
376     } else {
377       geom_pixmap = image_control->renderImage(geom_w, geom_h,
378                                                &resource.wstyle.t_focus);
379       XSetWindowBackgroundPixmap(getBaseDisplay().getXDisplay(),
380                                  geom_window, geom_pixmap);
381     }
382   } else {
383     if (resource.wstyle.l_focus.getTexture() ==
384                                       (BImage_Flat | BImage_Solid)) {
385       geom_pixmap = None;
386       XSetWindowBackground(getBaseDisplay().getXDisplay(), geom_window,
387                            resource.wstyle.l_focus.getColor()->getPixel());
388     } else {
389       geom_pixmap = image_control->renderImage(geom_w, geom_h,
390                                                &resource.wstyle.l_focus);
391       XSetWindowBackgroundPixmap(getBaseDisplay().getXDisplay(),
392                                  geom_window, geom_pixmap);
393     }
394   }
395
396   workspacemenu = new Workspacemenu(*this);
397   iconmenu = new Iconmenu(*this);
398   configmenu = new Configmenu(*this);
399
400   Workspace *wkspc = NULL;
401   if (resource.workspaces != 0) {
402     for (int i = 0; i < resource.workspaces; ++i) {
403       wkspc = new Workspace(*this, workspacesList->count());
404       workspacesList->insert(wkspc);
405       saveWorkspaceNames();
406       workspacemenu->insert(wkspc->getName(), wkspc->getMenu());
407     }
408   } else {
409     wkspc = new Workspace(*this, workspacesList->count());
410     workspacesList->insert(wkspc);
411     saveWorkspaceNames();
412     workspacemenu->insert(wkspc->getName(), wkspc->getMenu());
413   }
414
415   workspacemenu->insert(i18n->getMessage(IconSet, IconIcons, "Icons"),
416                         iconmenu);
417   workspacemenu->update();
418
419   current_workspace = workspacesList->first();
420   workspacemenu->setItemSelected(2, True);
421
422   toolbar = new Toolbar(*this, config);
423
424 #ifdef    SLIT
425   slit = new Slit(*this, config);
426 #endif // SLIT
427
428   InitMenu();
429
430   raiseWindows(0, 0);
431   rootmenu->update();
432
433   changeWorkspaceID(0);
434
435   int i;
436   unsigned int nchild;
437   Window r, p, *children;
438   XQueryTree(getBaseDisplay().getXDisplay(), getRootWindow(), &r, &p,
439              &children, &nchild);
440
441   // preen the window list of all icon windows... for better dockapp support
442   for (i = 0; i < (int) nchild; i++) {
443     if (children[i] == None) continue;
444
445     XWMHints *wmhints = XGetWMHints(getBaseDisplay().getXDisplay(),
446                                     children[i]);
447
448     if (wmhints) {
449       if ((wmhints->flags & IconWindowHint) &&
450           (wmhints->icon_window != children[i]))
451         for (int j = 0; j < (int) nchild; j++)
452           if (children[j] == wmhints->icon_window) {
453             children[j] = None;
454
455             break;
456           }
457
458       XFree(wmhints);
459     }
460   }
461
462   // manage shown windows
463   for (i = 0; i < (int) nchild; ++i) {
464     if (children[i] == None || (! openbox.validateWindow(children[i])))
465       continue;
466
467     XWindowAttributes attrib;
468     if (XGetWindowAttributes(getBaseDisplay().getXDisplay(), children[i],
469                              &attrib)) {
470       if (attrib.override_redirect) continue;
471
472       if (attrib.map_state != IsUnmapped) {
473         new OpenboxWindow(openbox, children[i], this);
474
475         OpenboxWindow *win = openbox.searchWindow(children[i]);
476         if (win) {
477           XMapRequestEvent mre;
478           mre.window = children[i];
479           win->restoreAttributes();
480           win->mapRequestEvent(&mre);
481         }
482       }
483     }
484   }
485
486   if (! resource.sloppy_focus)
487     XSetInputFocus(getBaseDisplay().getXDisplay(), toolbar->getWindowID(),
488                    RevertToParent, CurrentTime);
489
490   XFree(children);
491   XFlush(getBaseDisplay().getXDisplay());
492 }
493
494
495 BScreen::~BScreen(void) {
496   if (! managed) return;
497
498   if (geom_pixmap != None)
499     image_control->removeImage(geom_pixmap);
500
501   if (geom_window != None)
502     XDestroyWindow(getBaseDisplay().getXDisplay(), geom_window);
503
504   removeWorkspaceNames();
505
506   while (workspacesList->count())
507     delete workspacesList->remove(0);
508
509   while (rootmenuList->count())
510     rootmenuList->remove(0);
511
512   while (iconList->count())
513     delete iconList->remove(0);
514
515   while (netizenList->count())
516     delete netizenList->remove(0);
517
518 #ifdef    HAVE_STRFTIME
519   if (resource.strftime_format)
520     delete [] resource.strftime_format;
521 #endif // HAVE_STRFTIME
522
523   delete rootmenu;
524   delete workspacemenu;
525   delete iconmenu;
526   delete configmenu;
527
528 #ifdef    SLIT
529   delete slit;
530 #endif // SLIT
531
532   delete toolbar;
533   delete image_control;
534
535   delete workspacesList;
536   delete workspaceNames;
537   delete rootmenuList;
538   delete iconList;
539   delete netizenList;
540
541   if (resource.wstyle.fontset)
542     XFreeFontSet(getBaseDisplay().getXDisplay(), resource.wstyle.fontset);
543   if (resource.mstyle.t_fontset)
544     XFreeFontSet(getBaseDisplay().getXDisplay(), resource.mstyle.t_fontset);
545   if (resource.mstyle.f_fontset)
546     XFreeFontSet(getBaseDisplay().getXDisplay(), resource.mstyle.f_fontset);
547   if (resource.tstyle.fontset)
548     XFreeFontSet(getBaseDisplay().getXDisplay(), resource.tstyle.fontset);
549
550   if (resource.wstyle.font)
551     XFreeFont(getBaseDisplay().getXDisplay(), resource.wstyle.font);
552   if (resource.mstyle.t_font)
553     XFreeFont(getBaseDisplay().getXDisplay(), resource.mstyle.t_font);
554   if (resource.mstyle.f_font)
555     XFreeFont(getBaseDisplay().getXDisplay(), resource.mstyle.f_font);
556   if (resource.tstyle.font)
557     XFreeFont(getBaseDisplay().getXDisplay(), resource.tstyle.font);
558   if (resource.root_command != NULL)
559     delete [] resource.root_command;
560
561   XFreeGC(getBaseDisplay().getXDisplay(), opGC);
562
563   XFreeGC(getBaseDisplay().getXDisplay(),
564           resource.wstyle.l_text_focus_gc);
565   XFreeGC(getBaseDisplay().getXDisplay(),
566           resource.wstyle.l_text_unfocus_gc);
567   XFreeGC(getBaseDisplay().getXDisplay(),
568           resource.wstyle.b_pic_focus_gc);
569   XFreeGC(getBaseDisplay().getXDisplay(),
570           resource.wstyle.b_pic_unfocus_gc);
571
572   XFreeGC(getBaseDisplay().getXDisplay(),
573           resource.mstyle.t_text_gc);
574   XFreeGC(getBaseDisplay().getXDisplay(),
575           resource.mstyle.f_text_gc);
576   XFreeGC(getBaseDisplay().getXDisplay(),
577           resource.mstyle.h_text_gc);
578   XFreeGC(getBaseDisplay().getXDisplay(),
579           resource.mstyle.d_text_gc);
580   XFreeGC(getBaseDisplay().getXDisplay(),
581           resource.mstyle.hilite_gc);
582
583   XFreeGC(getBaseDisplay().getXDisplay(),
584           resource.tstyle.l_text_gc);
585   XFreeGC(getBaseDisplay().getXDisplay(),
586           resource.tstyle.w_text_gc);
587   XFreeGC(getBaseDisplay().getXDisplay(),
588           resource.tstyle.c_text_gc);
589   XFreeGC(getBaseDisplay().getXDisplay(),
590           resource.tstyle.b_pic_gc);
591 }
592
593
594 Rect BScreen::availableArea() const {
595   // the following code is temporary and will be taken care of by Screen in the
596   // future (with the NETWM 'strut')
597   Rect space(0, 0, size().w(), size().h());
598   if (!resource.full_max) {
599 #ifdef    SLIT
600     int slit_x = slit->autoHide() ? slit->hiddenOrigin().x() : slit->area().x(),
601     slit_y = slit->autoHide() ? slit->hiddenOrigin().y() : slit->area().y();
602     int tbarh = resource.hide_toolbar ? 0 :
603       toolbar->getExposedHeight() + resource.border_width * 2;
604     bool tbartop;
605     switch (toolbar->placement()) {
606     case Toolbar::TopLeft:
607     case Toolbar::TopCenter:
608     case Toolbar::TopRight:
609       tbartop = true;
610       break;
611     case Toolbar::BottomLeft:
612     case Toolbar::BottomCenter:
613     case Toolbar::BottomRight:
614       tbartop = false;
615       break;
616     default:
617       ASSERT(false);      // unhandled placement
618     }
619     if ((slit->direction() == Slit::Horizontal &&
620          (slit->placement() == Slit::TopLeft ||
621           slit->placement() == Slit::TopRight)) ||
622         slit->placement() == Slit::TopCenter) {
623       // exclude top
624       if (tbartop && slit_y + slit->area().h() < tbarh) {
625         space.setY(space.y() + tbarh);
626         space.setH(space.h() - tbarh);
627       } else {
628         space.setY(space.y() + (slit_y + slit->area().h() +
629                                 resource.border_width * 2));
630         space.setH(space.h() - (slit_y + slit->area().h() +
631                                 resource.border_width * 2));
632         if (!tbartop)
633           space.setH(space.h() - tbarh);
634       }
635     } else if ((slit->direction() == Slit::Vertical &&
636                 (slit->placement() == Slit::TopRight ||
637                  slit->placement() == Slit::BottomRight)) ||
638                slit->placement() == Slit::CenterRight) {
639       // exclude right
640       space.setW(space.w() - (size().w() - slit_x));
641       if (tbartop)
642         space.setY(space.y() + tbarh);
643       space.setH(space.h() - tbarh);
644     } else if ((slit->direction() == Slit::Horizontal &&
645                 (slit->placement() == Slit::BottomLeft ||
646                  slit->placement() == Slit::BottomRight)) ||
647                slit->placement() == Slit::BottomCenter) {
648       // exclude bottom
649       if (!tbartop && (size().h() - slit_y) < tbarh) {
650         space.setH(space.h() - tbarh);
651       } else {
652         space.setH(space.h() - (size().h() - slit_y));
653         if (tbartop) {
654           space.setY(space.y() + tbarh);
655           space.setH(space.h() - tbarh);
656         }
657       }
658     } else {// if ((slit->direction() == Slit::Vertical &&
659       //      (slit->placement() == Slit::TopLeft ||
660       //       slit->placement() == Slit::BottomLeft)) ||
661       //     slit->placement() == Slit::CenterLeft)
662       // exclude left
663       space.setX(slit_x + slit->area().w() +
664                  resource.border_width * 2);
665       space.setW(space.w() - (slit_x + slit->area().w() +
666                               resource.border_width * 2));
667       if (tbartop)
668         space.setY(space.y() + tbarh);
669       space.setH(space.h() - tbarh);
670     }
671 #else // !SLIT
672     int tbarh = resource.hide_toolbar() ? 0 :
673       toolbar->getExposedHeight() + resource.border_width * 2;
674     switch (toolbar->placement()) {
675     case Toolbar::TopLeft:
676     case Toolbar::TopCenter:
677     case Toolbar::TopRight:
678       space.setY(toolbar->getExposedHeight());
679       space.setH(space.h() - toolbar->getExposedHeight());
680       break;
681     case Toolbar::BottomLeft:
682     case Toolbar::BottomCenter:
683     case Toolbar::BottomRight:
684       space.setH(space.h() - tbarh);
685       break;
686     default:
687       ASSERT(false);      // unhandled placement
688     }
689 #endif // SLIT
690   }
691   return space;
692 }
693
694
695 void BScreen::readDatabaseTexture(const char *rname, const char *rclass,
696                                   BTexture *texture,
697                                   unsigned long default_pixel)
698 {
699   std::string s;
700   
701   if (resource.styleconfig.getValue(rname, rclass, s))
702     image_control->parseTexture(texture, s.c_str());
703   else
704     texture->setTexture(BImage_Solid | BImage_Flat);
705
706   if (texture->getTexture() & BImage_Solid) {
707     int clen = strlen(rclass) + 32, nlen = strlen(rname) + 32;
708
709     char *colorclass = new char[clen], *colorname = new char[nlen];
710
711     sprintf(colorclass, "%s.Color", rclass);
712     sprintf(colorname,  "%s.color", rname);
713
714     readDatabaseColor(colorname, colorclass, texture->getColor(),
715                       default_pixel);
716
717 #ifdef    INTERLACE
718     sprintf(colorclass, "%s.ColorTo", rclass);
719     sprintf(colorname,  "%s.colorTo", rname);
720
721     readDatabaseColor(colorname, colorclass, texture->getColorTo(),
722                       default_pixel);
723 #endif // INTERLACE
724
725     delete [] colorclass;
726     delete [] colorname;
727
728     if ((! texture->getColor()->isAllocated()) ||
729         (texture->getTexture() & BImage_Flat))
730       return;
731
732     XColor xcol;
733
734     xcol.red = (unsigned int) (texture->getColor()->getRed() +
735                                (texture->getColor()->getRed() >> 1));
736     if (xcol.red >= 0xff) xcol.red = 0xffff;
737     else xcol.red *= 0xff;
738     xcol.green = (unsigned int) (texture->getColor()->getGreen() +
739                                  (texture->getColor()->getGreen() >> 1));
740     if (xcol.green >= 0xff) xcol.green = 0xffff;
741     else xcol.green *= 0xff;
742     xcol.blue = (unsigned int) (texture->getColor()->getBlue() +
743                                 (texture->getColor()->getBlue() >> 1));
744     if (xcol.blue >= 0xff) xcol.blue = 0xffff;
745     else xcol.blue *= 0xff;
746
747     if (! XAllocColor(getBaseDisplay().getXDisplay(),
748                       getColormap(), &xcol))
749       xcol.pixel = 0;
750
751     texture->getHiColor()->setPixel(xcol.pixel);
752
753     xcol.red =
754       (unsigned int) ((texture->getColor()->getRed() >> 2) +
755                       (texture->getColor()->getRed() >> 1)) * 0xff;
756     xcol.green =
757       (unsigned int) ((texture->getColor()->getGreen() >> 2) +
758                       (texture->getColor()->getGreen() >> 1)) * 0xff;
759     xcol.blue =
760       (unsigned int) ((texture->getColor()->getBlue() >> 2) +
761                       (texture->getColor()->getBlue() >> 1)) * 0xff;
762
763     if (! XAllocColor(getBaseDisplay().getXDisplay(),
764                       getColormap(), &xcol))
765       xcol.pixel = 0;
766
767     texture->getLoColor()->setPixel(xcol.pixel);
768   } else if (texture->getTexture() & BImage_Gradient) {
769     int clen = strlen(rclass) + 10, nlen = strlen(rname) + 10;
770
771     char *colorclass = new char[clen], *colorname = new char[nlen],
772       *colortoclass = new char[clen], *colortoname = new char[nlen];
773
774     sprintf(colorclass, "%s.Color", rclass);
775     sprintf(colorname,  "%s.color", rname);
776
777     sprintf(colortoclass, "%s.ColorTo", rclass);
778     sprintf(colortoname,  "%s.colorTo", rname);
779
780     readDatabaseColor(colorname, colorclass, texture->getColor(),
781                       default_pixel);
782     readDatabaseColor(colortoname, colortoclass, texture->getColorTo(),
783                       default_pixel);
784
785     delete [] colorclass;
786     delete [] colorname;
787     delete [] colortoclass;
788     delete [] colortoname;
789   }
790 }
791
792
793 void BScreen::readDatabaseColor(const char *rname, const  char *rclass,
794                                 BColor *color, unsigned long default_pixel)
795 {
796   std::string s;
797   
798   if (resource.styleconfig.getValue(rname, rclass, s))
799     image_control->parseColor(color, s.c_str());
800   else {
801     // parsing with no color string just deallocates the color, if it has
802     // been previously allocated
803     image_control->parseColor(color);
804     color->setPixel(default_pixel);
805   }
806 }
807
808
809 void BScreen::readDatabaseFontSet(const char *rname, const char *rclass,
810                                   XFontSet *fontset) {
811   if (! fontset) return;
812
813   static char *defaultFont = "fixed";
814   bool load_default = false;
815   std::string s;
816
817   if (*fontset)
818     XFreeFontSet(getBaseDisplay().getXDisplay(), *fontset);
819
820   if (resource.styleconfig.getValue(rname, rclass, s)) {
821     if (! (*fontset = createFontSet(s.c_str())))
822       load_default = true;
823   } else
824     load_default = true;
825
826   if (load_default) {
827     *fontset = createFontSet(defaultFont);
828
829     if (! *fontset) {
830       fprintf(stderr, i18n->getMessage(ScreenSet, ScreenDefaultFontLoadFail,
831                        "BScreen::LoadStyle(): couldn't load default font.\n"));
832       exit(2);
833     }
834   }
835 }
836
837
838 void BScreen::readDatabaseFont(const char *rname, const char *rclass,
839                                XFontStruct **font) {
840   if (! font) return;
841
842   static char *defaultFont = "fixed";
843   bool load_default = false;
844   std::string s;
845
846   if (*font)
847     XFreeFont(getBaseDisplay().getXDisplay(), *font);
848
849   if (resource.styleconfig.getValue(rname, rclass, s)) {
850     if ((*font = XLoadQueryFont(getBaseDisplay().getXDisplay(),
851                                 s.c_str())) == NULL) {
852       fprintf(stderr, i18n->getMessage(ScreenSet, ScreenFontLoadFail,
853                          "BScreen::LoadStyle(): couldn't load font '%s'\n"),
854               s.c_str());
855       load_default = true;
856     }
857   } else
858     load_default = true;
859
860   if (load_default) {
861     if ((*font = XLoadQueryFont(getBaseDisplay().getXDisplay(),
862                                 defaultFont)) == NULL) {
863       fprintf(stderr, i18n->getMessage(ScreenSet, ScreenDefaultFontLoadFail,
864                  "BScreen::LoadStyle(): couldn't load default font.\n"));
865       exit(2);
866     }
867   }
868 }
869
870
871 XFontSet BScreen::createFontSet(const char *fontname) {
872   XFontSet fs;
873   char **missing, *def = "-";
874   int nmissing, pixel_size = 0, buf_size = 0;
875   char weight[FONT_ELEMENT_SIZE], slant[FONT_ELEMENT_SIZE];
876
877   fs = XCreateFontSet(getBaseDisplay().getXDisplay(),
878                       fontname, &missing, &nmissing, &def);
879   if (fs && (! nmissing)) return fs;
880
881 #ifdef    HAVE_SETLOCALE
882   if (! fs) {
883     if (nmissing) XFreeStringList(missing);
884
885     setlocale(LC_CTYPE, "C");
886     fs = XCreateFontSet(getBaseDisplay().getXDisplay(), fontname,
887                         &missing, &nmissing, &def);
888     setlocale(LC_CTYPE, "");
889   }
890 #endif // HAVE_SETLOCALE
891
892   if (fs) {
893     XFontStruct **fontstructs;
894     char **fontnames;
895     XFontsOfFontSet(fs, &fontstructs, &fontnames);
896     fontname = fontnames[0];
897   }
898
899   getFontElement(fontname, weight, FONT_ELEMENT_SIZE,
900                  "-medium-", "-bold-", "-demibold-", "-regular-", NULL);
901   getFontElement(fontname, slant, FONT_ELEMENT_SIZE,
902                  "-r-", "-i-", "-o-", "-ri-", "-ro-", NULL);
903   getFontSize(fontname, &pixel_size);
904
905   if (! strcmp(weight, "*")) strncpy(weight, "medium", FONT_ELEMENT_SIZE);
906   if (! strcmp(slant, "*")) strncpy(slant, "r", FONT_ELEMENT_SIZE);
907   if (pixel_size < 3) pixel_size = 3;
908   else if (pixel_size > 97) pixel_size = 97;
909
910   buf_size = strlen(fontname) + (FONT_ELEMENT_SIZE * 2) + 64;
911   char *pattern2 = new char[buf_size];
912   snprintf(pattern2, buf_size - 1,
913            "%s,"
914            "-*-*-%s-%s-*-*-%d-*-*-*-*-*-*-*,"
915            "-*-*-*-*-*-*-%d-*-*-*-*-*-*-*,*",
916            fontname, weight, slant, pixel_size, pixel_size);
917   fontname = pattern2;
918
919   if (nmissing) XFreeStringList(missing);
920   if (fs) XFreeFontSet(getBaseDisplay().getXDisplay(), fs);
921
922   fs = XCreateFontSet(getBaseDisplay().getXDisplay(), fontname,
923                       &missing, &nmissing, &def);
924   delete [] pattern2;
925
926   return fs;
927 }
928
929
930 void BScreen::setSloppyFocus(bool b) {
931   resource.sloppy_focus = b;
932   std::ostrstream s;
933   s << "session.screen" << getScreenNumber() << ".focusModel" << ends;
934   config.setValue(s.str(),
935                   (resource.sloppy_focus ?
936                   (resource.auto_raise ? "AutoRaiseSloppyFocus" : "SloppyFocus")
937                   : "ClickToFocus"));
938   s.rdbuf()->freeze(0);
939 }
940
941
942 void BScreen::setAutoRaise(bool a) {
943   resource.auto_raise = a;
944   std::ostrstream s;
945   s << "session.screen" << getScreenNumber() << ".focusModel" << ends;
946   config.setValue(s.str(),
947                   (resource.sloppy_focus ?
948                   (resource.auto_raise ? "AutoRaiseSloppyFocus" : "SloppyFocus")
949                   : "ClickToFocus"));
950   s.rdbuf()->freeze(0);
951 }
952
953
954 void BScreen::setImageDither(bool d, bool reconfig) {
955   resource.image_dither = d;
956   image_control->setDither(d);
957   std::ostrstream s;
958   s << "session.screen" << getScreenNumber() << ".imageDither" << ends;
959   config.setValue(s.str(), resource.image_dither);
960   s.rdbuf()->freeze(0);
961   if (reconfig)
962     reconfigure();
963 }
964
965
966 void BScreen::setOpaqueMove(bool o) {
967   resource.opaque_move = o;
968   std::ostrstream s;
969   s << "session.screen" << getScreenNumber() << ".opaqueMove" << ends;
970   config.setValue(s.str(), resource.opaque_move);
971   s.rdbuf()->freeze(0);
972 }
973
974
975 void BScreen::setFullMax(bool f) {
976   resource.full_max = f;
977   std::ostrstream s;
978   s << "session.screen" << getScreenNumber() << ".fullMaximization" << ends;
979   config.setValue(s.str(), resource.full_max);
980   s.rdbuf()->freeze(0);
981 }
982
983
984 void BScreen::setFocusNew(bool f) {
985   resource.focus_new = f;
986   std::ostrstream s;
987   s << "session.screen" << getScreenNumber() << ".focusNewWindows" << ends;
988   config.setValue(s.str(), resource.focus_new);
989   s.rdbuf()->freeze(0);
990 }
991
992
993 void BScreen::setFocusLast(bool f) {
994   resource.focus_last = f;
995   std::ostrstream s;
996   s << "session.screen" << getScreenNumber() << ".focusLastWindow" << ends;
997   config.setValue(s.str(), resource.focus_last);
998   s.rdbuf()->freeze(0);
999 }
1000
1001
1002 void BScreen::setWindowZones(int z) {
1003   resource.zones = z;
1004   std::ostrstream s;
1005   s << "session.screen" << getScreenNumber() << ".windowZones" << ends;
1006   config.setValue(s.str(), resource.zones);
1007   s.rdbuf()->freeze(0);
1008 }
1009
1010
1011 void BScreen::setWorkspaceCount(int w) {
1012   resource.workspaces = w;
1013   std::ostrstream s;
1014   s << "session.screen" << getScreenNumber() << ".workspaces" << ends;
1015   config.setValue(s.str(), resource.workspaces);
1016   s.rdbuf()->freeze(0);
1017 }
1018
1019
1020 void BScreen::setPlacementPolicy(int p) {
1021   resource.placement_policy = p;
1022   std::ostrstream s;
1023   s << "session.screen" << getScreenNumber() << ".windowPlacement" << ends;
1024   const char *placement;
1025   switch (resource.placement_policy) {
1026   case CascadePlacement: placement = "CascadePlacement"; break;
1027   case BestFitPlacement: placement = "BestFitPlacement"; break;
1028   case ColSmartPlacement: placement = "ColSmartPlacement"; break;
1029   default:
1030   case RowSmartPlacement: placement = "RowSmartPlacement"; break;
1031   }
1032   config.setValue(s.str(), placement);
1033   s.rdbuf()->freeze(0);
1034 }
1035
1036
1037 void BScreen::setEdgeSnapThreshold(int t) {
1038   resource.edge_snap_threshold = t;
1039   std::ostrstream s;
1040   s << "session.screen" << getScreenNumber() << ".edgeSnapThreshold" << ends;
1041   config.setValue(s.str(), resource.edge_snap_threshold);
1042   s.rdbuf()->freeze(0);
1043 }
1044
1045
1046 void BScreen::setRowPlacementDirection(int d) {
1047   resource.row_direction = d;
1048   std::ostrstream s;
1049   s << "session.screen" << getScreenNumber() << ".rowPlacementDirection" <<
1050     ends;
1051   config.setValue(s.str(),
1052                   resource.row_direction == LeftRight ?
1053                   "LeftToRight" : "RightToLeft");
1054   s.rdbuf()->freeze(0);
1055 }
1056
1057
1058 void BScreen::setColPlacementDirection(int d) {
1059   resource.col_direction = d;
1060   std::ostrstream s;
1061   s << "session.screen" << getScreenNumber() << ".colPlacementDirection" <<
1062     ends;
1063   config.setValue(s.str(),
1064                   resource.col_direction == TopBottom ?
1065                   "TopToBottom" : "BottomToTop");
1066   s.rdbuf()->freeze(0);
1067 }
1068
1069
1070 void BScreen::setRootCommand(const char *cmd) {
1071 if (resource.root_command != NULL)
1072     delete [] resource.root_command;
1073   if (cmd != NULL)
1074     resource.root_command = bstrdup(cmd);
1075   else
1076     resource.root_command = NULL;
1077   // this doesn't save to the Resources config because it can't be changed
1078   // inside Openbox, and this way we dont add an empty command which would over-
1079   // ride the styles command when none has been specified
1080 }
1081
1082
1083 #ifdef    HAVE_STRFTIME
1084 void BScreen::setStrftimeFormat(const char *f) {
1085   if (resource.strftime_format != NULL)
1086     delete [] resource.strftime_format;
1087
1088   resource.strftime_format = bstrdup(f);
1089   std::ostrstream s;
1090   s << "session.screen" << getScreenNumber() << ".strftimeFormat" << ends;
1091   config.setValue(s.str(), resource.strftime_format);
1092   s.rdbuf()->freeze(0);
1093 }
1094
1095 #else // !HAVE_STRFTIME
1096 void BScreen::setDateFormat(int f) {
1097   resource.date_format = f;
1098   std::ostrstream s;
1099   s << "session.screen" << getScreenNumber() << ".dateFormat" << ends;
1100   config.setValue(s.str(), resource.date_format == B_EuropeanDate ?
1101                   "European" : "American");
1102   s.rdbuf()->freeze(0);
1103 }
1104
1105 void BScreen::setClock24Hour(Bool c) {
1106   resource.clock24hour = c;
1107   std::ostrstream s;
1108   s << "session.screen" << getScreenNumber() << ".clockFormat" << ends;
1109   config.setValue(s.str(), resource.clock24hour ? 24 : 12);
1110   s.rdbuf()->freeze(0);
1111 }
1112 #endif // HAVE_STRFTIME
1113
1114 void BScreen::setHideToolbar(bool b) {
1115   resource.hide_toolbar = b;
1116   if (resource.hide_toolbar)
1117     getToolbar()->unMapToolbar();
1118   else
1119     getToolbar()->mapToolbar();
1120   std::ostrstream s;
1121   s << "session.screen" << getScreenNumber() << ".hideToolbar" << ends;
1122   config.setValue(s.str(), resource.hide_toolbar ? "True" : "False");
1123   s.rdbuf()->freeze(0);
1124 }
1125
1126 void BScreen::saveWorkspaceNames() {
1127   std::ostrstream rc, names;
1128
1129   for (int i = 0; i < resource.workspaces; i++) {
1130     Workspace *w = getWorkspace(i);
1131     if (w != NULL) {
1132       names << w->getName();
1133       if (i < resource.workspaces-1)
1134         names << ',';
1135     }
1136   }
1137   names << ends;
1138
1139   rc << "session.screen" << getScreenNumber() << ".workspaceNames" << ends;
1140   config.setValue(rc.str(), names.str());
1141   rc.rdbuf()->freeze(0);
1142   names.rdbuf()->freeze(0);
1143 }
1144
1145 void BScreen::save() {
1146   setSloppyFocus(resource.sloppy_focus);
1147   setAutoRaise(resource.auto_raise);
1148   setImageDither(resource.image_dither, false);
1149   setOpaqueMove(resource.opaque_move);
1150   setFullMax(resource.full_max);
1151   setFocusNew(resource.focus_new);
1152   setFocusLast(resource.focus_last);
1153   setWindowZones(resource.zones);
1154   setWorkspaceCount(resource.workspaces);
1155   setPlacementPolicy(resource.placement_policy);
1156   setEdgeSnapThreshold(resource.edge_snap_threshold);
1157   setRowPlacementDirection(resource.row_direction);
1158   setColPlacementDirection(resource.col_direction);
1159   setRootCommand(resource.root_command);
1160 #ifdef    HAVE_STRFTIME
1161   // it deletes the current value before setting the new one, so we have to
1162   // duplicate the current value.
1163   std::string s = resource.strftime_format;
1164   setStrftimeFormat(s.c_str()); 
1165 #else // !HAVE_STRFTIME
1166   setDateFormat(resource.date_format);
1167   setClock24Hour(resource.clock24hour);
1168 #endif // HAVE_STRFTIME
1169   setHideToolbar(resource.hide_toolbar);
1170 }
1171
1172 void BScreen::load() {
1173   std::ostrstream rscreen, rname, rclass;
1174   std::string s;
1175   bool b;
1176   long l;
1177   rscreen << "session.screen" << getScreenNumber() << '.' << ends;
1178
1179   rname << rscreen.str() << "hideToolbar" << ends;
1180   rclass << rscreen.str() << "HideToolbar" << ends;
1181   if (config.getValue(rname.str(), rclass.str(), b))
1182     resource.hide_toolbar = b;
1183   else
1184     resource.hide_toolbar = false;
1185   Toolbar *t = getToolbar();
1186   if (t != NULL) {
1187     if (resource.hide_toolbar)
1188       t->unMapToolbar();
1189     else
1190       t->mapToolbar();
1191   }
1192
1193   rname.seekp(0); rclass.seekp(0);
1194   rname << rscreen.str() << "fullMaximization" << ends;
1195   rclass << rscreen.str() << "FullMaximization" << ends;
1196   if (config.getValue(rname.str(), rclass.str(), b))
1197     resource.full_max = b;
1198   else
1199     resource.full_max = false;
1200
1201   rname.seekp(0); rclass.seekp(0);
1202   rname << rscreen.str() << "focusNewWindows" << ends;
1203   rclass << rscreen.str() << "FocusNewWindows" << ends;
1204   if (config.getValue(rname.str(), rclass.str(), b))
1205     resource.focus_new = b;
1206   else
1207     resource.focus_new = false;
1208
1209   rname.seekp(0); rclass.seekp(0);
1210   rname << rscreen.str() << "focusLastWindow" << ends;
1211   rclass << rscreen.str() << "FocusLastWindow" << ends;
1212   if (config.getValue(rname.str(), rclass.str(), b))
1213     resource.focus_last = b;
1214   else
1215     resource.focus_last = false;
1216
1217   rname.seekp(0); rclass.seekp(0);
1218   rname << rscreen.str() << "rowPlacementDirection" << ends;
1219   rclass << rscreen.str() << "RowPlacementDirection" << ends;
1220   if (config.getValue(rname.str(), rclass.str(), s)) {
1221     if (0 == strncasecmp(s.c_str(), "RightToLeft", s.length()))
1222       resource.row_direction = RightLeft;
1223     else if (0 == strncasecmp(s.c_str(), "LeftToRight", s.length()))
1224       resource.row_direction = LeftRight;
1225   } else
1226     resource.row_direction = LeftRight;
1227
1228   rname.seekp(0); rclass.seekp(0);
1229   rname << rscreen.str() << "colPlacementDirection" << ends;
1230   rclass << rscreen.str() << "ColPlacementDirection" << ends;
1231   if (config.getValue(rname.str(), rclass.str(), s)) {
1232     if (0 == strncasecmp(s.c_str(), "BottomToTop", s.length()))
1233       resource.col_direction = BottomTop;
1234     else if (0 == strncasecmp(s.c_str(), "TopToBottom", s.length()))
1235       resource.col_direction = TopBottom;
1236   } else
1237     resource.col_direction = TopBottom;
1238
1239   rname.seekp(0); rclass.seekp(0);
1240   rname << rscreen.str() << "workspaces" << ends;
1241   rclass << rscreen.str() << "Workspaces" << ends;
1242   if (config.getValue(rname.str(), rclass.str(), l))
1243     resource.workspaces = l;
1244   else
1245     resource.workspaces = 1;
1246
1247   removeWorkspaceNames();
1248   rname.seekp(0); rclass.seekp(0);
1249   rname << rscreen.str() << "workspaceNames" << ends;
1250   rclass << rscreen.str() << "WorkspaceNames" << ends;
1251   if (config.getValue(rname.str(), rclass.str(), s)) {
1252     std::string::const_iterator it = s.begin(), end = s.end();
1253     while(1) {
1254       std::string::const_iterator tmp = it;// current string.begin()
1255       it = std::find(tmp, end, ',');       // look for comma between tmp and end
1256       std::string name(tmp, it);           // name = s[tmp:it]
1257       addWorkspaceName(name.c_str());
1258       if (it == end)
1259         break;
1260       ++it;
1261     }
1262   }
1263   
1264   rname.seekp(0); rclass.seekp(0);
1265   rname << rscreen.str() << "focusModel" << ends;
1266   rclass << rscreen.str() << "FocusModel" << ends;
1267   if (config.getValue(rname.str(), rclass.str(), s)) {
1268     if (0 == strncasecmp(s.c_str(), "ClickToFocus", s.length())) {
1269       resource.auto_raise = false;
1270       resource.sloppy_focus = false;
1271     } else if (0 == strncasecmp(s.c_str(), "AutoRaiseSloppyFocus",
1272                                 s.length())) {
1273       resource.sloppy_focus = true;
1274       resource.auto_raise = true;
1275     } else if (0 == strncasecmp(s.c_str(), "SloppyFocus", s.length())) {
1276       resource.sloppy_focus = true;
1277       resource.auto_raise = false;
1278     }
1279   } else {
1280     resource.sloppy_focus = true;
1281     resource.auto_raise = false;
1282   }
1283
1284   rname.seekp(0); rclass.seekp(0);
1285   rname << rscreen.str() << "windowZones" << ends;
1286   rclass << rscreen.str() << "WindowZones" << ends;
1287   if (config.getValue(rname.str(), rclass.str(), l))
1288     resource.zones = (l == 1 || l == 2 || l == 4) ? l : 1;
1289   else
1290     resource.zones = 4;
1291
1292   rname.seekp(0); rclass.seekp(0);
1293   rname << rscreen.str() << "windowPlacement" << ends;
1294   rclass << rscreen.str() << "WindowPlacement" << ends;
1295   if (config.getValue(rname.str(), rclass.str(), s)) {
1296     if (0 == strncasecmp(s.c_str(), "RowSmartPlacement", s.length()))
1297       resource.placement_policy = RowSmartPlacement;
1298     else if (0 == strncasecmp(s.c_str(), "ColSmartPlacement", s.length()))
1299       resource.placement_policy = ColSmartPlacement;
1300     else if (0 == strncasecmp(s.c_str(), "BestFitPlacement", s.length()))
1301       resource.placement_policy = BestFitPlacement;
1302     else if (0 == strncasecmp(s.c_str(), "CascadePlacement", s.length()))
1303       resource.placement_policy = CascadePlacement;
1304   } else
1305     resource.placement_policy = CascadePlacement;
1306
1307 #ifdef    HAVE_STRFTIME
1308   rname.seekp(0); rclass.seekp(0);
1309   rname << rscreen.str() << "strftimeFormat" << ends;
1310   rclass << rscreen.str() << "StrftimeFormat" << ends;
1311
1312   if (resource.strftime_format != NULL)
1313     delete [] resource.strftime_format;
1314
1315   if (config.getValue(rname.str(), rclass.str(), s))
1316     resource.strftime_format = bstrdup(s.c_str());
1317   else
1318     resource.strftime_format = bstrdup("%I:%M %p");
1319 #else // !HAVE_STRFTIME
1320   rname.seekp(0); rclass.seekp(0);
1321   rname << rscreen.str() << "dateFormat" << ends;
1322   rclass << rscreen.str() << "DateFormat" << ends;
1323   if (config.getValue(rname.str(), rclass.str(), s)) {
1324     if (strncasecmp(s.c_str(), "European", s.length()))
1325       resource.date_format = B_EuropeanDate;
1326     else if (strncasecmp(s.c_str(), "American", s.length()))
1327       resource.date_format = B_AmericanDate;
1328   } else
1329     resource.date_format = B_AmericanDate;
1330
1331   rname.seekp(0); rclass.seekp(0);
1332   rname << rscreen.str() << "clockFormat" << ends;
1333   rclass << rscreen.str() << "ClockFormat" << ends;
1334   if (config.getValue(rname.str(), rclass.str(), l)) {
1335     if (clock == 24)
1336       resource.clock24hour = true;
1337     else if (clock == 12)
1338       resource.clock24hour =  false;
1339   } else
1340     resource.clock24hour =  false;
1341 #endif // HAVE_STRFTIME
1342
1343   rname.seekp(0); rclass.seekp(0);
1344   rname << rscreen.str() << "edgeSnapThreshold" << ends;
1345   rclass << rscreen.str() << "EdgeSnapThreshold" << ends;
1346   if (config.getValue(rname.str(), rclass.str(), l))
1347     resource.edge_snap_threshold = l;
1348   else
1349     resource.edge_snap_threshold = 4;
1350
1351   rname.seekp(0); rclass.seekp(0);
1352   rname << rscreen.str() << "imageDither" << ends;
1353   rclass << rscreen.str() << "ImageDither" << ends;
1354   if (config.getValue(rname.str(), rclass.str(), b))
1355     resource.image_dither = b;
1356   else
1357     resource.image_dither = true;
1358
1359   rname.seekp(0); rclass.seekp(0);
1360   rname << rscreen.str() << "rootCommand" << ends;
1361   rclass << rscreen.str() << "RootCommand" << ends;
1362
1363   if (resource.root_command != NULL)
1364     delete [] resource.root_command;
1365   
1366   if (config.getValue(rname.str(), rclass.str(), s))
1367     resource.root_command = bstrdup(s.c_str());
1368   else
1369     resource.root_command = NULL;
1370
1371   rname.seekp(0); rclass.seekp(0);
1372   rname << rscreen.str() << "opaqueMove" << ends;
1373   rclass << rscreen.str() << "OpaqueMove" << ends;
1374   if (config.getValue(rname.str(), rclass.str(), b))
1375     resource.opaque_move = b;
1376   else
1377     resource.opaque_move = false;
1378
1379   rscreen.rdbuf()->freeze(0);
1380   rname.rdbuf()->freeze(0);
1381   rclass.rdbuf()->freeze(0);
1382 }
1383
1384 void BScreen::reconfigure(void) {
1385   load();
1386   toolbar->load();
1387 #ifdef    SLIT
1388   slit->load();
1389 #endif // SLIT
1390   LoadStyle();
1391
1392   XGCValues gcv;
1393   unsigned long gc_value_mask = GCForeground;
1394   if (! i18n->multibyte()) gc_value_mask |= GCFont;
1395
1396   gcv.foreground = WhitePixel(getBaseDisplay().getXDisplay(),
1397                               getScreenNumber());
1398   gcv.function = GXinvert;
1399   gcv.subwindow_mode = IncludeInferiors;
1400   XChangeGC(getBaseDisplay().getXDisplay(), opGC,
1401             GCForeground | GCFunction | GCSubwindowMode, &gcv);
1402
1403   gcv.foreground = resource.wstyle.l_text_focus.getPixel();
1404   if (resource.wstyle.font)
1405     gcv.font = resource.wstyle.font->fid;
1406   XChangeGC(getBaseDisplay().getXDisplay(), resource.wstyle.l_text_focus_gc,
1407             gc_value_mask, &gcv);
1408
1409   gcv.foreground = resource.wstyle.l_text_unfocus.getPixel();
1410   XChangeGC(getBaseDisplay().getXDisplay(), resource.wstyle.l_text_unfocus_gc,
1411             gc_value_mask, &gcv);
1412
1413   gcv.foreground = resource.wstyle.b_pic_focus.getPixel();
1414   XChangeGC(getBaseDisplay().getXDisplay(), resource.wstyle.b_pic_focus_gc,
1415             GCForeground, &gcv);
1416
1417   gcv.foreground = resource.wstyle.b_pic_unfocus.getPixel();
1418   XChangeGC(getBaseDisplay().getXDisplay(), resource.wstyle.b_pic_unfocus_gc,
1419             GCForeground, &gcv);
1420
1421   gcv.foreground = resource.mstyle.t_text.getPixel();
1422   if (resource.mstyle.t_font)
1423     gcv.font = resource.mstyle.t_font->fid;
1424   XChangeGC(getBaseDisplay().getXDisplay(), resource.mstyle.t_text_gc,
1425             gc_value_mask, &gcv);
1426
1427   gcv.foreground = resource.mstyle.f_text.getPixel();
1428   if (resource.mstyle.f_font)
1429     gcv.font = resource.mstyle.f_font->fid;
1430   XChangeGC(getBaseDisplay().getXDisplay(), resource.mstyle.f_text_gc,
1431             gc_value_mask, &gcv);
1432
1433   gcv.foreground = resource.mstyle.h_text.getPixel();
1434   XChangeGC(getBaseDisplay().getXDisplay(), resource.mstyle.h_text_gc,
1435             gc_value_mask, &gcv);
1436
1437   gcv.foreground = resource.mstyle.d_text.getPixel();
1438   XChangeGC(getBaseDisplay().getXDisplay(), resource.mstyle.d_text_gc,
1439             gc_value_mask, &gcv);
1440
1441   gcv.foreground = resource.mstyle.hilite.getColor()->getPixel();
1442   XChangeGC(getBaseDisplay().getXDisplay(), resource.mstyle.hilite_gc,
1443             gc_value_mask, &gcv);
1444
1445   gcv.foreground = resource.tstyle.l_text.getPixel();
1446   if (resource.tstyle.font)
1447     gcv.font = resource.tstyle.font->fid;
1448   XChangeGC(getBaseDisplay().getXDisplay(), resource.tstyle.l_text_gc,
1449             gc_value_mask, &gcv);
1450
1451   gcv.foreground = resource.tstyle.w_text.getPixel();
1452   XChangeGC(getBaseDisplay().getXDisplay(), resource.tstyle.w_text_gc,
1453             gc_value_mask, &gcv);
1454
1455   gcv.foreground = resource.tstyle.c_text.getPixel();
1456   XChangeGC(getBaseDisplay().getXDisplay(), resource.tstyle.c_text_gc,
1457             gc_value_mask, &gcv);
1458
1459   gcv.foreground = resource.tstyle.b_pic.getPixel();
1460   XChangeGC(getBaseDisplay().getXDisplay(), resource.tstyle.b_pic_gc,
1461             gc_value_mask, &gcv);
1462
1463   const char *s = i18n->getMessage(ScreenSet, ScreenPositionLength,
1464                                    "0: 0000 x 0: 0000");
1465   int l = strlen(s);
1466
1467   if (i18n->multibyte()) {
1468     XRectangle ink, logical;
1469     XmbTextExtents(resource.wstyle.fontset, s, l, &ink, &logical);
1470     geom_w = logical.width;
1471
1472     geom_h = resource.wstyle.fontset_extents->max_ink_extent.height;
1473   } else {
1474     geom_w = XTextWidth(resource.wstyle.font, s, l);
1475
1476     geom_h = resource.wstyle.font->ascent +
1477              resource.wstyle.font->descent; 
1478   }
1479
1480   geom_w += (resource.bevel_width * 2);
1481   geom_h += (resource.bevel_width * 2);
1482
1483   Pixmap tmp = geom_pixmap;
1484   if (resource.wstyle.l_focus.getTexture() & BImage_ParentRelative) {
1485     if (resource.wstyle.t_focus.getTexture() ==
1486                                       (BImage_Flat | BImage_Solid)) {
1487       geom_pixmap = None;
1488       XSetWindowBackground(getBaseDisplay().getXDisplay(), geom_window,
1489                          resource.wstyle.t_focus.getColor()->getPixel());
1490     } else {
1491       geom_pixmap = image_control->renderImage(geom_w, geom_h,
1492                                                &resource.wstyle.t_focus);
1493       XSetWindowBackgroundPixmap(getBaseDisplay().getXDisplay(),
1494                                  geom_window, geom_pixmap);
1495     }
1496   } else {
1497     if (resource.wstyle.l_focus.getTexture() ==
1498                                       (BImage_Flat | BImage_Solid)) {
1499       geom_pixmap = None;
1500       XSetWindowBackground(getBaseDisplay().getXDisplay(), geom_window,
1501                          resource.wstyle.l_focus.getColor()->getPixel());
1502     } else {
1503       geom_pixmap = image_control->renderImage(geom_w, geom_h,
1504                                                &resource.wstyle.l_focus);
1505       XSetWindowBackgroundPixmap(getBaseDisplay().getXDisplay(),
1506                                  geom_window, geom_pixmap);
1507     }
1508   }
1509   if (tmp) image_control->removeImage(tmp);
1510
1511   XSetWindowBorderWidth(getBaseDisplay().getXDisplay(), geom_window,
1512                         resource.border_width);
1513   XSetWindowBorder(getBaseDisplay().getXDisplay(), geom_window,
1514                    resource.border_color.getPixel());
1515
1516   workspacemenu->reconfigure();
1517   iconmenu->reconfigure();
1518
1519   {
1520     int remember_sub = rootmenu->getCurrentSubmenu();
1521     InitMenu();
1522     raiseWindows(0, 0);
1523     rootmenu->reconfigure();
1524     rootmenu->drawSubmenu(remember_sub);
1525   }
1526
1527   configmenu->reconfigure();
1528
1529   toolbar->reconfigure();
1530
1531 #ifdef    SLIT
1532   slit->reconfigure();
1533 #endif // SLIT
1534
1535   LinkedListIterator<Workspace> wit(workspacesList);
1536   for (Workspace *w = wit.current(); w; wit++, w = wit.current())
1537     w->reconfigure();
1538
1539   LinkedListIterator<OpenboxWindow> iit(iconList);
1540   for (OpenboxWindow *bw = iit.current(); bw; iit++, bw = iit.current())
1541     if (bw->validateClient())
1542       bw->reconfigure();
1543
1544   image_control->timeout();
1545 }
1546
1547
1548 void BScreen::rereadMenu(void) {
1549   InitMenu();
1550   raiseWindows(0, 0);
1551
1552   rootmenu->reconfigure();
1553 }
1554
1555
1556 void BScreen::removeWorkspaceNames(void) {
1557   while (workspaceNames->count())
1558     delete [] workspaceNames->remove(0);
1559 }
1560
1561
1562 void BScreen::LoadStyle(void) {
1563   Resource &conf = resource.styleconfig;
1564   
1565   const char *sfile = openbox.getStyleFilename();
1566   bool loaded = false;
1567   if (sfile != NULL) {
1568     conf.setFile(sfile);
1569     loaded = conf.load();
1570   }
1571   if (!loaded) {
1572     conf.setFile(DEFAULTSTYLE);
1573     if (!conf.load()) {
1574       fprintf(stderr, i18n->getMessage(ScreenSet, ScreenDefaultStyleLoadFail,
1575                                        "BScreen::LoadStyle(): couldn't load "
1576                                        "default style.\n"));
1577       exit(2);
1578     }
1579   }
1580
1581   std::string s;
1582   long l;
1583   
1584   // load fonts/fontsets
1585
1586   if (i18n->multibyte()) {
1587     readDatabaseFontSet("window.font", "Window.Font",
1588                         &resource.wstyle.fontset);
1589     readDatabaseFontSet("toolbar.font", "Toolbar.Font",
1590                         &resource.tstyle.fontset);
1591     readDatabaseFontSet("menu.title.font", "Menu.Title.Font",
1592                         &resource.mstyle.t_fontset);
1593     readDatabaseFontSet("menu.frame.font", "Menu.Frame.Font",
1594                         &resource.mstyle.f_fontset);
1595
1596     resource.mstyle.t_fontset_extents =
1597       XExtentsOfFontSet(resource.mstyle.t_fontset);
1598     resource.mstyle.f_fontset_extents =
1599       XExtentsOfFontSet(resource.mstyle.f_fontset);
1600     resource.tstyle.fontset_extents =
1601       XExtentsOfFontSet(resource.tstyle.fontset);
1602     resource.wstyle.fontset_extents =
1603       XExtentsOfFontSet(resource.wstyle.fontset);
1604   } else {
1605     readDatabaseFont("window.font", "Window.Font",
1606                      &resource.wstyle.font);
1607     readDatabaseFont("menu.title.font", "Menu.Title.Font",
1608                      &resource.mstyle.t_font);
1609     readDatabaseFont("menu.frame.font", "Menu.Frame.Font",
1610                      &resource.mstyle.f_font);
1611     readDatabaseFont("toolbar.font", "Toolbar.Font",
1612                      &resource.tstyle.font);
1613   }
1614
1615   // load window config
1616   readDatabaseTexture("window.title.focus", "Window.Title.Focus",
1617                       &resource.wstyle.t_focus,
1618                       WhitePixel(getBaseDisplay().getXDisplay(),
1619                                  getScreenNumber()));
1620   readDatabaseTexture("window.title.unfocus", "Window.Title.Unfocus",
1621                       &resource.wstyle.t_unfocus,
1622                       BlackPixel(getBaseDisplay().getXDisplay(),
1623                                  getScreenNumber()));
1624   readDatabaseTexture("window.label.focus", "Window.Label.Focus",
1625                       &resource.wstyle.l_focus,
1626                       WhitePixel(getBaseDisplay().getXDisplay(),
1627                                  getScreenNumber()));
1628   readDatabaseTexture("window.label.unfocus", "Window.Label.Unfocus",
1629                       &resource.wstyle.l_unfocus,
1630                       BlackPixel(getBaseDisplay().getXDisplay(),
1631                                  getScreenNumber()));
1632   readDatabaseTexture("window.handle.focus", "Window.Handle.Focus",
1633                       &resource.wstyle.h_focus,
1634                       WhitePixel(getBaseDisplay().getXDisplay(),
1635                                  getScreenNumber()));
1636   readDatabaseTexture("window.handle.unfocus", "Window.Handle.Unfocus",
1637                       &resource.wstyle.h_unfocus,
1638                       BlackPixel(getBaseDisplay().getXDisplay(),
1639                                  getScreenNumber()));
1640   readDatabaseTexture("window.grip.focus", "Window.Grip.Focus",
1641                       &resource.wstyle.g_focus,
1642                       WhitePixel(getBaseDisplay().getXDisplay(),
1643                                  getScreenNumber()));
1644   readDatabaseTexture("window.grip.unfocus", "Window.Grip.Unfocus",
1645                       &resource.wstyle.g_unfocus,
1646                       BlackPixel(getBaseDisplay().getXDisplay(),
1647                                  getScreenNumber()));
1648   readDatabaseTexture("window.button.focus", "Window.Button.Focus",
1649                       &resource.wstyle.b_focus,
1650                       WhitePixel(getBaseDisplay().getXDisplay(),
1651                                  getScreenNumber()));
1652   readDatabaseTexture("window.button.unfocus", "Window.Button.Unfocus",
1653                       &resource.wstyle.b_unfocus,
1654                       BlackPixel(getBaseDisplay().getXDisplay(),
1655                                  getScreenNumber()));
1656   readDatabaseTexture("window.button.pressed", "Window.Button.Pressed",
1657                       &resource.wstyle.b_pressed,
1658                       BlackPixel(getBaseDisplay().getXDisplay(),
1659                                  getScreenNumber()));
1660   readDatabaseColor("window.frame.focusColor",
1661                     "Window.Frame.FocusColor",
1662                     &resource.wstyle.f_focus,
1663                     WhitePixel(getBaseDisplay().getXDisplay(),
1664                                getScreenNumber()));
1665   readDatabaseColor("window.frame.unfocusColor",
1666                     "Window.Frame.UnfocusColor",
1667                     &resource.wstyle.f_unfocus,
1668                     BlackPixel(getBaseDisplay().getXDisplay(),
1669                                getScreenNumber()));
1670   readDatabaseColor("window.label.focus.textColor",
1671                     "Window.Label.Focus.TextColor",
1672                     &resource.wstyle.l_text_focus,
1673                     BlackPixel(getBaseDisplay().getXDisplay(),
1674                                getScreenNumber()));
1675   readDatabaseColor("window.label.unfocus.textColor",
1676                     "Window.Label.Unfocus.TextColor",
1677                     &resource.wstyle.l_text_unfocus,
1678                     WhitePixel(getBaseDisplay().getXDisplay(),
1679                                getScreenNumber()));
1680   readDatabaseColor("window.button.focus.picColor",
1681                     "Window.Button.Focus.PicColor",
1682                     &resource.wstyle.b_pic_focus,
1683                     BlackPixel(getBaseDisplay().getXDisplay(),
1684                                getScreenNumber()));
1685   readDatabaseColor("window.button.unfocus.picColor",
1686                     "Window.Button.Unfocus.PicColor",
1687                     &resource.wstyle.b_pic_unfocus,
1688                     WhitePixel(getBaseDisplay().getXDisplay(),
1689                                getScreenNumber()));
1690
1691   if (conf.getValue("window.justify", "Window.Justify", s)) {
1692     if (0 == strncasecmp(s.c_str(), "right", s.length()))
1693       resource.wstyle.justify = BScreen::RightJustify;
1694     else if (0 == strncasecmp(s.c_str(), "center", s.length()))
1695       resource.wstyle.justify = BScreen::CenterJustify;
1696     else
1697       resource.wstyle.justify = BScreen::LeftJustify;
1698   } else
1699     resource.wstyle.justify = BScreen::LeftJustify;
1700
1701   // load toolbar config
1702   readDatabaseTexture("toolbar", "Toolbar",
1703                       &resource.tstyle.toolbar,
1704                       BlackPixel(getBaseDisplay().getXDisplay(),
1705                                  getScreenNumber()));
1706   readDatabaseTexture("toolbar.label", "Toolbar.Label",
1707                       &resource.tstyle.label,
1708                       BlackPixel(getBaseDisplay().getXDisplay(),
1709                                  getScreenNumber()));
1710   readDatabaseTexture("toolbar.windowLabel", "Toolbar.WindowLabel",
1711                       &resource.tstyle.window,
1712                       BlackPixel(getBaseDisplay().getXDisplay(),
1713                                  getScreenNumber()));
1714   readDatabaseTexture("toolbar.button", "Toolbar.Button",
1715                       &resource.tstyle.button,
1716                       WhitePixel(getBaseDisplay().getXDisplay(),
1717                                  getScreenNumber()));
1718   readDatabaseTexture("toolbar.button.pressed", "Toolbar.Button.Pressed",
1719                       &resource.tstyle.pressed,
1720                       BlackPixel(getBaseDisplay().getXDisplay(),
1721                                  getScreenNumber()));
1722   readDatabaseTexture("toolbar.clock", "Toolbar.Clock",
1723                       &resource.tstyle.clock,
1724                       BlackPixel(getBaseDisplay().getXDisplay(),
1725                                  getScreenNumber()));
1726   readDatabaseColor("toolbar.label.textColor", "Toolbar.Label.TextColor",
1727                     &resource.tstyle.l_text,
1728                     WhitePixel(getBaseDisplay().getXDisplay(),
1729                                getScreenNumber()));
1730   readDatabaseColor("toolbar.windowLabel.textColor",
1731                     "Toolbar.WindowLabel.TextColor",
1732                     &resource.tstyle.w_text,
1733                     WhitePixel(getBaseDisplay().getXDisplay(),
1734                                getScreenNumber()));
1735   readDatabaseColor("toolbar.clock.textColor", "Toolbar.Clock.TextColor",
1736                     &resource.tstyle.c_text,
1737                     WhitePixel(getBaseDisplay().getXDisplay(),
1738                                getScreenNumber()));
1739   readDatabaseColor("toolbar.button.picColor", "Toolbar.Button.PicColor",
1740                     &resource.tstyle.b_pic,
1741                     BlackPixel(getBaseDisplay().getXDisplay(),
1742                                getScreenNumber()));
1743
1744   if (conf.getValue("toolbar.justify", "Toolbar.Justify", s)) {
1745     if (0 == strncasecmp(s.c_str(), "right", s.length()))
1746       resource.tstyle.justify = BScreen::RightJustify;
1747     else if (0 == strncasecmp(s.c_str(), "center", s.length()))
1748       resource.tstyle.justify = BScreen::CenterJustify;
1749     else
1750       resource.tstyle.justify = BScreen::LeftJustify;
1751   } else
1752     resource.tstyle.justify = BScreen::LeftJustify;
1753
1754   // load menu config
1755   readDatabaseTexture("menu.title", "Menu.Title",
1756                       &resource.mstyle.title,
1757                       WhitePixel(getBaseDisplay().getXDisplay(),
1758                                  getScreenNumber()));
1759   readDatabaseTexture("menu.frame", "Menu.Frame",
1760                       &resource.mstyle.frame,
1761                       BlackPixel(getBaseDisplay().getXDisplay(),
1762                                  getScreenNumber()));
1763   readDatabaseTexture("menu.hilite", "Menu.Hilite",
1764                       &resource.mstyle.hilite,
1765                       WhitePixel(getBaseDisplay().getXDisplay(),
1766                                  getScreenNumber()));
1767   readDatabaseColor("menu.title.textColor", "Menu.Title.TextColor",
1768                     &resource.mstyle.t_text,
1769                     BlackPixel(getBaseDisplay().getXDisplay(),
1770                                getScreenNumber()));
1771   readDatabaseColor("menu.frame.textColor", "Menu.Frame.TextColor",
1772                     &resource.mstyle.f_text,
1773                     WhitePixel(getBaseDisplay().getXDisplay(),
1774                                getScreenNumber()));
1775   readDatabaseColor("menu.frame.disableColor", "Menu.Frame.DisableColor",
1776                     &resource.mstyle.d_text,
1777                     BlackPixel(getBaseDisplay().getXDisplay(),
1778                                getScreenNumber()));
1779   readDatabaseColor("menu.hilite.textColor", "Menu.Hilite.TextColor",
1780                     &resource.mstyle.h_text,
1781                     BlackPixel(getBaseDisplay().getXDisplay(),
1782                                getScreenNumber()));
1783
1784   if (conf.getValue("menu.title.justify", "Menu.Title.Justify", s)) {
1785     if (0 == strncasecmp(s.c_str(), "right", s.length()))
1786       resource.mstyle.t_justify = BScreen::RightJustify;
1787     else if (0 == strncasecmp(s.c_str(), "center", s.length()))
1788       resource.mstyle.t_justify = BScreen::CenterJustify;
1789     else
1790       resource.mstyle.t_justify = BScreen::LeftJustify;
1791   } else
1792     resource.mstyle.t_justify = BScreen::LeftJustify;
1793
1794   if (conf.getValue("menu.frame.justify", "Menu.Frame.Justify", s)) {
1795     if (0 == strncasecmp(s.c_str(), "right", s.length()))
1796       resource.mstyle.f_justify = BScreen::RightJustify;
1797     else if (0 == strncasecmp(s.c_str(), "center", s.length()))
1798       resource.mstyle.f_justify = BScreen::CenterJustify;
1799     else
1800       resource.mstyle.f_justify = BScreen::LeftJustify;
1801   } else
1802     resource.mstyle.f_justify = BScreen::LeftJustify;
1803
1804   if (conf.getValue("menu.bullet", "Menu.Bullet", s)) {
1805     if (0 == strncasecmp(s.c_str(), "empty", s.length()))
1806       resource.mstyle.bullet = Basemenu::Empty;
1807     else if (0 == strncasecmp(s.c_str(), "square", s.length()))
1808       resource.mstyle.bullet = Basemenu::Square;
1809     else if (0 == strncasecmp(s.c_str(), "diamond", s.length()))
1810       resource.mstyle.bullet = Basemenu::Diamond;
1811     else
1812       resource.mstyle.bullet = Basemenu::Triangle;
1813   } else
1814     resource.mstyle.bullet = Basemenu::Triangle;
1815
1816   if (conf.getValue("menu.bullet.position", "Menu.Bullet.Position", s)) {
1817     if (0 == strncasecmp(s.c_str(), "right", s.length()))
1818       resource.mstyle.bullet_pos = Basemenu::Right;
1819     else
1820       resource.mstyle.bullet_pos = Basemenu::Left;
1821   } else
1822     resource.mstyle.bullet_pos = Basemenu::Left;
1823
1824   readDatabaseColor("borderColor", "BorderColor", &resource.border_color,
1825                     BlackPixel(getBaseDisplay().getXDisplay(),
1826                                getScreenNumber()));
1827
1828   // load bevel, border and handle widths
1829   if (conf.getValue("handleWidth", "HandleWidth", l)) {
1830     if (l <= size().w() / 2 && l != 0)
1831       resource.handle_width = l;
1832     else
1833       resource.handle_width = 6;
1834   } else
1835     resource.handle_width = 6;
1836
1837   if (conf.getValue("borderWidth", "BorderWidth", l))
1838     resource.border_width = l;
1839   else
1840     resource.border_width = 1;
1841
1842   if (conf.getValue("bevelWidth", "BevelWidth", l)) {
1843     if (l <= size().w() / 2 && l != 0)
1844       resource.bevel_width = l;
1845     else
1846       resource.bevel_width = 3;
1847   } else
1848     resource.bevel_width = 3;
1849
1850   if (conf.getValue("frameWidth", "FrameWidth", l)) {
1851     if (l <= size().w() / 2)
1852       resource.frame_width = l;
1853     else
1854       resource.frame_width = resource.bevel_width;
1855   } else
1856     resource.frame_width = resource.bevel_width;
1857
1858   const char *cmd = resource.root_command;
1859   if (cmd != NULL || conf.getValue("rootCommand", "RootCommand", s)) {
1860     if (cmd == NULL)
1861       cmd = s.c_str(); // not specified by the screen, so use the one from the
1862                        // style file
1863 #ifndef    __EMX__
1864     char displaystring[MAXPATHLEN];
1865     sprintf(displaystring, "DISPLAY=%s",
1866             DisplayString(getBaseDisplay().getXDisplay()));
1867     sprintf(displaystring + strlen(displaystring) - 1, "%d",
1868             getScreenNumber());
1869
1870     bexec(cmd, displaystring);
1871 #else //   __EMX__
1872     spawnlp(P_NOWAIT, "cmd.exe", "cmd.exe", "/c", cmd, NULL);
1873 #endif // !__EMX__
1874   }
1875 }
1876
1877
1878 void BScreen::addIcon(OpenboxWindow *w) {
1879   if (! w) return;
1880
1881   w->setWorkspace(-1);
1882   w->setWindowNumber(iconList->count());
1883
1884   iconList->insert(w);
1885
1886   iconmenu->insert((const char **) w->getIconTitle());
1887   iconmenu->update();
1888 }
1889
1890
1891 void BScreen::removeIcon(OpenboxWindow *w) {
1892   if (! w) return;
1893
1894   iconList->remove(w->getWindowNumber());
1895
1896   iconmenu->remove(w->getWindowNumber());
1897   iconmenu->update();
1898
1899   LinkedListIterator<OpenboxWindow> it(iconList);
1900   OpenboxWindow *bw = it.current();
1901   for (int i = 0; bw; it++, bw = it.current())
1902     bw->setWindowNumber(i++);
1903 }
1904
1905
1906 OpenboxWindow *BScreen::getIcon(int index) {
1907   if (index >= 0 && index < iconList->count())
1908     return iconList->find(index);
1909
1910   return NULL;
1911 }
1912
1913
1914 int BScreen::addWorkspace(void) {
1915   Workspace *wkspc = new Workspace(*this, workspacesList->count());
1916   workspacesList->insert(wkspc);
1917   saveWorkspaceNames();
1918
1919   workspacemenu->insert(wkspc->getName(), wkspc->getMenu(),
1920                         wkspc->getWorkspaceID() + 2);
1921   workspacemenu->update();
1922
1923   toolbar->reconfigure();
1924
1925   updateNetizenWorkspaceCount();
1926
1927   return workspacesList->count();
1928 }
1929
1930
1931 int BScreen::removeLastWorkspace(void) {
1932   if (workspacesList->count() == 1)
1933     return 0;
1934
1935   Workspace *wkspc = workspacesList->last();
1936
1937   if (current_workspace->getWorkspaceID() == wkspc->getWorkspaceID())
1938     changeWorkspaceID(current_workspace->getWorkspaceID() - 1);
1939
1940   wkspc->removeAll();
1941
1942   workspacemenu->remove(wkspc->getWorkspaceID() + 2);
1943   workspacemenu->update();
1944
1945   workspacesList->remove(wkspc);
1946   delete wkspc;
1947
1948   toolbar->reconfigure();
1949
1950   updateNetizenWorkspaceCount();
1951
1952   return workspacesList->count();
1953 }
1954
1955
1956 void BScreen::changeWorkspaceID(int id) {
1957   if (! current_workspace) return;
1958
1959   if (id != current_workspace->getWorkspaceID()) {
1960     current_workspace->hideAll();
1961
1962     workspacemenu->setItemSelected(current_workspace->getWorkspaceID() + 2,
1963                                    False);
1964
1965     if (openbox.getFocusedWindow() &&
1966         openbox.getFocusedWindow()->getScreen() == this &&
1967         (! openbox.getFocusedWindow()->isStuck())) {
1968       current_workspace->setLastFocusedWindow(openbox.getFocusedWindow());
1969       openbox.setFocusedWindow(NULL);
1970     }
1971
1972     current_workspace = getWorkspace(id);
1973
1974     workspacemenu->setItemSelected(current_workspace->getWorkspaceID() + 2,
1975                                    True);
1976     toolbar->redrawWorkspaceLabel(True);
1977
1978     current_workspace->showAll();
1979
1980     if (resource.focus_last && current_workspace->getLastFocusedWindow()) {
1981       XSync(openbox.getXDisplay(), False);
1982       current_workspace->getLastFocusedWindow()->setInputFocus();
1983     }
1984   }
1985
1986   updateNetizenCurrentWorkspace();
1987 }
1988
1989
1990 void BScreen::addNetizen(Netizen *n) {
1991   netizenList->insert(n);
1992
1993   n->sendWorkspaceCount();
1994   n->sendCurrentWorkspace();
1995
1996   LinkedListIterator<Workspace> it(workspacesList);
1997   for (Workspace *w = it.current(); w; it++, w = it.current()) {
1998     for (int i = 0; i < w->getCount(); i++)
1999       n->sendWindowAdd(w->getWindow(i)->getClientWindow(),
2000                        w->getWorkspaceID());
2001   }
2002
2003   Window f = ((openbox.getFocusedWindow()) ?
2004               openbox.getFocusedWindow()->getClientWindow() : None);
2005   n->sendWindowFocus(f);
2006 }
2007
2008
2009 void BScreen::removeNetizen(Window w) {
2010   LinkedListIterator<Netizen> it(netizenList);
2011   int i = 0;
2012
2013   for (Netizen *n = it.current(); n; it++, i++, n = it.current())
2014     if (n->getWindowID() == w) {
2015       Netizen *tmp = netizenList->remove(i);
2016       delete tmp;
2017
2018       break;
2019     }
2020 }
2021
2022
2023 void BScreen::updateNetizenCurrentWorkspace(void) {
2024   LinkedListIterator<Netizen> it(netizenList);
2025   for (Netizen *n = it.current(); n; it++, n = it.current())
2026     n->sendCurrentWorkspace();
2027 }
2028
2029
2030 void BScreen::updateNetizenWorkspaceCount(void) {
2031   LinkedListIterator<Netizen> it(netizenList);
2032   for (Netizen *n = it.current(); n; it++, n = it.current())
2033     n->sendWorkspaceCount();
2034 }
2035
2036
2037 void BScreen::updateNetizenWindowFocus(void) {
2038   Window f = ((openbox.getFocusedWindow()) ?
2039               openbox.getFocusedWindow()->getClientWindow() : None);
2040   LinkedListIterator<Netizen> it(netizenList);
2041   for (Netizen *n = it.current(); n; it++, n = it.current())
2042     n->sendWindowFocus(f);
2043 }
2044
2045
2046 void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) {
2047   LinkedListIterator<Netizen> it(netizenList);
2048   for (Netizen *n = it.current(); n; it++, n = it.current())
2049     n->sendWindowAdd(w, p);
2050 }
2051
2052
2053 void BScreen::updateNetizenWindowDel(Window w) {
2054   LinkedListIterator<Netizen> it(netizenList);
2055   for (Netizen *n = it.current(); n; it++, n = it.current())
2056     n->sendWindowDel(w);
2057 }
2058
2059
2060 void BScreen::updateNetizenWindowRaise(Window w) {
2061   LinkedListIterator<Netizen> it(netizenList);
2062   for (Netizen *n = it.current(); n; it++, n = it.current())
2063     n->sendWindowRaise(w);
2064 }
2065
2066
2067 void BScreen::updateNetizenWindowLower(Window w) {
2068   LinkedListIterator<Netizen> it(netizenList);
2069   for (Netizen *n = it.current(); n; it++, n = it.current())
2070     n->sendWindowLower(w);
2071 }
2072
2073
2074 void BScreen::updateNetizenConfigNotify(XEvent *e) {
2075   LinkedListIterator<Netizen> it(netizenList);
2076   for (Netizen *n = it.current(); n; it++, n = it.current())
2077     n->sendConfigNotify(e);
2078 }
2079
2080
2081 void BScreen::raiseWindows(Window *workspace_stack, int num) {
2082   Window *session_stack = new
2083     Window[(num + workspacesList->count() + rootmenuList->count() + 13)];
2084   int i = 0, k = num;
2085
2086   XRaiseWindow(getBaseDisplay().getXDisplay(), iconmenu->getWindowID());
2087   *(session_stack + i++) = iconmenu->getWindowID();
2088
2089   LinkedListIterator<Workspace> wit(workspacesList);
2090   for (Workspace *tmp = wit.current(); tmp; wit++, tmp = wit.current())
2091     *(session_stack + i++) = tmp->getMenu()->getWindowID();
2092
2093   *(session_stack + i++) = workspacemenu->getWindowID();
2094
2095   *(session_stack + i++) = configmenu->getFocusmenu()->getWindowID();
2096   *(session_stack + i++) = configmenu->getPlacementmenu()->getWindowID();
2097   *(session_stack + i++) = configmenu->getWindowID();
2098
2099 #ifdef    SLIT
2100   *(session_stack + i++) = slit->getMenu()->getDirectionmenu()->getWindowID();
2101   *(session_stack + i++) = slit->getMenu()->getPlacementmenu()->getWindowID();
2102   *(session_stack + i++) = slit->getMenu()->getWindowID();
2103 #endif // SLIT
2104
2105   *(session_stack + i++) =
2106     toolbar->getMenu()->getPlacementmenu()->getWindowID();
2107   *(session_stack + i++) = toolbar->getMenu()->getWindowID();
2108
2109   LinkedListIterator<Rootmenu> rit(rootmenuList);
2110   for (Rootmenu *tmp = rit.current(); tmp; rit++, tmp = rit.current())
2111     *(session_stack + i++) = tmp->getWindowID();
2112   *(session_stack + i++) = rootmenu->getWindowID();
2113
2114   if (toolbar->onTop())
2115     *(session_stack + i++) = toolbar->getWindowID();
2116
2117 #ifdef    SLIT
2118   if (slit->onTop())
2119     *(session_stack + i++) = slit->getWindowID();
2120 #endif // SLIT
2121
2122   while (k--)
2123     *(session_stack + i++) = *(workspace_stack + k);
2124
2125   XRestackWindows(getBaseDisplay().getXDisplay(), session_stack, i);
2126
2127   delete [] session_stack;
2128 }
2129
2130
2131 void BScreen::addWorkspaceName(const char *name) {
2132   workspaceNames->insert(bstrdup(name));
2133 }
2134
2135 char* BScreen::getNameOfWorkspace(int id) {
2136   char *name = NULL;
2137
2138   if (id >= 0 && id < workspaceNames->count()) {
2139     char *wkspc_name = workspaceNames->find(id);
2140
2141     if (wkspc_name)
2142       name = wkspc_name;
2143   }
2144   return name;
2145 }
2146
2147
2148 void BScreen::reassociateWindow(OpenboxWindow *w, int wkspc_id, Bool ignore_sticky) {
2149   if (! w) return;
2150
2151   if (wkspc_id == -1)
2152     wkspc_id = current_workspace->getWorkspaceID();
2153
2154   if (w->getWorkspaceNumber() == wkspc_id)
2155     return;
2156
2157   if (w->isIconic()) {
2158     removeIcon(w);
2159     getWorkspace(wkspc_id)->addWindow(w);
2160   } else if (ignore_sticky || ! w->isStuck()) {
2161     getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
2162     getWorkspace(wkspc_id)->addWindow(w);
2163   }
2164 }
2165
2166
2167 void BScreen::nextFocus(void) {
2168   Bool have_focused = False;
2169   int focused_window_number = -1;
2170   OpenboxWindow *next;
2171
2172   if (openbox.getFocusedWindow()) {
2173     if (openbox.getFocusedWindow()->getScreen()->getScreenNumber() ==
2174         getScreenNumber()) {
2175       have_focused = True;
2176       focused_window_number = openbox.getFocusedWindow()->getWindowNumber();
2177     }
2178   }
2179
2180   if ((getCurrentWorkspace()->getCount() > 1) && have_focused) {
2181     int next_window_number = focused_window_number;
2182     do {
2183       if ((++next_window_number) >= getCurrentWorkspace()->getCount())
2184         next_window_number = 0;
2185
2186       next = getCurrentWorkspace()->getWindow(next_window_number);
2187     } while ((! next->setInputFocus()) && (next_window_number !=
2188                                            focused_window_number));
2189
2190     if (next_window_number != focused_window_number)
2191       getCurrentWorkspace()->raiseWindow(next);
2192   } else if (getCurrentWorkspace()->getCount() >= 1) {
2193     next = current_workspace->getWindow(0);
2194
2195     current_workspace->raiseWindow(next);
2196     next->setInputFocus();
2197   }
2198 }
2199
2200
2201 void BScreen::prevFocus(void) {
2202   Bool have_focused = False;
2203   int focused_window_number = -1;
2204   OpenboxWindow *prev;
2205
2206   if (openbox.getFocusedWindow()) {
2207     if (openbox.getFocusedWindow()->getScreen()->getScreenNumber() ==
2208         getScreenNumber()) {
2209       have_focused = True;
2210       focused_window_number = openbox.getFocusedWindow()->getWindowNumber();
2211     }
2212   }
2213
2214   if ((getCurrentWorkspace()->getCount() > 1) && have_focused) {
2215     int prev_window_number = focused_window_number;
2216     do {
2217       if ((--prev_window_number) < 0)
2218         prev_window_number = getCurrentWorkspace()->getCount() - 1;
2219
2220       prev = getCurrentWorkspace()->getWindow(prev_window_number);
2221     } while ((! prev->setInputFocus()) && (prev_window_number !=
2222                                            focused_window_number));
2223
2224     if (prev_window_number != focused_window_number)
2225       getCurrentWorkspace()->raiseWindow(prev);
2226   } else if (getCurrentWorkspace()->getCount() >= 1) {
2227     prev = current_workspace->getWindow(0);
2228
2229     current_workspace->raiseWindow(prev);
2230     prev->setInputFocus();
2231   }
2232 }
2233
2234
2235 void BScreen::raiseFocus(void) {
2236   Bool have_focused = False;
2237   int focused_window_number = -1;
2238
2239   if (openbox.getFocusedWindow()) {
2240     if (openbox.getFocusedWindow()->getScreen()->getScreenNumber() ==
2241         getScreenNumber()) {
2242       have_focused = True;
2243       focused_window_number = openbox.getFocusedWindow()->getWindowNumber();
2244     }
2245   }
2246
2247   if ((getCurrentWorkspace()->getCount() > 1) && have_focused)
2248     getWorkspace(openbox.getFocusedWindow()->getWorkspaceNumber())->
2249       raiseWindow(openbox.getFocusedWindow());
2250 }
2251
2252
2253 void BScreen::InitMenu(void) {
2254   if (rootmenu) {
2255     while (rootmenuList->count())
2256       rootmenuList->remove(0);
2257
2258     while (rootmenu->getCount())
2259       rootmenu->remove(0);
2260   } else {
2261     rootmenu = new Rootmenu(*this);
2262   }
2263   Bool defaultMenu = True;
2264
2265   if (openbox.getMenuFilename()) {
2266     FILE *menu_file = fopen(openbox.getMenuFilename(), "r");
2267
2268     if (!menu_file) {
2269       perror(openbox.getMenuFilename());
2270     } else {
2271       if (feof(menu_file)) {
2272         fprintf(stderr, i18n->getMessage(ScreenSet, ScreenEmptyMenuFile,
2273                                          "%s: Empty menu file"),
2274                 openbox.getMenuFilename());
2275       } else {
2276         char line[1024], label[1024];
2277         memset(line, 0, 1024);
2278         memset(label, 0, 1024);
2279
2280         while (fgets(line, 1024, menu_file) && ! feof(menu_file)) {
2281           if (line[0] != '#') {
2282             int i, key = 0, index = -1, len = strlen(line);
2283
2284             key = 0;
2285             for (i = 0; i < len; i++) {
2286               if (line[i] == '[') index = 0;
2287               else if (line[i] == ']') break;
2288               else if (line[i] != ' ')
2289                 if (index++ >= 0)
2290                   key += tolower(line[i]);
2291             }
2292
2293             if (key == 517) {
2294               index = -1;
2295               for (i = index; i < len; i++) {
2296                 if (line[i] == '(') index = 0;
2297                 else if (line[i] == ')') break;
2298                 else if (index++ >= 0) {
2299                   if (line[i] == '\\' && i < len - 1) i++;
2300                   label[index - 1] = line[i];
2301                 }
2302               }
2303
2304               if (index == -1) index = 0;
2305               label[index] = '\0';
2306
2307               rootmenu->setLabel(label);
2308               defaultMenu = parseMenuFile(menu_file, rootmenu);
2309               break;
2310             }
2311           }
2312         }
2313       }
2314       fclose(menu_file);
2315     }
2316   }
2317
2318   if (defaultMenu) {
2319     rootmenu->setInternalMenu();
2320     rootmenu->insert(i18n->getMessage(ScreenSet, Screenxterm, "xterm"),
2321                      BScreen::Execute,
2322                      i18n->getMessage(ScreenSet, Screenxterm, "xterm"));
2323     rootmenu->insert(i18n->getMessage(ScreenSet, ScreenRestart, "Restart"),
2324                      BScreen::Restart);
2325     rootmenu->insert(i18n->getMessage(ScreenSet, ScreenExit, "Exit"),
2326                      BScreen::Exit);
2327   } else {
2328     openbox.setMenuFilename(openbox.getMenuFilename());
2329   }
2330 }
2331
2332
2333 Bool BScreen::parseMenuFile(FILE *file, Rootmenu *menu) {
2334   char line[1024], label[1024], command[1024];
2335
2336   while (! feof(file)) {
2337     memset(line, 0, 1024);
2338     memset(label, 0, 1024);
2339     memset(command, 0, 1024);
2340
2341     if (fgets(line, 1024, file)) {
2342       if (line[0] != '#') {
2343         register int i, key = 0, parse = 0, index = -1,
2344           line_length = strlen(line),
2345           label_length = 0, command_length = 0;
2346
2347         // determine the keyword
2348         key = 0;
2349         for (i = 0; i < line_length; i++) {
2350           if (line[i] == '[') parse = 1;
2351           else if (line[i] == ']') break;
2352           else if (line[i] != ' ')
2353             if (parse)
2354               key += tolower(line[i]);
2355         }
2356
2357         // get the label enclosed in ()'s
2358         parse = 0;
2359
2360         for (i = 0; i < line_length; i++) {
2361           if (line[i] == '(') {
2362             index = 0;
2363             parse = 1;
2364           } else if (line[i] == ')') break;
2365           else if (index++ >= 0) {
2366             if (line[i] == '\\' && i < line_length - 1) i++;
2367             label[index - 1] = line[i];
2368           }
2369         }
2370
2371         if (parse) {
2372           label[index] = '\0';
2373           label_length = index;
2374         } else {
2375           label[0] = '\0';
2376           label_length = 0;
2377         }
2378
2379         // get the command enclosed in {}'s
2380         parse = 0;
2381         index = -1;
2382         for (i = 0; i < line_length; i++) {
2383           if (line[i] == '{') {
2384             index = 0;
2385             parse = 1;
2386           } else if (line[i] == '}') break;
2387           else if (index++ >= 0) {
2388             if (line[i] == '\\' && i < line_length - 1) i++;
2389             command[index - 1] = line[i];
2390           }
2391         }
2392
2393         if (parse) {
2394           command[index] = '\0';
2395           command_length = index;
2396         } else {
2397           command[0] = '\0';
2398           command_length = 0;
2399         }
2400
2401         switch (key) {
2402         case 311: //end
2403           return ((menu->getCount() == 0) ? True : False);
2404
2405           break;
2406
2407         case 333: // nop
2408           menu->insert(label);
2409
2410           break;
2411
2412         case 421: // exec
2413           if ((! *label) && (! *command)) {
2414             fprintf(stderr, i18n->getMessage(ScreenSet, ScreenEXECError,
2415                              "BScreen::parseMenuFile: [exec] error, "
2416                              "no menu label and/or command defined\n"));
2417             continue;
2418           }
2419
2420           menu->insert(label, BScreen::Execute, command);
2421
2422           break;
2423
2424         case 442: // exit
2425           if (! *label) {
2426             fprintf(stderr, i18n->getMessage(ScreenSet, ScreenEXITError,
2427                                      "BScreen::parseMenuFile: [exit] error, "
2428                                      "no menu label defined\n"));
2429             continue;
2430           }
2431
2432           menu->insert(label, BScreen::Exit);
2433
2434           break;
2435
2436         case 561: // style
2437           {
2438             if ((! *label) || (! *command)) {
2439               fprintf(stderr, i18n->getMessage(ScreenSet, ScreenSTYLEError,
2440                                  "BScreen::parseMenuFile: [style] error, "
2441                                  "no menu label and/or filename defined\n"));
2442               continue;
2443             }
2444
2445             char style[MAXPATHLEN];
2446
2447             // perform shell style ~ home directory expansion
2448             char *homedir = 0;
2449             int homedir_len = 0;
2450             if (*command == '~' && *(command + 1) == '/') {
2451               homedir = getenv("HOME");
2452               homedir_len = strlen(homedir);
2453             }
2454
2455             if (homedir && homedir_len != 0) {
2456               strncpy(style, homedir, homedir_len);
2457
2458               strncpy(style + homedir_len, command + 1,
2459                       command_length - 1);
2460               *(style + command_length + homedir_len - 1) = '\0';
2461             } else {
2462               strncpy(style, command, command_length);
2463               *(style + command_length) = '\0';
2464             }
2465
2466             menu->insert(label, BScreen::SetStyle, style);
2467           }
2468
2469           break;
2470
2471         case 630: // config
2472           if (! *label) {
2473             fprintf(stderr, i18n->getMessage(ScreenSet, ScreenCONFIGError,
2474                                "BScreen::parseMenufile: [config] error, "
2475                                "no label defined"));
2476             continue;
2477           }
2478
2479           menu->insert(label, configmenu);
2480
2481           break;
2482
2483         case 740: // include
2484           {
2485             if (! *label) {
2486               fprintf(stderr, i18n->getMessage(ScreenSet, ScreenINCLUDEError,
2487                                  "BScreen::parseMenuFile: [include] error, "
2488                                  "no filename defined\n"));
2489               continue;
2490             }
2491
2492             char newfile[MAXPATHLEN];
2493
2494             // perform shell style ~ home directory expansion
2495             char *homedir = 0;
2496             int homedir_len = 0;
2497             if (*label == '~' && *(label + 1) == '/') {
2498               homedir = getenv("HOME");
2499               homedir_len = strlen(homedir);
2500             }
2501
2502             if (homedir && homedir_len != 0) {
2503               strncpy(newfile, homedir, homedir_len);
2504
2505               strncpy(newfile + homedir_len, label + 1,
2506                       label_length - 1);
2507               *(newfile + label_length + homedir_len - 1) = '\0';
2508             } else {
2509               strncpy(newfile, label, label_length);
2510               *(newfile + label_length) = '\0';
2511             }
2512
2513             if (newfile) {
2514               FILE *submenufile = fopen(newfile, "r");
2515
2516               if (submenufile) {
2517                 struct stat buf;
2518                 if (fstat(fileno(submenufile), &buf) ||
2519                     (! S_ISREG(buf.st_mode))) {
2520                   fprintf(stderr,
2521                           i18n->getMessage(ScreenSet, ScreenINCLUDEErrorReg,
2522                              "BScreen::parseMenuFile: [include] error: "
2523                              "'%s' is not a regular file\n"), newfile);
2524                   break;
2525                 }
2526
2527                 if (! feof(submenufile)) {
2528                   if (! parseMenuFile(submenufile, menu))
2529                     openbox.setMenuFilename(newfile);
2530
2531                   fclose(submenufile);
2532                 }
2533               } else
2534                 perror(newfile);
2535             }
2536           }
2537
2538           break;
2539
2540         case 767: // submenu
2541           {
2542             if (! *label) {
2543               fprintf(stderr, i18n->getMessage(ScreenSet, ScreenSUBMENUError,
2544                                  "BScreen::parseMenuFile: [submenu] error, "
2545                                  "no menu label defined\n"));
2546               continue;
2547             }
2548
2549             Rootmenu *submenu = new Rootmenu(*this);
2550
2551             if (*command)
2552               submenu->setLabel(command);
2553             else
2554               submenu->setLabel(label);
2555
2556             parseMenuFile(file, submenu);
2557             submenu->update();
2558             menu->insert(label, submenu);
2559             rootmenuList->insert(submenu);
2560           }
2561
2562           break;
2563
2564         case 773: // restart
2565           {
2566             if (! *label) {
2567               fprintf(stderr, i18n->getMessage(ScreenSet, ScreenRESTARTError,
2568                                  "BScreen::parseMenuFile: [restart] error, "
2569                                  "no menu label defined\n"));
2570               continue;
2571             }
2572
2573             if (*command)
2574               menu->insert(label, BScreen::RestartOther, command);
2575             else
2576               menu->insert(label, BScreen::Restart);
2577           }
2578
2579           break;
2580
2581         case 845: // reconfig
2582           {
2583             if (! *label) {
2584               fprintf(stderr, i18n->getMessage(ScreenSet, ScreenRECONFIGError,
2585                                  "BScreen::parseMenuFile: [reconfig] error, "
2586                                  "no menu label defined\n"));
2587               continue;
2588             }
2589
2590             menu->insert(label, BScreen::Reconfigure);
2591           }
2592
2593           break;
2594
2595         case 995: // stylesdir
2596         case 1113: // stylesmenu
2597           {
2598             Bool newmenu = ((key == 1113) ? True : False);
2599
2600             if ((! *label) || ((! *command) && newmenu)) {
2601               fprintf(stderr,
2602                       i18n->getMessage(ScreenSet, ScreenSTYLESDIRError,
2603                          "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2604                          " error, no directory defined\n"));
2605               continue;
2606             }
2607
2608             char stylesdir[MAXPATHLEN];
2609
2610             char *directory = ((newmenu) ? command : label);
2611             int directory_length = ((newmenu) ? command_length : label_length);
2612
2613             // perform shell style ~ home directory expansion
2614             char *homedir = 0;
2615             int homedir_len = 0;
2616
2617             if (*directory == '~' && *(directory + 1) == '/') {
2618               homedir = getenv("HOME");
2619               homedir_len = strlen(homedir);
2620             }
2621
2622             if (homedir && homedir_len != 0) {
2623               strncpy(stylesdir, homedir, homedir_len);
2624
2625               strncpy(stylesdir + homedir_len, directory + 1,
2626                       directory_length - 1);
2627               *(stylesdir + directory_length + homedir_len - 1) = '\0';
2628             } else {
2629               strncpy(stylesdir, directory, directory_length);
2630               *(stylesdir + directory_length) = '\0';
2631             }
2632
2633             struct stat statbuf;
2634
2635             if (! stat(stylesdir, &statbuf)) {
2636               if (S_ISDIR(statbuf.st_mode)) {
2637                 Rootmenu *stylesmenu;
2638
2639                 if (newmenu)
2640                   stylesmenu = new Rootmenu(*this);
2641                 else
2642                   stylesmenu = menu;
2643
2644                 DIR *d = opendir(stylesdir);
2645                 int entries = 0;
2646                 struct dirent *p;
2647
2648                 // get the total number of directory entries
2649                 while ((p = readdir(d))) entries++;
2650                 rewinddir(d);
2651
2652                 char **ls = new char* [entries];
2653                 int index = 0;
2654                 while ((p = readdir(d)))
2655                   ls[index++] = bstrdup(p->d_name);
2656
2657                 closedir(d);
2658
2659                 std::sort(ls, ls + entries, dcmp());
2660
2661                 int n, slen = strlen(stylesdir);
2662                 for (n = 0; n < entries; n++) {
2663                   if (ls[n][strlen(ls[n])-1] != '~') {
2664                     int nlen = strlen(ls[n]);
2665                     char style[MAXPATHLEN + 1];
2666
2667                     strncpy(style, stylesdir, slen);
2668                     *(style + slen) = '/';
2669                     strncpy(style + slen + 1, ls[n], nlen + 1);
2670
2671                     if ((! stat(style, &statbuf)) && S_ISREG(statbuf.st_mode))
2672                       stylesmenu->insert(ls[n], BScreen::SetStyle, style);
2673                   }
2674
2675                   delete [] ls[n];
2676                 }
2677
2678                 delete [] ls;
2679
2680                 stylesmenu->update();
2681
2682                 if (newmenu) {
2683                   stylesmenu->setLabel(label);
2684                   menu->insert(label, stylesmenu);
2685                   rootmenuList->insert(stylesmenu);
2686                 }
2687
2688                 openbox.setMenuFilename(stylesdir);
2689               } else {
2690                 fprintf(stderr, i18n->getMessage(ScreenSet,
2691                                                  ScreenSTYLESDIRErrorNotDir,
2692                                    "BScreen::parseMenuFile:"
2693                                    " [stylesdir/stylesmenu] error, %s is not a"
2694                                    " directory\n"), stylesdir);
2695               }
2696             } else {
2697               fprintf(stderr,
2698                       i18n->getMessage(ScreenSet, ScreenSTYLESDIRErrorNoExist,
2699                          "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2700                          " error, %s does not exist\n"), stylesdir);
2701             }
2702
2703             break;
2704           }
2705
2706         case 1090: // workspaces
2707           {
2708             if (! *label) {
2709               fprintf(stderr,
2710                       i18n->getMessage(ScreenSet, ScreenWORKSPACESError,
2711                                "BScreen:parseMenuFile: [workspaces] error, "
2712                                "no menu label defined\n"));
2713               continue;
2714             }
2715
2716             menu->insert(label, workspacemenu);
2717
2718             break;
2719           }
2720         }
2721       }
2722     }
2723   }
2724
2725   return ((menu->getCount() == 0) ? True : False);
2726 }
2727
2728
2729 void BScreen::shutdown(void) {
2730   openbox.grab();
2731
2732   XSelectInput(getBaseDisplay().getXDisplay(), getRootWindow(), NoEventMask);
2733   XSync(getBaseDisplay().getXDisplay(), False);
2734
2735   LinkedListIterator<Workspace> it(workspacesList);
2736   for (Workspace *w = it.current(); w; it++, w = it.current())
2737     w->shutdown();
2738
2739   while (iconList->count()) {
2740     iconList->first()->restore();
2741     delete iconList->first();
2742   }
2743
2744 #ifdef    SLIT
2745   slit->shutdown();
2746 #endif // SLIT
2747
2748   openbox.ungrab();
2749 }
2750
2751
2752 void BScreen::showPosition(int x, int y) {
2753   if (! geom_visible) {
2754     XMoveResizeWindow(getBaseDisplay().getXDisplay(), geom_window,
2755                       (size().w() - geom_w) / 2,
2756                       (size().h() - geom_h) / 2, geom_w, geom_h);
2757     XMapWindow(getBaseDisplay().getXDisplay(), geom_window);
2758     XRaiseWindow(getBaseDisplay().getXDisplay(), geom_window);
2759
2760     geom_visible = True;
2761   }
2762
2763   char label[1024];
2764
2765   sprintf(label, i18n->getMessage(ScreenSet, ScreenPositionFormat,
2766                                   "X: %4d x Y: %4d"), x, y);
2767
2768   XClearWindow(getBaseDisplay().getXDisplay(), geom_window);
2769
2770   if (i18n->multibyte()) {
2771     XmbDrawString(getBaseDisplay().getXDisplay(), geom_window,
2772                   resource.wstyle.fontset, resource.wstyle.l_text_focus_gc,
2773                   resource.bevel_width, resource.bevel_width -
2774                   resource.wstyle.fontset_extents->max_ink_extent.y,
2775                   label, strlen(label));
2776   } else {
2777     XDrawString(getBaseDisplay().getXDisplay(), geom_window,
2778                 resource.wstyle.l_text_focus_gc,
2779                 resource.bevel_width,
2780                 resource.wstyle.font->ascent +
2781                 resource.bevel_width, label, strlen(label));
2782   }
2783 }
2784
2785
2786 void BScreen::showGeometry(unsigned int gx, unsigned int gy) {
2787   if (! geom_visible) {
2788     XMoveResizeWindow(getBaseDisplay().getXDisplay(), geom_window,
2789                       (size().w() - geom_w) / 2,
2790                       (size().h() - geom_h) / 2, geom_w, geom_h);
2791     XMapWindow(getBaseDisplay().getXDisplay(), geom_window);
2792     XRaiseWindow(getBaseDisplay().getXDisplay(), geom_window);
2793
2794     geom_visible = True;
2795   }
2796
2797   char label[1024];
2798
2799   sprintf(label, i18n->getMessage(ScreenSet, ScreenGeometryFormat,
2800                                   "W: %4d x H: %4d"), gx, gy);
2801
2802   XClearWindow(getBaseDisplay().getXDisplay(), geom_window);
2803
2804   if (i18n->multibyte()) {
2805     XmbDrawString(getBaseDisplay().getXDisplay(), geom_window,
2806                   resource.wstyle.fontset, resource.wstyle.l_text_focus_gc,
2807                   resource.bevel_width, resource.bevel_width -
2808                   resource.wstyle.fontset_extents->max_ink_extent.y,
2809                   label, strlen(label));
2810   } else {
2811     XDrawString(getBaseDisplay().getXDisplay(), geom_window,
2812                 resource.wstyle.l_text_focus_gc,
2813                 resource.bevel_width,
2814                 resource.wstyle.font->ascent +
2815                 resource.bevel_width, label, strlen(label));
2816   }
2817 }
2818
2819 void BScreen::hideGeometry(void) {
2820   if (geom_visible) {
2821     XUnmapWindow(getBaseDisplay().getXDisplay(), geom_window);
2822     geom_visible = False;
2823   }
2824 }