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