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