]> icculus.org git repositories - mikachu/openbox.git/blob - src/Screen.cc
add BFont class, with Xft support
[mikachu/openbox.git] / src / Screen.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Screen.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #include "../config.h"
25
26 extern "C" {
27 #include <X11/Xatom.h>
28 #include <X11/keysym.h>
29
30 #ifdef HAVE_STDLIB_H
31 #  include <stdlib.h>
32 #endif // HAVE_STDLIB_H
33
34 #ifdef HAVE_STRING_H
35 #  include <string.h>
36 #endif // HAVE_STRING_H
37
38 #ifdef    HAVE_CTYPE_H
39 #  include <ctype.h>
40 #endif // HAVE_CTYPE_H
41
42 #ifdef    HAVE_UNISTD_H
43 #  include <sys/types.h>
44 #  include <unistd.h>
45 #endif // HAVE_UNISTD_H
46
47 #ifdef    HAVE_DIRENT_H
48 #  include <dirent.h>
49 #endif // HAVE_DIRENT_H
50
51 #ifdef    HAVE_LOCALE_H
52 #  include <locale.h>
53 #endif // HAVE_LOCALE_H
54
55 #ifdef    HAVE_SYS_STAT_H
56 #  include <sys/stat.h>
57 #endif // HAVE_SYS_STAT_H
58
59 #ifdef    HAVE_STDARG_H
60 #  include <stdarg.h>
61 #endif // HAVE_STDARG_H
62 }
63
64 #include <assert.h>
65
66 #include <algorithm>
67 #include <functional>
68 #include <string>
69 using std::string;
70
71 #include "i18n.hh"
72 #include "blackbox.hh"
73 #include "Clientmenu.hh"
74 #include "Font.hh"
75 #include "GCCache.hh"
76 #include "Iconmenu.hh"
77 #include "Image.hh"
78 #include "Screen.hh"
79 #include "Slit.hh"
80 #include "Rootmenu.hh"
81 #include "Toolbar.hh"
82 #include "Util.hh"
83 #include "Window.hh"
84 #include "Workspace.hh"
85 #include "Workspacemenu.hh"
86 #include "XAtom.hh"
87
88 #ifndef   FONT_ELEMENT_SIZE
89 #define   FONT_ELEMENT_SIZE 50
90 #endif // FONT_ELEMENT_SIZE
91
92
93 static bool running = True;
94
95 static int anotherWMRunning(Display *display, XErrorEvent *) {
96   fprintf(stderr, i18n(ScreenSet, ScreenAnotherWMRunning,
97           "BScreen::BScreen: an error occured while querying the X server.\n"
98           "  another window manager already running on display %s.\n"),
99           DisplayString(display));
100
101   running = False;
102
103   return(-1);
104 }
105
106
107 BScreen::BScreen(Blackbox *bb, unsigned int scrn) : ScreenInfo(bb, scrn) {
108   blackbox = bb;
109   screenstr = (string)"session.screen" + itostring(scrn) + '.';
110   config = blackbox->getConfig();
111   xatom = blackbox->getXAtom();
112
113   event_mask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
114     SubstructureRedirectMask | ButtonPressMask | ButtonReleaseMask;
115
116   XErrorHandler old = XSetErrorHandler((XErrorHandler) anotherWMRunning);
117   XSelectInput(getBaseDisplay()->getXDisplay(), getRootWindow(), event_mask);
118   XSync(getBaseDisplay()->getXDisplay(), False);
119   XSetErrorHandler((XErrorHandler) old);
120
121   managed = running;
122   if (! managed) return;
123
124   fprintf(stderr, i18n(ScreenSet, ScreenManagingScreen,
125                        "BScreen::BScreen: managing screen %d "
126                        "using visual 0x%lx, depth %d\n"),
127           getScreenNumber(), XVisualIDFromVisual(getVisual()),
128           getDepth());
129
130   rootmenu = 0;
131
132   resource.mstyle.t_font = resource.mstyle.f_font = resource.tstyle.font =
133     resource.wstyle.font = (BFont *) 0;
134
135   xatom->setSupported(this);    // set-up netwm support
136 #ifdef    HAVE_GETPID
137   xatom->setValue(getRootWindow(), XAtom::blackbox_pid, XAtom::cardinal,
138                   (unsigned long) getpid());
139 #endif // HAVE_GETPID
140   unsigned long geometry[] = { getWidth(),
141                                getHeight()};
142   xatom->setValue(getRootWindow(), XAtom::net_desktop_geometry,
143                   XAtom::cardinal, geometry, 2);
144   unsigned long viewport[] = {0,0};
145   xatom->setValue(getRootWindow(), XAtom::net_desktop_viewport,
146                   XAtom::cardinal, viewport, 2);
147                   
148
149   XDefineCursor(blackbox->getXDisplay(), getRootWindow(),
150                 blackbox->getSessionCursor());
151
152   // start off full screen, top left.
153   usableArea.setSize(getWidth(), getHeight());
154
155   image_control =
156     new BImageControl(blackbox, this, True, blackbox->getColorsPerChannel(),
157                       blackbox->getCacheLife(), blackbox->getCacheMax());
158   image_control->installRootColormap();
159   root_colormap_installed = True;
160
161   load_rc();
162   LoadStyle();
163
164   XGCValues gcv;
165   gcv.foreground = WhitePixel(blackbox->getXDisplay(), getScreenNumber())
166     ^ BlackPixel(blackbox->getXDisplay(), getScreenNumber());
167   gcv.function = GXxor;
168   gcv.subwindow_mode = IncludeInferiors;
169   opGC = XCreateGC(blackbox->getXDisplay(), getRootWindow(),
170                    GCForeground | GCFunction | GCSubwindowMode, &gcv);
171
172   const char *s =  i18n(ScreenSet, ScreenPositionLength,
173                         "0: 0000 x 0: 0000");
174   geom_w = resource.wstyle.font->measureString(s) + resource.bevel_width * 2;
175   geom_h = resource.wstyle.font->height() + resource.bevel_width * 2;
176
177   XSetWindowAttributes attrib;
178   unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder;
179   attrib.border_pixel = getBorderColor()->pixel();
180   attrib.colormap = getColormap();
181   attrib.save_under = True;
182
183   geom_window = XCreateWindow(blackbox->getXDisplay(), getRootWindow(),
184                               0, 0, geom_w, geom_h, resource.border_width,
185                               getDepth(), InputOutput, getVisual(),
186                               mask, &attrib);
187   geom_visible = False;
188
189   BTexture* texture = &(resource.wstyle.l_focus);
190   geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
191   if (geom_pixmap == ParentRelative) {
192     texture = &(resource.wstyle.t_focus);
193     geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
194   }
195   if (! geom_pixmap)
196     XSetWindowBackground(blackbox->getXDisplay(), geom_window,
197                          texture->color().pixel());
198   else
199     XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
200                                geom_window, geom_pixmap);
201
202   workspacemenu = new Workspacemenu(this);
203   iconmenu = new Iconmenu(this);
204   configmenu = new Configmenu(this);
205
206   Workspace *wkspc = (Workspace *) 0;
207   if (resource.workspaces != 0) {
208     for (unsigned int i = 0; i < resource.workspaces; ++i) {
209       wkspc = new Workspace(this, workspacesList.size());
210       workspacesList.push_back(wkspc);
211       workspacemenu->insert(wkspc->getName(), wkspc->getMenu());
212     }
213   } else {
214     wkspc = new Workspace(this, workspacesList.size());
215     workspacesList.push_back(wkspc);
216     workspacemenu->insert(wkspc->getName(), wkspc->getMenu());
217   }
218   saveWorkspaceNames();
219
220   updateNetizenWorkspaceCount();
221
222   workspacemenu->insert(i18n(IconSet, IconIcons, "Icons"), iconmenu);
223   workspacemenu->update();
224
225   current_workspace = workspacesList.front();
226   
227   xatom->setValue(getRootWindow(), XAtom::net_current_desktop,
228                   XAtom::cardinal, 0); //first workspace
229
230   workspacemenu->setItemSelected(2, True);
231
232   toolbar = new Toolbar(this);
233
234   slit = new Slit(this);
235
236   InitMenu();
237
238   raiseWindows(0, 0);     // this also initializes the empty stacking list
239   rootmenu->update();
240
241   updateClientList();     // initialize the client list, which will be empty
242   updateAvailableArea();
243
244   changeWorkspaceID(0);
245
246   unsigned int i, j, nchild;
247   Window r, p, *children;
248   XQueryTree(blackbox->getXDisplay(), getRootWindow(), &r, &p,
249              &children, &nchild);
250
251   // preen the window list of all icon windows... for better dockapp support
252   for (i = 0; i < nchild; i++) {
253     if (children[i] == None) continue;
254
255     XWMHints *wmhints = XGetWMHints(blackbox->getXDisplay(),
256                                     children[i]);
257
258     if (wmhints) {
259       if ((wmhints->flags & IconWindowHint) &&
260           (wmhints->icon_window != children[i])) {
261         for (j = 0; j < nchild; j++) {
262           if (children[j] == wmhints->icon_window) {
263             children[j] = None;
264             break;
265           }
266         }
267       }
268
269       XFree(wmhints);
270     }
271   }
272
273   // manage shown windows
274   for (i = 0; i < nchild; ++i) {
275     if (children[i] == None || (! blackbox->validateWindow(children[i])))
276       continue;
277
278     XWindowAttributes attrib;
279     if (XGetWindowAttributes(blackbox->getXDisplay(), children[i], &attrib)) {
280       if (attrib.override_redirect) continue;
281
282       if (attrib.map_state != IsUnmapped) {
283         manageWindow(children[i]);
284       }
285     }
286   }
287
288   XFree(children);
289
290   // call this again just in case a window we found updates the Strut list
291   updateAvailableArea();
292 }
293
294
295 BScreen::~BScreen(void) {
296   if (! managed) return;
297
298   if (geom_pixmap != None)
299     image_control->removeImage(geom_pixmap);
300
301   if (geom_window != None)
302     XDestroyWindow(blackbox->getXDisplay(), geom_window);
303
304   std::for_each(workspacesList.begin(), workspacesList.end(),
305                 PointerAssassin());
306
307   std::for_each(iconList.begin(), iconList.end(), PointerAssassin());
308
309   std::for_each(netizenList.begin(), netizenList.end(), PointerAssassin());
310
311   delete rootmenu;
312   delete workspacemenu;
313   delete iconmenu;
314   delete configmenu;
315   delete slit;
316   delete toolbar;
317   delete image_control;
318
319   if (resource.wstyle.font)
320     delete resource.wstyle.font;
321   if (resource.mstyle.t_font)
322     delete resource.mstyle.t_font;
323   if (resource.mstyle.f_font)
324     delete resource.mstyle.f_font;
325   if (resource.tstyle.font)
326     delete resource.tstyle.font;
327
328   XFreeGC(blackbox->getXDisplay(), opGC);
329 }
330
331
332 void BScreen::saveSloppyFocus(bool s) {
333   resource.sloppy_focus = s;
334
335   string fmodel;
336   if (resource.sloppy_focus) {
337     fmodel = "SloppyFocus";
338     if (resource.auto_raise) fmodel += " AutoRaise";
339     if (resource.click_raise) fmodel += " ClickRaise";
340   } else {
341     fmodel = "ClickToFocus";
342   }
343   config->setValue(screenstr + "focusModel", fmodel);
344 }
345
346
347 void BScreen::saveAutoRaise(bool a) {
348   resource.auto_raise = a;
349   saveSloppyFocus(resource.sloppy_focus);
350 }
351
352
353 void BScreen::saveClickRaise(bool c) {
354   resource.click_raise = c;
355   saveSloppyFocus(resource.sloppy_focus);
356 }
357
358
359 void BScreen::saveImageDither(bool d) {
360   image_control->setDither(d);
361   config->setValue(screenstr + "imageDither", doImageDither());
362 }
363
364
365 void BScreen::saveOpaqueMove(bool o) {
366   resource.opaque_move = o;
367   config->setValue(screenstr + "opaqueMove", resource.opaque_move);
368 }
369
370
371 void BScreen::saveFullMax(bool f) {
372   resource.full_max = f;
373   config->setValue(screenstr + "fullMaximization", resource.full_max);
374 }
375
376
377 void BScreen::saveFocusNew(bool f) {
378   resource.focus_new = f;
379   config->setValue(screenstr + "focusNewWindows", resource.focus_new);
380 }
381
382
383 void BScreen::saveFocusLast(bool f) {
384   resource.focus_last = f;
385   config->setValue(screenstr + "focusLastWindow", resource.focus_last);
386 }
387
388
389 void BScreen::saveHideToolbar(bool h) {
390   resource.hide_toolbar = h;
391   if (resource.hide_toolbar)
392     toolbar->unmapToolbar();
393   else
394     toolbar->mapToolbar();
395   config->setValue(screenstr + "hideToolbar", resource.hide_toolbar);
396 }
397
398
399 void BScreen::saveWindowToWindowSnap(bool s) {
400   resource.window_to_window_snap = s;
401   config->setValue(screenstr + "windowToWindowSnap",
402                    resource.window_to_window_snap);
403 }
404
405
406 void BScreen::saveWindowCornerSnap(bool s) {
407   resource.window_corner_snap = s;
408   config->setValue(screenstr + "windowCornerSnap",
409                    resource.window_corner_snap);
410 }
411
412
413 void BScreen::saveWorkspaces(unsigned int w) {
414   resource.workspaces = w;
415   config->setValue(screenstr + "workspaces", resource.workspaces);
416 }
417
418
419 void BScreen::savePlacementPolicy(int p) {
420   resource.placement_policy = p; 
421   const char *placement;
422   switch (resource.placement_policy) {
423   case CascadePlacement: placement = "CascadePlacement"; break;
424   case ColSmartPlacement: placement = "ColSmartPlacement"; break;
425   case RowSmartPlacement: default: placement = "RowSmartPlacement"; break;
426   }
427   config->setValue(screenstr + "windowPlacement", placement);
428 }
429
430
431 void BScreen::saveEdgeSnapThreshold(int t) {
432   resource.edge_snap_threshold = t;
433   config->setValue(screenstr + "edgeSnapThreshold",
434                    resource.edge_snap_threshold);
435 }
436
437
438 void BScreen::saveRowPlacementDirection(int d) {
439   resource.row_direction = d;
440   config->setValue(screenstr + "rowPlacementDirection",
441                    resource.row_direction == LeftRight ?
442                    "LeftToRight" : "RightToLeft");
443 }
444
445
446 void BScreen::saveColPlacementDirection(int d) {
447   resource.col_direction = d;
448   config->setValue(screenstr + "colPlacementDirection",
449                    resource.col_direction == TopBottom ?
450                    "TopToBottom" : "BottomToTop");
451 }
452
453
454 #ifdef    HAVE_STRFTIME
455 void BScreen::saveStrftimeFormat(const std::string& format) {
456   resource.strftime_format = format;
457   config->setValue(screenstr + "strftimeFormat", resource.strftime_format);
458 }
459
460 #else // !HAVE_STRFTIME
461
462 void BScreen::saveDateFormat(int f) {
463   resource.date_format = f;
464   config->setValue(screenstr + "dateFormat",
465                    resource.date_format == B_EuropeanDate ?
466                    "European" : "American");
467 }
468
469
470 void BScreen::saveClock24Hour(Bool c) {
471   resource.clock24hour = c;
472   config->setValue(screenstr + "clockFormat", resource.clock24hour ? 24 : 12);
473 }
474 #endif // HAVE_STRFTIME
475
476
477 void BScreen::saveWorkspaceNames() {
478   XAtom::StringVect nameList;
479   unsigned long numnames = (unsigned) -1;
480   string names;
481  
482   if (numnames > 0 &&
483       xatom->getValue(getRootWindow(), XAtom::net_desktop_names, XAtom::utf8,
484                       numnames, nameList)) {
485     for (unsigned int i = 0; i < nameList.size(); ++i) {
486       if (i > 0) names += ",";
487       names += nameList[i];
488     }
489   }
490   config->setValue(screenstr + "workspaceNames", names);
491 }
492
493
494 void BScreen::save_rc(void) {
495   saveSloppyFocus(resource.sloppy_focus);
496   saveAutoRaise(resource.auto_raise);
497   saveImageDither(doImageDither());
498   saveOpaqueMove(resource.opaque_move);
499   saveFullMax(resource.full_max);
500   saveFocusNew(resource.focus_new);
501   saveFocusLast(resource.focus_last);
502   saveHideToolbar(resource.hide_toolbar);
503   saveWindowToWindowSnap(resource.window_to_window_snap);
504   saveWindowCornerSnap(resource.window_corner_snap);
505   saveWorkspaces(resource.workspaces);
506   savePlacementPolicy(resource.placement_policy);
507   saveEdgeSnapThreshold(resource.edge_snap_threshold);
508   saveRowPlacementDirection(resource.row_direction);
509   saveColPlacementDirection(resource.col_direction);
510 #ifdef    HAVE_STRFTIME
511   saveStrftimeFormat(resource.strftime_format); 
512 #else // !HAVE_STRFTIME
513   saveDateFormat(resource.date_format);
514   savwClock24Hour(resource.clock24hour);
515 #endif // HAVE_STRFTIME
516
517   toolbar->save_rc();
518   slit->save_rc();
519 }
520
521
522 void BScreen::load_rc(void) {
523   std::string s;
524   bool b;
525
526   if (! config->getValue(screenstr + "fullMaximization", resource.full_max))
527     resource.full_max = false;
528
529   if (! config->getValue(screenstr + "focusNewWindows", resource.focus_new))
530     resource.focus_new = false;
531
532   if (! config->getValue(screenstr + "focusLastWindow", resource.focus_last))
533     resource.focus_last = false;
534
535   if (! config->getValue(screenstr + "workspaces", resource.workspaces))
536     resource.workspaces = 1;
537
538   if (! config->getValue(screenstr + "opaqueMove", resource.opaque_move))
539     resource.opaque_move = false;
540
541   if (! config->getValue(screenstr + "hideToolbar", resource.hide_toolbar))
542     resource.hide_toolbar = false;
543
544   if (! config->getValue(screenstr + "windowToWindowSnap",
545                          resource.window_to_window_snap))
546     resource.window_to_window_snap = true;
547
548   if (! config->getValue(screenstr + "windowCornerSnap",
549                          resource.window_corner_snap))
550     resource.window_corner_snap = true;
551
552   if (! config->getValue(screenstr + "imageDither", b))
553     b = true;
554   image_control->setDither(b);
555
556   if (! config->getValue(screenstr + "edgeSnapThreshold",
557                         resource.edge_snap_threshold))
558     resource.edge_snap_threshold = 4;
559   
560   if (config->getValue(screenstr + "rowPlacementDirection", s) &&
561       s == "RightToLeft")
562     resource.row_direction = RightLeft;
563   else
564     resource.row_direction = LeftRight;
565
566   if (config->getValue(screenstr + "colPlacementDirection", s) &&
567       s == "BottomToTop")
568     resource.col_direction = BottomTop;
569   else
570     resource.col_direction = TopBottom;
571
572   XAtom::StringVect workspaceNames;
573   if (config->getValue(screenstr + "workspaceNames", s)) {
574     string::const_iterator it = s.begin(), end = s.end();
575     while(1) {
576       string::const_iterator tmp = it;     // current string.begin()
577       it = std::find(tmp, end, ',');       // look for comma between tmp and end
578       workspaceNames.push_back(string(tmp, it)); // s[tmp:it]
579       if (it == end)
580         break;
581       ++it;
582     }
583   }
584   xatom->setValue(getRootWindow(), XAtom::net_desktop_names, XAtom::utf8,
585                   workspaceNames);
586
587   resource.sloppy_focus = true;
588   resource.auto_raise = false;
589   resource.click_raise = false;
590   if (config->getValue(screenstr + "focusModel", s)) {
591     if (s.find("ClickToFocus") != string::npos) {
592       resource.sloppy_focus = false;
593     } else {
594       // must be sloppy
595       if (s.find("AutoRaise") != string::npos)
596         resource.auto_raise = true;
597       if (s.find("ClickRaise") != string::npos)
598         resource.click_raise = true;
599     }
600   }
601
602   if (config->getValue(screenstr + "windowPlacement", s)) {
603     if (s == "CascadePlacement")
604       resource.placement_policy = CascadePlacement;
605     else if (s == "ColSmartPlacement")
606       resource.placement_policy = ColSmartPlacement;
607     else //if (s == "RowSmartPlacement")
608       resource.placement_policy = RowSmartPlacement;
609   } else
610     resource.placement_policy = RowSmartPlacement;
611
612 #ifdef    HAVE_STRFTIME
613   if (config->getValue(screenstr + "strftimeFormat", s))
614     resource.strftime_format = s;
615   else
616     resource.strftime_format = "%I:%M %p";
617 #else // !HAVE_STRFTIME
618   long l;
619
620   if (config->getValue(screenstr + "dateFormat", s) && s == "European")
621     resource.date_format = B_EuropeanDate;
622  else
623     resource.date_format = B_AmericanDate;
624
625   if (! config->getValue(screenstr + "clockFormat", l))
626     l = 12;
627   resource.clock24hour = l == 24;
628 #endif // HAVE_STRFTIME
629 }
630
631
632 void BScreen::reconfigure(void) {
633   load_rc();
634   toolbar->load_rc();
635   slit->load_rc();
636   LoadStyle();
637
638   XGCValues gcv;
639   gcv.foreground = WhitePixel(blackbox->getXDisplay(),
640                               getScreenNumber());
641   gcv.function = GXinvert;
642   gcv.subwindow_mode = IncludeInferiors;
643   XChangeGC(blackbox->getXDisplay(), opGC,
644             GCForeground | GCFunction | GCSubwindowMode, &gcv);
645
646   const char *s = i18n(ScreenSet, ScreenPositionLength,
647                        "0: 0000 x 0: 0000");
648
649   geom_w = resource.wstyle.font->measureString(s) + resource.bevel_width * 2;
650   geom_h = resource.wstyle.font->height() + resource.bevel_width * 2;
651
652   BTexture* texture = &(resource.wstyle.l_focus);
653   geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
654   if (geom_pixmap == ParentRelative) {
655     texture = &(resource.wstyle.t_focus);
656     geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
657   }
658   if (! geom_pixmap)
659     XSetWindowBackground(blackbox->getXDisplay(), geom_window,
660                          texture->color().pixel());
661   else
662     XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
663                                geom_window, geom_pixmap);
664
665   XSetWindowBorderWidth(blackbox->getXDisplay(), geom_window,
666                         resource.border_width);
667   XSetWindowBorder(blackbox->getXDisplay(), geom_window,
668                    resource.border_color.pixel());
669
670   workspacemenu->reconfigure();
671   iconmenu->reconfigure();
672
673   typedef std::vector<int> SubList;
674   SubList remember_subs;
675
676   // save the current open menus
677   Basemenu *menu = rootmenu;
678   int submenu;
679   while ((submenu = menu->getCurrentSubmenu()) >= 0) {
680     remember_subs.push_back(submenu);
681     menu = menu->find(submenu)->submenu();
682     assert(menu);
683   }
684   
685   InitMenu();
686   raiseWindows(0, 0);
687   rootmenu->reconfigure();
688
689   // reopen the saved menus
690   menu = rootmenu;
691   const SubList::iterator subs_end = remember_subs.end();
692   for (SubList::iterator it = remember_subs.begin(); it != subs_end; ++it) {
693     menu->drawSubmenu(*it);
694     menu = menu->find(*it)->submenu();
695     if (! menu)
696       break;
697   }
698
699   configmenu->reconfigure();
700
701   toolbar->reconfigure();
702
703   slit->reconfigure();
704
705   std::for_each(workspacesList.begin(), workspacesList.end(),
706                 std::mem_fun(&Workspace::reconfigure));
707
708   BlackboxWindowList::iterator iit = iconList.begin();
709   for (; iit != iconList.end(); ++iit) {
710     BlackboxWindow *bw = *iit;
711     if (bw->validateClient())
712       bw->reconfigure();
713   }
714
715   image_control->timeout();
716 }
717
718
719 void BScreen::rereadMenu(void) {
720   InitMenu();
721   raiseWindows(0, 0);
722
723   rootmenu->reconfigure();
724 }
725
726
727 void BScreen::LoadStyle(void) {
728   Configuration style;
729
730   const char *sfile = blackbox->getStyleFilename();
731   if (sfile != NULL) {
732     style.setFile(sfile);
733     if (! style.load()) {
734       style.setFile(DEFAULTSTYLE);
735       if (! style.load())
736         style.create();  // hardcoded default values will be used.
737     }
738   }
739
740   string s;
741
742   // load fonts/fontsets
743   if (resource.wstyle.font)
744     delete resource.wstyle.font;
745   if (resource.tstyle.font)
746     delete resource.tstyle.font;
747   if (resource.mstyle.f_font)
748     delete resource.mstyle.f_font;
749   if (resource.mstyle.t_font)
750     delete resource.mstyle.t_font;
751   resource.wstyle.font = resource.tstyle.font = resource.mstyle.f_font =
752     resource.mstyle.t_font = (BFont *) 0;
753
754   resource.wstyle.font = readDatabaseFont("window.font", style);
755   resource.tstyle.font = readDatabaseFont("toolbar.font", style);
756   resource.mstyle.t_font = readDatabaseFont("menu.title.font", style);
757   resource.mstyle.f_font = readDatabaseFont("menu.frame.font", style);
758
759   // load window config
760   resource.wstyle.t_focus =
761     readDatabaseTexture("window.title.focus", "white", style);
762   resource.wstyle.t_unfocus =
763     readDatabaseTexture("window.title.unfocus", "black", style);
764   resource.wstyle.l_focus =
765     readDatabaseTexture("window.label.focus", "white", style);
766   resource.wstyle.l_unfocus =
767     readDatabaseTexture("window.label.unfocus", "black", style);
768   resource.wstyle.h_focus =
769     readDatabaseTexture("window.handle.focus", "white", style);
770   resource.wstyle.h_unfocus =
771     readDatabaseTexture("window.handle.unfocus", "black", style);
772   resource.wstyle.g_focus =
773     readDatabaseTexture("window.grip.focus", "white", style);
774   resource.wstyle.g_unfocus =
775     readDatabaseTexture("window.grip.unfocus", "black", style);
776   resource.wstyle.b_focus =
777     readDatabaseTexture("window.button.focus", "white", style);
778   resource.wstyle.b_unfocus =
779     readDatabaseTexture("window.button.unfocus", "black", style);
780   resource.wstyle.b_pressed =
781     readDatabaseTexture("window.button.pressed", "black", style);
782   resource.wstyle.f_focus =
783     readDatabaseColor("window.frame.focusColor", "white", style);
784   resource.wstyle.f_unfocus =
785     readDatabaseColor("window.frame.unfocusColor", "black", style);
786   resource.wstyle.l_text_focus =
787     readDatabaseColor("window.label.focus.textColor", "black", style);
788   resource.wstyle.l_text_unfocus =
789     readDatabaseColor("window.label.unfocus.textColor", "white", style);
790   resource.wstyle.b_pic_focus =
791     readDatabaseColor("window.button.focus.picColor", "black", style);
792   resource.wstyle.b_pic_unfocus =
793     readDatabaseColor("window.button.unfocus.picColor", "white", style);
794
795   resource.wstyle.justify = LeftJustify;
796   if (style.getValue("window.justify", s)) {
797     if (s == "right" || s == "Right")
798       resource.wstyle.justify = RightJustify;
799     else if (s == "center" || s == "Center")
800       resource.wstyle.justify = CenterJustify;
801   }
802
803   // load toolbar config
804   resource.tstyle.toolbar =
805     readDatabaseTexture("toolbar", "black", style);
806   resource.tstyle.label =
807     readDatabaseTexture("toolbar.label", "black", style);
808   resource.tstyle.window =
809     readDatabaseTexture("toolbar.windowLabel", "black", style);
810   resource.tstyle.button =
811     readDatabaseTexture("toolbar.button", "white", style);
812   resource.tstyle.pressed =
813     readDatabaseTexture("toolbar.button.pressed", "black", style);
814   resource.tstyle.clock =
815     readDatabaseTexture("toolbar.clock", "black", style);
816   resource.tstyle.l_text =
817     readDatabaseColor("toolbar.label.textColor", "white", style);
818   resource.tstyle.w_text =
819     readDatabaseColor("toolbar.windowLabel.textColor", "white", style);
820   resource.tstyle.c_text =
821     readDatabaseColor("toolbar.clock.textColor", "white", style);
822   resource.tstyle.b_pic =
823     readDatabaseColor("toolbar.button.picColor", "black", style);
824
825   resource.tstyle.justify = LeftJustify;
826   if (style.getValue("toolbar.justify", s)) {
827     if (s == "right" || s == "Right")
828       resource.tstyle.justify = RightJustify;
829     else if (s == "center" || s == "Center")
830       resource.tstyle.justify = CenterJustify;
831   }
832
833   // load menu config
834   resource.mstyle.title =
835     readDatabaseTexture("menu.title", "white", style);
836   resource.mstyle.frame =
837     readDatabaseTexture("menu.frame", "black", style);
838   resource.mstyle.hilite =
839     readDatabaseTexture("menu.hilite", "white", style);
840   resource.mstyle.t_text =
841     readDatabaseColor("menu.title.textColor", "black", style);
842   resource.mstyle.f_text =
843     readDatabaseColor("menu.frame.textColor", "white", style);
844   resource.mstyle.d_text =
845     readDatabaseColor("menu.frame.disableColor", "black", style);
846   resource.mstyle.h_text =
847     readDatabaseColor("menu.hilite.textColor", "black", style);
848
849   resource.mstyle.t_justify = LeftJustify;
850   if (style.getValue("menu.title.justify", s)) {
851     if (s == "right" || s == "Right")
852       resource.mstyle.t_justify = RightJustify;
853     else if (s == "center" || s == "Center")
854       resource.mstyle.t_justify = CenterJustify;
855   }
856
857   resource.mstyle.f_justify = LeftJustify;
858   if (style.getValue("menu.frame.justify", s)) {
859     if (s == "right" || s == "Right")
860       resource.mstyle.f_justify = RightJustify;
861     else if (s == "center" || s == "Center")
862       resource.mstyle.f_justify = CenterJustify;
863   }
864
865   resource.mstyle.bullet = Basemenu::Triangle;
866   if (style.getValue("menu.bullet", s)) {
867     if (s == "empty" || s == "Empty")
868       resource.mstyle.bullet = Basemenu::Empty;
869     else if (s == "square" || s == "Square")
870       resource.mstyle.bullet = Basemenu::Square;
871     else if (s == "diamond" || s == "Diamond")
872       resource.mstyle.bullet = Basemenu::Diamond;
873   }
874
875   resource.mstyle.bullet_pos = Basemenu::Left;
876   if (style.getValue("menu.bullet.position", s)) {
877     if (s == "right" || s == "Right")
878       resource.mstyle.bullet_pos = Basemenu::Right;
879   }
880
881   resource.border_color =
882     readDatabaseColor("borderColor", "black", style);
883
884   // load bevel, border and handle widths
885   if (! style.getValue("handleWidth", resource.handle_width) ||
886       resource.handle_width > (getWidth() / 2) || resource.handle_width == 0)
887     resource.handle_width = 6;
888
889   if (! style.getValue("borderWidth", resource.border_width))
890     resource.border_width = 1;
891
892   if (! style.getValue("bevelWidth", resource.bevel_width) ||
893       resource.bevel_width > (getWidth() / 2) || resource.bevel_width == 0)
894     resource.bevel_width = 3;
895
896   if (! style.getValue("frameWidth", resource.frame_width) ||
897       resource.frame_width > (getWidth() / 2))
898     resource.frame_width = resource.bevel_width;
899
900   if (style.getValue("rootCommand", s))
901     bexec(s, displayString());
902 }
903
904
905 void BScreen::addIcon(BlackboxWindow *w) {
906   if (! w) return;
907
908   w->setWorkspace(BSENTINEL);
909   w->setWindowNumber(iconList.size());
910
911   iconList.push_back(w);
912
913   const char* title = w->getIconTitle();
914   iconmenu->insert(title);
915   iconmenu->update();
916 }
917
918
919 void BScreen::removeIcon(BlackboxWindow *w) {
920   if (! w) return;
921
922   iconList.remove(w);
923
924   iconmenu->remove(w->getWindowNumber());
925   iconmenu->update();
926
927   BlackboxWindowList::iterator it = iconList.begin(),
928     end = iconList.end();
929   for (int i = 0; it != end; ++it)
930     (*it)->setWindowNumber(i++);
931 }
932
933
934 BlackboxWindow *BScreen::getIcon(unsigned int index) {
935   if (index < iconList.size()) {
936     BlackboxWindowList::iterator it = iconList.begin();
937     for (; index > 0; --index, ++it) ; /* increment to index */
938     return *it;
939   }
940
941   return (BlackboxWindow *) 0;
942 }
943
944
945 unsigned int BScreen::addWorkspace(void) {
946   Workspace *wkspc = new Workspace(this, workspacesList.size());
947   workspacesList.push_back(wkspc);
948   saveWorkspaces(getWorkspaceCount());
949
950   workspacemenu->insert(wkspc->getName(), wkspc->getMenu(),
951                         wkspc->getID() + 2);
952   workspacemenu->update();
953
954   toolbar->reconfigure();
955
956   updateNetizenWorkspaceCount();
957
958   return workspacesList.size();
959 }
960
961
962 unsigned int BScreen::removeLastWorkspace(void) {
963   if (workspacesList.size() == 1)
964     return 1;
965
966   Workspace *wkspc = workspacesList.back();
967
968   if (current_workspace->getID() == wkspc->getID())
969     changeWorkspaceID(current_workspace->getID() - 1);
970
971   wkspc->removeAll();
972
973   workspacemenu->remove(wkspc->getID() + 2);
974   workspacemenu->update();
975
976   workspacesList.pop_back();
977   delete wkspc;
978
979   saveWorkspaces(getWorkspaceCount());
980
981   toolbar->reconfigure();
982
983   updateNetizenWorkspaceCount();
984
985   return workspacesList.size();
986 }
987
988
989 void BScreen::changeWorkspaceID(unsigned int id) {
990   if (! current_workspace) return;
991
992   if (id != current_workspace->getID()) {
993     BlackboxWindow *focused = blackbox->getFocusedWindow();
994     if (focused && focused->getScreen() == this && ! focused->isStuck()) {
995       if (focused->getWorkspaceNumber() != current_workspace->getID()) {
996         fprintf(stderr, "%s is on the wrong workspace, aborting\n",
997                 focused->getTitle());
998         abort();
999       }
1000       current_workspace->setLastFocusedWindow(focused);
1001     } else {
1002       // if no window had focus, no need to store a last focus
1003       current_workspace->setLastFocusedWindow((BlackboxWindow *) 0);
1004     }
1005     // when we switch workspaces, unfocus whatever was focused
1006     blackbox->setFocusedWindow((BlackboxWindow *) 0);
1007     
1008     current_workspace->hideAll();
1009     workspacemenu->setItemSelected(current_workspace->getID() + 2, False);
1010
1011     current_workspace = getWorkspace(id);
1012
1013     xatom->setValue(getRootWindow(), XAtom::net_current_desktop,
1014                     XAtom::cardinal, id);
1015
1016     workspacemenu->setItemSelected(current_workspace->getID() + 2, True);
1017     toolbar->redrawWorkspaceLabel(True);
1018
1019     current_workspace->showAll();
1020
1021     if (resource.focus_last && current_workspace->getLastFocusedWindow()) {
1022       XSync(blackbox->getXDisplay(), False);
1023       current_workspace->getLastFocusedWindow()->setInputFocus();
1024     }
1025   }
1026
1027   updateNetizenCurrentWorkspace();
1028 }
1029
1030
1031 /*
1032  * Set the _NET_CLIENT_LIST root window property.
1033  */
1034 void BScreen::updateClientList(void) {
1035   if (windowList.size() > 0) {
1036     Window *windows = new Window[windowList.size()];
1037     Window *win_it = windows;
1038     BlackboxWindowList::iterator it = windowList.begin();
1039     const BlackboxWindowList::iterator end = windowList.end();
1040     for (; it != end; ++it, ++win_it)
1041       *win_it = (*it)->getClientWindow();
1042     xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
1043                     windows, windowList.size());
1044     delete [] windows;
1045   } else
1046     xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
1047                     0, 0);
1048 }
1049
1050
1051 /*
1052  * Set the _NET_CLIENT_LIST_STACKING root window property.
1053  */
1054 void BScreen::updateStackingList(void) {
1055
1056   BlackboxWindowList stack_order;
1057
1058   /*
1059    * Get the atacking order from all of the workspaces.
1060    * We start with the current workspace so that the sticky windows will be
1061    * in the right order on the current workspace.
1062    * XXX: Do we need to have sticky windows in the list once for each workspace?
1063    */
1064   getCurrentWorkspace()->appendStackOrder(stack_order);
1065   for (unsigned int i = 0; i < getWorkspaceCount(); ++i)
1066     if (i != getCurrentWorkspaceID())
1067       getWorkspace(i)->appendStackOrder(stack_order);
1068  
1069   if (stack_order.size() > 0) {
1070     // set the client list atoms
1071     Window *windows = new Window[stack_order.size()];
1072     Window *win_it = windows;
1073     BlackboxWindowList::iterator it = stack_order.begin();
1074     const BlackboxWindowList::iterator end = stack_order.end();
1075     for (; it != end; ++it, ++win_it)
1076       *win_it = (*it)->getClientWindow();
1077     xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
1078                     XAtom::window, windows, stack_order.size());
1079     delete [] windows;
1080   } else
1081     xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
1082                     XAtom::window, 0, 0);
1083 }
1084
1085
1086 void BScreen::addSystrayWindow(Window window) {
1087   systrayWindowList.push_back(window);
1088   xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
1089                   XAtom::window,
1090                   &systrayWindowList[0], systrayWindowList.size());
1091   blackbox->saveSystrayWindowSearch(window, this);
1092 }
1093
1094
1095 void BScreen::removeSystrayWindow(Window window) {
1096   WindowList::iterator it = systrayWindowList.begin();
1097   const WindowList::iterator end = systrayWindowList.end();
1098   for (; it != end; ++it)
1099     if (*it == window) {
1100       systrayWindowList.erase(it);
1101       xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
1102                       XAtom::window,
1103                       &systrayWindowList[0], systrayWindowList.size());
1104       blackbox->removeSystrayWindowSearch(window);
1105       break;
1106     }
1107 }
1108
1109
1110 void BScreen::addDesktopWindow(Window window) {
1111   desktopWindowList.push_back(window);
1112   XLowerWindow(blackbox->getXDisplay(), window);
1113   XSelectInput(blackbox->getXDisplay(), window, StructureNotifyMask);
1114   blackbox->saveDesktopWindowSearch(window, this);
1115 }
1116
1117
1118 void BScreen::removeDesktopWindow(Window window) {
1119   WindowList::iterator it = desktopWindowList.begin();
1120   const WindowList::iterator end = desktopWindowList.end();
1121   for (; it != end; ++it)
1122     if (*it == window) {
1123       desktopWindowList.erase(it);
1124       XSelectInput(blackbox->getXDisplay(), window, None);
1125       blackbox->removeDesktopWindowSearch(window);
1126       break;
1127     }
1128 }
1129
1130
1131 void BScreen::manageWindow(Window w) {
1132   new BlackboxWindow(blackbox, w, this);
1133
1134   BlackboxWindow *win = blackbox->searchWindow(w);
1135   if (! win)
1136     return;
1137   if (win->isDesktop()) {
1138     // desktop windows cant do anything, so we remove all the normal window
1139     // stuff from them, they are only kept around so that we can keep them on
1140     // the bottom of the z-order
1141     win->restore(True);
1142     addDesktopWindow(win->getClientWindow());
1143     delete win;
1144     return;
1145   }
1146
1147   windowList.push_back(win);
1148   updateClientList();
1149
1150   XMapRequestEvent mre;
1151   mre.window = w;
1152   if (blackbox->isStartup()) win->restoreAttributes();
1153   win->mapRequestEvent(&mre);
1154 }
1155
1156
1157 void BScreen::unmanageWindow(BlackboxWindow *w, bool remap) {
1158   w->restore(remap);
1159
1160   if (w->getWorkspaceNumber() != BSENTINEL &&
1161       w->getWindowNumber() != BSENTINEL)
1162     getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
1163   else if (w->isIconic())
1164     removeIcon(w);
1165
1166   windowList.remove(w);
1167   updateClientList();
1168
1169   if (blackbox->getFocusedWindow() == w)
1170     blackbox->setFocusedWindow((BlackboxWindow *) 0);
1171
1172   removeNetizen(w->getClientWindow());
1173
1174   /*
1175     some managed windows can also be window group controllers.  when
1176     unmanaging such windows, we should also delete the window group.
1177   */
1178   BWindowGroup *group = blackbox->searchGroup(w->getClientWindow());
1179   delete group;
1180
1181   delete w;
1182 }
1183
1184
1185 void BScreen::addNetizen(Netizen *n) {
1186   netizenList.push_back(n);
1187
1188   n->sendWorkspaceCount();
1189   n->sendCurrentWorkspace();
1190
1191   WorkspaceList::iterator it = workspacesList.begin();
1192   const WorkspaceList::iterator end = workspacesList.end();
1193   for (; it != end; ++it)
1194     (*it)->sendWindowList(*n);
1195
1196   Window f = ((blackbox->getFocusedWindow()) ?
1197               blackbox->getFocusedWindow()->getClientWindow() : None);
1198   n->sendWindowFocus(f);
1199 }
1200
1201
1202 void BScreen::removeNetizen(Window w) {
1203   NetizenList::iterator it = netizenList.begin();
1204   for (; it != netizenList.end(); ++it) {
1205     if ((*it)->getWindowID() == w) {
1206       delete *it;
1207       netizenList.erase(it);
1208       break;
1209     }
1210   }
1211 }
1212
1213
1214 void BScreen::updateWorkArea(void) {
1215   if (workspacesList.size() > 0) {
1216     unsigned long *dims = new unsigned long[4 * workspacesList.size()];
1217     for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
1218       // XXX: this could be different for each workspace
1219       const Rect &area = availableArea();
1220       dims[(i * 4) + 0] = area.x();
1221       dims[(i * 4) + 1] = area.y();
1222       dims[(i * 4) + 2] = area.width();
1223       dims[(i * 4) + 3] = area.height();
1224     }
1225     xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
1226                     dims, 4 * workspacesList.size());
1227     delete [] dims;
1228   } else
1229     xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
1230                     0, 0);
1231 }
1232
1233
1234 void BScreen::updateNetizenCurrentWorkspace(void) {
1235   std::for_each(netizenList.begin(), netizenList.end(),
1236                 std::mem_fun(&Netizen::sendCurrentWorkspace));
1237 }
1238
1239
1240 void BScreen::updateNetizenWorkspaceCount(void) {
1241   xatom->setValue(getRootWindow(), XAtom::net_number_of_desktops,
1242                   XAtom::cardinal, workspacesList.size());
1243
1244   updateWorkArea();
1245   
1246   std::for_each(netizenList.begin(), netizenList.end(),
1247                 std::mem_fun(&Netizen::sendWorkspaceCount));
1248 }
1249
1250
1251 void BScreen::updateNetizenWindowFocus(void) {
1252   Window f = ((blackbox->getFocusedWindow()) ?
1253               blackbox->getFocusedWindow()->getClientWindow() : None);
1254
1255   xatom->setValue(getRootWindow(), XAtom::net_active_window,
1256                   XAtom::window, f);
1257
1258   NetizenList::iterator it = netizenList.begin();
1259   for (; it != netizenList.end(); ++it)
1260     (*it)->sendWindowFocus(f);
1261 }
1262
1263
1264 void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) {
1265   NetizenList::iterator it = netizenList.begin();
1266   for (; it != netizenList.end(); ++it) {
1267     (*it)->sendWindowAdd(w, p);
1268   }
1269 }
1270
1271
1272 void BScreen::updateNetizenWindowDel(Window w) {
1273   NetizenList::iterator it = netizenList.begin();
1274   for (; it != netizenList.end(); ++it)
1275     (*it)->sendWindowDel(w);
1276 }
1277
1278
1279 void BScreen::updateNetizenWindowRaise(Window w) {
1280   NetizenList::iterator it = netizenList.begin();
1281   for (; it != netizenList.end(); ++it)
1282     (*it)->sendWindowRaise(w);
1283 }
1284
1285
1286 void BScreen::updateNetizenWindowLower(Window w) {
1287   NetizenList::iterator it = netizenList.begin();
1288   for (; it != netizenList.end(); ++it)
1289     (*it)->sendWindowLower(w);
1290 }
1291
1292
1293 void BScreen::updateNetizenConfigNotify(XEvent *e) {
1294   NetizenList::iterator it = netizenList.begin();
1295   for (; it != netizenList.end(); ++it)
1296     (*it)->sendConfigNotify(e);
1297 }
1298
1299
1300 void BScreen::raiseWindows(Window *workspace_stack, unsigned int num) {
1301   // the 13 represents the number of blackbox windows such as menus
1302   Window *session_stack = new
1303     Window[(num + workspacesList.size() + rootmenuList.size() + 13)];
1304   unsigned int i = 0, k = num;
1305
1306   XRaiseWindow(blackbox->getXDisplay(), iconmenu->getWindowID());
1307   *(session_stack + i++) = iconmenu->getWindowID();
1308
1309   WorkspaceList::iterator wit = workspacesList.begin();
1310   const WorkspaceList::iterator w_end = workspacesList.end();
1311   for (; wit != w_end; ++wit)
1312     *(session_stack + i++) = (*wit)->getMenu()->getWindowID();
1313
1314   *(session_stack + i++) = workspacemenu->getWindowID();
1315
1316   *(session_stack + i++) = configmenu->getFocusmenu()->getWindowID();
1317   *(session_stack + i++) = configmenu->getPlacementmenu()->getWindowID();
1318   *(session_stack + i++) = configmenu->getWindowID();
1319
1320   *(session_stack + i++) = slit->getMenu()->getDirectionmenu()->getWindowID();
1321   *(session_stack + i++) = slit->getMenu()->getPlacementmenu()->getWindowID();
1322   *(session_stack + i++) = slit->getMenu()->getWindowID();
1323
1324   *(session_stack + i++) =
1325     toolbar->getMenu()->getPlacementmenu()->getWindowID();
1326   *(session_stack + i++) = toolbar->getMenu()->getWindowID();
1327
1328   RootmenuList::iterator rit = rootmenuList.begin();
1329   for (; rit != rootmenuList.end(); ++rit)
1330     *(session_stack + i++) = (*rit)->getWindowID();
1331   *(session_stack + i++) = rootmenu->getWindowID();
1332
1333   if (toolbar->isOnTop())
1334     *(session_stack + i++) = toolbar->getWindowID();
1335
1336   if (slit->isOnTop())
1337     *(session_stack + i++) = slit->getWindowID();
1338
1339   while (k--)
1340     *(session_stack + i++) = *(workspace_stack + k);
1341
1342   XRestackWindows(blackbox->getXDisplay(), session_stack, i);
1343
1344   delete [] session_stack;
1345
1346   updateStackingList();
1347 }
1348
1349
1350 void BScreen::lowerDesktops(void) {
1351   if (desktopWindowList.empty()) return;
1352
1353   XLowerWindow(blackbox->getXDisplay(), desktopWindowList[0]);
1354   if (desktopWindowList.size() > 1)
1355     XRestackWindows(blackbox->getXDisplay(), &desktopWindowList[0],
1356                     desktopWindowList.size());
1357 }
1358
1359
1360 void BScreen::reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id,
1361                                 bool ignore_sticky) {
1362   if (! w) return;
1363
1364   if (wkspc_id == BSENTINEL)
1365     wkspc_id = current_workspace->getID();
1366
1367   if (w->getWorkspaceNumber() == wkspc_id)
1368     return;
1369
1370   if (w->isIconic()) {
1371     removeIcon(w);
1372     getWorkspace(wkspc_id)->addWindow(w);
1373   } else if (ignore_sticky || ! w->isStuck()) {
1374     getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
1375     getWorkspace(wkspc_id)->addWindow(w);
1376   }
1377 }
1378
1379
1380 void BScreen::propagateWindowName(const BlackboxWindow *bw) {
1381   if (bw->isIconic()) {
1382     iconmenu->changeItemLabel(bw->getWindowNumber(), bw->getIconTitle());
1383     iconmenu->update();
1384   }
1385   else {
1386     Clientmenu *clientmenu = getWorkspace(bw->getWorkspaceNumber())->getMenu();
1387     clientmenu->changeItemLabel(bw->getWindowNumber(), bw->getTitle());
1388     clientmenu->update();
1389
1390     if (blackbox->getFocusedWindow() == bw)
1391       toolbar->redrawWindowLabel(True);
1392   }
1393 }
1394
1395
1396 void BScreen::nextFocus(void) {
1397   BlackboxWindow *focused = blackbox->getFocusedWindow(),
1398     *next = focused;
1399
1400   if (focused) {
1401     // if window is not on this screen, ignore it
1402     if (focused->getScreen()->getScreenNumber() != getScreenNumber())
1403       focused = (BlackboxWindow*) 0;
1404   }
1405
1406   if (focused && current_workspace->getCount() > 1) {
1407     // next is the next window to recieve focus, current is a place holder
1408     BlackboxWindow *current;
1409     do {
1410       current = next;
1411       next = current_workspace->getNextWindowInList(current);
1412     } while(! next->setInputFocus() && next != focused);
1413
1414     if (next != focused)
1415       current_workspace->raiseWindow(next);
1416   } else if (current_workspace->getCount() >= 1) {
1417     next = current_workspace->getTopWindowOnStack();
1418
1419     current_workspace->raiseWindow(next);
1420     next->setInputFocus();
1421   }
1422 }
1423
1424
1425 void BScreen::prevFocus(void) {
1426   BlackboxWindow *focused = blackbox->getFocusedWindow(),
1427     *next = focused;
1428
1429   if (focused) {
1430     // if window is not on this screen, ignore it
1431     if (focused->getScreen()->getScreenNumber() != getScreenNumber())
1432       focused = (BlackboxWindow*) 0;
1433   }
1434
1435   if (focused && current_workspace->getCount() > 1) {
1436     // next is the next window to recieve focus, current is a place holder
1437     BlackboxWindow *current;
1438     do {
1439       current = next;
1440       next = current_workspace->getPrevWindowInList(current);
1441     } while(! next->setInputFocus() && next != focused);
1442
1443     if (next != focused)
1444       current_workspace->raiseWindow(next);
1445   } else if (current_workspace->getCount() >= 1) {
1446     next = current_workspace->getTopWindowOnStack();
1447
1448     current_workspace->raiseWindow(next);
1449     next->setInputFocus();
1450   }
1451 }
1452
1453
1454 void BScreen::raiseFocus(void) {
1455   BlackboxWindow *focused = blackbox->getFocusedWindow();
1456   if (! focused)
1457     return;
1458
1459   // if on this Screen, raise it
1460   if (focused->getScreen()->getScreenNumber() == getScreenNumber()) {
1461     Workspace *workspace = getWorkspace(focused->getWorkspaceNumber());
1462     workspace->raiseWindow(focused);
1463   }
1464 }
1465
1466
1467 void BScreen::InitMenu(void) {
1468   if (rootmenu) {
1469     rootmenuList.clear();
1470
1471     while (rootmenu->getCount())
1472       rootmenu->remove(0);
1473   } else {
1474     rootmenu = new Rootmenu(this);
1475   }
1476   bool defaultMenu = True;
1477
1478   FILE *menu_file = (FILE *) 0;
1479   const char *menu_filename = blackbox->getMenuFilename();
1480
1481   if (menu_filename) 
1482     if (! (menu_file = fopen(menu_filename, "r")))
1483       perror(menu_filename);
1484   if (! menu_file) {     // opening the menu file failed, try the default menu
1485     menu_filename = DEFAULTMENU;
1486     if (! (menu_file = fopen(menu_filename, "r")))
1487       perror(menu_filename);
1488   } 
1489
1490   if (menu_file) {
1491     if (feof(menu_file)) {
1492       fprintf(stderr, i18n(ScreenSet, ScreenEmptyMenuFile,
1493                            "%s: Empty menu file"),
1494               menu_filename);
1495     } else {
1496       char line[1024], label[1024];
1497       memset(line, 0, 1024);
1498       memset(label, 0, 1024);
1499
1500       while (fgets(line, 1024, menu_file) && ! feof(menu_file)) {
1501         if (line[0] != '#') {
1502           int i, key = 0, index = -1, len = strlen(line);
1503
1504           for (i = 0; i < len; i++) {
1505             if (line[i] == '[') index = 0;
1506             else if (line[i] == ']') break;
1507             else if (line[i] != ' ')
1508               if (index++ >= 0)
1509                 key += tolower(line[i]);
1510           }
1511
1512           if (key == 517) { // [begin]
1513             index = -1;
1514             for (i = index; i < len; i++) {
1515               if (line[i] == '(') index = 0;
1516               else if (line[i] == ')') break;
1517               else if (index++ >= 0) {
1518                 if (line[i] == '\\' && i < len - 1) i++;
1519                 label[index - 1] = line[i];
1520               }
1521             }
1522
1523             if (index == -1) index = 0;
1524             label[index] = '\0';
1525
1526             rootmenu->setLabel(label);
1527             defaultMenu = parseMenuFile(menu_file, rootmenu);
1528             if (! defaultMenu)
1529               blackbox->addMenuTimestamp(menu_filename);
1530             break;
1531           }
1532         }
1533       }
1534     }
1535     fclose(menu_file);
1536   }
1537
1538   if (defaultMenu) {
1539     rootmenu->setInternalMenu();
1540     rootmenu->insert(i18n(ScreenSet, Screenxterm, "xterm"),
1541                      BScreen::Execute,
1542                      i18n(ScreenSet, Screenxterm, "xterm"));
1543     rootmenu->insert(i18n(ScreenSet, ScreenRestart, "Restart"),
1544                      BScreen::Restart);
1545     rootmenu->insert(i18n(ScreenSet, ScreenExit, "Exit"),
1546                      BScreen::Exit);
1547     rootmenu->setLabel(i18n(BasemenuSet, BasemenuBlackboxMenu,
1548                             "Openbox Menu"));
1549   }
1550 }
1551
1552
1553 bool BScreen::parseMenuFile(FILE *file, Rootmenu *menu) {
1554   char line[1024], label[1024], command[1024];
1555
1556   while (! feof(file)) {
1557     memset(line, 0, 1024);
1558     memset(label, 0, 1024);
1559     memset(command, 0, 1024);
1560
1561     if (fgets(line, 1024, file)) {
1562       if (line[0] != '#') {
1563         int i, key = 0, parse = 0, index = -1, line_length = strlen(line);
1564
1565         // determine the keyword
1566         for (i = 0; i < line_length; i++) {
1567           if (line[i] == '[') parse = 1;
1568           else if (line[i] == ']') break;
1569           else if (line[i] != ' ')
1570             if (parse)
1571               key += tolower(line[i]);
1572         }
1573
1574         // get the label enclosed in ()'s
1575         parse = 0;
1576
1577         for (i = 0; i < line_length; i++) {
1578           if (line[i] == '(') {
1579             index = 0;
1580             parse = 1;
1581           } else if (line[i] == ')') break;
1582           else if (index++ >= 0) {
1583             if (line[i] == '\\' && i < line_length - 1) i++;
1584             label[index - 1] = line[i];
1585           }
1586         }
1587
1588         if (parse) {
1589           label[index] = '\0';
1590         } else {
1591           label[0] = '\0';
1592         }
1593
1594         // get the command enclosed in {}'s
1595         parse = 0;
1596         index = -1;
1597         for (i = 0; i < line_length; i++) {
1598           if (line[i] == '{') {
1599             index = 0;
1600             parse = 1;
1601           } else if (line[i] == '}') break;
1602           else if (index++ >= 0) {
1603             if (line[i] == '\\' && i < line_length - 1) i++;
1604             command[index - 1] = line[i];
1605           }
1606         }
1607
1608         if (parse) {
1609           command[index] = '\0';
1610         } else {
1611           command[0] = '\0';
1612         }
1613
1614         switch (key) {
1615         case 311: // end
1616           return ((menu->getCount() == 0) ? True : False);
1617
1618           break;
1619
1620         case 333: // nop
1621           if (! *label)
1622             label[0] = '\0';
1623           menu->insert(label);
1624
1625           break;
1626
1627         case 421: // exec
1628           if ((! *label) && (! *command)) {
1629             fprintf(stderr, i18n(ScreenSet, ScreenEXECError,
1630                                  "BScreen::parseMenuFile: [exec] error, "
1631                                  "no menu label and/or command defined\n"));
1632             continue;
1633           }
1634
1635           menu->insert(label, BScreen::Execute, command);
1636
1637           break;
1638
1639         case 442: // exit
1640           if (! *label) {
1641             fprintf(stderr, i18n(ScreenSet, ScreenEXITError,
1642                                  "BScreen::parseMenuFile: [exit] error, "
1643                                  "no menu label defined\n"));
1644             continue;
1645           }
1646
1647           menu->insert(label, BScreen::Exit);
1648
1649           break;
1650
1651         case 561: // style
1652           {
1653             if ((! *label) || (! *command)) {
1654               fprintf(stderr,
1655                       i18n(ScreenSet, ScreenSTYLEError,
1656                            "BScreen::parseMenuFile: [style] error, "
1657                            "no menu label and/or filename defined\n"));
1658               continue;
1659             }
1660
1661             string style = expandTilde(command);
1662
1663             menu->insert(label, BScreen::SetStyle, style.c_str());
1664           }
1665
1666           break;
1667
1668         case 630: // config
1669           if (! *label) {
1670             fprintf(stderr, i18n(ScreenSet, ScreenCONFIGError,
1671                                  "BScreen::parseMenufile: [config] error, "
1672                                  "no label defined"));
1673             continue;
1674           }
1675
1676           menu->insert(label, configmenu);
1677
1678           break;
1679
1680         case 740: // include
1681           {
1682             if (! *label) {
1683               fprintf(stderr, i18n(ScreenSet, ScreenINCLUDEError,
1684                                    "BScreen::parseMenuFile: [include] error, "
1685                                    "no filename defined\n"));
1686               continue;
1687             }
1688
1689             string newfile = expandTilde(label);
1690             FILE *submenufile = fopen(newfile.c_str(), "r");
1691
1692             if (submenufile) {
1693               struct stat buf;
1694               if (fstat(fileno(submenufile), &buf) ||
1695                   (! S_ISREG(buf.st_mode))) {
1696                 fprintf(stderr,
1697                         i18n(ScreenSet, ScreenINCLUDEErrorReg,
1698                              "BScreen::parseMenuFile: [include] error: "
1699                              "'%s' is not a regular file\n"), newfile.c_str());
1700                 break;
1701               }
1702
1703               if (! feof(submenufile)) {
1704                 if (! parseMenuFile(submenufile, menu))
1705                   blackbox->addMenuTimestamp(newfile);
1706
1707                 fclose(submenufile);
1708               }
1709             } else {
1710               perror(newfile.c_str());
1711             }
1712           }
1713
1714           break;
1715
1716         case 767: // submenu
1717           {
1718             if (! *label) {
1719               fprintf(stderr, i18n(ScreenSet, ScreenSUBMENUError,
1720                                    "BScreen::parseMenuFile: [submenu] error, "
1721                                    "no menu label defined\n"));
1722               continue;
1723             }
1724
1725             Rootmenu *submenu = new Rootmenu(this);
1726
1727             if (*command)
1728               submenu->setLabel(command);
1729             else
1730               submenu->setLabel(label);
1731
1732             parseMenuFile(file, submenu);
1733             submenu->update();
1734             menu->insert(label, submenu);
1735             rootmenuList.push_back(submenu);
1736           }
1737
1738           break;
1739
1740         case 773: // restart
1741           {
1742             if (! *label) {
1743               fprintf(stderr, i18n(ScreenSet, ScreenRESTARTError,
1744                                    "BScreen::parseMenuFile: [restart] error, "
1745                                    "no menu label defined\n"));
1746               continue;
1747             }
1748
1749             if (*command)
1750               menu->insert(label, BScreen::RestartOther, command);
1751             else
1752               menu->insert(label, BScreen::Restart);
1753           }
1754
1755           break;
1756
1757         case 845: // reconfig
1758           {
1759             if (! *label) {
1760               fprintf(stderr,
1761                       i18n(ScreenSet, ScreenRECONFIGError,
1762                            "BScreen::parseMenuFile: [reconfig] error, "
1763                            "no menu label defined\n"));
1764               continue;
1765             }
1766
1767             menu->insert(label, BScreen::Reconfigure);
1768           }
1769
1770           break;
1771
1772         case 995: // stylesdir
1773         case 1113: // stylesmenu
1774           {
1775             bool newmenu = ((key == 1113) ? True : False);
1776
1777             if ((! *label) || ((! *command) && newmenu)) {
1778               fprintf(stderr,
1779                       i18n(ScreenSet, ScreenSTYLESDIRError,
1780                            "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
1781                            " error, no directory defined\n"));
1782               continue;
1783             }
1784
1785             char *directory = ((newmenu) ? command : label);
1786
1787             string stylesdir = expandTilde(directory);
1788
1789             struct stat statbuf;
1790
1791             if (! stat(stylesdir.c_str(), &statbuf)) {
1792               if (S_ISDIR(statbuf.st_mode)) {
1793                 Rootmenu *stylesmenu;
1794
1795                 if (newmenu)
1796                   stylesmenu = new Rootmenu(this);
1797                 else
1798                   stylesmenu = menu;
1799
1800                 DIR *d = opendir(stylesdir.c_str());
1801                 struct dirent *p;
1802                 std::vector<string> ls;
1803
1804                 while((p = readdir(d)))
1805                   ls.push_back(p->d_name);
1806
1807                 closedir(d);
1808
1809                 std::sort(ls.begin(), ls.end());
1810
1811                 std::vector<string>::iterator it = ls.begin(),
1812                   end = ls.end();
1813                 for (; it != end; ++it) {
1814                   const string& fname = *it;
1815
1816                   if (fname[fname.size()-1] == '~')
1817                     continue;
1818
1819                   string style = stylesdir;
1820                   style += '/';
1821                   style += fname;
1822
1823                   if ((! stat(style.c_str(), &statbuf)) &&
1824                       S_ISREG(statbuf.st_mode))
1825                     stylesmenu->insert(fname, BScreen::SetStyle, style);
1826                 }
1827
1828                 stylesmenu->update();
1829
1830                 if (newmenu) {
1831                   stylesmenu->setLabel(label);
1832                   menu->insert(label, stylesmenu);
1833                   rootmenuList.push_back(stylesmenu);
1834                 }
1835
1836                 blackbox->addMenuTimestamp(stylesdir);
1837               } else {
1838                 fprintf(stderr,
1839                         i18n(ScreenSet, ScreenSTYLESDIRErrorNotDir,
1840                              "BScreen::parseMenuFile:"
1841                              " [stylesdir/stylesmenu] error, %s is not a"
1842                              " directory\n"), stylesdir.c_str());
1843               }
1844             } else {
1845               fprintf(stderr,
1846                       i18n(ScreenSet, ScreenSTYLESDIRErrorNoExist,
1847                            "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
1848                            " error, %s does not exist\n"), stylesdir.c_str());
1849             }
1850             break;
1851           }
1852
1853         case 1090: // workspaces
1854           {
1855             if (! *label) {
1856               fprintf(stderr,
1857                       i18n(ScreenSet, ScreenWORKSPACESError,
1858                            "BScreen:parseMenuFile: [workspaces] error, "
1859                            "no menu label defined\n"));
1860               continue;
1861             }
1862
1863             menu->insert(label, workspacemenu);
1864
1865             break;
1866           }
1867         }
1868       }
1869     }
1870   }
1871
1872   return ((menu->getCount() == 0) ? True : False);
1873 }
1874
1875
1876 void BScreen::shutdown(void) {
1877   XSelectInput(blackbox->getXDisplay(), getRootWindow(), NoEventMask);
1878   XSync(blackbox->getXDisplay(), False);
1879
1880   while(! windowList.empty())
1881     unmanageWindow(windowList.front(), True);
1882
1883   slit->shutdown();
1884 }
1885
1886
1887 void BScreen::showPosition(int x, int y) {
1888   if (! geom_visible) {
1889     XMoveResizeWindow(blackbox->getXDisplay(), geom_window,
1890                       (getWidth() - geom_w) / 2,
1891                       (getHeight() - geom_h) / 2, geom_w, geom_h);
1892     XMapWindow(blackbox->getXDisplay(), geom_window);
1893     XRaiseWindow(blackbox->getXDisplay(), geom_window);
1894
1895     geom_visible = True;
1896   }
1897
1898   char label[1024];
1899
1900   sprintf(label, i18n(ScreenSet, ScreenPositionFormat,
1901                       "X: %4d x Y: %4d"), x, y);
1902
1903   XClearWindow(blackbox->getXDisplay(), geom_window);
1904
1905   resource.wstyle.font->drawString(geom_window,
1906                                    resource.bevel_width, resource.bevel_width,
1907                                    resource.wstyle.l_text_focus,
1908                                    label);
1909 }
1910
1911
1912 void BScreen::showGeometry(unsigned int gx, unsigned int gy) {
1913   if (! geom_visible) {
1914     XMoveResizeWindow(blackbox->getXDisplay(), geom_window,
1915                       (getWidth() - geom_w) / 2,
1916                       (getHeight() - geom_h) / 2, geom_w, geom_h);
1917     XMapWindow(blackbox->getXDisplay(), geom_window);
1918     XRaiseWindow(blackbox->getXDisplay(), geom_window);
1919
1920     geom_visible = True;
1921   }
1922
1923   char label[1024];
1924
1925   sprintf(label, i18n(ScreenSet, ScreenGeometryFormat,
1926                       "W: %4d x H: %4d"), gx, gy);
1927
1928   XClearWindow(blackbox->getXDisplay(), geom_window);
1929
1930   resource.wstyle.font->drawString(geom_window,
1931                                    resource.bevel_width, resource.bevel_width,
1932                                    resource.wstyle.l_text_focus,
1933                                    label);
1934 }
1935
1936
1937 void BScreen::hideGeometry(void) {
1938   if (geom_visible) {
1939     XUnmapWindow(blackbox->getXDisplay(), geom_window);
1940     geom_visible = False;
1941   }
1942 }
1943
1944
1945 void BScreen::addStrut(Strut *strut) {
1946   strutList.push_back(strut);
1947 }
1948
1949
1950 void BScreen::removeStrut(Strut *strut) {
1951   strutList.remove(strut);
1952 }
1953
1954
1955 const Rect& BScreen::availableArea(void) const {
1956   if (doFullMax())
1957     return getRect(); // return the full screen
1958   return usableArea;
1959 }
1960
1961
1962 void BScreen::updateAvailableArea(void) {
1963   Rect old_area = usableArea;
1964   usableArea = getRect(); // reset to full screen
1965
1966   /* these values represent offsets from the screen edge
1967    * we look for the biggest offset on each edge and then apply them
1968    * all at once
1969    * do not be confused by the similarity to the names of Rect's members
1970    */
1971   unsigned int current_left = 0, current_right = 0, current_top = 0,
1972     current_bottom = 0;
1973
1974   StrutList::const_iterator it = strutList.begin(), end = strutList.end();
1975
1976   for(; it != end; ++it) {
1977     Strut *strut = *it;
1978     if (strut->left > current_left)
1979       current_left = strut->left;
1980     if (strut->top > current_top)
1981       current_top = strut->top;
1982     if (strut->right > current_right)
1983       current_right = strut->right;
1984     if (strut->bottom > current_bottom)
1985       current_bottom = strut->bottom;
1986   }
1987
1988   usableArea.setPos(current_left, current_top);
1989   usableArea.setSize(usableArea.width() - (current_left + current_right),
1990                      usableArea.height() - (current_top + current_bottom));
1991
1992   if (old_area != usableArea) {
1993     BlackboxWindowList::iterator it = windowList.begin(),
1994       end = windowList.end();
1995     for (; it != end; ++it)
1996       if ((*it)->isMaximized()) (*it)->remaximize();
1997   }
1998
1999   updateWorkArea();  
2000 }
2001
2002
2003 Workspace* BScreen::getWorkspace(unsigned int index) {
2004   assert(index < workspacesList.size());
2005   return workspacesList[index];
2006 }
2007
2008
2009 void BScreen::buttonPressEvent(XButtonEvent *xbutton) {
2010   if (xbutton->button == 1) {
2011     if (! isRootColormapInstalled())
2012       image_control->installRootColormap();
2013
2014     if (workspacemenu->isVisible())
2015       workspacemenu->hide();
2016
2017     if (rootmenu->isVisible())
2018       rootmenu->hide();
2019   } else if (xbutton->button == 2) {
2020     int mx = xbutton->x_root - (workspacemenu->getWidth() / 2);
2021     int my = xbutton->y_root - (workspacemenu->getTitleHeight() / 2);
2022
2023     if (mx < 0) mx = 0;
2024     if (my < 0) my = 0;
2025
2026     if (mx + workspacemenu->getWidth() > getWidth())
2027       mx = getWidth() - workspacemenu->getWidth() - getBorderWidth();
2028
2029     if (my + workspacemenu->getHeight() > getHeight())
2030       my = getHeight() - workspacemenu->getHeight() - getBorderWidth();
2031
2032     workspacemenu->move(mx, my);
2033
2034     if (! workspacemenu->isVisible()) {
2035       workspacemenu->removeParent();
2036       workspacemenu->show();
2037     }
2038   } else if (xbutton->button == 3) {
2039     int mx = xbutton->x_root - (rootmenu->getWidth() / 2);
2040     int my = xbutton->y_root - (rootmenu->getTitleHeight() / 2);
2041
2042     if (mx < 0) mx = 0;
2043     if (my < 0) my = 0;
2044
2045     if (mx + rootmenu->getWidth() > getWidth())
2046       mx = getWidth() - rootmenu->getWidth() - getBorderWidth();
2047
2048     if (my + rootmenu->getHeight() > getHeight())
2049       my = getHeight() - rootmenu->getHeight() - getBorderWidth();
2050
2051     rootmenu->move(mx, my);
2052
2053     if (! rootmenu->isVisible()) {
2054       blackbox->checkMenu();
2055       rootmenu->show();
2056     }
2057   // mouse wheel up
2058   } else if (xbutton->button == 4) {
2059     if (getCurrentWorkspaceID() >= getWorkspaceCount() - 1)
2060       changeWorkspaceID(0);
2061     else
2062       changeWorkspaceID(getCurrentWorkspaceID() + 1);
2063   // mouse wheel down
2064   } else if (xbutton->button == 5) {
2065     if (getCurrentWorkspaceID() == 0)
2066       changeWorkspaceID(getWorkspaceCount() - 1);
2067     else
2068       changeWorkspaceID(getCurrentWorkspaceID() - 1);
2069   }
2070 }
2071
2072
2073 void BScreen::toggleFocusModel(FocusModel model) {
2074   if (model == SloppyFocus) {
2075     saveSloppyFocus(True);
2076   } else {
2077     // we're cheating here to save writing the config file 3 times
2078     resource.auto_raise = False;
2079     resource.click_raise = False;
2080     saveSloppyFocus(False);
2081   }
2082
2083   updateFocusModel();
2084 }
2085
2086
2087 void BScreen::updateFocusModel()
2088 {
2089   std::for_each(workspacesList.begin(), workspacesList.end(),
2090                 std::mem_fun(&Workspace::updateFocusModel));
2091 }
2092
2093
2094 BTexture BScreen::readDatabaseTexture(const string &rname,
2095                                       const string &default_color,
2096                                       const Configuration &style) {
2097   BTexture texture;
2098   string s;
2099
2100   if (style.getValue(rname, s))
2101     texture = BTexture(s);
2102   else
2103     texture.setTexture(BTexture::Solid | BTexture::Flat);
2104
2105   // associate this texture with this screen
2106   texture.setDisplay(getBaseDisplay(), getScreenNumber());
2107   texture.setImageControl(image_control);
2108
2109   if (texture.texture() & BTexture::Solid) {
2110     texture.setColor(readDatabaseColor(rname + ".color",
2111                                        default_color, style));
2112     texture.setColorTo(readDatabaseColor(rname + ".colorTo",
2113                                          default_color, style));
2114   } else if (texture.texture() & BTexture::Gradient) {
2115     texture.setColor(readDatabaseColor(rname + ".color",
2116                                        default_color, style));
2117     texture.setColorTo(readDatabaseColor(rname + ".colorTo",
2118                                          default_color, style));
2119   }
2120
2121   return texture;
2122 }
2123
2124
2125 BColor BScreen::readDatabaseColor(const string &rname,
2126                                   const string &default_color,
2127                                   const Configuration &style) {
2128   BColor color;
2129   string s;
2130   if (style.getValue(rname, s))
2131     color = BColor(s, getBaseDisplay(), getScreenNumber());
2132   else
2133     color = BColor(default_color, getBaseDisplay(), getScreenNumber());
2134   return color;
2135 }
2136
2137
2138 BFont *BScreen::readDatabaseFont(const string &rname,
2139                                  const Configuration &style) {
2140   string fontname;
2141
2142   string s;
2143   style.getValue(rname, s); // if this fails, a blank string will be used,
2144                             // which will cause the fallback font to load.
2145
2146   BFont *b = new BFont(blackbox->getXDisplay(), this, s);
2147   if (! b->valid())
2148     exit(2);  // can't continue without a font
2149   return b;
2150 }