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