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