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