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)
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:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
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.
25 #include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
33 # include <X11/Xlib.h>
34 # include <X11/extensions/Xinerama.h>
39 #endif // HAVE_STDLIB_H
43 #endif // HAVE_STRING_H
47 #endif // HAVE_CTYPE_H
50 # include <sys/types.h>
52 #endif // HAVE_UNISTD_H
56 #endif // HAVE_DIRENT_H
60 #endif // HAVE_LOCALE_H
62 #ifdef HAVE_SYS_STAT_H
63 # include <sys/stat.h>
64 #endif // HAVE_SYS_STAT_H
68 #endif // HAVE_STDARG_H
79 #include "blackbox.hh"
80 #include "Clientmenu.hh"
83 #include "Iconmenu.hh"
87 #include "Rootmenu.hh"
91 #include "Workspace.hh"
92 #include "Workspacemenu.hh"
96 #ifndef FONT_ELEMENT_SIZE
97 #define FONT_ELEMENT_SIZE 50
98 #endif // FONT_ELEMENT_SIZE
101 static bool running
= True
;
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
));
115 BScreen::BScreen(Blackbox
*bb
, unsigned int scrn
) : ScreenInfo(bb
, scrn
) {
117 screenstr
= "session.screen" + itostring(scrn
) + '.';
118 config
= blackbox
->getConfig();
119 xatom
= blackbox
->getXAtom();
121 event_mask
= ColormapChangeMask
| EnterWindowMask
| PropertyChangeMask
|
122 SubstructureRedirectMask
| ButtonPressMask
| ButtonReleaseMask
;
124 XErrorHandler old
= XSetErrorHandler((XErrorHandler
) anotherWMRunning
);
125 XSelectInput(getBaseDisplay()->getXDisplay(), getRootWindow(), event_mask
);
126 XSync(getBaseDisplay()->getXDisplay(), False
);
127 XSetErrorHandler((XErrorHandler
) old
);
130 if (! managed
) return;
132 fprintf(stderr
, i18n(ScreenSet
, ScreenManagingScreen
,
133 "BScreen::BScreen: managing screen %d "
134 "using visual 0x%lx, depth %d\n"),
135 getScreenNumber(), XVisualIDFromVisual(getVisual()),
140 resource
.mstyle
.t_font
= resource
.mstyle
.f_font
= resource
.tstyle
.font
=
141 resource
.wstyle
.font
= (BFont
*) 0;
145 xatom
->setSupported(this); // set-up netwm support
147 xatom
->setValue(getRootWindow(), XAtom::blackbox_pid
, XAtom::cardinal
,
148 (unsigned long) getpid());
149 #endif // HAVE_GETPID
150 unsigned long geometry
[] = { getWidth(),
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);
159 XDefineCursor(blackbox
->getXDisplay(), getRootWindow(),
160 blackbox
->getSessionCursor());
162 updateAvailableArea();
165 new BImageControl(blackbox
, this, True
, blackbox
->getColorsPerChannel(),
166 blackbox
->getCacheLife(), blackbox
->getCacheMax());
167 image_control
->installRootColormap();
168 root_colormap_installed
= True
;
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
);
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;
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
;
192 geom_window
= XCreateWindow(blackbox
->getXDisplay(), getRootWindow(),
193 0, 0, geom_w
, geom_h
, resource
.border_width
,
194 getDepth(), InputOutput
, getVisual(),
196 geom_visible
= False
;
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
);
205 XSetWindowBackground(blackbox
->getXDisplay(), geom_window
,
206 texture
->color().pixel());
208 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
209 geom_window
, geom_pixmap
);
211 workspacemenu
= new Workspacemenu(this);
212 iconmenu
= new Iconmenu(this);
213 configmenu
= new Configmenu(this);
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();
224 Workspace
*wkspc
= new Workspace(this, workspacesList
.size());
225 workspacesList
.push_back(wkspc
);
226 workspacemenu
->insertWorkspace(wkspc
);
227 workspacemenu
->update();
229 saveWorkspaceNames();
231 updateNetizenWorkspaceCount();
233 workspacemenu
->insert(i18n(IconSet
, IconIcons
, "Icons"), iconmenu
);
234 workspacemenu
->update();
236 current_workspace
= workspacesList
.front();
238 xatom
->setValue(getRootWindow(), XAtom::net_current_desktop
,
239 XAtom::cardinal
, 0); //first workspace
241 workspacemenu
->setItemSelected(2, True
);
243 toolbar
= new Toolbar(this);
245 slit
= new Slit(this);
249 raiseWindows(0, 0); // this also initializes the empty stacking list
252 updateClientList(); // initialize the client lists, which will be empty
253 updateAvailableArea();
255 changeWorkspaceID(0);
257 unsigned int i
, j
, nchild
;
258 Window r
, p
, *children
;
259 XQueryTree(blackbox
->getXDisplay(), getRootWindow(), &r
, &p
,
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;
266 XWMHints
*wmhints
= XGetWMHints(blackbox
->getXDisplay(),
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
) {
284 // manage shown windows
285 for (i
= 0; i
< nchild
; ++i
) {
286 if (children
[i
] == None
|| ! blackbox
->validateWindow(children
[i
]))
289 XWindowAttributes attrib
;
290 if (XGetWindowAttributes(blackbox
->getXDisplay(), children
[i
], &attrib
)) {
291 if (attrib
.override_redirect
) continue;
293 if (attrib
.map_state
!= IsUnmapped
) {
294 manageWindow(children
[i
]);
301 // call this again just in case a window we found updates the Strut list
302 updateAvailableArea();
306 BScreen::~BScreen(void) {
307 if (! managed
) return;
309 if (geom_pixmap
!= None
)
310 image_control
->removeImage(geom_pixmap
);
312 if (geom_window
!= None
)
313 XDestroyWindow(blackbox
->getXDisplay(), geom_window
);
315 std::for_each(workspacesList
.begin(), workspacesList
.end(),
318 std::for_each(iconList
.begin(), iconList
.end(), PointerAssassin());
320 std::for_each(netizenList
.begin(), netizenList
.end(), PointerAssassin());
322 while (! systrayWindowList
.empty())
323 removeSystrayWindow(systrayWindowList
[0]);
326 delete workspacemenu
;
331 delete image_control
;
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
;
343 if (resource
.wstyle
.close_button
.mask
!= None
)
344 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.close_button
.mask
);
345 if (resource
.wstyle
.max_button
.mask
!= None
)
346 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.max_button
.mask
);
347 if (resource
.wstyle
.icon_button
.mask
!= None
)
348 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.icon_button
.mask
);
349 if (resource
.wstyle
.stick_button
.mask
!= None
)
350 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.stick_button
.mask
);
352 if (resource
.tstyle
.left_button
.mask
!= None
)
353 XFreePixmap(blackbox
->getXDisplay(), resource
.tstyle
.left_button
.mask
);
354 if (resource
.tstyle
.right_button
.mask
!= None
)
355 XFreePixmap(blackbox
->getXDisplay(), resource
.tstyle
.right_button
.mask
);
357 if (resource
.mstyle
.bullet_image
.mask
!= None
)
358 XFreePixmap(blackbox
->getXDisplay(), resource
.mstyle
.bullet_image
.mask
);
359 if (resource
.mstyle
.tick_image
.mask
!= None
)
360 XFreePixmap(blackbox
->getXDisplay(), resource
.mstyle
.tick_image
.mask
);
362 resource
.wstyle
.max_button
.mask
= resource
.wstyle
.close_button
.mask
=
363 resource
.wstyle
.icon_button
.mask
=
364 resource
.wstyle
.stick_button
.mask
= None
;
365 resource
.tstyle
.left_button
.mask
= resource
.tstyle
.right_button
.mask
= None
;
366 resource
.mstyle
.bullet_image
.mask
= resource
.mstyle
.tick_image
.mask
= None
;
367 #endif // BITMAPBUTTONS
369 XFreeGC(blackbox
->getXDisplay(), opGC
);
373 void BScreen::saveSloppyFocus(bool s
) {
374 resource
.sloppy_focus
= s
;
377 if (resource
.sloppy_focus
) {
378 fmodel
= "SloppyFocus";
379 if (resource
.auto_raise
) fmodel
+= " AutoRaise";
380 if (resource
.click_raise
) fmodel
+= " ClickRaise";
382 fmodel
= "ClickToFocus";
384 config
->setValue(screenstr
+ "focusModel", fmodel
);
388 void BScreen::saveAutoRaise(bool a
) {
389 resource
.auto_raise
= a
;
390 saveSloppyFocus(resource
.sloppy_focus
);
394 void BScreen::saveClickRaise(bool c
) {
395 resource
.click_raise
= c
;
396 saveSloppyFocus(resource
.sloppy_focus
);
400 void BScreen::saveImageDither(bool d
) {
401 image_control
->setDither(d
);
402 config
->setValue(screenstr
+ "imageDither", doImageDither());
406 void BScreen::saveOpaqueMove(bool o
) {
407 resource
.opaque_move
= o
;
408 config
->setValue(screenstr
+ "opaqueMove", resource
.opaque_move
);
412 void BScreen::saveFullMax(bool f
) {
413 resource
.full_max
= f
;
414 config
->setValue(screenstr
+ "fullMaximization", resource
.full_max
);
418 void BScreen::saveFocusNew(bool f
) {
419 resource
.focus_new
= f
;
420 config
->setValue(screenstr
+ "focusNewWindows", resource
.focus_new
);
424 void BScreen::saveFocusLast(bool f
) {
425 resource
.focus_last
= f
;
426 config
->setValue(screenstr
+ "focusLastWindow", resource
.focus_last
);
430 void BScreen::saveAAFonts(bool f
) {
431 resource
.aa_fonts
= f
;
432 config
->setValue(screenstr
+ "antialiasFonts", resource
.aa_fonts
);
437 void BScreen::saveShadowFonts(bool f
) {
438 resource
.shadow_fonts
= f
;
439 config
->setValue(screenstr
+ "dropShadowFonts", resource
.shadow_fonts
);
444 void BScreen::saveHideToolbar(bool h
) {
445 resource
.hide_toolbar
= h
;
446 if (resource
.hide_toolbar
)
447 toolbar
->unmapToolbar();
449 toolbar
->mapToolbar();
450 config
->setValue(screenstr
+ "hideToolbar", resource
.hide_toolbar
);
454 void BScreen::saveWindowToEdgeSnap(int s
) {
455 resource
.snap_to_edges
= s
;
458 switch (resource
.snap_to_edges
) {
459 case WindowNoSnap
: snap
= "NoSnap"; break;
460 case WindowResistance
: snap
= "Resistance"; break;
461 case WindowSnap
: default: snap
= "Snap"; break;
463 config
->setValue(screenstr
+ "windowToEdgeSnap", snap
);
467 void BScreen::saveWindowToWindowSnap(int s
) {
468 resource
.snap_to_windows
= s
;
471 switch (resource
.snap_to_windows
) {
472 case WindowNoSnap
: snap
= "NoSnap"; break;
473 case WindowResistance
: snap
= "Resistance"; break;
474 case WindowSnap
: default: snap
= "Snap"; break;
476 config
->setValue(screenstr
+ "windowToWindowSnap", snap
);
480 void BScreen::saveResizeZones(unsigned int z
) {
481 resource
.resize_zones
= z
;
482 config
->setValue(screenstr
+ "resizeZones", resource
.resize_zones
);
486 void BScreen::saveWindowCornerSnap(bool s
) {
487 resource
.window_corner_snap
= s
;
488 config
->setValue(screenstr
+ "windowCornerSnap",
489 resource
.window_corner_snap
);
493 void BScreen::saveWorkspaces(unsigned int w
) {
494 resource
.workspaces
= w
;
495 config
->setValue(screenstr
+ "workspaces", resource
.workspaces
);
499 void BScreen::savePlacementPolicy(int p
) {
500 resource
.placement_policy
= p
;
501 const char *placement
;
502 switch (resource
.placement_policy
) {
503 case CascadePlacement
: placement
= "CascadePlacement"; break;
504 case UnderMousePlacement
: placement
= "UnderMousePlacement"; break;
505 case ClickMousePlacement
: placement
= "ClickMousePlacement"; break;
506 case ColSmartPlacement
: placement
= "ColSmartPlacement"; break;
507 case RowSmartPlacement
: default: placement
= "RowSmartPlacement"; break;
509 config
->setValue(screenstr
+ "windowPlacement", placement
);
513 void BScreen::saveResistanceSize(int s
) {
514 resource
.resistance_size
= s
;
515 config
->setValue(screenstr
+ "resistanceSize",
516 resource
.resistance_size
);
520 void BScreen::saveSnapThreshold(int t
) {
521 resource
.snap_threshold
= t
;
522 config
->setValue(screenstr
+ "edgeSnapThreshold",
523 resource
.snap_threshold
);
527 void BScreen::saveSnapOffset(int t
) {
528 resource
.snap_offset
= t
;
529 config
->setValue(screenstr
+ "edgeSnapOffset",
530 resource
.snap_offset
);
534 void BScreen::saveRowPlacementDirection(int d
) {
535 resource
.row_direction
= d
;
536 config
->setValue(screenstr
+ "rowPlacementDirection",
537 resource
.row_direction
== LeftRight
?
538 "LeftToRight" : "RightToLeft");
542 void BScreen::saveColPlacementDirection(int d
) {
543 resource
.col_direction
= d
;
544 config
->setValue(screenstr
+ "colPlacementDirection",
545 resource
.col_direction
== TopBottom
?
546 "TopToBottom" : "BottomToTop");
551 void BScreen::saveStrftimeFormat(const std::string
& format
) {
552 resource
.strftime_format
= format
;
553 config
->setValue(screenstr
+ "strftimeFormat", resource
.strftime_format
);
556 #else // !HAVE_STRFTIME
558 void BScreen::saveDateFormat(int f
) {
559 resource
.date_format
= f
;
560 config
->setValue(screenstr
+ "dateFormat",
561 resource
.date_format
== B_EuropeanDate
?
562 "European" : "American");
566 void BScreen::saveClock24Hour(bool c
) {
567 resource
.clock24hour
= c
;
568 config
->setValue(screenstr
+ "clockFormat", resource
.clock24hour
? 24 : 12);
570 #endif // HAVE_STRFTIME
573 void BScreen::saveWorkspaceNames() {
576 for (unsigned int i
= 0; i
< workspacesList
.size(); ++i
) {
577 names
+= workspacesList
[i
]->getName();
578 if (i
< workspacesList
.size() - 1)
582 config
->setValue(screenstr
+ "workspaceNames", names
);
586 void BScreen::savePlaceIgnoreShaded(bool i
) {
587 resource
.ignore_shaded
= i
;
588 config
->setValue(screenstr
+ "placementIgnoreShaded",
589 resource
.ignore_shaded
);
593 void BScreen::savePlaceIgnoreMaximized(bool i
) {
594 resource
.ignore_maximized
= i
;
595 config
->setValue(screenstr
+ "placementIgnoreMaximized",
596 resource
.ignore_maximized
);
600 void BScreen::saveAllowScrollLock(bool a
) {
601 resource
.allow_scroll_lock
= a
;
602 config
->setValue(screenstr
+ "disableBindingsWithScrollLock",
603 resource
.allow_scroll_lock
);
607 void BScreen::saveWorkspaceWarping(bool w
) {
608 resource
.workspace_warping
= w
;
609 config
->setValue(screenstr
+ "workspaceWarping",
610 resource
.workspace_warping
);
614 void BScreen::saveRootScrollDirection(int d
) {
615 resource
.root_scroll
= d
;
617 switch (resource
.root_scroll
) {
618 case NoScroll
: dir
= "None"; break;
619 case ReverseScroll
: dir
= "Reverse"; break;
620 case NormalScroll
: default: dir
= "Normal"; break;
622 config
->setValue(screenstr
+ "rootScrollDirection", dir
);
626 void BScreen::saveRootMenuButton(unsigned int b
) {
627 resource
.root_menu_button
= b
;
629 switch (resource
.root_menu_button
) {
630 case 0: but
= "None"; break;
631 case 1: but
= "Left"; break;
632 case 2: but
= "Middle"; break;
633 case 3: default: but
= "Right"; break;
635 config
->setValue(screenstr
+ "rootMenuButton", but
);
639 void BScreen::saveWorkspaceMenuButton(unsigned int b
) {
640 resource
.workspace_menu_button
= b
;
642 switch (resource
.workspace_menu_button
) {
643 case 0: but
= "None"; break;
644 case 1: but
= "Left"; break;
645 case 2: default: but
= "Middle"; break;
646 case 3: but
= "Right"; break;
648 config
->setValue(screenstr
+ "workspaceMenuButton", but
);
652 void BScreen::save_rc(void) {
653 saveSloppyFocus(resource
.sloppy_focus
);
654 saveAutoRaise(resource
.auto_raise
);
655 saveImageDither(doImageDither());
656 saveShadowFonts(resource
.shadow_fonts
);
657 saveAAFonts(resource
.aa_fonts
);
658 saveResizeZones(resource
.resize_zones
);
659 saveOpaqueMove(resource
.opaque_move
);
660 saveFullMax(resource
.full_max
);
661 saveFocusNew(resource
.focus_new
);
662 saveFocusLast(resource
.focus_last
);
663 saveHideToolbar(resource
.hide_toolbar
);
664 saveWindowToWindowSnap(resource
.snap_to_windows
);
665 saveWindowToEdgeSnap(resource
.snap_to_edges
);
666 saveWindowCornerSnap(resource
.window_corner_snap
);
667 saveWorkspaces(resource
.workspaces
);
668 savePlacementPolicy(resource
.placement_policy
);
669 saveSnapThreshold(resource
.snap_threshold
);
670 saveSnapOffset(resource
.snap_offset
);
671 saveResistanceSize(resource
.resistance_size
);
672 saveRowPlacementDirection(resource
.row_direction
);
673 saveColPlacementDirection(resource
.col_direction
);
675 saveStrftimeFormat(resource
.strftime_format
);
676 #else // !HAVE_STRFTIME
677 saveDateFormat(resource
.date_format
);
678 savwClock24Hour(resource
.clock24hour
);
679 #endif // HAVE_STRFTIME
680 savePlaceIgnoreShaded(resource
.ignore_shaded
);
681 savePlaceIgnoreMaximized(resource
.ignore_maximized
);
682 saveAllowScrollLock(resource
.allow_scroll_lock
);
683 saveWorkspaceWarping(resource
.workspace_warping
);
684 saveRootScrollDirection(resource
.root_scroll
);
685 saveRootMenuButton(resource
.root_menu_button
);
686 saveWorkspaceMenuButton(resource
.workspace_menu_button
);
693 void BScreen::load_rc(void) {
697 if (! config
->getValue(screenstr
+ "fullMaximization", resource
.full_max
))
698 resource
.full_max
= false;
700 if (! config
->getValue(screenstr
+ "focusNewWindows", resource
.focus_new
))
701 resource
.focus_new
= false;
703 if (! config
->getValue(screenstr
+ "focusLastWindow", resource
.focus_last
))
704 resource
.focus_last
= false;
706 if (! config
->getValue(screenstr
+ "workspaces", resource
.workspaces
))
707 resource
.workspaces
= 1;
709 if (! config
->getValue(screenstr
+ "opaqueMove", resource
.opaque_move
))
710 resource
.opaque_move
= false;
712 if (! config
->getValue(screenstr
+ "antialiasFonts", resource
.aa_fonts
))
713 resource
.aa_fonts
= true;
715 if (! resource
.aa_fonts
||
716 ! config
->getValue(screenstr
+ "dropShadowFonts", resource
.shadow_fonts
))
717 resource
.shadow_fonts
= false;
719 if (! config
->getValue(screenstr
+ "resizeZones", resource
.resize_zones
) ||
720 (resource
.resize_zones
!= 1 && resource
.resize_zones
!= 2 &&
721 resource
.resize_zones
!= 4))
722 resource
.resize_zones
= 4;
724 if (! config
->getValue(screenstr
+ "hideToolbar", resource
.hide_toolbar
))
725 resource
.hide_toolbar
= false;
727 resource
.snap_to_windows
= WindowResistance
;
728 if (config
->getValue(screenstr
+ "windowToWindowSnap", s
)) {
730 resource
.snap_to_windows
= WindowNoSnap
;
731 else if (s
== "Snap")
732 resource
.snap_to_windows
= WindowSnap
;
735 resource
.snap_to_edges
= WindowResistance
;
736 if (config
->getValue(screenstr
+ "windowToEdgeSnap", s
)) {
738 resource
.snap_to_edges
= WindowNoSnap
;
739 else if (s
== "Snap")
740 resource
.snap_to_edges
= WindowSnap
;
743 if (! config
->getValue(screenstr
+ "windowCornerSnap",
744 resource
.window_corner_snap
))
745 resource
.window_corner_snap
= true;
747 if (! config
->getValue(screenstr
+ "imageDither", b
))
749 image_control
->setDither(b
);
751 if (! config
->getValue(screenstr
+ "edgeSnapOffset",
752 resource
.snap_offset
))
753 resource
.snap_offset
= 0;
754 if (resource
.snap_offset
> 50) // sanity check, setting this huge would
755 resource
.snap_offset
= 50; // seriously suck.
757 if (! config
->getValue(screenstr
+ "edgeSnapThreshold",
758 resource
.snap_threshold
))
759 resource
.snap_threshold
= 4;
761 if (! config
->getValue(screenstr
+ "resistanceSize",
762 resource
.resistance_size
))
763 resource
.resistance_size
= 18;
765 if (config
->getValue(screenstr
+ "rowPlacementDirection", s
) &&
767 resource
.row_direction
= RightLeft
;
769 resource
.row_direction
= LeftRight
;
771 if (config
->getValue(screenstr
+ "colPlacementDirection", s
) &&
773 resource
.col_direction
= BottomTop
;
775 resource
.col_direction
= TopBottom
;
777 if (config
->getValue(screenstr
+ "workspaceNames", s
)) {
778 XAtom::StringVect workspaceNames
;
780 string::const_iterator it
= s
.begin(), end
= s
.end();
782 string::const_iterator tmp
= it
; // current string.begin()
783 it
= std::find(tmp
, end
, ','); // look for comma between tmp and end
784 workspaceNames
.push_back(string(tmp
, it
)); // s[tmp:it]
790 xatom
->setValue(getRootWindow(), XAtom::net_desktop_names
, XAtom::utf8
,
794 resource
.sloppy_focus
= true;
795 resource
.auto_raise
= false;
796 resource
.click_raise
= false;
797 if (config
->getValue(screenstr
+ "focusModel", s
)) {
798 if (s
.find("ClickToFocus") != string::npos
) {
799 resource
.sloppy_focus
= false;
802 if (s
.find("AutoRaise") != string::npos
)
803 resource
.auto_raise
= true;
804 if (s
.find("ClickRaise") != string::npos
)
805 resource
.click_raise
= true;
809 if (config
->getValue(screenstr
+ "windowPlacement", s
)) {
810 if (s
== "CascadePlacement")
811 resource
.placement_policy
= CascadePlacement
;
812 else if (s
== "UnderMousePlacement")
813 resource
.placement_policy
= UnderMousePlacement
;
814 else if (s
== "ClickMousePlacement")
815 resource
.placement_policy
= ClickMousePlacement
;
816 else if (s
== "ColSmartPlacement")
817 resource
.placement_policy
= ColSmartPlacement
;
818 else //if (s == "RowSmartPlacement")
819 resource
.placement_policy
= RowSmartPlacement
;
821 resource
.placement_policy
= RowSmartPlacement
;
824 if (! config
->getValue(screenstr
+ "strftimeFormat",
825 resource
.strftime_format
))
826 resource
.strftime_format
= "%I:%M %p";
827 #else // !HAVE_STRFTIME
830 if (config
->getValue(screenstr
+ "dateFormat", s
) && s
== "European")
831 resource
.date_format
= B_EuropeanDate
;
833 resource
.date_format
= B_AmericanDate
;
835 if (! config
->getValue(screenstr
+ "clockFormat", l
))
837 resource
.clock24hour
= l
== 24;
838 #endif // HAVE_STRFTIME
840 if (! config
->getValue(screenstr
+ "placementIgnoreShaded",
841 resource
.ignore_shaded
))
842 resource
.ignore_shaded
= true;
844 if (! config
->getValue(screenstr
+ "placementIgnoreMaximized",
845 resource
.ignore_maximized
))
846 resource
.ignore_maximized
= true;
848 if (! config
->getValue(screenstr
+ "disableBindingsWithScrollLock",
849 resource
.allow_scroll_lock
))
850 resource
.allow_scroll_lock
= false;
852 if (! config
->getValue(screenstr
+ "workspaceWarping",
853 resource
.workspace_warping
))
854 resource
.workspace_warping
= false;
856 resource
.root_scroll
= NormalScroll
;
857 if (config
->getValue(screenstr
+ "rootScrollDirection", s
)) {
859 resource
.root_scroll
= NoScroll
;
860 else if (s
== "Reverse")
861 resource
.root_scroll
= ReverseScroll
;
864 resource
.root_menu_button
= 3;
865 if (config
->getValue(screenstr
+ "rootMenuButton", s
)) {
867 resource
.root_menu_button
= 0;
868 else if (s
== "Left")
869 resource
.root_menu_button
= 1;
870 else if (s
== "Middle")
871 resource
.root_menu_button
= 2;
874 resource
.workspace_menu_button
= 2;
875 if (config
->getValue(screenstr
+ "workspaceMenuButton", s
)) {
877 resource
.workspace_menu_button
= 0;
878 else if (s
== "Left")
879 resource
.workspace_menu_button
= 1;
880 else if (s
== "Right")
881 resource
.workspace_menu_button
= 3;
883 // cant both be the same
884 if (resource
.workspace_menu_button
== resource
.root_menu_button
)
885 resource
.workspace_menu_button
= 0;
889 void BScreen::changeWorkspaceCount(unsigned int new_count
) {
890 assert(new_count
> 0);
892 if (new_count
< workspacesList
.size()) {
894 for (unsigned int i
= workspacesList
.size(); i
> new_count
; --i
)
895 removeLastWorkspace();
896 // removeLast already sets the current workspace to the
897 // last available one.
898 } else if (new_count
> workspacesList
.size()) {
900 for(unsigned int i
= workspacesList
.size(); i
< new_count
; ++i
)
906 void BScreen::reconfigure(void) {
907 // don't reconfigure while saving the initial rc file, it's a waste and it
908 // breaks somethings (workspace names)
909 if (blackbox
->isStartup()) return;
916 // we need to do this explicitly, because just loading this value from the rc
918 changeWorkspaceCount(resource
.workspaces
);
921 gcv
.foreground
= WhitePixel(blackbox
->getXDisplay(),
923 gcv
.function
= GXinvert
;
924 gcv
.subwindow_mode
= IncludeInferiors
;
925 XChangeGC(blackbox
->getXDisplay(), opGC
,
926 GCForeground
| GCFunction
| GCSubwindowMode
, &gcv
);
928 const char *s
= i18n(ScreenSet
, ScreenPositionLength
,
929 "0: 0000 x 0: 0000");
931 geom_w
= resource
.wstyle
.font
->measureString(s
) + resource
.bevel_width
* 2;
932 geom_h
= resource
.wstyle
.font
->height() + resource
.bevel_width
* 2;
934 BTexture
* texture
= &(resource
.wstyle
.l_focus
);
935 geom_pixmap
= texture
->render(geom_w
, geom_h
, geom_pixmap
);
936 if (geom_pixmap
== ParentRelative
) {
937 texture
= &(resource
.wstyle
.t_focus
);
938 geom_pixmap
= texture
->render(geom_w
, geom_h
, geom_pixmap
);
941 XSetWindowBackground(blackbox
->getXDisplay(), geom_window
,
942 texture
->color().pixel());
944 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
945 geom_window
, geom_pixmap
);
947 XSetWindowBorderWidth(blackbox
->getXDisplay(), geom_window
,
948 resource
.border_width
);
949 XSetWindowBorder(blackbox
->getXDisplay(), geom_window
,
950 resource
.border_color
.pixel());
952 workspacemenu
->reconfigure();
953 iconmenu
->reconfigure();
955 typedef std::vector
<int> SubList
;
956 SubList remember_subs
;
958 // save the current open menus
959 Basemenu
*menu
= rootmenu
;
961 while ((submenu
= menu
->getCurrentSubmenu()) >= 0) {
962 remember_subs
.push_back(submenu
);
963 menu
= menu
->find(submenu
)->submenu();
969 rootmenu
->reconfigure();
971 // reopen the saved menus
973 const SubList::iterator subs_end
= remember_subs
.end();
974 for (SubList::iterator it
= remember_subs
.begin(); it
!= subs_end
; ++it
) {
975 menu
->drawSubmenu(*it
);
976 menu
= menu
->find(*it
)->submenu();
981 configmenu
->reconfigure();
983 toolbar
->reconfigure();
987 std::for_each(workspacesList
.begin(), workspacesList
.end(),
988 std::mem_fun(&Workspace::reconfigure
));
990 BlackboxWindowList::iterator iit
= iconList
.begin();
991 for (; iit
!= iconList
.end(); ++iit
) {
992 BlackboxWindow
*bw
= *iit
;
993 if (bw
->validateClient())
997 image_control
->timeout();
1001 void BScreen::rereadMenu(void) {
1005 rootmenu
->reconfigure();
1009 void BScreen::LoadStyle(void) {
1010 Configuration
style(False
);
1012 const char *sfile
= blackbox
->getStyleFilename();
1013 if (sfile
!= NULL
) {
1014 style
.setFile(sfile
);
1015 if (! style
.load()) {
1016 style
.setFile(DEFAULTSTYLE
);
1018 style
.create(); // hardcoded default values will be used.
1022 // merge in the rc file
1023 style
.merge(config
->file(), True
);
1027 // load fonts/fontsets
1028 if (resource
.wstyle
.font
)
1029 delete resource
.wstyle
.font
;
1030 if (resource
.tstyle
.font
)
1031 delete resource
.tstyle
.font
;
1032 if (resource
.mstyle
.f_font
)
1033 delete resource
.mstyle
.f_font
;
1034 if (resource
.mstyle
.t_font
)
1035 delete resource
.mstyle
.t_font
;
1036 resource
.wstyle
.font
= resource
.tstyle
.font
= resource
.mstyle
.f_font
=
1037 resource
.mstyle
.t_font
= (BFont
*) 0;
1039 resource
.wstyle
.font
= readDatabaseFont("window.", style
);
1040 resource
.tstyle
.font
= readDatabaseFont("toolbar.", style
);
1041 resource
.mstyle
.t_font
= readDatabaseFont("menu.title.", style
);
1042 resource
.mstyle
.f_font
= readDatabaseFont("menu.frame.", style
);
1044 // load window config
1045 resource
.wstyle
.t_focus
=
1046 readDatabaseTexture("window.title.focus", "white", style
);
1047 resource
.wstyle
.t_unfocus
=
1048 readDatabaseTexture("window.title.unfocus", "black", style
);
1049 resource
.wstyle
.l_focus
=
1050 readDatabaseTexture("window.label.focus", "white", style
);
1051 resource
.wstyle
.l_unfocus
=
1052 readDatabaseTexture("window.label.unfocus", "black", style
);
1053 resource
.wstyle
.h_focus
=
1054 readDatabaseTexture("window.handle.focus", "white", style
);
1055 resource
.wstyle
.h_unfocus
=
1056 readDatabaseTexture("window.handle.unfocus", "black", style
);
1057 resource
.wstyle
.g_focus
=
1058 readDatabaseTexture("window.grip.focus", "white", style
);
1059 resource
.wstyle
.g_unfocus
=
1060 readDatabaseTexture("window.grip.unfocus", "black", style
);
1061 resource
.wstyle
.b_focus
=
1062 readDatabaseTexture("window.button.focus", "white", style
);
1063 resource
.wstyle
.b_unfocus
=
1064 readDatabaseTexture("window.button.unfocus", "black", style
);
1065 resource
.wstyle
.b_pressed
=
1066 readDatabaseTexture("window.button.pressed", "black", style
);
1068 #ifdef BITMAPBUTTONS
1069 if (resource
.wstyle
.close_button
.mask
!= None
)
1070 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.close_button
.mask
);
1071 if (resource
.wstyle
.max_button
.mask
!= None
)
1072 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.max_button
.mask
);
1073 if (resource
.wstyle
.icon_button
.mask
!= None
)
1074 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.icon_button
.mask
);
1075 if (resource
.wstyle
.stick_button
.mask
!= None
)
1076 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.stick_button
.mask
);
1078 resource
.wstyle
.close_button
.mask
= resource
.wstyle
.max_button
.mask
=
1079 resource
.wstyle
.icon_button
.mask
=
1080 resource
.wstyle
.icon_button
.mask
= None
;
1082 readDatabaseMask("window.button.close.mask", resource
.wstyle
.close_button
,
1084 readDatabaseMask("window.button.max.mask", resource
.wstyle
.max_button
,
1086 readDatabaseMask("window.button.icon.mask", resource
.wstyle
.icon_button
,
1088 readDatabaseMask("window.button.stick.mask", resource
.wstyle
.stick_button
,
1090 #endif // BITMAPBUTTONS
1092 // we create the window.frame texture by hand because it exists only to
1093 // make the code cleaner and is not actually used for display
1094 BColor color
= readDatabaseColor("window.frame.focusColor", "white", style
);
1095 resource
.wstyle
.f_focus
= BTexture("solid flat", getBaseDisplay(),
1096 getScreenNumber(), image_control
);
1097 resource
.wstyle
.f_focus
.setColor(color
);
1099 color
= readDatabaseColor("window.frame.unfocusColor", "white", style
);
1100 resource
.wstyle
.f_unfocus
= BTexture("solid flat", getBaseDisplay(),
1101 getScreenNumber(), image_control
);
1102 resource
.wstyle
.f_unfocus
.setColor(color
);
1104 resource
.wstyle
.l_text_focus
=
1105 readDatabaseColor("window.label.focus.textColor", "black", style
);
1106 resource
.wstyle
.l_text_unfocus
=
1107 readDatabaseColor("window.label.unfocus.textColor", "white", style
);
1108 resource
.wstyle
.b_pic_focus
=
1109 readDatabaseColor("window.button.focus.picColor", "black", style
);
1110 resource
.wstyle
.b_pic_unfocus
=
1111 readDatabaseColor("window.button.unfocus.picColor", "white", style
);
1113 resource
.wstyle
.justify
= LeftJustify
;
1114 if (style
.getValue("window.justify", s
)) {
1115 if (s
== "right" || s
== "Right")
1116 resource
.wstyle
.justify
= RightJustify
;
1117 else if (s
== "center" || s
== "Center")
1118 resource
.wstyle
.justify
= CenterJustify
;
1122 if (resource
.wstyle
.t_focus
.texture() == BTexture::Parent_Relative
)
1123 resource
.wstyle
.t_focus
= resource
.wstyle
.f_focus
;
1124 if (resource
.wstyle
.t_unfocus
.texture() == BTexture::Parent_Relative
)
1125 resource
.wstyle
.t_unfocus
= resource
.wstyle
.f_unfocus
;
1126 if (resource
.wstyle
.h_focus
.texture() == BTexture::Parent_Relative
)
1127 resource
.wstyle
.h_focus
= resource
.wstyle
.f_focus
;
1128 if (resource
.wstyle
.h_unfocus
.texture() == BTexture::Parent_Relative
)
1129 resource
.wstyle
.h_unfocus
= resource
.wstyle
.f_unfocus
;
1131 // load toolbar config
1132 #ifdef BITMAPBUTTONS
1133 if (resource
.tstyle
.left_button
.mask
!= None
)
1134 XFreePixmap(blackbox
->getXDisplay(), resource
.tstyle
.left_button
.mask
);
1135 if (resource
.tstyle
.right_button
.mask
!= None
)
1136 XFreePixmap(blackbox
->getXDisplay(), resource
.tstyle
.right_button
.mask
);
1137 #endif // BITMAPBUTTONS
1139 resource
.tstyle
.toolbar
=
1140 readDatabaseTexture("toolbar", "black", style
);
1141 resource
.tstyle
.label
=
1142 readDatabaseTexture("toolbar.label", "black", style
);
1143 resource
.tstyle
.window
=
1144 readDatabaseTexture("toolbar.windowLabel", "black", style
);
1145 resource
.tstyle
.button
=
1146 readDatabaseTexture("toolbar.button", "white", style
);
1147 resource
.tstyle
.pressed
=
1148 readDatabaseTexture("toolbar.button.pressed", "black", style
);
1149 resource
.tstyle
.clock
=
1150 readDatabaseTexture("toolbar.clock", "black", style
);
1151 resource
.tstyle
.l_text
=
1152 readDatabaseColor("toolbar.label.textColor", "white", style
);
1153 resource
.tstyle
.w_text
=
1154 readDatabaseColor("toolbar.windowLabel.textColor", "white", style
);
1155 resource
.tstyle
.c_text
=
1156 readDatabaseColor("toolbar.clock.textColor", "white", style
);
1157 resource
.tstyle
.b_pic
=
1158 readDatabaseColor("toolbar.button.picColor", "black", style
);
1160 #ifdef BITMAPBUTTONS
1161 readDatabaseMask("toolbar.button.left.mask", resource
.tstyle
.left_button
,
1163 readDatabaseMask("toolbar.button.right.mask", resource
.tstyle
.right_button
,
1165 #endif // BITMAPBUTTONS
1167 resource
.tstyle
.justify
= LeftJustify
;
1168 if (style
.getValue("toolbar.justify", s
)) {
1169 if (s
== "right" || s
== "Right")
1170 resource
.tstyle
.justify
= RightJustify
;
1171 else if (s
== "center" || s
== "Center")
1172 resource
.tstyle
.justify
= CenterJustify
;
1176 if (resource
.tstyle
.toolbar
.texture() == BTexture::Parent_Relative
) {
1177 resource
.tstyle
.toolbar
= BTexture("solid flat", getBaseDisplay(),
1178 getScreenNumber(), image_control
);
1179 resource
.tstyle
.toolbar
.setColor(BColor("black", getBaseDisplay(),
1180 getScreenNumber()));
1184 #ifdef BITMAPBUTTONS
1185 if (resource
.mstyle
.bullet_image
.mask
!= None
)
1186 XFreePixmap(blackbox
->getXDisplay(), resource
.mstyle
.bullet_image
.mask
);
1187 if (resource
.mstyle
.tick_image
.mask
!= None
)
1188 XFreePixmap(blackbox
->getXDisplay(), resource
.mstyle
.tick_image
.mask
);
1189 #endif // BITMAPBUTTONS
1191 resource
.mstyle
.title
=
1192 readDatabaseTexture("menu.title", "white", style
);
1193 resource
.mstyle
.frame
=
1194 readDatabaseTexture("menu.frame", "black", style
);
1195 resource
.mstyle
.hilite
=
1196 readDatabaseTexture("menu.hilite", "white", style
);
1197 resource
.mstyle
.t_text
=
1198 readDatabaseColor("menu.title.textColor", "black", style
);
1199 resource
.mstyle
.f_text
=
1200 readDatabaseColor("menu.frame.textColor", "white", style
);
1201 resource
.mstyle
.d_text
=
1202 readDatabaseColor("menu.frame.disableColor", "black", style
);
1203 resource
.mstyle
.h_text
=
1204 readDatabaseColor("menu.hilite.textColor", "black", style
);
1206 #ifdef BITMAPBUTTONS
1207 readDatabaseMask("menu.arrow.mask", resource
.mstyle
.bullet_image
, style
);
1208 readDatabaseMask("menu.selected.mask", resource
.mstyle
.tick_image
, style
);
1209 #endif // BITMAPBUTTONS
1211 resource
.mstyle
.t_justify
= LeftJustify
;
1212 if (style
.getValue("menu.title.justify", s
)) {
1213 if (s
== "right" || s
== "Right")
1214 resource
.mstyle
.t_justify
= RightJustify
;
1215 else if (s
== "center" || s
== "Center")
1216 resource
.mstyle
.t_justify
= CenterJustify
;
1219 resource
.mstyle
.f_justify
= LeftJustify
;
1220 if (style
.getValue("menu.frame.justify", s
)) {
1221 if (s
== "right" || s
== "Right")
1222 resource
.mstyle
.f_justify
= RightJustify
;
1223 else if (s
== "center" || s
== "Center")
1224 resource
.mstyle
.f_justify
= CenterJustify
;
1227 resource
.mstyle
.bullet
= Basemenu::Triangle
;
1228 if (style
.getValue("menu.bullet", s
)) {
1229 if (s
== "empty" || s
== "Empty")
1230 resource
.mstyle
.bullet
= Basemenu::Empty
;
1231 else if (s
== "square" || s
== "Square")
1232 resource
.mstyle
.bullet
= Basemenu::Square
;
1233 else if (s
== "diamond" || s
== "Diamond")
1234 resource
.mstyle
.bullet
= Basemenu::Diamond
;
1237 resource
.mstyle
.bullet_pos
= Basemenu::Left
;
1238 if (style
.getValue("menu.bullet.position", s
)) {
1239 if (s
== "right" || s
== "Right")
1240 resource
.mstyle
.bullet_pos
= Basemenu::Right
;
1244 if (resource
.mstyle
.frame
.texture() == BTexture::Parent_Relative
) {
1245 resource
.mstyle
.frame
= BTexture("solid flat", getBaseDisplay(),
1246 getScreenNumber(), image_control
);
1247 resource
.mstyle
.frame
.setColor(BColor("black", getBaseDisplay(),
1248 getScreenNumber()));
1251 resource
.border_color
=
1252 readDatabaseColor("borderColor", "black", style
);
1254 // load bevel, border and handle widths
1255 if (! style
.getValue("handleWidth", resource
.handle_width
) ||
1256 resource
.handle_width
> (getWidth() / 2) || resource
.handle_width
== 0)
1257 resource
.handle_width
= 6;
1259 if (! style
.getValue("borderWidth", resource
.border_width
))
1260 resource
.border_width
= 1;
1262 if (! style
.getValue("bevelWidth", resource
.bevel_width
) ||
1263 resource
.bevel_width
> (getWidth() / 2) || resource
.bevel_width
== 0)
1264 resource
.bevel_width
= 3;
1266 if (! style
.getValue("frameWidth", resource
.frame_width
) ||
1267 resource
.frame_width
> (getWidth() / 2))
1268 resource
.frame_width
= resource
.bevel_width
;
1270 if (style
.getValue("rootCommand", s
))
1271 bexec(s
, displayString());
1275 void BScreen::addIcon(BlackboxWindow
*w
) {
1278 w
->setWorkspace(BSENTINEL
);
1279 w
->setWindowNumber(iconList
.size());
1281 iconList
.push_back(w
);
1283 const char* title
= w
->getIconTitle();
1284 iconmenu
->insert(title
);
1289 void BScreen::removeIcon(BlackboxWindow
*w
) {
1294 iconmenu
->remove(w
->getWindowNumber());
1297 BlackboxWindowList::iterator it
= iconList
.begin(),
1298 end
= iconList
.end();
1299 for (int i
= 0; it
!= end
; ++it
)
1300 (*it
)->setWindowNumber(i
++);
1304 BlackboxWindow
*BScreen::getIcon(unsigned int index
) {
1305 if (index
< iconList
.size()) {
1306 BlackboxWindowList::iterator it
= iconList
.begin();
1307 while (index
-- > 0) // increment to index
1312 return (BlackboxWindow
*) 0;
1316 unsigned int BScreen::addWorkspace(void) {
1317 Workspace
*wkspc
= new Workspace(this, workspacesList
.size());
1318 workspacesList
.push_back(wkspc
);
1319 saveWorkspaces(getWorkspaceCount());
1320 saveWorkspaceNames();
1322 workspacemenu
->insertWorkspace(wkspc
);
1323 workspacemenu
->update();
1325 toolbar
->reconfigure();
1327 updateNetizenWorkspaceCount();
1329 return workspacesList
.size();
1333 unsigned int BScreen::removeLastWorkspace(void) {
1334 if (workspacesList
.size() == 1)
1337 Workspace
*wkspc
= workspacesList
.back();
1339 if (current_workspace
->getID() == wkspc
->getID())
1340 changeWorkspaceID(current_workspace
->getID() - 1);
1344 workspacemenu
->removeWorkspace(wkspc
);
1345 workspacemenu
->update();
1347 workspacesList
.pop_back();
1350 saveWorkspaces(getWorkspaceCount());
1351 saveWorkspaceNames();
1353 toolbar
->reconfigure();
1355 updateNetizenWorkspaceCount();
1357 return workspacesList
.size();
1361 void BScreen::changeWorkspaceID(unsigned int id
) {
1362 if (! current_workspace
|| id
== current_workspace
->getID()) return;
1364 BlackboxWindow
*focused
= blackbox
->getFocusedWindow();
1365 if (focused
&& focused
->getScreen() == this) {
1366 assert(focused
->isStuck() ||
1367 focused
->getWorkspaceNumber() == current_workspace
->getID());
1369 current_workspace
->setLastFocusedWindow(focused
);
1371 // if no window had focus, no need to store a last focus
1372 current_workspace
->setLastFocusedWindow((BlackboxWindow
*) 0);
1375 // when we switch workspaces, unfocus whatever was focused if it is going
1377 if (focused
&& ! focused
->isStuck())
1378 blackbox
->setFocusedWindow((BlackboxWindow
*) 0);
1380 current_workspace
->hideAll();
1381 workspacemenu
->setItemSelected(current_workspace
->getID() + 2, False
);
1383 current_workspace
= getWorkspace(id
);
1385 xatom
->setValue(getRootWindow(), XAtom::net_current_desktop
,
1386 XAtom::cardinal
, id
);
1388 workspacemenu
->setItemSelected(current_workspace
->getID() + 2, True
);
1389 toolbar
->redrawWorkspaceLabel(True
);
1391 current_workspace
->showAll();
1396 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
1399 XSync(blackbox
->getXDisplay(), False
);
1401 // If sloppy focus and we can find the client window under the pointer,
1403 if (resource
.sloppy_focus
&&
1404 XQueryPointer(blackbox
->getXDisplay(), getRootWindow(), &r
, &c
,
1405 &rx
, &ry
, &x
, &y
, &m
) &&
1407 if ( (win
= blackbox
->searchWindow(c
)) )
1408 f
= win
->setInputFocus();
1411 // If that fails, and we're doing focus_last, try to focus the last window.
1412 if (! f
&& resource
.focus_last
&&
1413 (win
= current_workspace
->getLastFocusedWindow()))
1414 f
= win
->setInputFocus();
1417 if we found a focus target, then we set the focused window explicitly
1418 because it is possible to switch off this workspace before the x server
1419 generates the FocusIn event for the window. if that happens, openbox would
1420 lose track of what window was the 'LastFocused' window on the workspace.
1422 if we did not find a focus target, then set the current focused window to
1426 blackbox
->setFocusedWindow(win
);
1428 blackbox
->setFocusedWindow((BlackboxWindow
*) 0);
1430 updateNetizenCurrentWorkspace();
1435 * Set the _NET_CLIENT_LIST root window property.
1437 void BScreen::updateClientList(void) {
1438 if (windowList
.size() > 0) {
1439 Window
*windows
= new Window
[windowList
.size()];
1440 Window
*win_it
= windows
;
1441 BlackboxWindowList::iterator it
= windowList
.begin();
1442 const BlackboxWindowList::iterator end
= windowList
.end();
1443 for (; it
!= end
; ++it
, ++win_it
)
1444 *win_it
= (*it
)->getClientWindow();
1445 xatom
->setValue(getRootWindow(), XAtom::net_client_list
, XAtom::window
,
1446 windows
, windowList
.size());
1449 xatom
->setValue(getRootWindow(), XAtom::net_client_list
, XAtom::window
,
1452 updateStackingList();
1457 * Set the _NET_CLIENT_LIST_STACKING root window property.
1459 void BScreen::updateStackingList(void) {
1461 BlackboxWindowList stack_order
;
1464 * Get the stacking order from all of the workspaces.
1465 * We start with the current workspace so that the sticky windows will be
1466 * in the right order on the current workspace.
1467 * XXX: Do we need to have sticky windows in the list once for each workspace?
1469 getCurrentWorkspace()->appendStackOrder(stack_order
);
1470 for (unsigned int i
= 0; i
< getWorkspaceCount(); ++i
)
1471 if (i
!= getCurrentWorkspaceID())
1472 getWorkspace(i
)->appendStackOrder(stack_order
);
1474 if (stack_order
.size() > 0) {
1475 // set the client list atoms
1476 Window
*windows
= new Window
[stack_order
.size()];
1477 Window
*win_it
= windows
;
1478 BlackboxWindowList::iterator it
= stack_order
.begin(),
1479 end
= stack_order
.end();
1480 for (; it
!= end
; ++it
, ++win_it
)
1481 *win_it
= (*it
)->getClientWindow();
1482 xatom
->setValue(getRootWindow(), XAtom::net_client_list_stacking
,
1483 XAtom::window
, windows
, stack_order
.size());
1486 xatom
->setValue(getRootWindow(), XAtom::net_client_list_stacking
,
1487 XAtom::window
, 0, 0);
1491 void BScreen::addSystrayWindow(Window window
) {
1492 XGrabServer(blackbox
->getXDisplay());
1494 XSelectInput(blackbox
->getXDisplay(), window
, StructureNotifyMask
);
1495 systrayWindowList
.push_back(window
);
1496 xatom
->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows
,
1498 &systrayWindowList
[0], systrayWindowList
.size());
1499 blackbox
->saveSystrayWindowSearch(window
, this);
1501 XUngrabServer(blackbox
->getXDisplay());
1505 void BScreen::removeSystrayWindow(Window window
) {
1506 XGrabServer(blackbox
->getXDisplay());
1508 WindowList::iterator it
= systrayWindowList
.begin();
1509 const WindowList::iterator end
= systrayWindowList
.end();
1510 for (; it
!= end
; ++it
)
1511 if (*it
== window
) {
1512 systrayWindowList
.erase(it
);
1513 xatom
->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows
,
1515 &systrayWindowList
[0], systrayWindowList
.size());
1516 blackbox
->removeSystrayWindowSearch(window
);
1517 XSelectInput(blackbox
->getXDisplay(), window
, NoEventMask
);
1521 assert(it
!= end
); // not a systray window
1523 XUngrabServer(blackbox
->getXDisplay());
1527 void BScreen::manageWindow(Window w
) {
1528 // is the window a KDE systray window?
1530 if (xatom
->getValue(w
, XAtom::kde_net_wm_system_tray_window_for
,
1531 XAtom::window
, systray
) && systray
!= None
) {
1532 addSystrayWindow(w
);
1536 // is the window a docking app
1537 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), w
);
1538 if (wmhint
&& (wmhint
->flags
& StateHint
) &&
1539 wmhint
->initial_state
== WithdrawnState
) {
1544 new BlackboxWindow(blackbox
, w
, this);
1546 BlackboxWindow
*win
= blackbox
->searchWindow(w
);
1550 if (win
->isDesktop()) {
1551 desktopWindowList
.push_back(win
->getFrameWindow());
1552 } else { // if (win->isNormal()) {
1553 // don't list desktop windows as managed windows
1554 windowList
.push_back(win
);
1557 if (win
->isTopmost())
1558 specialWindowList
.push_back(win
->getFrameWindow());
1561 XMapRequestEvent mre
;
1563 if (blackbox
->isStartup() && win
->isNormal()) win
->restoreAttributes();
1564 win
->mapRequestEvent(&mre
);
1568 void BScreen::unmanageWindow(BlackboxWindow
*w
, bool remap
) {
1569 // is the window a KDE systray window?
1571 if (xatom
->getValue(w
->getClientWindow(),
1572 XAtom::kde_net_wm_system_tray_window_for
,
1573 XAtom::window
, systray
) && systray
!= None
) {
1574 removeSystrayWindow(w
->getClientWindow());
1580 // Remove the modality so that its parent won't try to re-focus the window
1581 if (w
->isModal()) w
->setModal(False
);
1583 if (w
->getWorkspaceNumber() != BSENTINEL
&&
1584 w
->getWindowNumber() != BSENTINEL
) {
1585 getWorkspace(w
->getWorkspaceNumber())->removeWindow(w
);
1587 for (unsigned int i
= 0; i
< getNumberOfWorkspaces(); ++i
)
1588 if (i
!= w
->getWorkspaceNumber())
1589 getWorkspace(i
)->removeWindow(w
, True
);
1591 } else if (w
->isIconic())
1594 if (w
->isDesktop()) {
1595 WindowList::iterator it
= desktopWindowList
.begin();
1596 const WindowList::iterator end
= desktopWindowList
.end();
1597 for (; it
!= end
; ++it
)
1598 if (*it
== w
->getFrameWindow()) {
1599 desktopWindowList
.erase(it
);
1602 assert(it
!= end
); // the window wasnt a desktop window?
1603 } else { // if (w->isNormal()) {
1604 // we don't list desktop windows as managed windows
1605 windowList
.remove(w
);
1608 if (w
->isTopmost()) {
1609 WindowList::iterator it
= specialWindowList
.begin();
1610 const WindowList::iterator end
= specialWindowList
.end();
1611 for (; it
!= end
; ++it
)
1612 if (*it
== w
->getFrameWindow()) {
1613 specialWindowList
.erase(it
);
1616 assert(it
!= end
); // the window wasnt a special window?
1620 if (blackbox
->getFocusedWindow() == w
)
1621 blackbox
->setFocusedWindow((BlackboxWindow
*) 0);
1623 removeNetizen(w
->getClientWindow());
1626 some managed windows can also be window group controllers. when
1627 unmanaging such windows, we should also delete the window group.
1629 BWindowGroup
*group
= blackbox
->searchGroup(w
->getClientWindow());
1636 void BScreen::addNetizen(Netizen
*n
) {
1637 netizenList
.push_back(n
);
1639 n
->sendWorkspaceCount();
1640 n
->sendCurrentWorkspace();
1642 WorkspaceList::iterator it
= workspacesList
.begin();
1643 const WorkspaceList::iterator end
= workspacesList
.end();
1644 for (; it
!= end
; ++it
)
1645 (*it
)->sendWindowList(*n
);
1647 Window f
= ((blackbox
->getFocusedWindow()) ?
1648 blackbox
->getFocusedWindow()->getClientWindow() : None
);
1649 n
->sendWindowFocus(f
);
1653 void BScreen::removeNetizen(Window w
) {
1654 NetizenList::iterator it
= netizenList
.begin();
1655 for (; it
!= netizenList
.end(); ++it
) {
1656 if ((*it
)->getWindowID() == w
) {
1658 netizenList
.erase(it
);
1665 void BScreen::updateWorkArea(void) {
1666 if (workspacesList
.size() > 0) {
1667 unsigned long *dims
= new unsigned long[4 * workspacesList
.size()];
1668 for (unsigned int i
= 0, m
= workspacesList
.size(); i
< m
; ++i
) {
1669 // XXX: this could be different for each workspace
1670 const Rect
&area
= availableArea();
1671 dims
[(i
* 4) + 0] = area
.x();
1672 dims
[(i
* 4) + 1] = area
.y();
1673 dims
[(i
* 4) + 2] = area
.width();
1674 dims
[(i
* 4) + 3] = area
.height();
1676 xatom
->setValue(getRootWindow(), XAtom::net_workarea
, XAtom::cardinal
,
1677 dims
, 4 * workspacesList
.size());
1680 xatom
->setValue(getRootWindow(), XAtom::net_workarea
, XAtom::cardinal
,
1685 void BScreen::updateNetizenCurrentWorkspace(void) {
1686 std::for_each(netizenList
.begin(), netizenList
.end(),
1687 std::mem_fun(&Netizen::sendCurrentWorkspace
));
1691 void BScreen::updateNetizenWorkspaceCount(void) {
1692 xatom
->setValue(getRootWindow(), XAtom::net_number_of_desktops
,
1693 XAtom::cardinal
, workspacesList
.size());
1697 std::for_each(netizenList
.begin(), netizenList
.end(),
1698 std::mem_fun(&Netizen::sendWorkspaceCount
));
1702 void BScreen::updateNetizenWindowFocus(void) {
1703 Window f
= ((blackbox
->getFocusedWindow()) ?
1704 blackbox
->getFocusedWindow()->getClientWindow() : None
);
1706 xatom
->setValue(getRootWindow(), XAtom::net_active_window
,
1709 NetizenList::iterator it
= netizenList
.begin();
1710 for (; it
!= netizenList
.end(); ++it
)
1711 (*it
)->sendWindowFocus(f
);
1715 void BScreen::updateNetizenWindowAdd(Window w
, unsigned long p
) {
1716 NetizenList::iterator it
= netizenList
.begin();
1717 for (; it
!= netizenList
.end(); ++it
) {
1718 (*it
)->sendWindowAdd(w
, p
);
1723 void BScreen::updateNetizenWindowDel(Window w
) {
1724 NetizenList::iterator it
= netizenList
.begin();
1725 for (; it
!= netizenList
.end(); ++it
)
1726 (*it
)->sendWindowDel(w
);
1730 void BScreen::updateNetizenWindowRaise(Window w
) {
1731 NetizenList::iterator it
= netizenList
.begin();
1732 for (; it
!= netizenList
.end(); ++it
)
1733 (*it
)->sendWindowRaise(w
);
1737 void BScreen::updateNetizenWindowLower(Window w
) {
1738 NetizenList::iterator it
= netizenList
.begin();
1739 for (; it
!= netizenList
.end(); ++it
)
1740 (*it
)->sendWindowLower(w
);
1744 void BScreen::updateNetizenConfigNotify(XEvent
*e
) {
1745 NetizenList::iterator it
= netizenList
.begin();
1746 for (; it
!= netizenList
.end(); ++it
)
1747 (*it
)->sendConfigNotify(e
);
1751 void BScreen::raiseWindows(Window
*workspace_stack
, unsigned int num
) {
1752 // the 13 represents the number of blackbox windows such as menus
1761 Window
*session_stack
= new
1762 Window
[(num
+ workspacesList
.size() + rootmenuList
.size() +
1763 specialWindowList
.size() + bbwins
)];
1764 unsigned int i
= 0, k
= num
;
1766 XRaiseWindow(blackbox
->getXDisplay(), iconmenu
->getWindowID());
1767 *(session_stack
+ i
++) = iconmenu
->getWindowID();
1769 WorkspaceList::iterator wit
= workspacesList
.begin();
1770 const WorkspaceList::iterator w_end
= workspacesList
.end();
1771 for (; wit
!= w_end
; ++wit
)
1772 *(session_stack
+ i
++) = (*wit
)->getMenu()->getWindowID();
1774 *(session_stack
+ i
++) = workspacemenu
->getWindowID();
1776 *(session_stack
+ i
++) = configmenu
->getFocusmenu()->getWindowID();
1777 *(session_stack
+ i
++) = configmenu
->getPlacementmenu()->getWindowID();
1778 *(session_stack
+ i
++) = configmenu
->getWindowSnapmenu()->getWindowID();
1779 *(session_stack
+ i
++) = configmenu
->getEdgeSnapmenu()->getWindowID();
1781 *(session_stack
+ i
++) = configmenu
->getXineramamenu()->getWindowID();
1784 *(session_stack
+ i
++) = configmenu
->getXftmenu()->getWindowID();
1786 *(session_stack
+ i
++) = configmenu
->getWindowID();
1788 *(session_stack
+ i
++) = slit
->getMenu()->getDirectionmenu()->getWindowID();
1789 *(session_stack
+ i
++) = slit
->getMenu()->getPlacementmenu()->getWindowID();
1790 *(session_stack
+ i
++) = slit
->getMenu()->getWindowID();
1792 *(session_stack
+ i
++) =
1793 toolbar
->getMenu()->getPlacementmenu()->getWindowID();
1794 *(session_stack
+ i
++) = toolbar
->getMenu()->getWindowID();
1796 RootmenuList::iterator rit
= rootmenuList
.begin();
1797 for (; rit
!= rootmenuList
.end(); ++rit
)
1798 *(session_stack
+ i
++) = (*rit
)->getWindowID();
1799 *(session_stack
+ i
++) = rootmenu
->getWindowID();
1801 if (toolbar
->isOnTop())
1802 *(session_stack
+ i
++) = toolbar
->getWindowID();
1804 if (slit
->isOnTop())
1805 *(session_stack
+ i
++) = slit
->getWindowID();
1807 WindowList::iterator sit
, send
= specialWindowList
.end();
1808 for (sit
= specialWindowList
.begin(); sit
!= send
; ++sit
)
1809 *(session_stack
+ i
++) = *sit
;
1812 *(session_stack
+ i
++) = *(workspace_stack
+ k
);
1814 XRestackWindows(blackbox
->getXDisplay(), session_stack
, i
);
1816 delete [] session_stack
;
1818 updateStackingList();
1822 void BScreen::lowerWindows(Window
*workspace_stack
, unsigned int num
) {
1823 assert(num
> 0); // this would cause trouble in the XRaiseWindow call
1825 Window
*session_stack
= new Window
[(num
+ desktopWindowList
.size())];
1826 unsigned int i
= 0, k
= num
;
1828 XLowerWindow(blackbox
->getXDisplay(), workspace_stack
[0]);
1831 *(session_stack
+ i
++) = *(workspace_stack
+ k
);
1833 WindowList::iterator dit
= desktopWindowList
.begin();
1834 const WindowList::iterator d_end
= desktopWindowList
.end();
1835 for (; dit
!= d_end
; ++dit
)
1836 *(session_stack
+ i
++) = *dit
;
1838 XRestackWindows(blackbox
->getXDisplay(), session_stack
, i
);
1840 delete [] session_stack
;
1842 updateStackingList();
1846 void BScreen::reassociateWindow(BlackboxWindow
*w
, unsigned int wkspc_id
,
1847 bool ignore_sticky
) {
1850 if (wkspc_id
== BSENTINEL
)
1851 wkspc_id
= current_workspace
->getID();
1853 if (w
->getWorkspaceNumber() == wkspc_id
)
1856 if (w
->isIconic()) {
1858 getWorkspace(wkspc_id
)->addWindow(w
);
1860 for (unsigned int i
= 0; i
< getNumberOfWorkspaces(); ++i
)
1861 if (i
!= w
->getWorkspaceNumber())
1862 getWorkspace(i
)->addWindow(w
, True
);
1863 } else if (ignore_sticky
|| ! w
->isStuck()) {
1866 getWorkspace(w
->getWorkspaceNumber())->removeWindow(w
);
1867 getWorkspace(wkspc_id
)->addWindow(w
);
1869 updateStackingList();
1873 void BScreen::propagateWindowName(const BlackboxWindow
*bw
) {
1874 if (bw
->isIconic()) {
1875 iconmenu
->changeItemLabel(bw
->getWindowNumber(), bw
->getIconTitle());
1878 Clientmenu
*clientmenu
= getWorkspace(bw
->getWorkspaceNumber())->getMenu();
1879 clientmenu
->changeItemLabel(bw
->getWindowNumber(), bw
->getTitle());
1880 clientmenu
->update();
1882 if (blackbox
->getFocusedWindow() == bw
)
1883 toolbar
->redrawWindowLabel(True
);
1888 void BScreen::nextFocus(void) const {
1889 BlackboxWindow
*focused
= blackbox
->getFocusedWindow(),
1893 focused
->getScreen()->getScreenNumber() == getScreenNumber() &&
1894 current_workspace
->getCount() > 1) {
1896 next
= current_workspace
->getNextWindowInList(next
);
1897 } while (next
!= focused
&& ! next
->setInputFocus());
1899 if (next
!= focused
)
1900 current_workspace
->raiseWindow(next
);
1901 } else if (current_workspace
->getCount() > 0) {
1902 next
= current_workspace
->getTopWindowOnStack();
1903 next
->setInputFocus();
1904 current_workspace
->raiseWindow(next
);
1909 void BScreen::prevFocus(void) const {
1910 BlackboxWindow
*focused
= blackbox
->getFocusedWindow(),
1914 // if window is not on this screen, ignore it
1915 if (focused
->getScreen()->getScreenNumber() != getScreenNumber())
1916 focused
= (BlackboxWindow
*) 0;
1920 focused
->getScreen()->getScreenNumber() == getScreenNumber() &&
1921 current_workspace
->getCount() > 1) {
1922 // next is the next window to receive focus, current is a place holder
1924 next
= current_workspace
->getPrevWindowInList(next
);
1925 } while (next
!= focused
&& ! next
->setInputFocus());
1927 if (next
!= focused
)
1928 current_workspace
->raiseWindow(next
);
1929 } else if (current_workspace
->getCount() > 0) {
1930 next
= current_workspace
->getTopWindowOnStack();
1931 next
->setInputFocus();
1932 current_workspace
->raiseWindow(next
);
1937 void BScreen::raiseFocus(void) const {
1938 BlackboxWindow
*focused
= blackbox
->getFocusedWindow();
1942 // if on this Screen, raise it
1943 if (focused
->getScreen()->getScreenNumber() == getScreenNumber()) {
1944 Workspace
*workspace
= getWorkspace(focused
->getWorkspaceNumber());
1945 workspace
->raiseWindow(focused
);
1950 void BScreen::InitMenu(void) {
1952 rootmenuList
.clear();
1954 while (rootmenu
->getCount())
1955 rootmenu
->remove(0);
1957 rootmenu
= new Rootmenu(this);
1959 bool defaultMenu
= True
;
1961 FILE *menu_file
= (FILE *) 0;
1962 const char *menu_filename
= blackbox
->getMenuFilename();
1965 if (! (menu_file
= fopen(menu_filename
, "r")))
1966 perror(menu_filename
);
1967 if (! menu_file
) { // opening the menu file failed, try the default menu
1968 menu_filename
= DEFAULTMENU
;
1969 if (! (menu_file
= fopen(menu_filename
, "r")))
1970 perror(menu_filename
);
1974 if (feof(menu_file
)) {
1975 fprintf(stderr
, i18n(ScreenSet
, ScreenEmptyMenuFile
,
1976 "%s: Empty menu file"),
1979 char line
[1024], label
[1024];
1980 memset(line
, 0, 1024);
1981 memset(label
, 0, 1024);
1983 while (fgets(line
, 1024, menu_file
) && ! feof(menu_file
)) {
1987 int i
, key
= 0, index
= -1, len
= strlen(line
);
1989 for (i
= 0; i
< len
; i
++) {
1990 if (line
[i
] == '[') index
= 0;
1991 else if (line
[i
] == ']') break;
1992 else if (line
[i
] != ' ')
1994 key
+= tolower(line
[i
]);
1997 if (key
== 517) { // [begin]
1999 for (i
= index
; i
< len
; i
++) {
2000 if (line
[i
] == '(') index
= 0;
2001 else if (line
[i
] == ')') break;
2002 else if (index
++ >= 0) {
2003 if (line
[i
] == '\\' && i
< len
- 1) i
++;
2004 label
[index
- 1] = line
[i
];
2008 if (index
== -1) index
= 0;
2009 label
[index
] = '\0';
2011 rootmenu
->setLabel(label
);
2012 defaultMenu
= parseMenuFile(menu_file
, rootmenu
);
2014 blackbox
->addMenuTimestamp(menu_filename
);
2023 rootmenu
->setInternalMenu();
2024 rootmenu
->insert(i18n(ScreenSet
, Screenxterm
, "xterm"),
2026 i18n(ScreenSet
, Screenxterm
, "xterm"));
2027 rootmenu
->insert(i18n(ScreenSet
, ScreenRestart
, "Restart"),
2029 rootmenu
->insert(i18n(ScreenSet
, ScreenExit
, "Exit"),
2031 rootmenu
->setLabel(i18n(BasemenuSet
, BasemenuBlackboxMenu
,
2038 size_t string_within(char begin
, char end
,
2039 const char *input
, size_t start_at
, size_t length
,
2043 size_t i
= start_at
;
2044 for (; i
< length
; ++i
) {
2045 if (input
[i
] == begin
) {
2047 } else if (input
[i
] == end
) {
2050 if (input
[i
] == '\\' && i
< length
- 1) i
++;
2051 output
[index
++] = input
[i
];
2056 output
[index
] = '\0';
2064 bool BScreen::parseMenuFile(FILE *file
, Rootmenu
*menu
) {
2065 char line
[1024], keyword
[1024], label
[1024], command
[1024];
2068 while (! (done
|| feof(file
))) {
2069 memset(line
, 0, 1024);
2070 memset(label
, 0, 1024);
2071 memset(command
, 0, 1024);
2073 if (! fgets(line
, 1024, file
))
2076 if (line
[0] == '#') // comment, skip it
2079 size_t line_length
= strlen(line
);
2080 unsigned int key
= 0;
2082 // get the keyword enclosed in []'s
2083 size_t pos
= string_within('[', ']', line
, 0, line_length
, keyword
);
2085 if (keyword
[0] == '\0') { // no keyword, no menu entry
2088 size_t len
= strlen(keyword
);
2089 for (size_t i
= 0; i
< len
; ++i
) {
2090 if (keyword
[i
] != ' ')
2091 key
+= tolower(keyword
[i
]);
2095 // get the label enclosed in ()'s
2096 pos
= string_within('(', ')', line
, pos
, line_length
, label
);
2098 // get the command enclosed in {}'s
2099 pos
= string_within('{', '}', line
, pos
, line_length
, command
);
2110 menu
->insert(label
);
2115 if (! (*label
&& *command
)) {
2116 fprintf(stderr
, i18n(ScreenSet
, ScreenEXECError
,
2117 "BScreen::parseMenuFile: [exec] error, "
2118 "no menu label and/or command defined\n"));
2122 menu
->insert(label
, BScreen::Execute
, command
);
2128 fprintf(stderr
, i18n(ScreenSet
, ScreenEXITError
,
2129 "BScreen::parseMenuFile: [exit] error, "
2130 "no menu label defined\n"));
2134 menu
->insert(label
, BScreen::Exit
);
2138 case 561: { // style
2139 if (! (*label
&& *command
)) {
2141 i18n(ScreenSet
, ScreenSTYLEError
,
2142 "BScreen::parseMenuFile: [style] error, "
2143 "no menu label and/or filename defined\n"));
2147 string style
= expandTilde(command
);
2149 menu
->insert(label
, BScreen::SetStyle
, style
.c_str());
2155 fprintf(stderr
, i18n(ScreenSet
, ScreenCONFIGError
,
2156 "BScreen::parseMenufile: [config] error, "
2157 "no label defined"));
2161 menu
->insert(label
, configmenu
);
2165 case 740: { // include
2167 fprintf(stderr
, i18n(ScreenSet
, ScreenINCLUDEError
,
2168 "BScreen::parseMenuFile: [include] error, "
2169 "no filename defined\n"));
2173 string newfile
= expandTilde(label
);
2174 FILE *submenufile
= fopen(newfile
.c_str(), "r");
2176 if (! submenufile
) {
2177 perror(newfile
.c_str());
2182 if (fstat(fileno(submenufile
), &buf
) ||
2183 ! S_ISREG(buf
.st_mode
)) {
2185 i18n(ScreenSet
, ScreenINCLUDEErrorReg
,
2186 "BScreen::parseMenuFile: [include] error: "
2187 "'%s' is not a regular file\n"), newfile
.c_str());
2191 if (! feof(submenufile
)) {
2192 if (! parseMenuFile(submenufile
, menu
))
2193 blackbox
->addMenuTimestamp(newfile
);
2195 fclose(submenufile
);
2201 case 767: { // submenu
2203 fprintf(stderr
, i18n(ScreenSet
, ScreenSUBMENUError
,
2204 "BScreen::parseMenuFile: [submenu] error, "
2205 "no menu label defined\n"));
2209 Rootmenu
*submenu
= new Rootmenu(this);
2212 submenu
->setLabel(command
);
2214 submenu
->setLabel(label
);
2216 parseMenuFile(file
, submenu
);
2218 menu
->insert(label
, submenu
);
2219 rootmenuList
.push_back(submenu
);
2224 case 773: { // restart
2226 fprintf(stderr
, i18n(ScreenSet
, ScreenRESTARTError
,
2227 "BScreen::parseMenuFile: [restart] error, "
2228 "no menu label defined\n"));
2233 menu
->insert(label
, BScreen::RestartOther
, command
);
2235 menu
->insert(label
, BScreen::Restart
);
2240 case 845: { // reconfig
2243 i18n(ScreenSet
, ScreenRECONFIGError
,
2244 "BScreen::parseMenuFile: [reconfig] error, "
2245 "no menu label defined\n"));
2249 menu
->insert(label
, BScreen::Reconfigure
);
2254 case 995: // stylesdir
2255 case 1113: { // stylesmenu
2256 bool newmenu
= ((key
== 1113) ? True
: False
);
2258 if (! *label
|| (! *command
&& newmenu
)) {
2260 i18n(ScreenSet
, ScreenSTYLESDIRError
,
2261 "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2262 " error, no directory defined\n"));
2266 char *directory
= ((newmenu
) ? command
: label
);
2268 string stylesdir
= expandTilde(directory
);
2270 struct stat statbuf
;
2272 if (stat(stylesdir
.c_str(), &statbuf
) == -1) {
2274 i18n(ScreenSet
, ScreenSTYLESDIRErrorNoExist
,
2275 "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2276 " error, %s does not exist\n"), stylesdir
.c_str());
2279 if (! S_ISDIR(statbuf
.st_mode
)) {
2281 i18n(ScreenSet
, ScreenSTYLESDIRErrorNotDir
,
2282 "BScreen::parseMenuFile:"
2283 " [stylesdir/stylesmenu] error, %s is not a"
2284 " directory\n"), stylesdir
.c_str());
2288 Rootmenu
*stylesmenu
;
2291 stylesmenu
= new Rootmenu(this);
2295 DIR *d
= opendir(stylesdir
.c_str());
2297 std::vector
<string
> ls
;
2299 while((p
= readdir(d
)))
2300 ls
.push_back(p
->d_name
);
2304 std::sort(ls
.begin(), ls
.end());
2306 std::vector
<string
>::iterator it
= ls
.begin(),
2308 for (; it
!= end
; ++it
) {
2309 const string
& fname
= *it
;
2311 if (fname
[fname
.size()-1] == '~')
2314 string style
= stylesdir
;
2318 if (! stat(style
.c_str(), &statbuf
) && S_ISREG(statbuf
.st_mode
))
2319 stylesmenu
->insert(fname
, BScreen::SetStyle
, style
);
2322 stylesmenu
->update();
2325 stylesmenu
->setLabel(label
);
2326 menu
->insert(label
, stylesmenu
);
2327 rootmenuList
.push_back(stylesmenu
);
2330 blackbox
->addMenuTimestamp(stylesdir
);
2334 case 1090: { // workspaces
2337 i18n(ScreenSet
, ScreenWORKSPACESError
,
2338 "BScreen:parseMenuFile: [workspaces] error, "
2339 "no menu label defined\n"));
2343 menu
->insert(label
, workspacemenu
);
2349 return ((menu
->getCount() == 0) ? True
: False
);
2353 void BScreen::shutdown(void) {
2354 XSelectInput(blackbox
->getXDisplay(), getRootWindow(), NoEventMask
);
2355 XSync(blackbox
->getXDisplay(), False
);
2357 while(! windowList
.empty())
2358 unmanageWindow(windowList
.front(), True
);
2360 while(! desktopWindowList
.empty()) {
2361 BlackboxWindow
*win
= blackbox
->searchWindow(desktopWindowList
.front());
2363 unmanageWindow(win
, True
);
2370 void BScreen::showPosition(int x
, int y
) {
2371 if (! geom_visible
) {
2372 XMoveResizeWindow(blackbox
->getXDisplay(), geom_window
,
2373 (getWidth() - geom_w
) / 2,
2374 (getHeight() - geom_h
) / 2, geom_w
, geom_h
);
2375 XMapWindow(blackbox
->getXDisplay(), geom_window
);
2376 XRaiseWindow(blackbox
->getXDisplay(), geom_window
);
2378 geom_visible
= True
;
2383 sprintf(label
, i18n(ScreenSet
, ScreenPositionFormat
,
2384 "X: %4d x Y: %4d"), x
, y
);
2386 XClearWindow(blackbox
->getXDisplay(), geom_window
);
2388 resource
.wstyle
.font
->drawString(geom_window
,
2389 resource
.bevel_width
, resource
.bevel_width
,
2390 resource
.wstyle
.l_text_focus
,
2395 void BScreen::showGeometry(unsigned int gx
, unsigned int gy
) {
2396 if (! geom_visible
) {
2397 XMoveResizeWindow(blackbox
->getXDisplay(), geom_window
,
2398 (getWidth() - geom_w
) / 2,
2399 (getHeight() - geom_h
) / 2, geom_w
, geom_h
);
2400 XMapWindow(blackbox
->getXDisplay(), geom_window
);
2401 XRaiseWindow(blackbox
->getXDisplay(), geom_window
);
2403 geom_visible
= True
;
2408 sprintf(label
, i18n(ScreenSet
, ScreenGeometryFormat
,
2409 "W: %4d x H: %4d"), gx
, gy
);
2411 XClearWindow(blackbox
->getXDisplay(), geom_window
);
2413 resource
.wstyle
.font
->drawString(geom_window
,
2414 resource
.bevel_width
, resource
.bevel_width
,
2415 resource
.wstyle
.l_text_focus
,
2420 void BScreen::hideGeometry(void) {
2422 XUnmapWindow(blackbox
->getXDisplay(), geom_window
);
2423 geom_visible
= False
;
2428 void BScreen::addStrut(Strut
*strut
) {
2429 strutList
.push_back(strut
);
2433 void BScreen::removeStrut(Strut
*strut
) {
2434 strutList
.remove(strut
);
2438 const Rect
& BScreen::availableArea(void) const {
2440 return getRect(); // return the full screen
2446 const RectList
& BScreen::allAvailableAreas(void) const {
2447 assert(isXineramaActive());
2448 assert(xineramaUsableArea
.size() > 0);
2449 fprintf(stderr
, "1found x %d y %d w %d h %d\n",
2450 xineramaUsableArea
[0].x(), xineramaUsableArea
[0].y(),
2451 xineramaUsableArea
[0].width(), xineramaUsableArea
[0].height());
2452 return xineramaUsableArea
;
2457 void BScreen::updateAvailableArea(void) {
2458 Rect old_area
= usableArea
;
2459 usableArea
= getRect(); // reset to full screen
2462 // reset to the full areas
2463 if (isXineramaActive())
2464 xineramaUsableArea
= getXineramaAreas();
2467 /* these values represent offsets from the screen edge
2468 * we look for the biggest offset on each edge and then apply them
2470 * do not be confused by the similarity to the names of Rect's members
2472 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
2475 StrutList::const_iterator it
= strutList
.begin(), end
= strutList
.end();
2477 for(; it
!= end
; ++it
) {
2479 if (strut
->left
> current_left
)
2480 current_left
= strut
->left
;
2481 if (strut
->top
> current_top
)
2482 current_top
= strut
->top
;
2483 if (strut
->right
> current_right
)
2484 current_right
= strut
->right
;
2485 if (strut
->bottom
> current_bottom
)
2486 current_bottom
= strut
->bottom
;
2489 usableArea
.setPos(current_left
, current_top
);
2490 usableArea
.setSize(usableArea
.width() - (current_left
+ current_right
),
2491 usableArea
.height() - (current_top
+ current_bottom
));
2494 if (isXineramaActive()) {
2495 // keep each of the ximerama-defined areas inside the strut
2496 RectList::iterator xit
, xend
= xineramaUsableArea
.end();
2497 for (xit
= xineramaUsableArea
.begin(); xit
!= xend
; ++xit
) {
2498 if (xit
->x() < usableArea
.x()) {
2499 xit
->setX(usableArea
.x());
2500 xit
->setWidth(xit
->width() - usableArea
.x());
2502 if (xit
->y() < usableArea
.y()) {
2503 xit
->setY(usableArea
.y());
2504 xit
->setHeight(xit
->height() - usableArea
.y());
2506 if (xit
->x() + xit
->width() > usableArea
.width())
2507 xit
->setWidth(usableArea
.width() - xit
->x());
2508 if (xit
->y() + xit
->height() > usableArea
.height())
2509 xit
->setHeight(usableArea
.height() - xit
->y());
2514 if (old_area
!= usableArea
) {
2515 BlackboxWindowList::iterator it
= windowList
.begin(),
2516 end
= windowList
.end();
2517 for (; it
!= end
; ++it
)
2518 if ((*it
)->isMaximized()) (*it
)->remaximize();
2525 Workspace
* BScreen::getWorkspace(unsigned int index
) const {
2526 assert(index
< workspacesList
.size());
2527 return workspacesList
[index
];
2531 void BScreen::buttonPressEvent(const XButtonEvent
*xbutton
) {
2532 if (xbutton
->button
== 1) {
2533 if (! isRootColormapInstalled())
2534 image_control
->installRootColormap();
2536 if (workspacemenu
->isVisible())
2537 workspacemenu
->hide();
2539 if (rootmenu
->isVisible())
2542 } else if ((xbutton
->button
== 4 && resource
.root_scroll
== NormalScroll
) ||
2543 (xbutton
->button
== 5 && resource
.root_scroll
== ReverseScroll
)) {
2544 if (getCurrentWorkspaceID() >= getWorkspaceCount() - 1)
2545 changeWorkspaceID(0);
2547 changeWorkspaceID(getCurrentWorkspaceID() + 1);
2549 } else if ((xbutton
->button
== 5 && resource
.root_scroll
== NormalScroll
) ||
2550 (xbutton
->button
== 4 && resource
.root_scroll
== ReverseScroll
)) {
2551 if (getCurrentWorkspaceID() == 0)
2552 changeWorkspaceID(getWorkspaceCount() - 1);
2554 changeWorkspaceID(getCurrentWorkspaceID() - 1);
2557 if (resource
.root_menu_button
> 0 &&
2558 xbutton
->button
== resource
.root_menu_button
)
2559 showRootMenu(xbutton
->x_root
, xbutton
->y_root
);
2560 else if (resource
.workspace_menu_button
> 0 &&
2561 xbutton
->button
== resource
.workspace_menu_button
)
2562 showWorkspaceMenu(xbutton
->x_root
, xbutton
->y_root
);
2566 void BScreen::showWorkspaceMenu(int x
, int y
) {
2567 int mx
= x
- (workspacemenu
->getWidth() / 2);
2568 int my
= y
- (workspacemenu
->getTitleHeight() / 2);
2573 if (mx
+ workspacemenu
->getWidth() > getWidth())
2574 mx
= getWidth() - workspacemenu
->getWidth() - getBorderWidth();
2576 if (my
+ workspacemenu
->getHeight() > getHeight())
2577 my
= getHeight() - workspacemenu
->getHeight() - getBorderWidth();
2579 workspacemenu
->move(mx
, my
);
2581 if (! workspacemenu
->isVisible()) {
2582 workspacemenu
->removeParent();
2583 workspacemenu
->show();
2588 void BScreen::showRootMenu(int x
, int y
) {
2589 int mx
= x
- (rootmenu
->getWidth() / 2);
2590 int my
= y
- (rootmenu
->getTitleHeight() / 2);
2595 if (mx
+ rootmenu
->getWidth() > getWidth())
2596 mx
= getWidth() - rootmenu
->getWidth() - getBorderWidth();
2598 if (my
+ rootmenu
->getHeight() > getHeight())
2599 my
= getHeight() - rootmenu
->getHeight() - getBorderWidth();
2601 rootmenu
->move(mx
, my
);
2603 if (! rootmenu
->isVisible()) {
2604 blackbox
->checkMenu();
2610 void BScreen::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2611 if (pe
->atom
== xatom
->getAtom(XAtom::net_desktop_names
)) {
2612 // _NET_WM_DESKTOP_NAMES
2613 WorkspaceList::iterator it
= workspacesList
.begin();
2614 const WorkspaceList::iterator end
= workspacesList
.end();
2615 for (; it
!= end
; ++it
) {
2616 (*it
)->readName(); // re-read its name from the window property
2617 workspacemenu
->changeWorkspaceLabel((*it
)->getID(), (*it
)->getName());
2619 workspacemenu
->update();
2620 toolbar
->reconfigure();
2621 saveWorkspaceNames();
2626 void BScreen::toggleFocusModel(FocusModel model
) {
2627 std::for_each(windowList
.begin(), windowList
.end(),
2628 std::mem_fun(&BlackboxWindow::ungrabButtons
));
2630 if (model
== SloppyFocus
) {
2631 saveSloppyFocus(True
);
2633 // we're cheating here to save writing the config file 3 times
2634 resource
.auto_raise
= False
;
2635 resource
.click_raise
= False
;
2636 saveSloppyFocus(False
);
2639 std::for_each(windowList
.begin(), windowList
.end(),
2640 std::mem_fun(&BlackboxWindow::grabButtons
));
2643 #ifdef BITMAPBUTTONS
2644 void BScreen::readDatabaseMask(const string
&rname
, PixmapMask
&pixmapMask
,
2645 const Configuration
&style
) {
2647 int hx
, hy
; //ignored
2648 int ret
= BitmapOpenFailed
; //default to failure.
2650 if (style
.getValue(rname
, s
))
2652 if (s
[0] != '/' && s
[0] != '~')
2654 std::string xbmFile
= std::string("~/.openbox/buttons/") + s
;
2655 ret
= XReadBitmapFile(blackbox
->getXDisplay(), getRootWindow(),
2656 expandTilde(xbmFile
).c_str(), &pixmapMask
.w
,
2657 &pixmapMask
.h
, &pixmapMask
.mask
, &hx
, &hy
);
2659 ret
= XReadBitmapFile(blackbox
->getXDisplay(), getRootWindow(),
2660 expandTilde(s
).c_str(), &pixmapMask
.w
,
2661 &pixmapMask
.h
, &pixmapMask
.mask
, &hx
, &hy
);
2663 if (ret
== BitmapSuccess
)
2667 pixmapMask
.mask
= None
;
2668 pixmapMask
.w
= pixmapMask
.h
= 0;
2670 #endif // BITMAPSUCCESS
2672 BTexture
BScreen::readDatabaseTexture(const string
&rname
,
2673 const string
&default_color
,
2674 const Configuration
&style
) {
2678 if (style
.getValue(rname
, s
))
2679 texture
= BTexture(s
);
2681 texture
.setTexture(BTexture::Solid
| BTexture::Flat
);
2683 // associate this texture with this screen
2684 texture
.setDisplay(getBaseDisplay(), getScreenNumber());
2685 texture
.setImageControl(image_control
);
2687 texture
.setColor(readDatabaseColor(rname
+ ".color", default_color
, style
));
2688 texture
.setColorTo(readDatabaseColor(rname
+ ".colorTo", default_color
,
2690 texture
.setBorderColor(readDatabaseColor(rname
+ ".borderColor",
2691 default_color
, style
));
2697 BColor
BScreen::readDatabaseColor(const string
&rname
,
2698 const string
&default_color
,
2699 const Configuration
&style
) {
2702 if (style
.getValue(rname
, s
))
2703 color
= BColor(s
, getBaseDisplay(), getScreenNumber());
2705 color
= BColor(default_color
, getBaseDisplay(), getScreenNumber());
2710 BFont
*BScreen::readDatabaseFont(const string
&rbasename
,
2711 const Configuration
&style
) {
2718 if (style
.getValue(rbasename
+ "xft.font", s
) &&
2719 style
.getValue(rbasename
+ "xft.size", i
)) {
2722 bool italic
= False
;
2723 if (style
.getValue(rbasename
+ "xft.flags", s
)) {
2724 if (s
.find("bold") != string::npos
)
2726 if (s
.find("italic") != string::npos
)
2730 BFont
*b
= new BFont(blackbox
->getXDisplay(), this, family
, i
, bold
,
2731 italic
, resource
.shadow_fonts
, resource
.aa_fonts
);
2735 delete b
; // fall back to the normal X font stuff
2739 style
.getValue(rbasename
+ "font", s
);
2740 // if this fails, a blank string will be used, which will cause the fallback
2743 BFont
*b
= new BFont(blackbox
->getXDisplay(), this, s
);
2745 exit(2); // can't continue without a font