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