]> icculus.org git repositories - dana/openbox.git/blob - src/Screen.cc
merged with 2_1-merged-to-HEAD-2002-09-30
[dana/openbox.git] / src / Screen.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Screen.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef    HAVE_CONFIG_H
25 #include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
31
32 #ifdef    XINERAMA
33 #  include <X11/Xlib.h>
34 #  include <X11/extensions/Xinerama.h>
35 #endif // XINERAMA
36
37 #ifdef HAVE_STDLIB_H
38 #  include <stdlib.h>
39 #endif // HAVE_STDLIB_H
40
41 #ifdef HAVE_STRING_H
42 #  include <string.h>
43 #endif // HAVE_STRING_H
44
45 #ifdef    HAVE_CTYPE_H
46 #  include <ctype.h>
47 #endif // HAVE_CTYPE_H
48
49 #ifdef    HAVE_UNISTD_H
50 #  include <sys/types.h>
51 #  include <unistd.h>
52 #endif // HAVE_UNISTD_H
53
54 #ifdef    HAVE_DIRENT_H
55 #  include <dirent.h>
56 #endif // HAVE_DIRENT_H
57
58 #ifdef    HAVE_LOCALE_H
59 #  include <locale.h>
60 #endif // HAVE_LOCALE_H
61
62 #ifdef    HAVE_SYS_STAT_H
63 #  include <sys/stat.h>
64 #endif // HAVE_SYS_STAT_H
65
66 #ifdef    HAVE_STDARG_H
67 #  include <stdarg.h>
68 #endif // HAVE_STDARG_H
69 }
70
71 #include <assert.h>
72
73 #include <algorithm>
74 #include <functional>
75 #include <string>
76 using std::string;
77
78 #include "i18n.hh"
79 #include "blackbox.hh"
80 #include "Clientmenu.hh"
81 #include "Font.hh"
82 #include "GCCache.hh"
83 #include "Iconmenu.hh"
84 #include "Image.hh"
85 #include "Screen.hh"
86 #include "Slit.hh"
87 #include "Rootmenu.hh"
88 #include "Toolbar.hh"
89 #include "Util.hh"
90 #include "Window.hh"
91 #include "Workspace.hh"
92 #include "Workspacemenu.hh"
93 #include "Util.hh"
94 #include "XAtom.hh"
95
96 #ifndef   FONT_ELEMENT_SIZE
97 #define   FONT_ELEMENT_SIZE 50
98 #endif // FONT_ELEMENT_SIZE
99
100
101 static bool running = True;
102
103 static int anotherWMRunning(Display *display, XErrorEvent *) {
104   fprintf(stderr, i18n(ScreenSet, ScreenAnotherWMRunning,
105           "BScreen::BScreen: an error occured while querying the X server.\n"
106           "  another window manager already running on display %s.\n"),
107           DisplayString(display));
108
109   running = False;
110
111   return(-1);
112 }
113
114
115 BScreen::BScreen(Blackbox *bb, unsigned int scrn) : ScreenInfo(bb, scrn) {
116   blackbox = bb;
117   screenstr = "session.screen" + itostring(scrn) + '.';
118   config = blackbox->getConfig();
119   xatom = blackbox->getXAtom();
120
121   event_mask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
122     SubstructureRedirectMask | ButtonPressMask | ButtonReleaseMask;
123
124   XErrorHandler old = XSetErrorHandler((XErrorHandler) anotherWMRunning);
125   XSelectInput(getBaseDisplay()->getXDisplay(), getRootWindow(), event_mask);
126   XSync(getBaseDisplay()->getXDisplay(), False);
127   XSetErrorHandler((XErrorHandler) old);
128
129   managed = running;
130   if (! managed) return;
131
132   fprintf(stderr, i18n(ScreenSet, ScreenManagingScreen,
133                        "BScreen::BScreen: managing screen %d "
134                        "using visual 0x%lx, depth %d\n"),
135           getScreenNumber(), XVisualIDFromVisual(getVisual()),
136           getDepth());
137
138   rootmenu = 0;
139
140   resource.mstyle.t_font = resource.mstyle.f_font = resource.tstyle.font =
141     resource.wstyle.font = (BFont *) 0;
142
143   geom_pixmap = None;
144
145   xatom->setSupported(this);    // set-up netwm support
146 #ifdef    HAVE_GETPID
147   xatom->setValue(getRootWindow(), XAtom::blackbox_pid, XAtom::cardinal,
148                   (unsigned long) getpid());
149 #endif // HAVE_GETPID
150   unsigned long geometry[] = { getWidth(),
151                                getHeight()};
152   xatom->setValue(getRootWindow(), XAtom::net_desktop_geometry,
153                   XAtom::cardinal, geometry, 2);
154   unsigned long viewport[] = {0,0};
155   xatom->setValue(getRootWindow(), XAtom::net_desktop_viewport,
156                   XAtom::cardinal, viewport, 2);
157                   
158
159   XDefineCursor(blackbox->getXDisplay(), getRootWindow(),
160                 blackbox->getSessionCursor());
161
162   updateAvailableArea();
163
164   image_control =
165     new BImageControl(blackbox, this, True, blackbox->getColorsPerChannel(),
166                       blackbox->getCacheLife(), blackbox->getCacheMax());
167   image_control->installRootColormap();
168   root_colormap_installed = True;
169
170   load_rc();
171   LoadStyle();
172
173   XGCValues gcv;
174   gcv.foreground = WhitePixel(blackbox->getXDisplay(), getScreenNumber())
175     ^ BlackPixel(blackbox->getXDisplay(), getScreenNumber());
176   gcv.function = GXxor;
177   gcv.subwindow_mode = IncludeInferiors;
178   opGC = XCreateGC(blackbox->getXDisplay(), getRootWindow(),
179                    GCForeground | GCFunction | GCSubwindowMode, &gcv);
180
181   const char *s =  i18n(ScreenSet, ScreenPositionLength,
182                         "0: 0000 x 0: 0000");
183   geom_w = resource.wstyle.font->measureString(s) + resource.bevel_width * 2;
184   geom_h = resource.wstyle.font->height() + resource.bevel_width * 2;
185
186   XSetWindowAttributes attrib;
187   unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder;
188   attrib.border_pixel = getBorderColor()->pixel();
189   attrib.colormap = getColormap();
190   attrib.save_under = True;
191
192   geom_window = XCreateWindow(blackbox->getXDisplay(), getRootWindow(),
193                               0, 0, geom_w, geom_h, resource.border_width,
194                               getDepth(), InputOutput, getVisual(),
195                               mask, &attrib);
196   geom_visible = False;
197
198   BTexture* texture = &(resource.wstyle.l_focus);
199   geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
200   if (geom_pixmap == ParentRelative) {
201     texture = &(resource.wstyle.t_focus);
202     geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
203   }
204   if (! geom_pixmap)
205     XSetWindowBackground(blackbox->getXDisplay(), geom_window,
206                          texture->color().pixel());
207   else
208     XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
209                                geom_window, geom_pixmap);
210
211   workspacemenu = new Workspacemenu(this);
212   iconmenu = new Iconmenu(this);
213   configmenu = new Configmenu(this);
214
215   if (resource.workspaces > 0) {
216     for (unsigned int i = 0; i < resource.workspaces; ++i) {
217       Workspace *wkspc = new Workspace(this, workspacesList.size());
218       workspacesList.push_back(wkspc);
219       workspacemenu->insertWorkspace(wkspc);
220       workspacemenu->update();
221
222     }
223   } else {
224     Workspace *wkspc = new Workspace(this, workspacesList.size());
225     workspacesList.push_back(wkspc);
226     workspacemenu->insertWorkspace(wkspc);
227     workspacemenu->update();
228   }
229   saveWorkspaceNames();
230
231   updateNetizenWorkspaceCount();
232
233   workspacemenu->insert(i18n(IconSet, IconIcons, "Icons"), iconmenu);
234   workspacemenu->update();
235
236   current_workspace = workspacesList.front();
237   
238   xatom->setValue(getRootWindow(), XAtom::net_current_desktop,
239                   XAtom::cardinal, 0); //first workspace
240
241   workspacemenu->setItemSelected(2, True);
242
243   toolbar = new Toolbar(this);
244
245   slit = new Slit(this);
246
247   InitMenu();
248
249   raiseWindows(0, 0);     // this also initializes the empty stacking list
250   rootmenu->update();
251
252   updateClientList();     // initialize the client lists, which will be empty
253   updateAvailableArea();
254
255   changeWorkspaceID(0);
256
257   unsigned int i, j, nchild;
258   Window r, p, *children;
259   XQueryTree(blackbox->getXDisplay(), getRootWindow(), &r, &p,
260              &children, &nchild);
261
262   // preen the window list of all icon windows... for better dockapp support
263   for (i = 0; i < nchild; i++) {
264     if (children[i] == None) continue;
265
266     XWMHints *wmhints = XGetWMHints(blackbox->getXDisplay(),
267                                     children[i]);
268
269     if (wmhints) {
270       if ((wmhints->flags & IconWindowHint) &&
271           (wmhints->icon_window != children[i])) {
272         for (j = 0; j < nchild; j++) {
273           if (children[j] == wmhints->icon_window) {
274             children[j] = None;
275             break;
276           }
277         }
278       }
279
280       XFree(wmhints);
281     }
282   }
283
284   // manage shown windows
285   for (i = 0; i < nchild; ++i) {
286     if (children[i] == None || ! blackbox->validateWindow(children[i]))
287       continue;
288
289     XWindowAttributes attrib;
290     if (XGetWindowAttributes(blackbox->getXDisplay(), children[i], &attrib)) {
291       if (attrib.override_redirect) continue;
292
293       if (attrib.map_state != IsUnmapped) {
294         manageWindow(children[i]);
295       }
296     }
297   }
298
299   XFree(children);
300
301   // call this again just in case a window we found updates the Strut list
302   updateAvailableArea();
303 }
304
305
306 BScreen::~BScreen(void) {
307   if (! managed) return;
308
309   if (geom_pixmap != None)
310     image_control->removeImage(geom_pixmap);
311
312   if (geom_window != None)
313     XDestroyWindow(blackbox->getXDisplay(), geom_window);
314
315   std::for_each(workspacesList.begin(), workspacesList.end(),
316                 PointerAssassin());
317
318   std::for_each(iconList.begin(), iconList.end(), PointerAssassin());
319
320   std::for_each(netizenList.begin(), netizenList.end(), PointerAssassin());
321
322   while (! systrayWindowList.empty())
323     removeSystrayWindow(systrayWindowList[0]);
324
325   delete rootmenu;
326   delete workspacemenu;
327   delete iconmenu;
328   delete configmenu;
329   delete slit;
330   delete toolbar;
331   delete image_control;
332
333   if (resource.wstyle.font)
334     delete resource.wstyle.font;
335   if (resource.mstyle.t_font)
336     delete resource.mstyle.t_font;
337   if (resource.mstyle.f_font)
338     delete resource.mstyle.f_font;
339   if (resource.tstyle.font)
340     delete resource.tstyle.font;
341
342 #ifdef    BITMAPBUTTONS
343   if (resource.wstyle.close_button.mask != None)
344     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.close_button.mask);
345   if (resource.wstyle.max_button.mask != None)
346     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.max_button.mask);
347   if (resource.wstyle.icon_button.mask != None)
348     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.icon_button.mask);
349   if (resource.wstyle.stick_button.mask != None)
350     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.stick_button.mask);
351
352   if (resource.tstyle.left_button.mask != None)
353     XFreePixmap(blackbox->getXDisplay(), resource.tstyle.left_button.mask);
354   if (resource.tstyle.right_button.mask != None)
355     XFreePixmap(blackbox->getXDisplay(), resource.tstyle.right_button.mask);
356
357   if (resource.mstyle.bullet_image.mask != None)
358     XFreePixmap(blackbox->getXDisplay(), resource.mstyle.bullet_image.mask);
359   if (resource.mstyle.tick_image.mask != None)
360     XFreePixmap(blackbox->getXDisplay(), resource.mstyle.tick_image.mask);
361     
362   resource.wstyle.max_button.mask = resource.wstyle.close_button.mask =
363     resource.wstyle.icon_button.mask =
364     resource.wstyle.stick_button.mask = None;
365   resource.tstyle.left_button.mask = resource.tstyle.right_button.mask = None;
366   resource.mstyle.bullet_image.mask = resource.mstyle.tick_image.mask = None;
367 #endif // BITMAPBUTTONS
368   
369   XFreeGC(blackbox->getXDisplay(), opGC);
370 }
371
372
373 void BScreen::saveSloppyFocus(bool s) {
374   resource.sloppy_focus = s;
375
376   string fmodel;
377   if (resource.sloppy_focus) {
378     fmodel = "SloppyFocus";
379     if (resource.auto_raise) fmodel += " AutoRaise";
380     if (resource.click_raise) fmodel += " ClickRaise";
381   } else {
382     fmodel = "ClickToFocus";
383   }
384   config->setValue(screenstr + "focusModel", fmodel);
385 }
386
387
388 void BScreen::saveAutoRaise(bool a) {
389   resource.auto_raise = a;
390   saveSloppyFocus(resource.sloppy_focus);
391 }
392
393
394 void BScreen::saveClickRaise(bool c) {
395   resource.click_raise = c;
396   saveSloppyFocus(resource.sloppy_focus);
397 }
398
399
400 void BScreen::saveImageDither(bool d) {
401   image_control->setDither(d);
402   config->setValue(screenstr + "imageDither", doImageDither());
403 }
404
405
406 void BScreen::saveOpaqueMove(bool o) {
407   resource.opaque_move = o;
408   config->setValue(screenstr + "opaqueMove", resource.opaque_move);
409 }
410
411
412 void BScreen::saveFullMax(bool f) {
413   resource.full_max = f;
414   config->setValue(screenstr + "fullMaximization", resource.full_max);
415 }
416
417
418 void BScreen::saveFocusNew(bool f) {
419   resource.focus_new = f;
420   config->setValue(screenstr + "focusNewWindows", resource.focus_new);
421 }
422
423
424 void BScreen::saveFocusLast(bool f) {
425   resource.focus_last = f;
426   config->setValue(screenstr + "focusLastWindow", resource.focus_last);
427 }
428
429
430 void BScreen::saveAAFonts(bool f) {
431   resource.aa_fonts = f;
432   config->setValue(screenstr + "antialiasFonts", resource.aa_fonts);
433   reconfigure();
434 }
435
436
437 void BScreen::saveShadowFonts(bool f) {
438   resource.shadow_fonts = f;
439   config->setValue(screenstr + "dropShadowFonts", resource.shadow_fonts);
440   reconfigure();
441 }
442
443
444 void BScreen::saveHideToolbar(bool h) {
445   resource.hide_toolbar = h;
446   if (resource.hide_toolbar)
447     toolbar->unmapToolbar();
448   else
449     toolbar->mapToolbar();
450   config->setValue(screenstr + "hideToolbar", resource.hide_toolbar);
451 }
452
453
454 void BScreen::saveWindowToEdgeSnap(int s) {
455   resource.snap_to_edges = s;
456
457   const char *snap;
458   switch (resource.snap_to_edges) {
459   case WindowNoSnap: snap = "NoSnap"; break;
460   case WindowResistance: snap = "Resistance"; break;
461   case WindowSnap: default: snap = "Snap"; break;
462   }
463   config->setValue(screenstr + "windowToEdgeSnap", snap);
464 }
465
466
467 void BScreen::saveWindowToWindowSnap(int s) {
468   resource.snap_to_windows = s;
469   
470   const char *snap;
471   switch (resource.snap_to_windows) {
472   case WindowNoSnap: snap = "NoSnap"; break;
473   case WindowResistance: snap = "Resistance"; break;
474   case WindowSnap: default: snap = "Snap"; break;
475   }
476   config->setValue(screenstr + "windowToWindowSnap", snap);
477 }
478
479
480 void BScreen::saveResizeZones(unsigned int z) {
481   resource.resize_zones = z;
482   config->setValue(screenstr + "resizeZones", resource.resize_zones);
483 }
484
485
486 void BScreen::saveWindowCornerSnap(bool s) {
487   resource.window_corner_snap = s;
488   config->setValue(screenstr + "windowCornerSnap",
489                    resource.window_corner_snap);
490 }
491
492
493 void BScreen::saveWorkspaces(unsigned int w) {
494   resource.workspaces = w;
495   config->setValue(screenstr + "workspaces", resource.workspaces);
496 }
497
498
499 void BScreen::savePlacementPolicy(int p) {
500   resource.placement_policy = p; 
501   const char *placement;
502   switch (resource.placement_policy) {
503   case CascadePlacement: placement = "CascadePlacement"; break;
504   case UnderMousePlacement: placement = "UnderMousePlacement"; break;
505   case ClickMousePlacement: placement = "ClickMousePlacement"; break;
506   case ColSmartPlacement: placement = "ColSmartPlacement"; break;
507   case RowSmartPlacement: default: placement = "RowSmartPlacement"; break;
508   }
509   config->setValue(screenstr + "windowPlacement", placement);
510 }
511
512
513 void BScreen::saveResistanceSize(int s) {
514   resource.resistance_size = s;
515   config->setValue(screenstr + "resistanceSize",
516                    resource.resistance_size);
517 }
518
519
520 void BScreen::saveSnapThreshold(int t) {
521   resource.snap_threshold = t;
522   config->setValue(screenstr + "edgeSnapThreshold",
523                    resource.snap_threshold);
524 }
525
526
527 void BScreen::saveSnapOffset(int t) {
528   resource.snap_offset = t;
529   config->setValue(screenstr + "edgeSnapOffset",
530                    resource.snap_offset);
531 }
532
533
534 void BScreen::saveRowPlacementDirection(int d) {
535   resource.row_direction = d;
536   config->setValue(screenstr + "rowPlacementDirection",
537                    resource.row_direction == LeftRight ?
538                    "LeftToRight" : "RightToLeft");
539 }
540
541
542 void BScreen::saveColPlacementDirection(int d) {
543   resource.col_direction = d;
544   config->setValue(screenstr + "colPlacementDirection",
545                    resource.col_direction == TopBottom ?
546                    "TopToBottom" : "BottomToTop");
547 }
548
549
550 #ifdef    HAVE_STRFTIME
551 void BScreen::saveStrftimeFormat(const std::string& format) {
552   resource.strftime_format = format;
553   config->setValue(screenstr + "strftimeFormat", resource.strftime_format);
554 }
555
556 #else // !HAVE_STRFTIME
557
558 void BScreen::saveDateFormat(int f) {
559   resource.date_format = f;
560   config->setValue(screenstr + "dateFormat",
561                    resource.date_format == B_EuropeanDate ?
562                    "European" : "American");
563 }
564
565
566 void BScreen::saveClock24Hour(bool c) {
567   resource.clock24hour = c;
568   config->setValue(screenstr + "clockFormat", resource.clock24hour ? 24 : 12);
569 }
570 #endif // HAVE_STRFTIME
571
572
573 void BScreen::saveWorkspaceNames() {
574   string names;
575  
576   for (unsigned int i = 0; i < workspacesList.size(); ++i) {
577     names += workspacesList[i]->getName();
578     if (i < workspacesList.size() - 1)
579       names += ',';
580   }
581
582   config->setValue(screenstr + "workspaceNames", names);
583 }
584
585
586 void BScreen::savePlaceIgnoreShaded(bool i) {
587   resource.ignore_shaded = i;
588   config->setValue(screenstr + "placementIgnoreShaded",
589                    resource.ignore_shaded);
590 }
591
592
593 void BScreen::savePlaceIgnoreMaximized(bool i) {
594   resource.ignore_maximized = i;
595   config->setValue(screenstr + "placementIgnoreMaximized",
596                    resource.ignore_maximized);
597 }
598
599
600 void BScreen::saveAllowScrollLock(bool a) {
601   resource.allow_scroll_lock = a;
602   config->setValue(screenstr + "disableBindingsWithScrollLock",
603                    resource.allow_scroll_lock);
604 }
605
606
607 void BScreen::saveWorkspaceWarping(bool w) {
608   resource.workspace_warping = w;
609   config->setValue(screenstr + "workspaceWarping",
610                    resource.workspace_warping);
611 }
612
613
614 void BScreen::saveRootScrollDirection(int d) {
615   resource.root_scroll = d;
616   const char *dir;
617   switch (resource.root_scroll) {
618   case NoScroll: dir = "None"; break;
619   case ReverseScroll: dir = "Reverse"; break;
620   case NormalScroll: default: dir = "Normal"; break;
621   }
622   config->setValue(screenstr + "rootScrollDirection", dir);
623 }
624
625
626 void BScreen::saveRootMenuButton(unsigned int b) {
627   resource.root_menu_button = b;
628   const char *but;
629   switch (resource.root_menu_button) {
630   case 0: but = "None"; break;
631   case 1: but = "Left"; break;
632   case 2: but = "Middle"; break;
633   case 3: default: but = "Right"; break;
634   }
635   config->setValue(screenstr + "rootMenuButton", but);
636 }
637
638
639 void BScreen::saveWorkspaceMenuButton(unsigned int b) {
640   resource.workspace_menu_button = b;
641   const char *but;
642   switch (resource.workspace_menu_button) {
643   case 0: but = "None"; break;
644   case 1: but = "Left"; break;
645   case 2: default: but = "Middle"; break;
646   case 3: but = "Right"; break;
647   }
648   config->setValue(screenstr + "workspaceMenuButton", but);
649 }
650
651
652 void BScreen::save_rc(void) {
653   saveSloppyFocus(resource.sloppy_focus);
654   saveAutoRaise(resource.auto_raise);
655   saveImageDither(doImageDither());
656   saveShadowFonts(resource.shadow_fonts);
657   saveAAFonts(resource.aa_fonts);
658   saveResizeZones(resource.resize_zones);
659   saveOpaqueMove(resource.opaque_move);
660   saveFullMax(resource.full_max);
661   saveFocusNew(resource.focus_new);
662   saveFocusLast(resource.focus_last);
663   saveHideToolbar(resource.hide_toolbar);
664   saveWindowToWindowSnap(resource.snap_to_windows);
665   saveWindowToEdgeSnap(resource.snap_to_edges);
666   saveWindowCornerSnap(resource.window_corner_snap);
667   saveWorkspaces(resource.workspaces);
668   savePlacementPolicy(resource.placement_policy);
669   saveSnapThreshold(resource.snap_threshold);
670   saveSnapOffset(resource.snap_offset);
671   saveResistanceSize(resource.resistance_size);
672   saveRowPlacementDirection(resource.row_direction);
673   saveColPlacementDirection(resource.col_direction);
674 #ifdef    HAVE_STRFTIME
675   saveStrftimeFormat(resource.strftime_format); 
676 #else // !HAVE_STRFTIME
677   saveDateFormat(resource.date_format);
678   savwClock24Hour(resource.clock24hour);
679 #endif // HAVE_STRFTIME
680   savePlaceIgnoreShaded(resource.ignore_shaded);
681   savePlaceIgnoreMaximized(resource.ignore_maximized);
682   saveAllowScrollLock(resource.allow_scroll_lock);
683   saveWorkspaceWarping(resource.workspace_warping);
684   saveRootScrollDirection(resource.root_scroll);
685   saveRootMenuButton(resource.root_menu_button);
686   saveWorkspaceMenuButton(resource.workspace_menu_button);
687
688   toolbar->save_rc();
689   slit->save_rc();
690 }
691
692
693 void BScreen::load_rc(void) {
694   std::string s;
695   bool b;
696
697   if (! config->getValue(screenstr + "fullMaximization", resource.full_max))
698     resource.full_max = false;
699
700   if (! config->getValue(screenstr + "focusNewWindows", resource.focus_new))
701     resource.focus_new = false;
702
703   if (! config->getValue(screenstr + "focusLastWindow", resource.focus_last))
704     resource.focus_last = false;
705
706   if (! config->getValue(screenstr + "workspaces", resource.workspaces))
707     resource.workspaces = 1;
708
709   if (! config->getValue(screenstr + "opaqueMove", resource.opaque_move))
710     resource.opaque_move = false;
711
712   if (! config->getValue(screenstr + "antialiasFonts", resource.aa_fonts))
713     resource.aa_fonts = true;
714
715   if (! resource.aa_fonts ||
716       ! config->getValue(screenstr + "dropShadowFonts", resource.shadow_fonts))
717     resource.shadow_fonts = false;
718
719   if (! config->getValue(screenstr + "resizeZones", resource.resize_zones) ||
720       (resource.resize_zones != 1 && resource.resize_zones != 2 &&
721        resource.resize_zones != 4))
722       resource.resize_zones = 4;
723
724   if (! config->getValue(screenstr + "hideToolbar", resource.hide_toolbar))
725     resource.hide_toolbar = false;
726
727   resource.snap_to_windows = WindowResistance;
728   if (config->getValue(screenstr + "windowToWindowSnap", s)) {
729     if (s == "NoSnap")
730       resource.snap_to_windows = WindowNoSnap;
731     else if (s == "Snap")
732       resource.snap_to_windows = WindowSnap;
733   }
734
735   resource.snap_to_edges = WindowResistance;
736   if (config->getValue(screenstr + "windowToEdgeSnap", s)) {
737     if (s == "NoSnap")
738       resource.snap_to_edges = WindowNoSnap;
739     else if (s == "Snap")
740       resource.snap_to_edges = WindowSnap;
741   }
742
743   if (! config->getValue(screenstr + "windowCornerSnap",
744                          resource.window_corner_snap))
745     resource.window_corner_snap = true;
746
747   if (! config->getValue(screenstr + "imageDither", b))
748     b = true;
749   image_control->setDither(b);
750
751   if (! config->getValue(screenstr + "edgeSnapOffset",
752                         resource.snap_offset))
753     resource.snap_offset = 0;
754   if (resource.snap_offset > 50)  // sanity check, setting this huge would
755     resource.snap_offset = 50;    // seriously suck.
756   
757   if (! config->getValue(screenstr + "edgeSnapThreshold",
758                         resource.snap_threshold))
759     resource.snap_threshold = 4;
760   
761   if (! config->getValue(screenstr + "resistanceSize",
762                         resource.resistance_size))
763     resource.resistance_size = 18;
764   
765   if (config->getValue(screenstr + "rowPlacementDirection", s) &&
766       s == "RightToLeft")
767     resource.row_direction = RightLeft;
768   else
769     resource.row_direction = LeftRight;
770
771   if (config->getValue(screenstr + "colPlacementDirection", s) &&
772       s == "BottomToTop")
773     resource.col_direction = BottomTop;
774   else
775     resource.col_direction = TopBottom;
776
777   if (config->getValue(screenstr + "workspaceNames", s)) {
778     XAtom::StringVect workspaceNames;
779
780     string::const_iterator it = s.begin(), end = s.end();
781     while(1) {
782       string::const_iterator tmp = it;     // current string.begin()
783       it = std::find(tmp, end, ',');       // look for comma between tmp and end
784       workspaceNames.push_back(string(tmp, it)); // s[tmp:it]
785       if (it == end)
786         break;
787       ++it;
788     }
789
790     xatom->setValue(getRootWindow(), XAtom::net_desktop_names, XAtom::utf8,
791                     workspaceNames);
792   }
793
794   resource.sloppy_focus = true;
795   resource.auto_raise = false;
796   resource.click_raise = false;
797   if (config->getValue(screenstr + "focusModel", s)) {
798     if (s.find("ClickToFocus") != string::npos) {
799       resource.sloppy_focus = false;
800     } else {
801       // must be sloppy
802       if (s.find("AutoRaise") != string::npos)
803         resource.auto_raise = true;
804       if (s.find("ClickRaise") != string::npos)
805         resource.click_raise = true;
806     }
807   }
808
809   if (config->getValue(screenstr + "windowPlacement", s)) {
810     if (s == "CascadePlacement")
811       resource.placement_policy = CascadePlacement;
812     else if (s == "UnderMousePlacement")
813       resource.placement_policy = UnderMousePlacement;
814     else if (s == "ClickMousePlacement")
815       resource.placement_policy = ClickMousePlacement;
816     else if (s == "ColSmartPlacement")
817       resource.placement_policy = ColSmartPlacement;
818     else //if (s == "RowSmartPlacement")
819       resource.placement_policy = RowSmartPlacement;
820   } else
821     resource.placement_policy = RowSmartPlacement;
822
823 #ifdef    HAVE_STRFTIME
824   if (! config->getValue(screenstr + "strftimeFormat",
825                          resource.strftime_format))
826     resource.strftime_format = "%I:%M %p";
827 #else // !HAVE_STRFTIME
828   long l;
829
830   if (config->getValue(screenstr + "dateFormat", s) && s == "European")
831     resource.date_format = B_EuropeanDate;
832  else
833     resource.date_format = B_AmericanDate;
834
835   if (! config->getValue(screenstr + "clockFormat", l))
836     l = 12;
837   resource.clock24hour = l == 24;
838 #endif // HAVE_STRFTIME
839   
840   if (! config->getValue(screenstr + "placementIgnoreShaded",
841                          resource.ignore_shaded))
842     resource.ignore_shaded = true;
843
844   if (! config->getValue(screenstr + "placementIgnoreMaximized",
845                          resource.ignore_maximized))
846     resource.ignore_maximized = true;
847
848   if (! config->getValue(screenstr + "disableBindingsWithScrollLock",
849                        resource.allow_scroll_lock))
850     resource.allow_scroll_lock = false;
851
852   if (! config->getValue(screenstr + "workspaceWarping",
853                          resource.workspace_warping))
854     resource.workspace_warping = false;
855
856   resource.root_scroll = NormalScroll;
857   if (config->getValue(screenstr + "rootScrollDirection", s)) {
858     if (s == "None")
859       resource.root_scroll = NoScroll;
860     else if (s == "Reverse")
861       resource.root_scroll = ReverseScroll;
862   }
863
864   resource.root_menu_button = 3;
865   if (config->getValue(screenstr + "rootMenuButton", s)) {
866     if (s == "None")
867       resource.root_menu_button = 0;
868     else if (s == "Left")
869       resource.root_menu_button = 1;
870     else if (s == "Middle")
871       resource.root_menu_button = 2;
872   }
873
874   resource.workspace_menu_button = 2;
875   if (config->getValue(screenstr + "workspaceMenuButton", s)) {
876     if (s == "None")
877       resource.workspace_menu_button = 0;
878     else if (s == "Left")
879       resource.workspace_menu_button = 1;
880     else if (s == "Right")
881       resource.workspace_menu_button = 3;
882   }
883   // cant both be the same
884   if (resource.workspace_menu_button == resource.root_menu_button)
885     resource.workspace_menu_button = 0;
886 }
887
888
889 void BScreen::changeWorkspaceCount(unsigned int new_count) {
890   assert(new_count > 0);
891
892   if (new_count < workspacesList.size()) {
893     // shrink
894     for (unsigned int i = workspacesList.size(); i > new_count; --i)
895       removeLastWorkspace();
896     // removeLast already sets the current workspace to the 
897     // last available one.
898   } else if (new_count > workspacesList.size()) {
899     // grow
900     for(unsigned int i = workspacesList.size(); i < new_count; ++i)
901       addWorkspace();
902   }
903 }
904
905
906 void BScreen::reconfigure(void) {
907   // don't reconfigure while saving the initial rc file, it's a waste and it
908   // breaks somethings (workspace names)
909   if (blackbox->isStartup()) return;
910
911   load_rc();
912   toolbar->load_rc();
913   slit->load_rc();
914   LoadStyle();
915
916   // we need to do this explicitly, because just loading this value from the rc
917   // does nothing
918   changeWorkspaceCount(resource.workspaces);
919
920   XGCValues gcv;
921   gcv.foreground = WhitePixel(blackbox->getXDisplay(),
922                               getScreenNumber());
923   gcv.function = GXinvert;
924   gcv.subwindow_mode = IncludeInferiors;
925   XChangeGC(blackbox->getXDisplay(), opGC,
926             GCForeground | GCFunction | GCSubwindowMode, &gcv);
927
928   const char *s = i18n(ScreenSet, ScreenPositionLength,
929                        "0: 0000 x 0: 0000");
930
931   geom_w = resource.wstyle.font->measureString(s) + resource.bevel_width * 2;
932   geom_h = resource.wstyle.font->height() + resource.bevel_width * 2;
933
934   BTexture* texture = &(resource.wstyle.l_focus);
935   geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
936   if (geom_pixmap == ParentRelative) {
937     texture = &(resource.wstyle.t_focus);
938     geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
939   }
940   if (! geom_pixmap)
941     XSetWindowBackground(blackbox->getXDisplay(), geom_window,
942                          texture->color().pixel());
943   else
944     XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
945                                geom_window, geom_pixmap);
946
947   XSetWindowBorderWidth(blackbox->getXDisplay(), geom_window,
948                         resource.border_width);
949   XSetWindowBorder(blackbox->getXDisplay(), geom_window,
950                    resource.border_color.pixel());
951
952   workspacemenu->reconfigure();
953   iconmenu->reconfigure();
954
955   typedef std::vector<int> SubList;
956   SubList remember_subs;
957
958   // save the current open menus
959   Basemenu *menu = rootmenu;
960   int submenu;
961   while ((submenu = menu->getCurrentSubmenu()) >= 0) {
962     remember_subs.push_back(submenu);
963     menu = menu->find(submenu)->submenu();
964     assert(menu);
965   }
966   
967   InitMenu();
968   raiseWindows(0, 0);
969   rootmenu->reconfigure();
970
971   // reopen the saved menus
972   menu = rootmenu;
973   const SubList::iterator subs_end = remember_subs.end();
974   for (SubList::iterator it = remember_subs.begin(); it != subs_end; ++it) {
975     menu->drawSubmenu(*it);
976     menu = menu->find(*it)->submenu();
977     if (! menu)
978       break;
979   }
980
981   configmenu->reconfigure();
982
983   toolbar->reconfigure();
984
985   slit->reconfigure();
986
987   std::for_each(workspacesList.begin(), workspacesList.end(),
988                 std::mem_fun(&Workspace::reconfigure));
989
990   BlackboxWindowList::iterator iit = iconList.begin();
991   for (; iit != iconList.end(); ++iit) {
992     BlackboxWindow *bw = *iit;
993     if (bw->validateClient())
994       bw->reconfigure();
995   }
996
997   image_control->timeout();
998 }
999
1000
1001 void BScreen::rereadMenu(void) {
1002   InitMenu();
1003   raiseWindows(0, 0);
1004
1005   rootmenu->reconfigure();
1006 }
1007
1008
1009 void BScreen::LoadStyle(void) {
1010   Configuration style(False);
1011
1012   const char *sfile = blackbox->getStyleFilename();
1013   if (sfile != NULL) {
1014     style.setFile(sfile);
1015     if (! style.load()) {
1016       style.setFile(DEFAULTSTYLE);
1017       if (! style.load())
1018         style.create();  // hardcoded default values will be used.
1019     }
1020   }
1021
1022   // merge in the rc file
1023   style.merge(config->file(), True);
1024
1025   string s;
1026
1027   // load fonts/fontsets
1028   if (resource.wstyle.font)
1029     delete resource.wstyle.font;
1030   if (resource.tstyle.font)
1031     delete resource.tstyle.font;
1032   if (resource.mstyle.f_font)
1033     delete resource.mstyle.f_font;
1034   if (resource.mstyle.t_font)
1035     delete resource.mstyle.t_font;
1036   resource.wstyle.font = resource.tstyle.font = resource.mstyle.f_font =
1037     resource.mstyle.t_font = (BFont *) 0;
1038
1039   resource.wstyle.font = readDatabaseFont("window.", style);
1040   resource.tstyle.font = readDatabaseFont("toolbar.", style);
1041   resource.mstyle.t_font = readDatabaseFont("menu.title.", style);
1042   resource.mstyle.f_font = readDatabaseFont("menu.frame.", style);
1043
1044   // load window config
1045   resource.wstyle.t_focus =
1046     readDatabaseTexture("window.title.focus", "white", style);
1047   resource.wstyle.t_unfocus =
1048     readDatabaseTexture("window.title.unfocus", "black", style);
1049   resource.wstyle.l_focus =
1050     readDatabaseTexture("window.label.focus", "white", style);
1051   resource.wstyle.l_unfocus =
1052     readDatabaseTexture("window.label.unfocus", "black", style);
1053   resource.wstyle.h_focus =
1054     readDatabaseTexture("window.handle.focus", "white", style);
1055   resource.wstyle.h_unfocus =
1056     readDatabaseTexture("window.handle.unfocus", "black", style);
1057   resource.wstyle.g_focus =
1058     readDatabaseTexture("window.grip.focus", "white", style);
1059   resource.wstyle.g_unfocus =
1060     readDatabaseTexture("window.grip.unfocus", "black", style);
1061   resource.wstyle.b_focus =
1062     readDatabaseTexture("window.button.focus", "white", style);
1063   resource.wstyle.b_unfocus =
1064     readDatabaseTexture("window.button.unfocus", "black", style);
1065   resource.wstyle.b_pressed =
1066     readDatabaseTexture("window.button.pressed", "black", style);
1067
1068 #ifdef    BITMAPBUTTONS
1069   if (resource.wstyle.close_button.mask != None)
1070     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.close_button.mask);
1071   if (resource.wstyle.max_button.mask != None)
1072     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.max_button.mask);
1073   if (resource.wstyle.icon_button.mask != None)
1074     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.icon_button.mask);
1075   if (resource.wstyle.stick_button.mask != None)
1076     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.stick_button.mask);
1077
1078   resource.wstyle.close_button.mask = resource.wstyle.max_button.mask =
1079     resource.wstyle.icon_button.mask =
1080     resource.wstyle.icon_button.mask = None;
1081   
1082   readDatabaseMask("window.button.close.mask", resource.wstyle.close_button,
1083                    style);
1084   readDatabaseMask("window.button.max.mask", resource.wstyle.max_button,
1085                    style);
1086   readDatabaseMask("window.button.icon.mask", resource.wstyle.icon_button,
1087                    style);
1088   readDatabaseMask("window.button.stick.mask", resource.wstyle.stick_button,
1089                    style);
1090 #endif // BITMAPBUTTONS
1091
1092   // we create the window.frame texture by hand because it exists only to
1093   // make the code cleaner and is not actually used for display
1094   BColor color = readDatabaseColor("window.frame.focusColor", "white", style);
1095   resource.wstyle.f_focus = BTexture("solid flat", getBaseDisplay(),
1096                                      getScreenNumber(), image_control);
1097   resource.wstyle.f_focus.setColor(color);
1098
1099   color = readDatabaseColor("window.frame.unfocusColor", "white", style);
1100   resource.wstyle.f_unfocus = BTexture("solid flat", getBaseDisplay(),
1101                                        getScreenNumber(), image_control);
1102   resource.wstyle.f_unfocus.setColor(color);
1103
1104   resource.wstyle.l_text_focus =
1105     readDatabaseColor("window.label.focus.textColor", "black", style);
1106   resource.wstyle.l_text_unfocus =
1107     readDatabaseColor("window.label.unfocus.textColor", "white", style);
1108   resource.wstyle.b_pic_focus =
1109     readDatabaseColor("window.button.focus.picColor", "black", style);
1110   resource.wstyle.b_pic_unfocus =
1111     readDatabaseColor("window.button.unfocus.picColor", "white", style);
1112
1113   resource.wstyle.justify = LeftJustify;
1114   if (style.getValue("window.justify", s)) {
1115     if (s == "right" || s == "Right")
1116       resource.wstyle.justify = RightJustify;
1117     else if (s == "center" || s == "Center")
1118       resource.wstyle.justify = CenterJustify;
1119   }
1120
1121   // sanity checks
1122   if (resource.wstyle.t_focus.texture() == BTexture::Parent_Relative)
1123     resource.wstyle.t_focus = resource.wstyle.f_focus;
1124   if (resource.wstyle.t_unfocus.texture() == BTexture::Parent_Relative)
1125     resource.wstyle.t_unfocus = resource.wstyle.f_unfocus;
1126   if (resource.wstyle.h_focus.texture() == BTexture::Parent_Relative)
1127     resource.wstyle.h_focus = resource.wstyle.f_focus;
1128   if (resource.wstyle.h_unfocus.texture() == BTexture::Parent_Relative)
1129     resource.wstyle.h_unfocus = resource.wstyle.f_unfocus;
1130
1131   // load toolbar config
1132 #ifdef    BITMAPBUTTONS
1133   if (resource.tstyle.left_button.mask != None)
1134     XFreePixmap(blackbox->getXDisplay(), resource.tstyle.left_button.mask);
1135   if (resource.tstyle.right_button.mask != None)
1136     XFreePixmap(blackbox->getXDisplay(), resource.tstyle.right_button.mask);
1137 #endif // BITMAPBUTTONS
1138   
1139   resource.tstyle.toolbar =
1140     readDatabaseTexture("toolbar", "black", style);
1141   resource.tstyle.label =
1142     readDatabaseTexture("toolbar.label", "black", style);
1143   resource.tstyle.window =
1144     readDatabaseTexture("toolbar.windowLabel", "black", style);
1145   resource.tstyle.button =
1146     readDatabaseTexture("toolbar.button", "white", style);
1147   resource.tstyle.pressed =
1148     readDatabaseTexture("toolbar.button.pressed", "black", style);
1149   resource.tstyle.clock =
1150     readDatabaseTexture("toolbar.clock", "black", style);
1151   resource.tstyle.l_text =
1152     readDatabaseColor("toolbar.label.textColor", "white", style);
1153   resource.tstyle.w_text =
1154     readDatabaseColor("toolbar.windowLabel.textColor", "white", style);
1155   resource.tstyle.c_text =
1156     readDatabaseColor("toolbar.clock.textColor", "white", style);
1157   resource.tstyle.b_pic =
1158     readDatabaseColor("toolbar.button.picColor", "black", style);
1159
1160 #ifdef    BITMAPBUTTONS
1161   readDatabaseMask("toolbar.button.left.mask", resource.tstyle.left_button,
1162                    style);
1163   readDatabaseMask("toolbar.button.right.mask", resource.tstyle.right_button,
1164                    style);
1165 #endif // BITMAPBUTTONS
1166   
1167   resource.tstyle.justify = LeftJustify;
1168   if (style.getValue("toolbar.justify", s)) {
1169     if (s == "right" || s == "Right")
1170       resource.tstyle.justify = RightJustify;
1171     else if (s == "center" || s == "Center")
1172       resource.tstyle.justify = CenterJustify;
1173   }
1174
1175   // sanity checks
1176   if (resource.tstyle.toolbar.texture() == BTexture::Parent_Relative) {
1177     resource.tstyle.toolbar = BTexture("solid flat", getBaseDisplay(),
1178                                        getScreenNumber(), image_control);
1179     resource.tstyle.toolbar.setColor(BColor("black", getBaseDisplay(),
1180                                             getScreenNumber()));
1181   }
1182
1183   // load menu config
1184 #ifdef   BITMAPBUTTONS
1185   if (resource.mstyle.bullet_image.mask != None)
1186     XFreePixmap(blackbox->getXDisplay(), resource.mstyle.bullet_image.mask);
1187   if (resource.mstyle.tick_image.mask != None)
1188     XFreePixmap(blackbox->getXDisplay(), resource.mstyle.tick_image.mask);
1189 #endif // BITMAPBUTTONS
1190   
1191   resource.mstyle.title =
1192     readDatabaseTexture("menu.title", "white", style);
1193   resource.mstyle.frame =
1194     readDatabaseTexture("menu.frame", "black", style);
1195   resource.mstyle.hilite =
1196     readDatabaseTexture("menu.hilite", "white", style);
1197   resource.mstyle.t_text =
1198     readDatabaseColor("menu.title.textColor", "black", style);
1199   resource.mstyle.f_text =
1200     readDatabaseColor("menu.frame.textColor", "white", style);
1201   resource.mstyle.d_text =
1202     readDatabaseColor("menu.frame.disableColor", "black", style);
1203   resource.mstyle.h_text =
1204     readDatabaseColor("menu.hilite.textColor", "black", style);
1205
1206 #ifdef    BITMAPBUTTONS
1207   readDatabaseMask("menu.arrow.mask", resource.mstyle.bullet_image, style);
1208   readDatabaseMask("menu.selected.mask", resource.mstyle.tick_image, style);
1209 #endif // BITMAPBUTTONS
1210     
1211   resource.mstyle.t_justify = LeftJustify;
1212   if (style.getValue("menu.title.justify", s)) {
1213     if (s == "right" || s == "Right")
1214       resource.mstyle.t_justify = RightJustify;
1215     else if (s == "center" || s == "Center")
1216       resource.mstyle.t_justify = CenterJustify;
1217   }
1218
1219   resource.mstyle.f_justify = LeftJustify;
1220   if (style.getValue("menu.frame.justify", s)) {
1221     if (s == "right" || s == "Right")
1222       resource.mstyle.f_justify = RightJustify;
1223     else if (s == "center" || s == "Center")
1224       resource.mstyle.f_justify = CenterJustify;
1225   }
1226
1227   resource.mstyle.bullet = Basemenu::Triangle;
1228   if (style.getValue("menu.bullet", s)) {
1229     if (s == "empty" || s == "Empty")
1230       resource.mstyle.bullet = Basemenu::Empty;
1231     else if (s == "square" || s == "Square")
1232       resource.mstyle.bullet = Basemenu::Square;
1233     else if (s == "diamond" || s == "Diamond")
1234       resource.mstyle.bullet = Basemenu::Diamond;
1235   }
1236
1237   resource.mstyle.bullet_pos = Basemenu::Left;
1238   if (style.getValue("menu.bullet.position", s)) {
1239     if (s == "right" || s == "Right")
1240       resource.mstyle.bullet_pos = Basemenu::Right;
1241   }
1242
1243   // sanity checks
1244   if (resource.mstyle.frame.texture() == BTexture::Parent_Relative) {
1245     resource.mstyle.frame = BTexture("solid flat", getBaseDisplay(),
1246                                      getScreenNumber(), image_control);
1247     resource.mstyle.frame.setColor(BColor("black", getBaseDisplay(),
1248                                           getScreenNumber()));
1249   }
1250
1251   resource.border_color =
1252     readDatabaseColor("borderColor", "black", style);
1253
1254   // load bevel, border and handle widths
1255   if (! style.getValue("handleWidth", resource.handle_width) ||
1256       resource.handle_width > (getWidth() / 2) || resource.handle_width == 0)
1257     resource.handle_width = 6;
1258
1259   if (! style.getValue("borderWidth", resource.border_width))
1260     resource.border_width = 1;
1261
1262   if (! style.getValue("bevelWidth", resource.bevel_width) ||
1263       resource.bevel_width > (getWidth() / 2) || resource.bevel_width == 0)
1264     resource.bevel_width = 3;
1265
1266   if (! style.getValue("frameWidth", resource.frame_width) ||
1267       resource.frame_width > (getWidth() / 2))
1268     resource.frame_width = resource.bevel_width;
1269
1270   if (style.getValue("rootCommand", s))
1271     bexec(s, displayString());
1272 }
1273
1274
1275 void BScreen::addIcon(BlackboxWindow *w) {
1276   if (! w) return;
1277
1278   w->setWorkspace(BSENTINEL);
1279   w->setWindowNumber(iconList.size());
1280
1281   iconList.push_back(w);
1282
1283   const char* title = w->getIconTitle();
1284   iconmenu->insert(title);
1285   iconmenu->update();
1286 }
1287
1288
1289 void BScreen::removeIcon(BlackboxWindow *w) {
1290   if (! w) return;
1291
1292   iconList.remove(w);
1293
1294   iconmenu->remove(w->getWindowNumber());
1295   iconmenu->update();
1296
1297   BlackboxWindowList::iterator it = iconList.begin(),
1298     end = iconList.end();
1299   for (int i = 0; it != end; ++it)
1300     (*it)->setWindowNumber(i++);
1301 }
1302
1303
1304 BlackboxWindow *BScreen::getIcon(unsigned int index) {
1305   if (index < iconList.size()) {
1306     BlackboxWindowList::iterator it = iconList.begin();
1307     while (index-- > 0) // increment to index
1308       ++it;
1309     return *it;
1310   }
1311
1312   return (BlackboxWindow *) 0;
1313 }
1314
1315
1316 unsigned int BScreen::addWorkspace(void) {
1317   Workspace *wkspc = new Workspace(this, workspacesList.size());
1318   workspacesList.push_back(wkspc);
1319   saveWorkspaces(getWorkspaceCount());
1320   saveWorkspaceNames();
1321
1322   workspacemenu->insertWorkspace(wkspc);
1323   workspacemenu->update();
1324
1325   toolbar->reconfigure();
1326
1327   updateNetizenWorkspaceCount();
1328
1329   return workspacesList.size();
1330 }
1331
1332
1333 unsigned int BScreen::removeLastWorkspace(void) {
1334   if (workspacesList.size() == 1)
1335     return 1;
1336
1337   Workspace *wkspc = workspacesList.back();
1338
1339   if (current_workspace->getID() == wkspc->getID())
1340     changeWorkspaceID(current_workspace->getID() - 1);
1341
1342   wkspc->removeAll();
1343
1344   workspacemenu->removeWorkspace(wkspc);
1345   workspacemenu->update();
1346
1347   workspacesList.pop_back();
1348   delete wkspc;
1349
1350   saveWorkspaces(getWorkspaceCount());
1351   saveWorkspaceNames();
1352
1353   toolbar->reconfigure();
1354
1355   updateNetizenWorkspaceCount();
1356
1357   return workspacesList.size();
1358 }
1359
1360
1361 void BScreen::changeWorkspaceID(unsigned int id) {
1362   if (! current_workspace || id == current_workspace->getID()) return;
1363
1364   BlackboxWindow *focused = blackbox->getFocusedWindow();
1365   if (focused && focused->getScreen() == this) {
1366     assert(focused->isStuck() ||
1367            focused->getWorkspaceNumber() == current_workspace->getID());
1368
1369     current_workspace->setLastFocusedWindow(focused);
1370   } else {
1371     // if no window had focus, no need to store a last focus
1372     current_workspace->setLastFocusedWindow((BlackboxWindow *) 0);
1373   }
1374
1375   // when we switch workspaces, unfocus whatever was focused if it is going
1376   // to be unmapped
1377   if (focused && ! focused->isStuck())
1378     blackbox->setFocusedWindow((BlackboxWindow *) 0);
1379
1380   current_workspace->hideAll();
1381   workspacemenu->setItemSelected(current_workspace->getID() + 2, False);
1382
1383   current_workspace = getWorkspace(id);
1384
1385   xatom->setValue(getRootWindow(), XAtom::net_current_desktop,
1386                   XAtom::cardinal, id);
1387
1388   workspacemenu->setItemSelected(current_workspace->getID() + 2, True);
1389   toolbar->redrawWorkspaceLabel(True);
1390
1391   current_workspace->showAll();
1392
1393   int x, y, rx, ry;
1394   Window c, r;
1395   unsigned int m;
1396   BlackboxWindow *win = (BlackboxWindow *) 0;
1397   bool f = False;
1398
1399   XSync(blackbox->getXDisplay(), False);
1400
1401   // If sloppy focus and we can find the client window under the pointer,
1402   // try to focus it.  
1403   if (resource.sloppy_focus &&
1404       XQueryPointer(blackbox->getXDisplay(), getRootWindow(), &r, &c,
1405                     &rx, &ry, &x, &y, &m) &&
1406       c != None) {
1407     if ( (win = blackbox->searchWindow(c)) )
1408       f = win->setInputFocus();
1409   }
1410
1411   // If that fails, and we're doing focus_last, try to focus the last window.
1412   if (! f && resource.focus_last &&
1413       (win = current_workspace->getLastFocusedWindow()))
1414     f = win->setInputFocus();
1415
1416   /*
1417     if we found a focus target, then we set the focused window explicitly
1418     because it is possible to switch off this workspace before the x server
1419     generates the FocusIn event for the window. if that happens, openbox would
1420     lose track of what window was the 'LastFocused' window on the workspace.
1421
1422     if we did not find a focus target, then set the current focused window to
1423     nothing.
1424   */
1425   if (f)
1426     blackbox->setFocusedWindow(win);
1427   else
1428     blackbox->setFocusedWindow((BlackboxWindow *) 0);
1429
1430   updateNetizenCurrentWorkspace();
1431 }
1432
1433
1434 /*
1435  * Set the _NET_CLIENT_LIST root window property.
1436  */
1437 void BScreen::updateClientList(void) {
1438   if (windowList.size() > 0) {
1439     Window *windows = new Window[windowList.size()];
1440     Window *win_it = windows;
1441     BlackboxWindowList::iterator it = windowList.begin();
1442     const BlackboxWindowList::iterator end = windowList.end();
1443     for (; it != end; ++it, ++win_it)
1444       *win_it = (*it)->getClientWindow();
1445     xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
1446                     windows, windowList.size());
1447     delete [] windows;
1448   } else
1449     xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
1450                     0, 0);
1451
1452   updateStackingList();
1453 }
1454
1455
1456 /*
1457  * Set the _NET_CLIENT_LIST_STACKING root window property.
1458  */
1459 void BScreen::updateStackingList(void) {
1460
1461   BlackboxWindowList stack_order;
1462
1463   /*
1464    * Get the stacking order from all of the workspaces.
1465    * We start with the current workspace so that the sticky windows will be
1466    * in the right order on the current workspace.
1467    * XXX: Do we need to have sticky windows in the list once for each workspace?
1468    */
1469   getCurrentWorkspace()->appendStackOrder(stack_order);
1470   for (unsigned int i = 0; i < getWorkspaceCount(); ++i)
1471     if (i != getCurrentWorkspaceID())
1472       getWorkspace(i)->appendStackOrder(stack_order);
1473
1474   if (stack_order.size() > 0) {
1475     // set the client list atoms
1476     Window *windows = new Window[stack_order.size()];
1477     Window *win_it = windows;
1478     BlackboxWindowList::iterator it = stack_order.begin(),
1479                                  end = stack_order.end();
1480     for (; it != end; ++it, ++win_it)
1481       *win_it = (*it)->getClientWindow();
1482     xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
1483                     XAtom::window, windows, stack_order.size());
1484     delete [] windows;
1485   } else
1486     xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
1487                     XAtom::window, 0, 0);
1488 }
1489
1490
1491 void BScreen::addSystrayWindow(Window window) {
1492   XGrabServer(blackbox->getXDisplay());
1493   
1494   XSelectInput(blackbox->getXDisplay(), window, StructureNotifyMask);
1495   systrayWindowList.push_back(window);
1496   xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
1497                   XAtom::window,
1498                   &systrayWindowList[0], systrayWindowList.size());
1499   blackbox->saveSystrayWindowSearch(window, this);
1500
1501   XUngrabServer(blackbox->getXDisplay());
1502 }
1503
1504
1505 void BScreen::removeSystrayWindow(Window window) {
1506   XGrabServer(blackbox->getXDisplay());
1507   
1508   WindowList::iterator it = systrayWindowList.begin();
1509   const WindowList::iterator end = systrayWindowList.end();
1510   for (; it != end; ++it)
1511     if (*it == window) {
1512       systrayWindowList.erase(it);
1513       xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
1514                       XAtom::window,
1515                       &systrayWindowList[0], systrayWindowList.size());
1516       blackbox->removeSystrayWindowSearch(window);
1517       XSelectInput(blackbox->getXDisplay(), window, NoEventMask);
1518       break;
1519     }
1520
1521   assert(it != end);    // not a systray window
1522
1523   XUngrabServer(blackbox->getXDisplay());
1524 }
1525
1526
1527 void BScreen::manageWindow(Window w) {
1528   // is the window a KDE systray window?
1529   Window systray;
1530   if (xatom->getValue(w, XAtom::kde_net_wm_system_tray_window_for,
1531                       XAtom::window, systray) && systray != None) {
1532     addSystrayWindow(w);
1533     return;
1534   }
1535
1536   // is the window a docking app
1537   XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), w);
1538   if (wmhint && (wmhint->flags & StateHint) &&
1539       wmhint->initial_state == WithdrawnState) {
1540     slit->addClient(w);
1541     return;
1542   }
1543
1544   new BlackboxWindow(blackbox, w, this);
1545
1546   BlackboxWindow *win = blackbox->searchWindow(w);
1547   if (! win)
1548     return;
1549
1550   if (win->isDesktop()) {
1551     desktopWindowList.push_back(win->getFrameWindow());
1552   } else { // if (win->isNormal()) {
1553     // don't list desktop windows as managed windows
1554     windowList.push_back(win);
1555     updateClientList();
1556   
1557     if (win->isTopmost())
1558       specialWindowList.push_back(win->getFrameWindow());
1559   }
1560   
1561   XMapRequestEvent mre;
1562   mre.window = w;
1563   if (blackbox->isStartup() && win->isNormal()) win->restoreAttributes();
1564   win->mapRequestEvent(&mre);
1565 }
1566
1567
1568 void BScreen::unmanageWindow(BlackboxWindow *w, bool remap) {
1569   // is the window a KDE systray window?
1570   Window systray;
1571   if (xatom->getValue(w->getClientWindow(),
1572                       XAtom::kde_net_wm_system_tray_window_for,
1573                       XAtom::window, systray) && systray != None) {
1574     removeSystrayWindow(w->getClientWindow());
1575     return;
1576   }
1577
1578   w->restore(remap);
1579
1580   // Remove the modality so that its parent won't try to re-focus the window
1581   if (w->isModal()) w->setModal(False);
1582   
1583   if (w->getWorkspaceNumber() != BSENTINEL &&
1584       w->getWindowNumber() != BSENTINEL) {
1585     getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
1586     if (w->isStuck()) {
1587       for (unsigned int i = 0; i < getNumberOfWorkspaces(); ++i)
1588         if (i != w->getWorkspaceNumber())
1589           getWorkspace(i)->removeWindow(w, True);
1590     }
1591   } else if (w->isIconic())
1592     removeIcon(w);
1593
1594   if (w->isDesktop()) {
1595     WindowList::iterator it = desktopWindowList.begin();
1596     const WindowList::iterator end = desktopWindowList.end();
1597     for (; it != end; ++it)
1598       if (*it == w->getFrameWindow()) {
1599         desktopWindowList.erase(it);
1600         break;
1601       }
1602     assert(it != end);  // the window wasnt a desktop window?
1603   } else { // if (w->isNormal()) {
1604     // we don't list desktop windows as managed windows
1605     windowList.remove(w);
1606     updateClientList();
1607
1608     if (w->isTopmost()) {
1609       WindowList::iterator it = specialWindowList.begin();
1610       const WindowList::iterator end = specialWindowList.end();
1611       for (; it != end; ++it)
1612         if (*it == w->getFrameWindow()) {
1613           specialWindowList.erase(it);
1614           break;
1615         }
1616       assert(it != end);  // the window wasnt a special window?
1617     }
1618   }
1619
1620   if (blackbox->getFocusedWindow() == w)
1621     blackbox->setFocusedWindow((BlackboxWindow *) 0);
1622
1623   removeNetizen(w->getClientWindow());
1624
1625   /*
1626     some managed windows can also be window group controllers.  when
1627     unmanaging such windows, we should also delete the window group.
1628   */
1629   BWindowGroup *group = blackbox->searchGroup(w->getClientWindow());
1630   delete group;
1631
1632   delete w;
1633 }
1634
1635
1636 void BScreen::addNetizen(Netizen *n) {
1637   netizenList.push_back(n);
1638
1639   n->sendWorkspaceCount();
1640   n->sendCurrentWorkspace();
1641
1642   WorkspaceList::iterator it = workspacesList.begin();
1643   const WorkspaceList::iterator end = workspacesList.end();
1644   for (; it != end; ++it)
1645     (*it)->sendWindowList(*n);
1646
1647   Window f = ((blackbox->getFocusedWindow()) ?
1648               blackbox->getFocusedWindow()->getClientWindow() : None);
1649   n->sendWindowFocus(f);
1650 }
1651
1652
1653 void BScreen::removeNetizen(Window w) {
1654   NetizenList::iterator it = netizenList.begin();
1655   for (; it != netizenList.end(); ++it) {
1656     if ((*it)->getWindowID() == w) {
1657       delete *it;
1658       netizenList.erase(it);
1659       break;
1660     }
1661   }
1662 }
1663
1664
1665 void BScreen::updateWorkArea(void) {
1666   if (workspacesList.size() > 0) {
1667     unsigned long *dims = new unsigned long[4 * workspacesList.size()];
1668     for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
1669       // XXX: this could be different for each workspace
1670       const Rect &area = availableArea();
1671       dims[(i * 4) + 0] = area.x();
1672       dims[(i * 4) + 1] = area.y();
1673       dims[(i * 4) + 2] = area.width();
1674       dims[(i * 4) + 3] = area.height();
1675     }
1676     xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
1677                     dims, 4 * workspacesList.size());
1678     delete [] dims;
1679   } else
1680     xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
1681                     0, 0);
1682 }
1683
1684
1685 void BScreen::updateNetizenCurrentWorkspace(void) {
1686   std::for_each(netizenList.begin(), netizenList.end(),
1687                 std::mem_fun(&Netizen::sendCurrentWorkspace));
1688 }
1689
1690
1691 void BScreen::updateNetizenWorkspaceCount(void) {
1692   xatom->setValue(getRootWindow(), XAtom::net_number_of_desktops,
1693                   XAtom::cardinal, workspacesList.size());
1694
1695   updateWorkArea();
1696   
1697   std::for_each(netizenList.begin(), netizenList.end(),
1698                 std::mem_fun(&Netizen::sendWorkspaceCount));
1699 }
1700
1701
1702 void BScreen::updateNetizenWindowFocus(void) {
1703   Window f = ((blackbox->getFocusedWindow()) ?
1704               blackbox->getFocusedWindow()->getClientWindow() : None);
1705
1706   xatom->setValue(getRootWindow(), XAtom::net_active_window,
1707                   XAtom::window, f);
1708
1709   NetizenList::iterator it = netizenList.begin();
1710   for (; it != netizenList.end(); ++it)
1711     (*it)->sendWindowFocus(f);
1712 }
1713
1714
1715 void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) {
1716   NetizenList::iterator it = netizenList.begin();
1717   for (; it != netizenList.end(); ++it) {
1718     (*it)->sendWindowAdd(w, p);
1719   }
1720 }
1721
1722
1723 void BScreen::updateNetizenWindowDel(Window w) {
1724   NetizenList::iterator it = netizenList.begin();
1725   for (; it != netizenList.end(); ++it)
1726     (*it)->sendWindowDel(w);
1727 }
1728
1729
1730 void BScreen::updateNetizenWindowRaise(Window w) {
1731   NetizenList::iterator it = netizenList.begin();
1732   for (; it != netizenList.end(); ++it)
1733     (*it)->sendWindowRaise(w);
1734 }
1735
1736
1737 void BScreen::updateNetizenWindowLower(Window w) {
1738   NetizenList::iterator it = netizenList.begin();
1739   for (; it != netizenList.end(); ++it)
1740     (*it)->sendWindowLower(w);
1741 }
1742
1743
1744 void BScreen::updateNetizenConfigNotify(XEvent *e) {
1745   NetizenList::iterator it = netizenList.begin();
1746   for (; it != netizenList.end(); ++it)
1747     (*it)->sendConfigNotify(e);
1748 }
1749
1750
1751 void BScreen::raiseWindows(Window *workspace_stack, unsigned int num) {
1752   // the 13 represents the number of blackbox windows such as menus
1753   int bbwins = 15;
1754 #ifdef    XINERAMA
1755   ++bbwins;
1756 #endif // XINERAMA
1757 #ifdef    XFT
1758   ++bbwins;
1759 #endif // XFT
1760
1761   Window *session_stack = new
1762     Window[(num + workspacesList.size() + rootmenuList.size() +
1763             specialWindowList.size() + bbwins)];
1764   unsigned int i = 0, k = num;
1765
1766   XRaiseWindow(blackbox->getXDisplay(), iconmenu->getWindowID());
1767   *(session_stack + i++) = iconmenu->getWindowID();
1768
1769   WorkspaceList::iterator wit = workspacesList.begin();
1770   const WorkspaceList::iterator w_end = workspacesList.end();
1771   for (; wit != w_end; ++wit)
1772     *(session_stack + i++) = (*wit)->getMenu()->getWindowID();
1773
1774   *(session_stack + i++) = workspacemenu->getWindowID();
1775
1776   *(session_stack + i++) = configmenu->getFocusmenu()->getWindowID();
1777   *(session_stack + i++) = configmenu->getPlacementmenu()->getWindowID();
1778   *(session_stack + i++) = configmenu->getWindowSnapmenu()->getWindowID();
1779   *(session_stack + i++) = configmenu->getEdgeSnapmenu()->getWindowID();
1780 #ifdef    XINERAMA
1781   *(session_stack + i++) = configmenu->getXineramamenu()->getWindowID();
1782 #endif // XINERAMA
1783 #ifdef    XFT
1784   *(session_stack + i++) = configmenu->getXftmenu()->getWindowID();
1785 #endif // XFT
1786   *(session_stack + i++) = configmenu->getWindowID();
1787
1788   *(session_stack + i++) = slit->getMenu()->getDirectionmenu()->getWindowID();
1789   *(session_stack + i++) = slit->getMenu()->getPlacementmenu()->getWindowID();
1790   *(session_stack + i++) = slit->getMenu()->getWindowID();
1791
1792   *(session_stack + i++) =
1793     toolbar->getMenu()->getPlacementmenu()->getWindowID();
1794   *(session_stack + i++) = toolbar->getMenu()->getWindowID();
1795
1796   RootmenuList::iterator rit = rootmenuList.begin();
1797   for (; rit != rootmenuList.end(); ++rit)
1798     *(session_stack + i++) = (*rit)->getWindowID();
1799   *(session_stack + i++) = rootmenu->getWindowID();
1800
1801   if (toolbar->isOnTop())
1802     *(session_stack + i++) = toolbar->getWindowID();
1803
1804   if (slit->isOnTop())
1805     *(session_stack + i++) = slit->getWindowID();
1806
1807   WindowList::iterator sit, send = specialWindowList.end();
1808   for (sit = specialWindowList.begin(); sit != send; ++sit)
1809     *(session_stack + i++) = *sit;
1810
1811   while (k--)
1812     *(session_stack + i++) = *(workspace_stack + k);
1813
1814   XRestackWindows(blackbox->getXDisplay(), session_stack, i);
1815
1816   delete [] session_stack;
1817
1818   updateStackingList();
1819 }
1820
1821
1822 void BScreen::lowerWindows(Window *workspace_stack, unsigned int num) {
1823   assert(num > 0);  // this would cause trouble in the XRaiseWindow call
1824
1825   Window *session_stack = new Window[(num + desktopWindowList.size())];
1826   unsigned int i = 0, k = num;
1827
1828   XLowerWindow(blackbox->getXDisplay(), workspace_stack[0]);
1829
1830   while (k--)
1831     *(session_stack + i++) = *(workspace_stack + k);
1832
1833   WindowList::iterator dit = desktopWindowList.begin();
1834   const WindowList::iterator d_end = desktopWindowList.end();
1835   for (; dit != d_end; ++dit)
1836     *(session_stack + i++) = *dit;
1837
1838   XRestackWindows(blackbox->getXDisplay(), session_stack, i);
1839
1840   delete [] session_stack;
1841
1842   updateStackingList();
1843 }
1844
1845
1846 void BScreen::reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id,
1847                                 bool ignore_sticky) {
1848   if (! w) return;
1849
1850   if (wkspc_id == BSENTINEL)
1851     wkspc_id = current_workspace->getID();
1852
1853   if (w->getWorkspaceNumber() == wkspc_id)
1854     return;
1855
1856   if (w->isIconic()) {
1857     removeIcon(w);
1858     getWorkspace(wkspc_id)->addWindow(w);
1859     if (w->isStuck())
1860       for (unsigned int i = 0; i < getNumberOfWorkspaces(); ++i)
1861         if (i != w->getWorkspaceNumber())
1862           getWorkspace(i)->addWindow(w, True);
1863   } else if (ignore_sticky || ! w->isStuck()) {
1864     if (w->isStuck())
1865       w->stick();
1866     getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
1867     getWorkspace(wkspc_id)->addWindow(w);
1868   }
1869   updateStackingList();
1870 }
1871
1872
1873 void BScreen::propagateWindowName(const BlackboxWindow *bw) {
1874   if (bw->isIconic()) {
1875     iconmenu->changeItemLabel(bw->getWindowNumber(), bw->getIconTitle());
1876     iconmenu->update();
1877   } else {
1878     Clientmenu *clientmenu = getWorkspace(bw->getWorkspaceNumber())->getMenu();
1879     clientmenu->changeItemLabel(bw->getWindowNumber(), bw->getTitle());
1880     clientmenu->update();
1881
1882     if (blackbox->getFocusedWindow() == bw)
1883       toolbar->redrawWindowLabel(True);
1884   }
1885 }
1886
1887
1888 void BScreen::nextFocus(void) const {
1889   BlackboxWindow *focused = blackbox->getFocusedWindow(),
1890     *next = focused;
1891
1892   if (focused &&
1893       focused->getScreen()->getScreenNumber() == getScreenNumber() &&
1894       current_workspace->getCount() > 1) {
1895     do {
1896       next = current_workspace->getNextWindowInList(next);
1897     } while (next != focused && ! next->setInputFocus());
1898
1899     if (next != focused)
1900       current_workspace->raiseWindow(next);
1901   } else if (current_workspace->getCount() > 0) {
1902     next = current_workspace->getTopWindowOnStack();
1903     next->setInputFocus();
1904     current_workspace->raiseWindow(next);
1905   }
1906 }
1907
1908
1909 void BScreen::prevFocus(void) const {
1910   BlackboxWindow *focused = blackbox->getFocusedWindow(),
1911     *next = focused;
1912
1913   if (focused) {
1914     // if window is not on this screen, ignore it
1915     if (focused->getScreen()->getScreenNumber() != getScreenNumber())
1916       focused = (BlackboxWindow*) 0;
1917   }
1918   
1919   if (focused &&
1920       focused->getScreen()->getScreenNumber() == getScreenNumber() &&
1921       current_workspace->getCount() > 1) {
1922     // next is the next window to receive focus, current is a place holder
1923     do {
1924       next = current_workspace->getPrevWindowInList(next);
1925     } while (next != focused && ! next->setInputFocus());
1926
1927     if (next != focused)
1928       current_workspace->raiseWindow(next);
1929   } else if (current_workspace->getCount() > 0) {
1930     next = current_workspace->getTopWindowOnStack();
1931     next->setInputFocus();
1932     current_workspace->raiseWindow(next);
1933   }
1934 }
1935
1936
1937 void BScreen::raiseFocus(void) const {
1938   BlackboxWindow *focused = blackbox->getFocusedWindow();
1939   if (! focused)
1940     return;
1941
1942   // if on this Screen, raise it
1943   if (focused->getScreen()->getScreenNumber() == getScreenNumber()) {
1944     Workspace *workspace = getWorkspace(focused->getWorkspaceNumber());
1945     workspace->raiseWindow(focused);
1946   }
1947 }
1948
1949
1950 void BScreen::InitMenu(void) {
1951   if (rootmenu) {
1952     rootmenuList.clear();
1953
1954     while (rootmenu->getCount())
1955       rootmenu->remove(0);
1956   } else {
1957     rootmenu = new Rootmenu(this);
1958   }
1959   bool defaultMenu = True;
1960
1961   FILE *menu_file = (FILE *) 0;
1962   const char *menu_filename = blackbox->getMenuFilename();
1963
1964   if (menu_filename) 
1965     if (! (menu_file = fopen(menu_filename, "r")))
1966       perror(menu_filename);
1967   if (! menu_file) {     // opening the menu file failed, try the default menu
1968     menu_filename = DEFAULTMENU;
1969     if (! (menu_file = fopen(menu_filename, "r")))
1970       perror(menu_filename);
1971   } 
1972
1973   if (menu_file) {
1974     if (feof(menu_file)) {
1975       fprintf(stderr, i18n(ScreenSet, ScreenEmptyMenuFile,
1976                            "%s: Empty menu file"),
1977               menu_filename);
1978     } else {
1979       char line[1024], label[1024];
1980       memset(line, 0, 1024);
1981       memset(label, 0, 1024);
1982
1983       while (fgets(line, 1024, menu_file) && ! feof(menu_file)) {
1984         if (line[0] == '#')
1985           continue;
1986
1987         int i, key = 0, index = -1, len = strlen(line);
1988
1989         for (i = 0; i < len; i++) {
1990           if (line[i] == '[') index = 0;
1991           else if (line[i] == ']') break;
1992           else if (line[i] != ' ')
1993             if (index++ >= 0)
1994               key += tolower(line[i]);
1995         }
1996
1997         if (key == 517) { // [begin]
1998           index = -1;
1999           for (i = index; i < len; i++) {
2000             if (line[i] == '(') index = 0;
2001             else if (line[i] == ')') break;
2002             else if (index++ >= 0) {
2003               if (line[i] == '\\' && i < len - 1) i++;
2004               label[index - 1] = line[i];
2005             }
2006           }
2007
2008           if (index == -1) index = 0;
2009           label[index] = '\0';
2010
2011           rootmenu->setLabel(label);
2012           defaultMenu = parseMenuFile(menu_file, rootmenu);
2013           if (! defaultMenu)
2014             blackbox->addMenuTimestamp(menu_filename);
2015           break;
2016         }
2017       }
2018     }
2019     fclose(menu_file);
2020   }
2021
2022   if (defaultMenu) {
2023     rootmenu->setInternalMenu();
2024     rootmenu->insert(i18n(ScreenSet, Screenxterm, "xterm"),
2025                      BScreen::Execute,
2026                      i18n(ScreenSet, Screenxterm, "xterm"));
2027     rootmenu->insert(i18n(ScreenSet, ScreenRestart, "Restart"),
2028                      BScreen::Restart);
2029     rootmenu->insert(i18n(ScreenSet, ScreenExit, "Exit"),
2030                      BScreen::Exit);
2031     rootmenu->setLabel(i18n(BasemenuSet, BasemenuBlackboxMenu,
2032                             "Openbox Menu"));
2033   }
2034 }
2035
2036
2037 static
2038 size_t string_within(char begin, char end,
2039                      const char *input, size_t start_at, size_t length,
2040                      char *output) {
2041   bool parse = False;
2042   size_t index = 0;
2043   size_t i = start_at;
2044   for (; i < length; ++i) {
2045     if (input[i] == begin) {
2046       parse = True;
2047     } else if (input[i] == end) {
2048       break;
2049     } else if (parse) {
2050       if (input[i] == '\\' && i < length - 1) i++;
2051       output[index++] = input[i];
2052     } 
2053   }
2054
2055   if (parse)
2056     output[index] = '\0';
2057   else
2058     output[0] = '\0';
2059
2060   return i;
2061 }
2062
2063
2064 bool BScreen::parseMenuFile(FILE *file, Rootmenu *menu) {
2065   char line[1024], keyword[1024], label[1024], command[1024];
2066   bool done = False;
2067
2068   while (! (done || feof(file))) {
2069     memset(line, 0, 1024);
2070     memset(label, 0, 1024);
2071     memset(command, 0, 1024);
2072
2073     if (! fgets(line, 1024, file))
2074       continue;
2075
2076     if (line[0] == '#') // comment, skip it
2077       continue;
2078
2079     size_t line_length = strlen(line);
2080     unsigned int key = 0;
2081
2082     // get the keyword enclosed in []'s
2083     size_t pos = string_within('[', ']', line, 0, line_length, keyword);
2084
2085     if (keyword[0] == '\0') {  // no keyword, no menu entry
2086       continue;
2087     } else {
2088       size_t len = strlen(keyword);
2089       for (size_t i = 0; i < len; ++i) {
2090         if (keyword[i] != ' ')
2091           key += tolower(keyword[i]);
2092       }
2093     }
2094
2095     // get the label enclosed in ()'s
2096     pos = string_within('(', ')', line, pos, line_length, label);
2097
2098     // get the command enclosed in {}'s
2099     pos = string_within('{', '}', line, pos, line_length, command);
2100
2101     switch (key) {
2102     case 311: // end
2103       done = True;
2104
2105       break;
2106
2107     case 333: // nop
2108       if (! *label)
2109         label[0] = '\0';
2110       menu->insert(label);
2111
2112       break;
2113
2114     case 421: // exec
2115       if (! (*label && *command)) {
2116         fprintf(stderr, i18n(ScreenSet, ScreenEXECError,
2117                              "BScreen::parseMenuFile: [exec] error, "
2118                              "no menu label and/or command defined\n"));
2119         continue;
2120       }
2121
2122       menu->insert(label, BScreen::Execute, command);
2123
2124       break;
2125
2126     case 442: // exit
2127       if (! *label) {
2128         fprintf(stderr, i18n(ScreenSet, ScreenEXITError,
2129                              "BScreen::parseMenuFile: [exit] error, "
2130                              "no menu label defined\n"));
2131         continue;
2132       }
2133
2134       menu->insert(label, BScreen::Exit);
2135
2136       break;
2137
2138     case 561: { // style
2139       if (! (*label && *command)) {
2140         fprintf(stderr,
2141                 i18n(ScreenSet, ScreenSTYLEError,
2142                      "BScreen::parseMenuFile: [style] error, "
2143                      "no menu label and/or filename defined\n"));
2144         continue;
2145       }
2146
2147       string style = expandTilde(command);
2148
2149       menu->insert(label, BScreen::SetStyle, style.c_str());
2150     }
2151       break;
2152
2153     case 630: // config
2154       if (! *label) {
2155         fprintf(stderr, i18n(ScreenSet, ScreenCONFIGError,
2156                              "BScreen::parseMenufile: [config] error, "
2157                              "no label defined"));
2158         continue;
2159       }
2160
2161       menu->insert(label, configmenu);
2162
2163       break;
2164
2165     case 740: { // include
2166       if (! *label) {
2167         fprintf(stderr, i18n(ScreenSet, ScreenINCLUDEError,
2168                              "BScreen::parseMenuFile: [include] error, "
2169                              "no filename defined\n"));
2170         continue;
2171       }
2172
2173       string newfile = expandTilde(label);
2174       FILE *submenufile = fopen(newfile.c_str(), "r");
2175
2176       if (! submenufile) {
2177         perror(newfile.c_str());
2178         continue;
2179       }
2180
2181       struct stat buf;
2182       if (fstat(fileno(submenufile), &buf) ||
2183           ! S_ISREG(buf.st_mode)) {
2184         fprintf(stderr,
2185                 i18n(ScreenSet, ScreenINCLUDEErrorReg,
2186                      "BScreen::parseMenuFile: [include] error: "
2187                      "'%s' is not a regular file\n"), newfile.c_str());
2188         break;
2189       }
2190
2191       if (! feof(submenufile)) {
2192         if (! parseMenuFile(submenufile, menu))
2193           blackbox->addMenuTimestamp(newfile);
2194
2195         fclose(submenufile);
2196       }
2197     }
2198
2199       break;
2200
2201     case 767: { // submenu
2202       if (! *label) {
2203         fprintf(stderr, i18n(ScreenSet, ScreenSUBMENUError,
2204                              "BScreen::parseMenuFile: [submenu] error, "
2205                              "no menu label defined\n"));
2206         continue;
2207       }
2208
2209       Rootmenu *submenu = new Rootmenu(this);
2210
2211       if (*command)
2212         submenu->setLabel(command);
2213       else
2214         submenu->setLabel(label);
2215
2216       parseMenuFile(file, submenu);
2217       submenu->update();
2218       menu->insert(label, submenu);
2219       rootmenuList.push_back(submenu);
2220     }
2221
2222       break;
2223
2224     case 773: { // restart
2225       if (! *label) {
2226         fprintf(stderr, i18n(ScreenSet, ScreenRESTARTError,
2227                              "BScreen::parseMenuFile: [restart] error, "
2228                              "no menu label defined\n"));
2229         continue;
2230       }
2231
2232       if (*command)
2233         menu->insert(label, BScreen::RestartOther, command);
2234       else
2235         menu->insert(label, BScreen::Restart);
2236     }
2237
2238       break;
2239
2240     case 845: { // reconfig
2241       if (! *label) {
2242         fprintf(stderr,
2243                 i18n(ScreenSet, ScreenRECONFIGError,
2244                      "BScreen::parseMenuFile: [reconfig] error, "
2245                      "no menu label defined\n"));
2246         continue;
2247       }
2248
2249       menu->insert(label, BScreen::Reconfigure);
2250     }
2251
2252       break;
2253
2254     case 995:    // stylesdir
2255     case 1113: { // stylesmenu
2256       bool newmenu = ((key == 1113) ? True : False);
2257
2258       if (! *label || (! *command && newmenu)) {
2259         fprintf(stderr,
2260                 i18n(ScreenSet, ScreenSTYLESDIRError,
2261                      "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2262                      " error, no directory defined\n"));
2263         continue;
2264       }
2265
2266       char *directory = ((newmenu) ? command : label);
2267
2268       string stylesdir = expandTilde(directory);
2269
2270       struct stat statbuf;
2271
2272       if (stat(stylesdir.c_str(), &statbuf) == -1) {
2273         fprintf(stderr,
2274                 i18n(ScreenSet, ScreenSTYLESDIRErrorNoExist,
2275                      "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2276                      " error, %s does not exist\n"), stylesdir.c_str());
2277         continue;
2278       }
2279       if (! S_ISDIR(statbuf.st_mode)) {
2280         fprintf(stderr,
2281                 i18n(ScreenSet, ScreenSTYLESDIRErrorNotDir,
2282                      "BScreen::parseMenuFile:"
2283                      " [stylesdir/stylesmenu] error, %s is not a"
2284                      " directory\n"), stylesdir.c_str());
2285         continue;
2286       }
2287
2288       Rootmenu *stylesmenu;
2289
2290       if (newmenu)
2291         stylesmenu = new Rootmenu(this);
2292       else
2293         stylesmenu = menu;
2294
2295       DIR *d = opendir(stylesdir.c_str());
2296       struct dirent *p;
2297       std::vector<string> ls;
2298
2299       while((p = readdir(d)))
2300         ls.push_back(p->d_name);
2301
2302       closedir(d);
2303
2304       std::sort(ls.begin(), ls.end());
2305
2306       std::vector<string>::iterator it = ls.begin(),
2307         end = ls.end();
2308       for (; it != end; ++it) {
2309         const string& fname = *it;
2310
2311         if (fname[fname.size()-1] == '~')
2312           continue;
2313
2314         string style = stylesdir;
2315         style += '/';
2316         style += fname;
2317
2318         if (! stat(style.c_str(), &statbuf) && S_ISREG(statbuf.st_mode))
2319           stylesmenu->insert(fname, BScreen::SetStyle, style);
2320       }
2321
2322       stylesmenu->update();
2323
2324       if (newmenu) {
2325         stylesmenu->setLabel(label);
2326         menu->insert(label, stylesmenu);
2327         rootmenuList.push_back(stylesmenu);
2328       }
2329
2330       blackbox->addMenuTimestamp(stylesdir);
2331     }
2332       break;
2333
2334     case 1090: { // workspaces
2335       if (! *label) {
2336         fprintf(stderr,
2337                 i18n(ScreenSet, ScreenWORKSPACESError,
2338                      "BScreen:parseMenuFile: [workspaces] error, "
2339                      "no menu label defined\n"));
2340         continue;
2341       }
2342
2343       menu->insert(label, workspacemenu);
2344     }
2345       break;
2346     }
2347   }
2348
2349   return ((menu->getCount() == 0) ? True : False);
2350 }
2351
2352
2353 void BScreen::shutdown(void) {
2354   XSelectInput(blackbox->getXDisplay(), getRootWindow(), NoEventMask);
2355   XSync(blackbox->getXDisplay(), False);
2356
2357   while(! windowList.empty())
2358     unmanageWindow(windowList.front(), True);
2359
2360   while(! desktopWindowList.empty()) {
2361     BlackboxWindow *win = blackbox->searchWindow(desktopWindowList.front());
2362     assert(win);
2363     unmanageWindow(win, True);
2364   }
2365
2366   slit->shutdown();
2367 }
2368
2369
2370 void BScreen::showPosition(int x, int y) {
2371   if (! geom_visible) {
2372     XMoveResizeWindow(blackbox->getXDisplay(), geom_window,
2373                       (getWidth() - geom_w) / 2,
2374                       (getHeight() - geom_h) / 2, geom_w, geom_h);
2375     XMapWindow(blackbox->getXDisplay(), geom_window);
2376     XRaiseWindow(blackbox->getXDisplay(), geom_window);
2377
2378     geom_visible = True;
2379   }
2380
2381   char label[1024];
2382
2383   sprintf(label, i18n(ScreenSet, ScreenPositionFormat,
2384                       "X: %4d x Y: %4d"), x, y);
2385
2386   XClearWindow(blackbox->getXDisplay(), geom_window);
2387
2388   resource.wstyle.font->drawString(geom_window,
2389                                    resource.bevel_width, resource.bevel_width,
2390                                    resource.wstyle.l_text_focus,
2391                                    label);
2392 }
2393
2394
2395 void BScreen::showGeometry(unsigned int gx, unsigned int gy) {
2396   if (! geom_visible) {
2397     XMoveResizeWindow(blackbox->getXDisplay(), geom_window,
2398                       (getWidth() - geom_w) / 2,
2399                       (getHeight() - geom_h) / 2, geom_w, geom_h);
2400     XMapWindow(blackbox->getXDisplay(), geom_window);
2401     XRaiseWindow(blackbox->getXDisplay(), geom_window);
2402
2403     geom_visible = True;
2404   }
2405
2406   char label[1024];
2407
2408   sprintf(label, i18n(ScreenSet, ScreenGeometryFormat,
2409                       "W: %4d x H: %4d"), gx, gy);
2410
2411   XClearWindow(blackbox->getXDisplay(), geom_window);
2412
2413   resource.wstyle.font->drawString(geom_window,
2414                                    resource.bevel_width, resource.bevel_width,
2415                                    resource.wstyle.l_text_focus,
2416                                    label);
2417 }
2418
2419
2420 void BScreen::hideGeometry(void) {
2421   if (geom_visible) {
2422     XUnmapWindow(blackbox->getXDisplay(), geom_window);
2423     geom_visible = False;
2424   }
2425 }
2426
2427
2428 void BScreen::addStrut(Strut *strut) {
2429   strutList.push_back(strut);
2430 }
2431
2432
2433 void BScreen::removeStrut(Strut *strut) {
2434   strutList.remove(strut);
2435 }
2436
2437
2438 const Rect& BScreen::availableArea(void) const {
2439   if (doFullMax())
2440     return getRect(); // return the full screen
2441   return usableArea;
2442 }
2443
2444
2445 #ifdef    XINERAMA
2446 const RectList& BScreen::allAvailableAreas(void) const {
2447   assert(isXineramaActive());
2448   assert(xineramaUsableArea.size() > 0);
2449   fprintf(stderr, "1found x %d y %d w %d h %d\n",
2450           xineramaUsableArea[0].x(), xineramaUsableArea[0].y(),
2451           xineramaUsableArea[0].width(), xineramaUsableArea[0].height());
2452   return xineramaUsableArea;
2453 }
2454 #endif // XINERAMA
2455
2456
2457 void BScreen::updateAvailableArea(void) {
2458   Rect old_area = usableArea;
2459   usableArea = getRect(); // reset to full screen
2460
2461 #ifdef    XINERAMA
2462   // reset to the full areas
2463   if (isXineramaActive())
2464     xineramaUsableArea = getXineramaAreas();
2465 #endif // XINERAMA
2466
2467   /* these values represent offsets from the screen edge
2468    * we look for the biggest offset on each edge and then apply them
2469    * all at once
2470    * do not be confused by the similarity to the names of Rect's members
2471    */
2472   unsigned int current_left = 0, current_right = 0, current_top = 0,
2473     current_bottom = 0;
2474
2475   StrutList::const_iterator it = strutList.begin(), end = strutList.end();
2476
2477   for(; it != end; ++it) {
2478     Strut *strut = *it;
2479     if (strut->left > current_left)
2480       current_left = strut->left;
2481     if (strut->top > current_top)
2482       current_top = strut->top;
2483     if (strut->right > current_right)
2484       current_right = strut->right;
2485     if (strut->bottom > current_bottom)
2486       current_bottom = strut->bottom;
2487   }
2488
2489   usableArea.setPos(current_left, current_top);
2490   usableArea.setSize(usableArea.width() - (current_left + current_right),
2491                      usableArea.height() - (current_top + current_bottom));
2492
2493 #ifdef    XINERAMA
2494   if (isXineramaActive()) {
2495     // keep each of the ximerama-defined areas inside the strut
2496     RectList::iterator xit, xend = xineramaUsableArea.end();
2497     for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
2498       if (xit->x() < usableArea.x()) {
2499         xit->setX(usableArea.x());
2500         xit->setWidth(xit->width() - usableArea.x());
2501       }
2502       if (xit->y() < usableArea.y()) {
2503         xit->setY(usableArea.y());
2504         xit->setHeight(xit->height() - usableArea.y());
2505       }
2506       if (xit->x() + xit->width() > usableArea.width())
2507         xit->setWidth(usableArea.width() - xit->x());
2508       if (xit->y() + xit->height() > usableArea.height())
2509         xit->setHeight(usableArea.height() - xit->y());
2510     }
2511   }
2512 #endif // XINERAMA
2513
2514   if (old_area != usableArea) {
2515     BlackboxWindowList::iterator it = windowList.begin(),
2516       end = windowList.end();
2517     for (; it != end; ++it)
2518       if ((*it)->isMaximized()) (*it)->remaximize();
2519   }
2520
2521   updateWorkArea();  
2522 }
2523
2524
2525 Workspace* BScreen::getWorkspace(unsigned int index) const {
2526   assert(index < workspacesList.size());
2527   return workspacesList[index];
2528 }
2529
2530
2531 void BScreen::buttonPressEvent(const XButtonEvent *xbutton) {
2532   if (xbutton->button == 1) {
2533     if (! isRootColormapInstalled())
2534       image_control->installRootColormap();
2535
2536     if (workspacemenu->isVisible())
2537       workspacemenu->hide();
2538
2539     if (rootmenu->isVisible())
2540       rootmenu->hide();
2541   // mouse wheel up
2542   } else if ((xbutton->button == 4 && resource.root_scroll == NormalScroll) ||
2543              (xbutton->button == 5 && resource.root_scroll == ReverseScroll)) {
2544     if (getCurrentWorkspaceID() >= getWorkspaceCount() - 1)
2545       changeWorkspaceID(0);
2546     else
2547       changeWorkspaceID(getCurrentWorkspaceID() + 1);
2548   // mouse wheel down
2549   } else if ((xbutton->button == 5 && resource.root_scroll == NormalScroll) ||
2550              (xbutton->button == 4 && resource.root_scroll == ReverseScroll)) {
2551     if (getCurrentWorkspaceID() == 0)
2552       changeWorkspaceID(getWorkspaceCount() - 1);
2553     else
2554       changeWorkspaceID(getCurrentWorkspaceID() - 1);
2555   }
2556
2557   if (resource.root_menu_button > 0 &&
2558       xbutton->button == resource.root_menu_button)
2559     showRootMenu(xbutton->x_root, xbutton->y_root);
2560   else if (resource.workspace_menu_button > 0 &&
2561            xbutton->button == resource.workspace_menu_button)
2562     showWorkspaceMenu(xbutton->x_root, xbutton->y_root);
2563 }
2564
2565
2566 void BScreen::showWorkspaceMenu(int x, int y) {
2567   int mx = x - (workspacemenu->getWidth() / 2);
2568   int my = y - (workspacemenu->getTitleHeight() / 2);
2569
2570   if (mx < 0) mx = 0;
2571   if (my < 0) my = 0;
2572
2573   if (mx + workspacemenu->getWidth() > getWidth())
2574     mx = getWidth() - workspacemenu->getWidth() - getBorderWidth();
2575
2576   if (my + workspacemenu->getHeight() > getHeight())
2577     my = getHeight() - workspacemenu->getHeight() - getBorderWidth();
2578
2579   workspacemenu->move(mx, my);
2580
2581   if (! workspacemenu->isVisible()) {
2582     workspacemenu->removeParent();
2583     workspacemenu->show();
2584   }
2585 }
2586
2587
2588 void BScreen::showRootMenu(int x, int y) {
2589   int mx = x - (rootmenu->getWidth() / 2);
2590   int my = y - (rootmenu->getTitleHeight() / 2);
2591
2592   if (mx < 0) mx = 0;
2593   if (my < 0) my = 0;
2594
2595   if (mx + rootmenu->getWidth() > getWidth())
2596     mx = getWidth() - rootmenu->getWidth() - getBorderWidth();
2597
2598   if (my + rootmenu->getHeight() > getHeight())
2599     my = getHeight() - rootmenu->getHeight() - getBorderWidth();
2600
2601   rootmenu->move(mx, my);
2602
2603   if (! rootmenu->isVisible()) {
2604     blackbox->checkMenu();
2605     rootmenu->show();
2606   }
2607 }
2608
2609
2610 void BScreen::propertyNotifyEvent(const XPropertyEvent *pe) {
2611   if (pe->atom == xatom->getAtom(XAtom::net_desktop_names)) {
2612     // _NET_WM_DESKTOP_NAMES
2613     WorkspaceList::iterator it = workspacesList.begin();
2614     const WorkspaceList::iterator end = workspacesList.end();
2615     for (; it != end; ++it) {
2616       (*it)->readName(); // re-read its name from the window property
2617       workspacemenu->changeWorkspaceLabel((*it)->getID(), (*it)->getName());
2618     }
2619     workspacemenu->update();
2620     toolbar->reconfigure();
2621     saveWorkspaceNames();
2622   }
2623 }
2624
2625
2626 void BScreen::toggleFocusModel(FocusModel model) {
2627   std::for_each(windowList.begin(), windowList.end(),
2628                 std::mem_fun(&BlackboxWindow::ungrabButtons));
2629
2630   if (model == SloppyFocus) {
2631     saveSloppyFocus(True);
2632   } else {
2633     // we're cheating here to save writing the config file 3 times
2634     resource.auto_raise = False;
2635     resource.click_raise = False;
2636     saveSloppyFocus(False);
2637   }
2638
2639   std::for_each(windowList.begin(), windowList.end(),
2640                 std::mem_fun(&BlackboxWindow::grabButtons));
2641 }
2642
2643 #ifdef    BITMAPBUTTONS
2644 void BScreen::readDatabaseMask(const string &rname, PixmapMask &pixmapMask,
2645                                const Configuration &style) {
2646   string s;
2647   int hx, hy; //ignored
2648   int ret = BitmapOpenFailed; //default to failure.
2649   
2650   if (style.getValue(rname, s))
2651   {
2652     if (s[0] != '/' && s[0] != '~')
2653     {
2654       std::string xbmFile = std::string("~/.openbox/buttons/") + s;
2655       ret = XReadBitmapFile(blackbox->getXDisplay(), getRootWindow(),
2656                             expandTilde(xbmFile).c_str(), &pixmapMask.w,
2657                             &pixmapMask.h, &pixmapMask.mask, &hx, &hy);
2658     } else
2659       ret = XReadBitmapFile(blackbox->getXDisplay(), getRootWindow(),
2660                             expandTilde(s).c_str(), &pixmapMask.w,
2661                             &pixmapMask.h, &pixmapMask.mask, &hx, &hy);
2662     
2663     if (ret == BitmapSuccess)
2664       return;
2665   }
2666
2667   pixmapMask.mask = None;
2668   pixmapMask.w = pixmapMask.h = 0;
2669 }
2670 #endif // BITMAPSUCCESS
2671
2672 BTexture BScreen::readDatabaseTexture(const string &rname,
2673                                       const string &default_color,
2674                                       const Configuration &style) {
2675   BTexture texture;
2676   string s;
2677
2678   if (style.getValue(rname, s))
2679     texture = BTexture(s);
2680   else
2681     texture.setTexture(BTexture::Solid | BTexture::Flat);
2682
2683   // associate this texture with this screen
2684   texture.setDisplay(getBaseDisplay(), getScreenNumber());
2685   texture.setImageControl(image_control);
2686
2687   texture.setColor(readDatabaseColor(rname + ".color", default_color, style));
2688   texture.setColorTo(readDatabaseColor(rname + ".colorTo", default_color,
2689                                        style));
2690   texture.setBorderColor(readDatabaseColor(rname + ".borderColor",
2691                                            default_color, style));
2692   
2693   return texture;
2694 }
2695
2696
2697 BColor BScreen::readDatabaseColor(const string &rname,
2698                                   const string &default_color,
2699                                   const Configuration &style) {
2700   BColor color;
2701   string s;
2702   if (style.getValue(rname, s))
2703     color = BColor(s, getBaseDisplay(), getScreenNumber());
2704   else
2705     color = BColor(default_color, getBaseDisplay(), getScreenNumber());
2706   return color;
2707 }
2708
2709
2710 BFont *BScreen::readDatabaseFont(const string &rbasename,
2711                                  const Configuration &style) {
2712   string fontname;
2713
2714   string s;
2715
2716 #ifdef    XFT
2717   int i;
2718   if (style.getValue(rbasename + "xft.font", s) &&
2719       style.getValue(rbasename + "xft.size", i)) {
2720     string family = s;
2721     bool bold = False;
2722     bool italic = False;
2723     if (style.getValue(rbasename + "xft.flags", s)) {
2724       if (s.find("bold") != string::npos)
2725         bold = True;
2726       if (s.find("italic") != string::npos)
2727         italic = True;
2728     }
2729     
2730     BFont *b = new BFont(blackbox->getXDisplay(), this, family, i, bold,
2731                          italic, resource.shadow_fonts, resource.aa_fonts);
2732     if (b->valid())
2733       return b;
2734     else
2735       delete b; // fall back to the normal X font stuff
2736   }
2737 #endif // XFT
2738
2739   style.getValue(rbasename + "font", s);
2740   // if this fails, a blank string will be used, which will cause the fallback
2741   // font to load.
2742
2743   BFont *b = new BFont(blackbox->getXDisplay(), this, s);
2744   if (! b->valid())
2745     exit(2);  // can't continue without a font
2746   return b;
2747 }