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