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