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