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