]> icculus.org git repositories - mikachu/openbox.git/blob - src/Screen.cc
no more menus, at last. woop
[mikachu/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   //if neither of these can be found, we will use the previous resource
1069   resource.wstyle.b_pressed_focus =
1070     readDatabaseTexture("window.button.pressed.focus", "black", style, true);
1071   resource.wstyle.b_pressed_unfocus =
1072     readDatabaseTexture("window.button.pressed.unfocus", "black", style, true);
1073
1074 #ifdef    BITMAPBUTTONS
1075   if (resource.wstyle.close_button.mask != None)
1076     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.close_button.mask);
1077   if (resource.wstyle.max_button.mask != None)
1078     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.max_button.mask);
1079   if (resource.wstyle.icon_button.mask != None)
1080     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.icon_button.mask);
1081   if (resource.wstyle.stick_button.mask != None)
1082     XFreePixmap(blackbox->getXDisplay(), resource.wstyle.stick_button.mask);
1083
1084   resource.wstyle.close_button.mask = resource.wstyle.max_button.mask =
1085     resource.wstyle.icon_button.mask =
1086     resource.wstyle.icon_button.mask = None;
1087   
1088   readDatabaseMask("window.button.close.mask", resource.wstyle.close_button,
1089                    style);
1090   readDatabaseMask("window.button.max.mask", resource.wstyle.max_button,
1091                    style);
1092   readDatabaseMask("window.button.icon.mask", resource.wstyle.icon_button,
1093                    style);
1094   readDatabaseMask("window.button.stick.mask", resource.wstyle.stick_button,
1095                    style);
1096 #endif // BITMAPBUTTONS
1097
1098   // we create the window.frame texture by hand because it exists only to
1099   // make the code cleaner and is not actually used for display
1100   BColor color = readDatabaseColor("window.frame.focusColor", "white", style);
1101   resource.wstyle.f_focus = BTexture("solid flat", getBaseDisplay(),
1102                                      getScreenNumber(), image_control);
1103   resource.wstyle.f_focus.setColor(color);
1104
1105   color = readDatabaseColor("window.frame.unfocusColor", "white", style);
1106   resource.wstyle.f_unfocus = BTexture("solid flat", getBaseDisplay(),
1107                                        getScreenNumber(), image_control);
1108   resource.wstyle.f_unfocus.setColor(color);
1109
1110   resource.wstyle.l_text_focus =
1111     readDatabaseColor("window.label.focus.textColor", "black", style);
1112   resource.wstyle.l_text_unfocus =
1113     readDatabaseColor("window.label.unfocus.textColor", "white", style);
1114   resource.wstyle.b_pic_focus =
1115     readDatabaseColor("window.button.focus.picColor", "black", style);
1116   resource.wstyle.b_pic_unfocus =
1117     readDatabaseColor("window.button.unfocus.picColor", "white", style);
1118
1119   resource.wstyle.justify = LeftJustify;
1120   if (style.getValue("window.justify", s)) {
1121     if (s == "right" || s == "Right")
1122       resource.wstyle.justify = RightJustify;
1123     else if (s == "center" || s == "Center")
1124       resource.wstyle.justify = CenterJustify;
1125   }
1126
1127   // sanity checks
1128   if (resource.wstyle.t_focus.texture() == BTexture::Parent_Relative)
1129     resource.wstyle.t_focus = resource.wstyle.f_focus;
1130   if (resource.wstyle.t_unfocus.texture() == BTexture::Parent_Relative)
1131     resource.wstyle.t_unfocus = resource.wstyle.f_unfocus;
1132   if (resource.wstyle.h_focus.texture() == BTexture::Parent_Relative)
1133     resource.wstyle.h_focus = resource.wstyle.f_focus;
1134   if (resource.wstyle.h_unfocus.texture() == BTexture::Parent_Relative)
1135     resource.wstyle.h_unfocus = resource.wstyle.f_unfocus;
1136
1137   // load toolbar config
1138 #ifdef    BITMAPBUTTONS
1139   if (resource.tstyle.left_button.mask != None)
1140     XFreePixmap(blackbox->getXDisplay(), resource.tstyle.left_button.mask);
1141   if (resource.tstyle.right_button.mask != None)
1142     XFreePixmap(blackbox->getXDisplay(), resource.tstyle.right_button.mask);
1143 #endif // BITMAPBUTTONS
1144   
1145   resource.tstyle.toolbar =
1146     readDatabaseTexture("toolbar", "black", style);
1147   resource.tstyle.label =
1148     readDatabaseTexture("toolbar.label", "black", style);
1149   resource.tstyle.window =
1150     readDatabaseTexture("toolbar.windowLabel", "black", style);
1151   resource.tstyle.button =
1152     readDatabaseTexture("toolbar.button", "white", style);
1153   resource.tstyle.pressed =
1154     readDatabaseTexture("toolbar.button.pressed", "black", style);
1155   resource.tstyle.clock =
1156     readDatabaseTexture("toolbar.clock", "black", style);
1157   resource.tstyle.l_text =
1158     readDatabaseColor("toolbar.label.textColor", "white", style);
1159   resource.tstyle.w_text =
1160     readDatabaseColor("toolbar.windowLabel.textColor", "white", style);
1161   resource.tstyle.c_text =
1162     readDatabaseColor("toolbar.clock.textColor", "white", style);
1163   resource.tstyle.b_pic =
1164     readDatabaseColor("toolbar.button.picColor", "black", style);
1165
1166 #ifdef    BITMAPBUTTONS
1167   readDatabaseMask("toolbar.button.left.mask", resource.tstyle.left_button,
1168                    style);
1169   readDatabaseMask("toolbar.button.right.mask", resource.tstyle.right_button,
1170                    style);
1171 #endif // BITMAPBUTTONS
1172   
1173   resource.tstyle.justify = LeftJustify;
1174   if (style.getValue("toolbar.justify", s)) {
1175     if (s == "right" || s == "Right")
1176       resource.tstyle.justify = RightJustify;
1177     else if (s == "center" || s == "Center")
1178       resource.tstyle.justify = CenterJustify;
1179   }
1180
1181   // sanity checks
1182   if (resource.tstyle.toolbar.texture() == BTexture::Parent_Relative) {
1183     resource.tstyle.toolbar = BTexture("solid flat", getBaseDisplay(),
1184                                        getScreenNumber(), image_control);
1185     resource.tstyle.toolbar.setColor(BColor("black", getBaseDisplay(),
1186                                             getScreenNumber()));
1187   }
1188
1189   // load menu config
1190 #ifdef   BITMAPBUTTONS
1191   if (resource.mstyle.bullet_image.mask != None)
1192     XFreePixmap(blackbox->getXDisplay(), resource.mstyle.bullet_image.mask);
1193   if (resource.mstyle.tick_image.mask != None)
1194     XFreePixmap(blackbox->getXDisplay(), resource.mstyle.tick_image.mask);
1195 #endif // BITMAPBUTTONS
1196   
1197   resource.mstyle.title =
1198     readDatabaseTexture("menu.title", "white", style);
1199   resource.mstyle.frame =
1200     readDatabaseTexture("menu.frame", "black", style);
1201   resource.mstyle.hilite =
1202     readDatabaseTexture("menu.hilite", "white", style);
1203   resource.mstyle.t_text =
1204     readDatabaseColor("menu.title.textColor", "black", style);
1205   resource.mstyle.f_text =
1206     readDatabaseColor("menu.frame.textColor", "white", style);
1207   resource.mstyle.d_text =
1208     readDatabaseColor("menu.frame.disableColor", "black", style);
1209   resource.mstyle.h_text =
1210     readDatabaseColor("menu.hilite.textColor", "black", style);
1211
1212 #ifdef    BITMAPBUTTONS
1213   readDatabaseMask("menu.arrow.mask", resource.mstyle.bullet_image, style);
1214   readDatabaseMask("menu.selected.mask", resource.mstyle.tick_image, style);
1215 #endif // BITMAPBUTTONS
1216     
1217   resource.mstyle.t_justify = LeftJustify;
1218   if (style.getValue("menu.title.justify", s)) {
1219     if (s == "right" || s == "Right")
1220       resource.mstyle.t_justify = RightJustify;
1221     else if (s == "center" || s == "Center")
1222       resource.mstyle.t_justify = CenterJustify;
1223   }
1224
1225   resource.mstyle.f_justify = LeftJustify;
1226   if (style.getValue("menu.frame.justify", s)) {
1227     if (s == "right" || s == "Right")
1228       resource.mstyle.f_justify = RightJustify;
1229     else if (s == "center" || s == "Center")
1230       resource.mstyle.f_justify = CenterJustify;
1231   }
1232
1233   resource.mstyle.bullet = Basemenu::Triangle;
1234   if (style.getValue("menu.bullet", s)) {
1235     if (s == "empty" || s == "Empty")
1236       resource.mstyle.bullet = Basemenu::Empty;
1237     else if (s == "square" || s == "Square")
1238       resource.mstyle.bullet = Basemenu::Square;
1239     else if (s == "diamond" || s == "Diamond")
1240       resource.mstyle.bullet = Basemenu::Diamond;
1241   }
1242
1243   resource.mstyle.bullet_pos = Basemenu::Left;
1244   if (style.getValue("menu.bullet.position", s)) {
1245     if (s == "right" || s == "Right")
1246       resource.mstyle.bullet_pos = Basemenu::Right;
1247   }
1248
1249   // sanity checks
1250   if (resource.mstyle.frame.texture() == BTexture::Parent_Relative) {
1251     resource.mstyle.frame = BTexture("solid flat", getBaseDisplay(),
1252                                      getScreenNumber(), image_control);
1253     resource.mstyle.frame.setColor(BColor("black", getBaseDisplay(),
1254                                           getScreenNumber()));
1255   }
1256
1257   resource.border_color =
1258     readDatabaseColor("borderColor", "black", style);
1259
1260   // load bevel, border and handle widths
1261   if (! style.getValue("handleWidth", resource.handle_width) ||
1262       resource.handle_width > (getWidth() / 2) || resource.handle_width == 0)
1263     resource.handle_width = 6;
1264
1265   if (! style.getValue("borderWidth", resource.border_width))
1266     resource.border_width = 1;
1267
1268   if (! style.getValue("bevelWidth", resource.bevel_width) ||
1269       resource.bevel_width > (getWidth() / 2) || resource.bevel_width == 0)
1270     resource.bevel_width = 3;
1271
1272   if (! style.getValue("frameWidth", resource.frame_width) ||
1273       resource.frame_width > (getWidth() / 2))
1274     resource.frame_width = resource.bevel_width;
1275
1276   if (style.getValue("rootCommand", s))
1277     bexec(s, displayString());
1278 }
1279
1280
1281 void BScreen::addIcon(BlackboxWindow *w) {
1282   if (! w) return;
1283
1284   w->setWorkspace(BSENTINEL);
1285   w->setWindowNumber(iconList.size());
1286
1287   iconList.push_back(w);
1288
1289   const char* title = w->getIconTitle();
1290   iconmenu->insert(title);
1291   iconmenu->update();
1292 }
1293
1294
1295 void BScreen::removeIcon(BlackboxWindow *w) {
1296   if (! w) return;
1297
1298   iconList.remove(w);
1299
1300   iconmenu->remove(w->getWindowNumber());
1301   iconmenu->update();
1302
1303   BlackboxWindowList::iterator it = iconList.begin(),
1304     end = iconList.end();
1305   for (int i = 0; it != end; ++it)
1306     (*it)->setWindowNumber(i++);
1307 }
1308
1309
1310 BlackboxWindow *BScreen::getIcon(unsigned int index) {
1311   if (index < iconList.size()) {
1312     BlackboxWindowList::iterator it = iconList.begin();
1313     while (index-- > 0) // increment to index
1314       ++it;
1315     return *it;
1316   }
1317
1318   return (BlackboxWindow *) 0;
1319 }
1320
1321
1322 unsigned int BScreen::addWorkspace(void) {
1323   Workspace *wkspc = new Workspace(this, workspacesList.size());
1324   workspacesList.push_back(wkspc);
1325   saveWorkspaces(getWorkspaceCount());
1326   saveWorkspaceNames();
1327
1328   workspacemenu->insertWorkspace(wkspc);
1329   workspacemenu->update();
1330
1331   toolbar->reconfigure();
1332
1333   updateNetizenWorkspaceCount();
1334
1335   return workspacesList.size();
1336 }
1337
1338
1339 unsigned int BScreen::removeLastWorkspace(void) {
1340   if (workspacesList.size() == 1)
1341     return 1;
1342
1343   Workspace *wkspc = workspacesList.back();
1344
1345   if (current_workspace->getID() == wkspc->getID())
1346     changeWorkspaceID(current_workspace->getID() - 1);
1347
1348   wkspc->removeAll();
1349
1350   workspacemenu->removeWorkspace(wkspc);
1351   workspacemenu->update();
1352
1353   workspacesList.pop_back();
1354   delete wkspc;
1355
1356   saveWorkspaces(getWorkspaceCount());
1357   saveWorkspaceNames();
1358
1359   toolbar->reconfigure();
1360
1361   updateNetizenWorkspaceCount();
1362
1363   return workspacesList.size();
1364 }
1365
1366
1367 void BScreen::changeWorkspaceID(unsigned int id) {
1368   if (! current_workspace || id == current_workspace->getID()) return;
1369
1370   BlackboxWindow *focused = blackbox->getFocusedWindow();
1371   if (focused && focused->getScreen() == this) {
1372     assert(focused->isStuck() ||
1373            focused->getWorkspaceNumber() == current_workspace->getID());
1374
1375     current_workspace->setLastFocusedWindow(focused);
1376   } else {
1377     // if no window had focus, no need to store a last focus
1378     current_workspace->setLastFocusedWindow((BlackboxWindow *) 0);
1379   }
1380
1381   // when we switch workspaces, unfocus whatever was focused if it is going
1382   // to be unmapped
1383   if (focused && ! focused->isStuck())
1384     blackbox->setFocusedWindow((BlackboxWindow *) 0);
1385
1386   current_workspace->hideAll();
1387   workspacemenu->setItemSelected(current_workspace->getID() + 2, False);
1388
1389   current_workspace = getWorkspace(id);
1390
1391   xatom->setValue(getRootWindow(), XAtom::net_current_desktop,
1392                   XAtom::cardinal, id);
1393
1394   workspacemenu->setItemSelected(current_workspace->getID() + 2, True);
1395   toolbar->redrawWorkspaceLabel(True);
1396
1397   current_workspace->showAll();
1398
1399   int x, y, rx, ry;
1400   Window c, r;
1401   unsigned int m;
1402   BlackboxWindow *win = (BlackboxWindow *) 0;
1403   bool f = False;
1404
1405   XSync(blackbox->getXDisplay(), False);
1406
1407   // If sloppy focus and we can find the client window under the pointer,
1408   // try to focus it.  
1409   if (resource.sloppy_focus &&
1410       XQueryPointer(blackbox->getXDisplay(), getRootWindow(), &r, &c,
1411                     &rx, &ry, &x, &y, &m) &&
1412       c != None) {
1413     if ( (win = blackbox->searchWindow(c)) )
1414       f = win->setInputFocus();
1415   }
1416
1417   // If that fails, and we're doing focus_last, try to focus the last window.
1418   if (! f && resource.focus_last &&
1419       (win = current_workspace->getLastFocusedWindow()))
1420     f = win->setInputFocus();
1421
1422   /*
1423     if we found a focus target, then we set the focused window explicitly
1424     because it is possible to switch off this workspace before the x server
1425     generates the FocusIn event for the window. if that happens, openbox would
1426     lose track of what window was the 'LastFocused' window on the workspace.
1427
1428     if we did not find a focus target, then set the current focused window to
1429     nothing.
1430   */
1431   if (f)
1432     blackbox->setFocusedWindow(win);
1433   else
1434     blackbox->setFocusedWindow((BlackboxWindow *) 0);
1435
1436   updateNetizenCurrentWorkspace();
1437 }
1438
1439
1440 /*
1441  * Set the _NET_CLIENT_LIST root window property.
1442  */
1443 void BScreen::updateClientList(void) {
1444   if (windowList.size() > 0) {
1445     Window *windows = new Window[windowList.size()];
1446     Window *win_it = windows;
1447     BlackboxWindowList::iterator it = windowList.begin();
1448     const BlackboxWindowList::iterator end = windowList.end();
1449     for (; it != end; ++it, ++win_it)
1450       *win_it = (*it)->getClientWindow();
1451     xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
1452                     windows, windowList.size());
1453     delete [] windows;
1454   } else
1455     xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
1456                     0, 0);
1457
1458   updateStackingList();
1459 }
1460
1461
1462 /*
1463  * Set the _NET_CLIENT_LIST_STACKING root window property.
1464  */
1465 void BScreen::updateStackingList(void) {
1466
1467   BlackboxWindowList stack_order;
1468
1469   /*
1470    * Get the stacking order from all of the workspaces.
1471    * We start with the current workspace so that the sticky windows will be
1472    * in the right order on the current workspace.
1473    * XXX: Do we need to have sticky windows in the list once for each workspace?
1474    */
1475   getCurrentWorkspace()->appendStackOrder(stack_order);
1476   for (unsigned int i = 0; i < getWorkspaceCount(); ++i)
1477     if (i != getCurrentWorkspaceID())
1478       getWorkspace(i)->appendStackOrder(stack_order);
1479
1480   if (stack_order.size() > 0) {
1481     // set the client list atoms
1482     Window *windows = new Window[stack_order.size()];
1483     Window *win_it = windows;
1484     BlackboxWindowList::iterator it = stack_order.begin(),
1485                                  end = stack_order.end();
1486     for (; it != end; ++it, ++win_it)
1487       *win_it = (*it)->getClientWindow();
1488     xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
1489                     XAtom::window, windows, stack_order.size());
1490     delete [] windows;
1491   } else
1492     xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
1493                     XAtom::window, 0, 0);
1494 }
1495
1496
1497 void BScreen::addSystrayWindow(Window window) {
1498   XGrabServer(blackbox->getXDisplay());
1499   
1500   XSelectInput(blackbox->getXDisplay(), window, StructureNotifyMask);
1501   systrayWindowList.push_back(window);
1502   xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
1503                   XAtom::window,
1504                   &systrayWindowList[0], systrayWindowList.size());
1505   blackbox->saveSystrayWindowSearch(window, this);
1506
1507   XUngrabServer(blackbox->getXDisplay());
1508 }
1509
1510
1511 void BScreen::removeSystrayWindow(Window window) {
1512   XGrabServer(blackbox->getXDisplay());
1513   
1514   WindowList::iterator it = systrayWindowList.begin();
1515   const WindowList::iterator end = systrayWindowList.end();
1516   for (; it != end; ++it)
1517     if (*it == window) {
1518       systrayWindowList.erase(it);
1519       xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
1520                       XAtom::window,
1521                       &systrayWindowList[0], systrayWindowList.size());
1522       blackbox->removeSystrayWindowSearch(window);
1523       XSelectInput(blackbox->getXDisplay(), window, NoEventMask);
1524       break;
1525     }
1526
1527   assert(it != end);    // not a systray window
1528
1529   XUngrabServer(blackbox->getXDisplay());
1530 }
1531
1532
1533 void BScreen::manageWindow(Window w) {
1534   // is the window a KDE systray window?
1535   Window systray;
1536   if (xatom->getValue(w, XAtom::kde_net_wm_system_tray_window_for,
1537                       XAtom::window, systray) && systray != None) {
1538     addSystrayWindow(w);
1539     return;
1540   }
1541
1542   // is the window a docking app
1543   XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), w);
1544   if (wmhint && (wmhint->flags & StateHint) &&
1545       wmhint->initial_state == WithdrawnState) {
1546     slit->addClient(w);
1547     return;
1548   }
1549
1550   new BlackboxWindow(blackbox, w, this);
1551
1552   BlackboxWindow *win = blackbox->searchWindow(w);
1553   if (! win)
1554     return;
1555
1556   if (win->isDesktop()) {
1557     desktopWindowList.push_back(win->getFrameWindow());
1558   } else { // if (win->isNormal()) {
1559     // don't list desktop windows as managed windows
1560     windowList.push_back(win);
1561     updateClientList();
1562   
1563     if (win->isTopmost())
1564       specialWindowList.push_back(win->getFrameWindow());
1565   }
1566   
1567   XMapRequestEvent mre;
1568   mre.window = w;
1569   if (blackbox->isStartup() && win->isNormal()) win->restoreAttributes();
1570   win->mapRequestEvent(&mre);
1571 }
1572
1573
1574 void BScreen::unmanageWindow(BlackboxWindow *w, bool remap) {
1575   // is the window a KDE systray window?
1576   Window systray;
1577   if (xatom->getValue(w->getClientWindow(),
1578                       XAtom::kde_net_wm_system_tray_window_for,
1579                       XAtom::window, systray) && systray != None) {
1580     removeSystrayWindow(w->getClientWindow());
1581     return;
1582   }
1583
1584   w->restore(remap);
1585
1586   // Remove the modality so that its parent won't try to re-focus the window
1587   if (w->isModal()) w->setModal(False);
1588   
1589   if (w->getWorkspaceNumber() != BSENTINEL &&
1590       w->getWindowNumber() != BSENTINEL) {
1591     getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
1592     if (w->isStuck()) {
1593       for (unsigned int i = 0; i < getNumberOfWorkspaces(); ++i)
1594         if (i != w->getWorkspaceNumber())
1595           getWorkspace(i)->removeWindow(w, True);
1596     }
1597   } else if (w->isIconic())
1598     removeIcon(w);
1599
1600   if (w->isDesktop()) {
1601     WindowList::iterator it = desktopWindowList.begin();
1602     const WindowList::iterator end = desktopWindowList.end();
1603     for (; it != end; ++it)
1604       if (*it == w->getFrameWindow()) {
1605         desktopWindowList.erase(it);
1606         break;
1607       }
1608     assert(it != end);  // the window wasnt a desktop window?
1609   } else { // if (w->isNormal()) {
1610     // we don't list desktop windows as managed windows
1611     windowList.remove(w);
1612     updateClientList();
1613
1614     if (w->isTopmost()) {
1615       WindowList::iterator it = specialWindowList.begin();
1616       const WindowList::iterator end = specialWindowList.end();
1617       for (; it != end; ++it)
1618         if (*it == w->getFrameWindow()) {
1619           specialWindowList.erase(it);
1620           break;
1621         }
1622       assert(it != end);  // the window wasnt a special window?
1623     }
1624   }
1625
1626   if (blackbox->getFocusedWindow() == w)
1627     blackbox->setFocusedWindow((BlackboxWindow *) 0);
1628
1629   removeNetizen(w->getClientWindow());
1630
1631   /*
1632     some managed windows can also be window group controllers.  when
1633     unmanaging such windows, we should also delete the window group.
1634   */
1635   BWindowGroup *group = blackbox->searchGroup(w->getClientWindow());
1636   delete group;
1637
1638   delete w;
1639 }
1640
1641
1642 void BScreen::addNetizen(Netizen *n) {
1643   netizenList.push_back(n);
1644
1645   n->sendWorkspaceCount();
1646   n->sendCurrentWorkspace();
1647
1648   WorkspaceList::iterator it = workspacesList.begin();
1649   const WorkspaceList::iterator end = workspacesList.end();
1650   for (; it != end; ++it)
1651     (*it)->sendWindowList(*n);
1652
1653   Window f = ((blackbox->getFocusedWindow()) ?
1654               blackbox->getFocusedWindow()->getClientWindow() : None);
1655   n->sendWindowFocus(f);
1656 }
1657
1658
1659 void BScreen::removeNetizen(Window w) {
1660   NetizenList::iterator it = netizenList.begin();
1661   for (; it != netizenList.end(); ++it) {
1662     if ((*it)->getWindowID() == w) {
1663       delete *it;
1664       netizenList.erase(it);
1665       break;
1666     }
1667   }
1668 }
1669
1670
1671 void BScreen::updateWorkArea(void) {
1672   if (workspacesList.size() > 0) {
1673     unsigned long *dims = new unsigned long[4 * workspacesList.size()];
1674     for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
1675       // XXX: this could be different for each workspace
1676       const Rect &area = availableArea();
1677       dims[(i * 4) + 0] = area.x();
1678       dims[(i * 4) + 1] = area.y();
1679       dims[(i * 4) + 2] = area.width();
1680       dims[(i * 4) + 3] = area.height();
1681     }
1682     xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
1683                     dims, 4 * workspacesList.size());
1684     delete [] dims;
1685   } else
1686     xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
1687                     0, 0);
1688 }
1689
1690
1691 void BScreen::updateNetizenCurrentWorkspace(void) {
1692   std::for_each(netizenList.begin(), netizenList.end(),
1693                 std::mem_fun(&Netizen::sendCurrentWorkspace));
1694 }
1695
1696
1697 void BScreen::updateNetizenWorkspaceCount(void) {
1698   xatom->setValue(getRootWindow(), XAtom::net_number_of_desktops,
1699                   XAtom::cardinal, workspacesList.size());
1700
1701   updateWorkArea();
1702   
1703   std::for_each(netizenList.begin(), netizenList.end(),
1704                 std::mem_fun(&Netizen::sendWorkspaceCount));
1705 }
1706
1707
1708 void BScreen::updateNetizenWindowFocus(void) {
1709   Window f = ((blackbox->getFocusedWindow()) ?
1710               blackbox->getFocusedWindow()->getClientWindow() : None);
1711
1712   xatom->setValue(getRootWindow(), XAtom::net_active_window,
1713                   XAtom::window, f);
1714
1715   NetizenList::iterator it = netizenList.begin();
1716   for (; it != netizenList.end(); ++it)
1717     (*it)->sendWindowFocus(f);
1718 }
1719
1720
1721 void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) {
1722   NetizenList::iterator it = netizenList.begin();
1723   for (; it != netizenList.end(); ++it) {
1724     (*it)->sendWindowAdd(w, p);
1725   }
1726 }
1727
1728
1729 void BScreen::updateNetizenWindowDel(Window w) {
1730   NetizenList::iterator it = netizenList.begin();
1731   for (; it != netizenList.end(); ++it)
1732     (*it)->sendWindowDel(w);
1733 }
1734
1735
1736 void BScreen::updateNetizenWindowRaise(Window w) {
1737   NetizenList::iterator it = netizenList.begin();
1738   for (; it != netizenList.end(); ++it)
1739     (*it)->sendWindowRaise(w);
1740 }
1741
1742
1743 void BScreen::updateNetizenWindowLower(Window w) {
1744   NetizenList::iterator it = netizenList.begin();
1745   for (; it != netizenList.end(); ++it)
1746     (*it)->sendWindowLower(w);
1747 }
1748
1749
1750 void BScreen::updateNetizenConfigNotify(XEvent *e) {
1751   NetizenList::iterator it = netizenList.begin();
1752   for (; it != netizenList.end(); ++it)
1753     (*it)->sendConfigNotify(e);
1754 }
1755
1756
1757 void BScreen::raiseWindows(Window *workspace_stack, unsigned int num) {
1758   // the 13 represents the number of blackbox windows such as menus
1759   int bbwins = 15;
1760 #ifdef    XINERAMA
1761   ++bbwins;
1762 #endif // XINERAMA
1763 #ifdef    XFT
1764   ++bbwins;
1765 #endif // XFT
1766
1767   Window *session_stack = new
1768     Window[(num + workspacesList.size() + rootmenuList.size() +
1769             specialWindowList.size() + bbwins)];
1770   unsigned int i = 0, k = num;
1771
1772   XRaiseWindow(blackbox->getXDisplay(), iconmenu->getWindowID());
1773   *(session_stack + i++) = iconmenu->getWindowID();
1774
1775   WorkspaceList::iterator wit = workspacesList.begin();
1776   const WorkspaceList::iterator w_end = workspacesList.end();
1777   for (; wit != w_end; ++wit)
1778     *(session_stack + i++) = (*wit)->getMenu()->getWindowID();
1779
1780   *(session_stack + i++) = workspacemenu->getWindowID();
1781
1782   *(session_stack + i++) = configmenu->getFocusmenu()->getWindowID();
1783   *(session_stack + i++) = configmenu->getPlacementmenu()->getWindowID();
1784   *(session_stack + i++) = configmenu->getWindowSnapmenu()->getWindowID();
1785   *(session_stack + i++) = configmenu->getEdgeSnapmenu()->getWindowID();
1786 #ifdef    XINERAMA
1787   *(session_stack + i++) = configmenu->getXineramamenu()->getWindowID();
1788 #endif // XINERAMA
1789 #ifdef    XFT
1790   *(session_stack + i++) = configmenu->getXftmenu()->getWindowID();
1791 #endif // XFT
1792   *(session_stack + i++) = configmenu->getWindowID();
1793
1794   *(session_stack + i++) = slit->getMenu()->getDirectionmenu()->getWindowID();
1795   *(session_stack + i++) = slit->getMenu()->getPlacementmenu()->getWindowID();
1796   *(session_stack + i++) = slit->getMenu()->getWindowID();
1797
1798   *(session_stack + i++) =
1799     toolbar->getMenu()->getPlacementmenu()->getWindowID();
1800   *(session_stack + i++) = toolbar->getMenu()->getWindowID();
1801
1802   RootmenuList::iterator rit = rootmenuList.begin();
1803   for (; rit != rootmenuList.end(); ++rit)
1804     *(session_stack + i++) = (*rit)->getWindowID();
1805   *(session_stack + i++) = rootmenu->getWindowID();
1806
1807   if (toolbar->isOnTop())
1808     *(session_stack + i++) = toolbar->getWindowID();
1809
1810   if (slit->isOnTop())
1811     *(session_stack + i++) = slit->getWindowID();
1812
1813   WindowList::iterator sit, send = specialWindowList.end();
1814   for (sit = specialWindowList.begin(); sit != send; ++sit)
1815     *(session_stack + i++) = *sit;
1816
1817   while (k--)
1818     *(session_stack + i++) = *(workspace_stack + k);
1819
1820   XRestackWindows(blackbox->getXDisplay(), session_stack, i);
1821
1822   delete [] session_stack;
1823
1824   updateStackingList();
1825 }
1826
1827
1828 void BScreen::lowerWindows(Window *workspace_stack, unsigned int num) {
1829   assert(num > 0);  // this would cause trouble in the XRaiseWindow call
1830
1831   Window *session_stack = new Window[(num + desktopWindowList.size())];
1832   unsigned int i = 0, k = num;
1833
1834   XLowerWindow(blackbox->getXDisplay(), workspace_stack[0]);
1835
1836   while (k--)
1837     *(session_stack + i++) = *(workspace_stack + k);
1838
1839   WindowList::iterator dit = desktopWindowList.begin();
1840   const WindowList::iterator d_end = desktopWindowList.end();
1841   for (; dit != d_end; ++dit)
1842     *(session_stack + i++) = *dit;
1843
1844   XRestackWindows(blackbox->getXDisplay(), session_stack, i);
1845
1846   delete [] session_stack;
1847
1848   updateStackingList();
1849 }
1850
1851
1852 void BScreen::reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id,
1853                                 bool ignore_sticky) {
1854   if (! w) return;
1855
1856   if (wkspc_id == BSENTINEL)
1857     wkspc_id = current_workspace->getID();
1858
1859   if (w->getWorkspaceNumber() == wkspc_id)
1860     return;
1861
1862   if (w->isIconic()) {
1863     removeIcon(w);
1864     getWorkspace(wkspc_id)->addWindow(w);
1865     if (w->isStuck())
1866       for (unsigned int i = 0; i < getNumberOfWorkspaces(); ++i)
1867         if (i != w->getWorkspaceNumber())
1868           getWorkspace(i)->addWindow(w, True);
1869   } else if (ignore_sticky || ! w->isStuck()) {
1870     if (w->isStuck())
1871       w->stick();
1872     getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
1873     getWorkspace(wkspc_id)->addWindow(w);
1874   }
1875   updateStackingList();
1876 }
1877
1878
1879 void BScreen::propagateWindowName(const BlackboxWindow *bw) {
1880   if (bw->isIconic()) {
1881     iconmenu->changeItemLabel(bw->getWindowNumber(), bw->getIconTitle());
1882     iconmenu->update();
1883   } else {
1884     Clientmenu *clientmenu = getWorkspace(bw->getWorkspaceNumber())->getMenu();
1885     clientmenu->changeItemLabel(bw->getWindowNumber(), bw->getTitle());
1886     clientmenu->update();
1887
1888     if (blackbox->getFocusedWindow() == bw)
1889       toolbar->redrawWindowLabel(True);
1890   }
1891 }
1892
1893
1894 void BScreen::nextFocus(void) const {
1895   BlackboxWindow *focused = blackbox->getFocusedWindow(),
1896     *next = focused;
1897
1898   if (focused &&
1899       focused->getScreen()->getScreenNumber() == getScreenNumber() &&
1900       current_workspace->getCount() > 1) {
1901     do {
1902       next = current_workspace->getNextWindowInList(next);
1903     } while (next != focused && ! next->setInputFocus());
1904
1905     if (next != focused)
1906       current_workspace->raiseWindow(next);
1907   } else if (current_workspace->getCount() > 0) {
1908     next = current_workspace->getTopWindowOnStack();
1909     next->setInputFocus();
1910     current_workspace->raiseWindow(next);
1911   }
1912 }
1913
1914
1915 void BScreen::prevFocus(void) const {
1916   BlackboxWindow *focused = blackbox->getFocusedWindow(),
1917     *next = focused;
1918
1919   if (focused) {
1920     // if window is not on this screen, ignore it
1921     if (focused->getScreen()->getScreenNumber() != getScreenNumber())
1922       focused = (BlackboxWindow*) 0;
1923   }
1924   
1925   if (focused &&
1926       focused->getScreen()->getScreenNumber() == getScreenNumber() &&
1927       current_workspace->getCount() > 1) {
1928     // next is the next window to receive focus, current is a place holder
1929     do {
1930       next = current_workspace->getPrevWindowInList(next);
1931     } while (next != focused && ! next->setInputFocus());
1932
1933     if (next != focused)
1934       current_workspace->raiseWindow(next);
1935   } else if (current_workspace->getCount() > 0) {
1936     next = current_workspace->getTopWindowOnStack();
1937     next->setInputFocus();
1938     current_workspace->raiseWindow(next);
1939   }
1940 }
1941
1942
1943 void BScreen::raiseFocus(void) const {
1944   BlackboxWindow *focused = blackbox->getFocusedWindow();
1945   if (! focused)
1946     return;
1947
1948   // if on this Screen, raise it
1949   if (focused->getScreen()->getScreenNumber() == getScreenNumber()) {
1950     Workspace *workspace = getWorkspace(focused->getWorkspaceNumber());
1951     workspace->raiseWindow(focused);
1952   }
1953 }
1954
1955
1956 void BScreen::InitMenu(void) {
1957   if (rootmenu) {
1958     rootmenuList.clear();
1959
1960     while (rootmenu->getCount())
1961       rootmenu->remove(0);
1962   } else {
1963     rootmenu = new Rootmenu(this);
1964   }
1965   bool defaultMenu = True;
1966
1967   FILE *menu_file = (FILE *) 0;
1968   const char *menu_filename = blackbox->getMenuFilename();
1969
1970   if (menu_filename) 
1971     if (! (menu_file = fopen(menu_filename, "r")))
1972       perror(menu_filename);
1973   if (! menu_file) {     // opening the menu file failed, try the default menu
1974     menu_filename = DEFAULTMENU;
1975     if (! (menu_file = fopen(menu_filename, "r")))
1976       perror(menu_filename);
1977   } 
1978
1979   if (menu_file) {
1980     if (feof(menu_file)) {
1981       fprintf(stderr, i18n(ScreenSet, ScreenEmptyMenuFile,
1982                            "%s: Empty menu file"),
1983               menu_filename);
1984     } else {
1985       char line[1024], label[1024];
1986       memset(line, 0, 1024);
1987       memset(label, 0, 1024);
1988
1989       while (fgets(line, 1024, menu_file) && ! feof(menu_file)) {
1990         if (line[0] == '#')
1991           continue;
1992
1993         int i, key = 0, index = -1, len = strlen(line);
1994
1995         for (i = 0; i < len; i++) {
1996           if (line[i] == '[') index = 0;
1997           else if (line[i] == ']') break;
1998           else if (line[i] != ' ')
1999             if (index++ >= 0)
2000               key += tolower(line[i]);
2001         }
2002
2003         if (key == 517) { // [begin]
2004           index = -1;
2005           for (i = index; i < len; i++) {
2006             if (line[i] == '(') index = 0;
2007             else if (line[i] == ')') break;
2008             else if (index++ >= 0) {
2009               if (line[i] == '\\' && i < len - 1) i++;
2010               label[index - 1] = line[i];
2011             }
2012           }
2013
2014           if (index == -1) index = 0;
2015           label[index] = '\0';
2016
2017           rootmenu->setLabel(label);
2018           defaultMenu = parseMenuFile(menu_file, rootmenu);
2019           if (! defaultMenu)
2020             blackbox->addMenuTimestamp(menu_filename);
2021           break;
2022         }
2023       }
2024     }
2025     fclose(menu_file);
2026   }
2027
2028   if (defaultMenu) {
2029     rootmenu->setInternalMenu();
2030     rootmenu->insert(i18n(ScreenSet, Screenxterm, "xterm"),
2031                      BScreen::Execute,
2032                      i18n(ScreenSet, Screenxterm, "xterm"));
2033     rootmenu->insert(i18n(ScreenSet, ScreenRestart, "Restart"),
2034                      BScreen::Restart);
2035     rootmenu->insert(i18n(ScreenSet, ScreenExit, "Exit"),
2036                      BScreen::Exit);
2037     rootmenu->setLabel(i18n(BasemenuSet, BasemenuBlackboxMenu,
2038                             "Openbox Menu"));
2039   }
2040 }
2041
2042
2043 static
2044 size_t string_within(char begin, char end,
2045                      const char *input, size_t start_at, size_t length,
2046                      char *output) {
2047   bool parse = False;
2048   size_t index = 0;
2049   size_t i = start_at;
2050   for (; i < length; ++i) {
2051     if (input[i] == begin) {
2052       parse = True;
2053     } else if (input[i] == end) {
2054       break;
2055     } else if (parse) {
2056       if (input[i] == '\\' && i < length - 1) i++;
2057       output[index++] = input[i];
2058     } 
2059   }
2060
2061   if (parse)
2062     output[index] = '\0';
2063   else
2064     output[0] = '\0';
2065
2066   return i;
2067 }
2068
2069
2070 bool BScreen::parseMenuFile(FILE *file, Rootmenu *menu) {
2071   char line[1024], keyword[1024], label[1024], command[1024];
2072   bool done = False;
2073
2074   while (! (done || feof(file))) {
2075     memset(line, 0, 1024);
2076     memset(label, 0, 1024);
2077     memset(command, 0, 1024);
2078
2079     if (! fgets(line, 1024, file))
2080       continue;
2081
2082     if (line[0] == '#') // comment, skip it
2083       continue;
2084
2085     size_t line_length = strlen(line);
2086     unsigned int key = 0;
2087
2088     // get the keyword enclosed in []'s
2089     size_t pos = string_within('[', ']', line, 0, line_length, keyword);
2090
2091     if (keyword[0] == '\0') {  // no keyword, no menu entry
2092       continue;
2093     } else {
2094       size_t len = strlen(keyword);
2095       for (size_t i = 0; i < len; ++i) {
2096         if (keyword[i] != ' ')
2097           key += tolower(keyword[i]);
2098       }
2099     }
2100
2101     // get the label enclosed in ()'s
2102     pos = string_within('(', ')', line, pos, line_length, label);
2103
2104     // get the command enclosed in {}'s
2105     pos = string_within('{', '}', line, pos, line_length, command);
2106
2107     switch (key) {
2108     case 311: // end
2109       done = True;
2110
2111       break;
2112
2113     case 333: // nop
2114       if (! *label)
2115         label[0] = '\0';
2116       menu->insert(label);
2117
2118       break;
2119
2120     case 421: // exec
2121       if (! (*label && *command)) {
2122         fprintf(stderr, i18n(ScreenSet, ScreenEXECError,
2123                              "BScreen::parseMenuFile: [exec] error, "
2124                              "no menu label and/or command defined\n"));
2125         continue;
2126       }
2127
2128       menu->insert(label, BScreen::Execute, command);
2129
2130       break;
2131
2132     case 442: // exit
2133       if (! *label) {
2134         fprintf(stderr, i18n(ScreenSet, ScreenEXITError,
2135                              "BScreen::parseMenuFile: [exit] error, "
2136                              "no menu label defined\n"));
2137         continue;
2138       }
2139
2140       menu->insert(label, BScreen::Exit);
2141
2142       break;
2143
2144     case 561: { // style
2145       if (! (*label && *command)) {
2146         fprintf(stderr,
2147                 i18n(ScreenSet, ScreenSTYLEError,
2148                      "BScreen::parseMenuFile: [style] error, "
2149                      "no menu label and/or filename defined\n"));
2150         continue;
2151       }
2152
2153       string style = expandTilde(command);
2154
2155       menu->insert(label, BScreen::SetStyle, style.c_str());
2156     }
2157       break;
2158
2159     case 630: // config
2160       if (! *label) {
2161         fprintf(stderr, i18n(ScreenSet, ScreenCONFIGError,
2162                              "BScreen::parseMenufile: [config] error, "
2163                              "no label defined"));
2164         continue;
2165       }
2166
2167       menu->insert(label, configmenu);
2168
2169       break;
2170
2171     case 740: { // include
2172       if (! *label) {
2173         fprintf(stderr, i18n(ScreenSet, ScreenINCLUDEError,
2174                              "BScreen::parseMenuFile: [include] error, "
2175                              "no filename defined\n"));
2176         continue;
2177       }
2178
2179       string newfile = expandTilde(label);
2180       FILE *submenufile = fopen(newfile.c_str(), "r");
2181
2182       if (! submenufile) {
2183         perror(newfile.c_str());
2184         continue;
2185       }
2186
2187       struct stat buf;
2188       if (fstat(fileno(submenufile), &buf) ||
2189           ! S_ISREG(buf.st_mode)) {
2190         fprintf(stderr,
2191                 i18n(ScreenSet, ScreenINCLUDEErrorReg,
2192                      "BScreen::parseMenuFile: [include] error: "
2193                      "'%s' is not a regular file\n"), newfile.c_str());
2194         break;
2195       }
2196
2197       if (! feof(submenufile)) {
2198         if (! parseMenuFile(submenufile, menu))
2199           blackbox->addMenuTimestamp(newfile);
2200
2201         fclose(submenufile);
2202       }
2203     }
2204
2205       break;
2206
2207     case 767: { // submenu
2208       if (! *label) {
2209         fprintf(stderr, i18n(ScreenSet, ScreenSUBMENUError,
2210                              "BScreen::parseMenuFile: [submenu] error, "
2211                              "no menu label defined\n"));
2212         continue;
2213       }
2214
2215       Rootmenu *submenu = new Rootmenu(this);
2216
2217       if (*command)
2218         submenu->setLabel(command);
2219       else
2220         submenu->setLabel(label);
2221
2222       parseMenuFile(file, submenu);
2223       submenu->update();
2224       menu->insert(label, submenu);
2225       rootmenuList.push_back(submenu);
2226     }
2227
2228       break;
2229
2230     case 773: { // restart
2231       if (! *label) {
2232         fprintf(stderr, i18n(ScreenSet, ScreenRESTARTError,
2233                              "BScreen::parseMenuFile: [restart] error, "
2234                              "no menu label defined\n"));
2235         continue;
2236       }
2237
2238       if (*command)
2239         menu->insert(label, BScreen::RestartOther, command);
2240       else
2241         menu->insert(label, BScreen::Restart);
2242     }
2243
2244       break;
2245
2246     case 845: { // reconfig
2247       if (! *label) {
2248         fprintf(stderr,
2249                 i18n(ScreenSet, ScreenRECONFIGError,
2250                      "BScreen::parseMenuFile: [reconfig] error, "
2251                      "no menu label defined\n"));
2252         continue;
2253       }
2254
2255       menu->insert(label, BScreen::Reconfigure);
2256     }
2257
2258       break;
2259
2260     case 995:    // stylesdir
2261     case 1113: { // stylesmenu
2262       bool newmenu = ((key == 1113) ? True : False);
2263
2264       if (! *label || (! *command && newmenu)) {
2265         fprintf(stderr,
2266                 i18n(ScreenSet, ScreenSTYLESDIRError,
2267                      "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2268                      " error, no directory defined\n"));
2269         continue;
2270       }
2271
2272       char *directory = ((newmenu) ? command : label);
2273
2274       string stylesdir = expandTilde(directory);
2275
2276       struct stat statbuf;
2277
2278       if (stat(stylesdir.c_str(), &statbuf) == -1) {
2279         fprintf(stderr,
2280                 i18n(ScreenSet, ScreenSTYLESDIRErrorNoExist,
2281                      "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2282                      " error, %s does not exist\n"), stylesdir.c_str());
2283         continue;
2284       }
2285       if (! S_ISDIR(statbuf.st_mode)) {
2286         fprintf(stderr,
2287                 i18n(ScreenSet, ScreenSTYLESDIRErrorNotDir,
2288                      "BScreen::parseMenuFile:"
2289                      " [stylesdir/stylesmenu] error, %s is not a"
2290                      " directory\n"), stylesdir.c_str());
2291         continue;
2292       }
2293
2294       Rootmenu *stylesmenu;
2295
2296       if (newmenu)
2297         stylesmenu = new Rootmenu(this);
2298       else
2299         stylesmenu = menu;
2300
2301       DIR *d = opendir(stylesdir.c_str());
2302       struct dirent *p;
2303       std::vector<string> ls;
2304
2305       while((p = readdir(d)))
2306         ls.push_back(p->d_name);
2307
2308       closedir(d);
2309
2310       std::sort(ls.begin(), ls.end());
2311
2312       std::vector<string>::iterator it = ls.begin(),
2313         end = ls.end();
2314       for (; it != end; ++it) {
2315         const string& fname = *it;
2316
2317         //ignore backups and dot files
2318         if (fname[fname.size()-1] == '~' || fname[0] == '.')
2319           continue;
2320
2321         string style = stylesdir;
2322         style += '/';
2323         style += fname;
2324
2325         if (! stat(style.c_str(), &statbuf) && S_ISREG(statbuf.st_mode))
2326           stylesmenu->insert(fname, BScreen::SetStyle, style);
2327       }
2328
2329       stylesmenu->update();
2330
2331       if (newmenu) {
2332         stylesmenu->setLabel(label);
2333         menu->insert(label, stylesmenu);
2334         rootmenuList.push_back(stylesmenu);
2335       }
2336
2337       blackbox->addMenuTimestamp(stylesdir);
2338     }
2339       break;
2340
2341     case 1090: { // workspaces
2342       if (! *label) {
2343         fprintf(stderr,
2344                 i18n(ScreenSet, ScreenWORKSPACESError,
2345                      "BScreen:parseMenuFile: [workspaces] error, "
2346                      "no menu label defined\n"));
2347         continue;
2348       }
2349
2350       menu->insert(label, workspacemenu);
2351     }
2352       break;
2353     }
2354   }
2355
2356   return ((menu->getCount() == 0) ? True : False);
2357 }
2358
2359
2360 void BScreen::shutdown(void) {
2361   XSelectInput(blackbox->getXDisplay(), getRootWindow(), NoEventMask);
2362   XSync(blackbox->getXDisplay(), False);
2363
2364   while(! windowList.empty())
2365     unmanageWindow(windowList.front(), True);
2366
2367   while(! desktopWindowList.empty()) {
2368     BlackboxWindow *win = blackbox->searchWindow(desktopWindowList.front());
2369     assert(win);
2370     unmanageWindow(win, True);
2371   }
2372
2373   slit->shutdown();
2374 }
2375
2376
2377 void BScreen::showPosition(int x, int y) {
2378   if (! geom_visible) {
2379     XMoveResizeWindow(blackbox->getXDisplay(), geom_window,
2380                       (getWidth() - geom_w) / 2,
2381                       (getHeight() - geom_h) / 2, geom_w, geom_h);
2382     XMapWindow(blackbox->getXDisplay(), geom_window);
2383     XRaiseWindow(blackbox->getXDisplay(), geom_window);
2384
2385     geom_visible = True;
2386   }
2387
2388   char label[1024];
2389
2390   sprintf(label, i18n(ScreenSet, ScreenPositionFormat,
2391                       "X: %4d x Y: %4d"), x, y);
2392
2393   XClearWindow(blackbox->getXDisplay(), geom_window);
2394
2395   resource.wstyle.font->drawString(geom_window,
2396                                    resource.bevel_width, resource.bevel_width,
2397                                    resource.wstyle.l_text_focus,
2398                                    label);
2399 }
2400
2401
2402 void BScreen::showGeometry(unsigned int gx, unsigned int gy) {
2403   if (! geom_visible) {
2404     XMoveResizeWindow(blackbox->getXDisplay(), geom_window,
2405                       (getWidth() - geom_w) / 2,
2406                       (getHeight() - geom_h) / 2, geom_w, geom_h);
2407     XMapWindow(blackbox->getXDisplay(), geom_window);
2408     XRaiseWindow(blackbox->getXDisplay(), geom_window);
2409
2410     geom_visible = True;
2411   }
2412
2413   char label[1024];
2414
2415   sprintf(label, i18n(ScreenSet, ScreenGeometryFormat,
2416                       "W: %4d x H: %4d"), gx, gy);
2417
2418   XClearWindow(blackbox->getXDisplay(), geom_window);
2419
2420   resource.wstyle.font->drawString(geom_window,
2421                                    resource.bevel_width, resource.bevel_width,
2422                                    resource.wstyle.l_text_focus,
2423                                    label);
2424 }
2425
2426
2427 void BScreen::hideGeometry(void) {
2428   if (geom_visible) {
2429     XUnmapWindow(blackbox->getXDisplay(), geom_window);
2430     geom_visible = False;
2431   }
2432 }
2433
2434
2435 void BScreen::addStrut(Strut *strut) {
2436   strutList.push_back(strut);
2437 }
2438
2439
2440 void BScreen::removeStrut(Strut *strut) {
2441   strutList.remove(strut);
2442 }
2443
2444
2445 const Rect& BScreen::availableArea(void) const {
2446   if (doFullMax())
2447     return getRect(); // return the full screen
2448   return usableArea;
2449 }
2450
2451
2452 #ifdef    XINERAMA
2453 const RectList& BScreen::allAvailableAreas(void) const {
2454   assert(isXineramaActive());
2455   assert(xineramaUsableArea.size() > 0);
2456   fprintf(stderr, "1found x %d y %d w %d h %d\n",
2457           xineramaUsableArea[0].x(), xineramaUsableArea[0].y(),
2458           xineramaUsableArea[0].width(), xineramaUsableArea[0].height());
2459   return xineramaUsableArea;
2460 }
2461 #endif // XINERAMA
2462
2463
2464 void BScreen::updateAvailableArea(void) {
2465   Rect old_area = usableArea;
2466   usableArea = getRect(); // reset to full screen
2467
2468 #ifdef    XINERAMA
2469   // reset to the full areas
2470   if (isXineramaActive())
2471     xineramaUsableArea = getXineramaAreas();
2472 #endif // XINERAMA
2473
2474   /* these values represent offsets from the screen edge
2475    * we look for the biggest offset on each edge and then apply them
2476    * all at once
2477    * do not be confused by the similarity to the names of Rect's members
2478    */
2479   unsigned int current_left = 0, current_right = 0, current_top = 0,
2480     current_bottom = 0;
2481
2482   StrutList::const_iterator it = strutList.begin(), end = strutList.end();
2483
2484   for(; it != end; ++it) {
2485     Strut *strut = *it;
2486     if (strut->left > current_left)
2487       current_left = strut->left;
2488     if (strut->top > current_top)
2489       current_top = strut->top;
2490     if (strut->right > current_right)
2491       current_right = strut->right;
2492     if (strut->bottom > current_bottom)
2493       current_bottom = strut->bottom;
2494   }
2495
2496   usableArea.setPos(current_left, current_top);
2497   usableArea.setSize(usableArea.width() - (current_left + current_right),
2498                      usableArea.height() - (current_top + current_bottom));
2499
2500 #ifdef    XINERAMA
2501   if (isXineramaActive()) {
2502     // keep each of the ximerama-defined areas inside the strut
2503     RectList::iterator xit, xend = xineramaUsableArea.end();
2504     for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
2505       if (xit->x() < usableArea.x()) {
2506         xit->setX(usableArea.x());
2507         xit->setWidth(xit->width() - usableArea.x());
2508       }
2509       if (xit->y() < usableArea.y()) {
2510         xit->setY(usableArea.y());
2511         xit->setHeight(xit->height() - usableArea.y());
2512       }
2513       if (xit->x() + xit->width() > usableArea.width())
2514         xit->setWidth(usableArea.width() - xit->x());
2515       if (xit->y() + xit->height() > usableArea.height())
2516         xit->setHeight(usableArea.height() - xit->y());
2517     }
2518   }
2519 #endif // XINERAMA
2520
2521   if (old_area != usableArea) {
2522     BlackboxWindowList::iterator it = windowList.begin(),
2523       end = windowList.end();
2524     for (; it != end; ++it)
2525       if ((*it)->isMaximized()) (*it)->remaximize();
2526   }
2527
2528   updateWorkArea();  
2529 }
2530
2531
2532 Workspace* BScreen::getWorkspace(unsigned int index) const {
2533   assert(index < workspacesList.size());
2534   return workspacesList[index];
2535 }
2536
2537
2538 void BScreen::buttonPressEvent(const XButtonEvent *xbutton) {
2539   if (xbutton->button == 1) {
2540     if (! isRootColormapInstalled())
2541       image_control->installRootColormap();
2542
2543     if (workspacemenu->isVisible())
2544       workspacemenu->hide();
2545
2546     if (rootmenu->isVisible())
2547       rootmenu->hide();
2548   // mouse wheel up
2549   } else if ((xbutton->button == 4 && resource.root_scroll == NormalScroll) ||
2550              (xbutton->button == 5 && resource.root_scroll == ReverseScroll)) {
2551     if (getCurrentWorkspaceID() >= getWorkspaceCount() - 1)
2552       changeWorkspaceID(0);
2553     else
2554       changeWorkspaceID(getCurrentWorkspaceID() + 1);
2555   // mouse wheel down
2556   } else if ((xbutton->button == 5 && resource.root_scroll == NormalScroll) ||
2557              (xbutton->button == 4 && resource.root_scroll == ReverseScroll)) {
2558     if (getCurrentWorkspaceID() == 0)
2559       changeWorkspaceID(getWorkspaceCount() - 1);
2560     else
2561       changeWorkspaceID(getCurrentWorkspaceID() - 1);
2562   }
2563
2564   if (resource.root_menu_button > 0 &&
2565       xbutton->button == resource.root_menu_button)
2566     showRootMenu(xbutton->x_root, xbutton->y_root);
2567   else if (resource.workspace_menu_button > 0 &&
2568            xbutton->button == resource.workspace_menu_button)
2569     showWorkspaceMenu(xbutton->x_root, xbutton->y_root);
2570 }
2571
2572
2573 void BScreen::showWorkspaceMenu(int x, int y) {
2574   int mx = x - (workspacemenu->getWidth() / 2);
2575   int my = y - (workspacemenu->getTitleHeight() / 2);
2576
2577   if (mx < 0) mx = 0;
2578   if (my < 0) my = 0;
2579
2580   if (mx + workspacemenu->getWidth() > getWidth())
2581     mx = getWidth() - workspacemenu->getWidth() - getBorderWidth();
2582
2583   if (my + workspacemenu->getHeight() > getHeight())
2584     my = getHeight() - workspacemenu->getHeight() - getBorderWidth();
2585
2586   workspacemenu->move(mx, my);
2587
2588   if (! workspacemenu->isVisible()) {
2589     workspacemenu->removeParent();
2590     workspacemenu->show();
2591   }
2592 }
2593
2594
2595 void BScreen::showRootMenu(int x, int y) {
2596   int mx = x - (rootmenu->getWidth() / 2);
2597   int my = y - (rootmenu->getTitleHeight() / 2);
2598
2599   if (mx < 0) mx = 0;
2600   if (my < 0) my = 0;
2601
2602   if (mx + rootmenu->getWidth() > getWidth())
2603     mx = getWidth() - rootmenu->getWidth() - getBorderWidth();
2604
2605   if (my + rootmenu->getHeight() > getHeight())
2606     my = getHeight() - rootmenu->getHeight() - getBorderWidth();
2607
2608   rootmenu->move(mx, my);
2609
2610   if (! rootmenu->isVisible()) {
2611     blackbox->checkMenu();
2612     rootmenu->show();
2613   }
2614 }
2615
2616
2617 void BScreen::propertyNotifyEvent(const XPropertyEvent *pe) {
2618   if (pe->atom == xatom->getAtom(XAtom::net_desktop_names)) {
2619     // _NET_WM_DESKTOP_NAMES
2620     WorkspaceList::iterator it = workspacesList.begin();
2621     const WorkspaceList::iterator end = workspacesList.end();
2622     for (; it != end; ++it) {
2623       (*it)->readName(); // re-read its name from the window property
2624       workspacemenu->changeWorkspaceLabel((*it)->getID(), (*it)->getName());
2625     }
2626     workspacemenu->update();
2627     toolbar->reconfigure();
2628     saveWorkspaceNames();
2629   }
2630 }
2631
2632
2633 void BScreen::toggleFocusModel(FocusModel model) {
2634   std::for_each(windowList.begin(), windowList.end(),
2635                 std::mem_fun(&BlackboxWindow::ungrabButtons));
2636
2637   if (model == SloppyFocus) {
2638     saveSloppyFocus(True);
2639   } else {
2640     // we're cheating here to save writing the config file 3 times
2641     resource.auto_raise = False;
2642     resource.click_raise = False;
2643     saveSloppyFocus(False);
2644   }
2645
2646   std::for_each(windowList.begin(), windowList.end(),
2647                 std::mem_fun(&BlackboxWindow::grabButtons));
2648 }
2649
2650 #ifdef    BITMAPBUTTONS
2651 void BScreen::readDatabaseMask(const string &rname, PixmapMask &pixmapMask,
2652                                const Configuration &style) {
2653   string s;
2654   int hx, hy; //ignored
2655   int ret = BitmapOpenFailed; //default to failure.
2656   
2657   if (style.getValue(rname, s))
2658   {
2659     if (s[0] != '/' && s[0] != '~')
2660     {
2661       std::string xbmFile = std::string("~/.openbox/buttons/") + s;
2662       ret = XReadBitmapFile(blackbox->getXDisplay(), getRootWindow(),
2663                             expandTilde(xbmFile).c_str(), &pixmapMask.w,
2664                             &pixmapMask.h, &pixmapMask.mask, &hx, &hy);
2665     } else
2666       ret = XReadBitmapFile(blackbox->getXDisplay(), getRootWindow(),
2667                             expandTilde(s).c_str(), &pixmapMask.w,
2668                             &pixmapMask.h, &pixmapMask.mask, &hx, &hy);
2669     
2670     if (ret == BitmapSuccess)
2671       return;
2672   }
2673
2674   pixmapMask.mask = None;
2675   pixmapMask.w = pixmapMask.h = 0;
2676 }
2677 #endif // BITMAPSUCCESS
2678
2679 BTexture BScreen::readDatabaseTexture(const string &rname,
2680                                       const string &default_color,
2681                                       const Configuration &style, 
2682                                       bool allowNoTexture) {
2683   BTexture texture;
2684   string s;
2685
2686   if (style.getValue(rname, s))
2687     texture = BTexture(s);
2688   else if (allowNoTexture) //no default
2689     texture.setTexture(BTexture::NoTexture);
2690   else
2691     texture.setTexture(BTexture::Solid | BTexture::Flat);
2692
2693   // associate this texture with this screen
2694   texture.setDisplay(getBaseDisplay(), getScreenNumber());
2695   texture.setImageControl(image_control);
2696
2697   if (texture.texture() != BTexture::NoTexture) {
2698     texture.setColor(readDatabaseColor(rname + ".color", default_color,
2699                                        style));
2700     texture.setColorTo(readDatabaseColor(rname + ".colorTo", default_color,
2701                                          style));
2702     texture.setBorderColor(readDatabaseColor(rname + ".borderColor",
2703                                              default_color, style));
2704   }
2705
2706   return texture;
2707 }
2708
2709
2710 BColor BScreen::readDatabaseColor(const string &rname,
2711                                   const string &default_color,
2712                                   const Configuration &style) {
2713   BColor color;
2714   string s;
2715   if (style.getValue(rname, s))
2716     color = BColor(s, getBaseDisplay(), getScreenNumber());
2717   else
2718     color = BColor(default_color, getBaseDisplay(), getScreenNumber());
2719   return color;
2720 }
2721
2722
2723 BFont *BScreen::readDatabaseFont(const string &rbasename,
2724                                  const Configuration &style) {
2725   string fontname;
2726
2727   string s;
2728
2729 #ifdef    XFT
2730   int i;
2731   if (style.getValue(rbasename + "xft.font", s) &&
2732       style.getValue(rbasename + "xft.size", i)) {
2733     string family = s;
2734     bool bold = False;
2735     bool italic = False;
2736     bool dropShadow = False;
2737
2738     if (style.getValue(rbasename + "xft.flags", s)) {
2739       if (s.find("bold") != string::npos)
2740         bold = True;
2741       if (s.find("italic") != string::npos)
2742         italic = True;
2743       if (s.find("shadow") != string::npos)
2744         dropShadow = True;
2745     }
2746     
2747     unsigned char offset = 1;
2748     if (style.getValue(rbasename + "xft.shadow.offset", s)) {
2749       offset = atoi(s.c_str()); //doesn't detect errors
2750       if (offset > CHAR_MAX)
2751         offset = 1;
2752     }
2753
2754     int tint = 25;
2755     if (style.getValue(rbasename + "xft.shadow.tint", s)) {
2756       tint = atoi(s.c_str());
2757     }
2758
2759     if (tint > 100) tint = 100;
2760     if (tint < -100) tint = -100;
2761     
2762     BFont *b = new BFont(blackbox->getXDisplay(), this, family, i, bold,
2763                          italic, dropShadow && resource.shadow_fonts, offset, 
2764                          tint, resource.aa_fonts);
2765     if (b->valid())
2766       return b;
2767     else
2768       delete b; // fall back to the normal X font stuff
2769   }
2770 #endif // XFT
2771
2772   style.getValue(rbasename + "font", s);
2773   // if this fails, a blank string will be used, which will cause the fallback
2774   // font to load.
2775
2776   BFont *b = new BFont(blackbox->getXDisplay(), this, s);
2777   if (! b->valid())
2778     exit(2);  // can't continue without a font
2779   return b;
2780 }