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 //if neither of these can be found, we will use the previous resource
1069 resource
.wstyle
.b_pressed_focus
=
1070 readDatabaseTexture("window.button.pressed.focus", "black", style
, true);
1071 resource
.wstyle
.b_pressed_unfocus
=
1072 readDatabaseTexture("window.button.pressed.unfocus", "black", style
, true);
1074 #ifdef BITMAPBUTTONS
1075 if (resource
.wstyle
.close_button
.mask
!= None
)
1076 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.close_button
.mask
);
1077 if (resource
.wstyle
.max_button
.mask
!= None
)
1078 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.max_button
.mask
);
1079 if (resource
.wstyle
.icon_button
.mask
!= None
)
1080 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.icon_button
.mask
);
1081 if (resource
.wstyle
.stick_button
.mask
!= None
)
1082 XFreePixmap(blackbox
->getXDisplay(), resource
.wstyle
.stick_button
.mask
);
1084 resource
.wstyle
.close_button
.mask
= resource
.wstyle
.max_button
.mask
=
1085 resource
.wstyle
.icon_button
.mask
=
1086 resource
.wstyle
.icon_button
.mask
= None
;
1088 readDatabaseMask("window.button.close.mask", resource
.wstyle
.close_button
,
1090 readDatabaseMask("window.button.max.mask", resource
.wstyle
.max_button
,
1092 readDatabaseMask("window.button.icon.mask", resource
.wstyle
.icon_button
,
1094 readDatabaseMask("window.button.stick.mask", resource
.wstyle
.stick_button
,
1096 #endif // BITMAPBUTTONS
1098 // we create the window.frame texture by hand because it exists only to
1099 // make the code cleaner and is not actually used for display
1100 BColor color
= readDatabaseColor("window.frame.focusColor", "white", style
);
1101 resource
.wstyle
.f_focus
= BTexture("solid flat", getBaseDisplay(),
1102 getScreenNumber(), image_control
);
1103 resource
.wstyle
.f_focus
.setColor(color
);
1105 color
= readDatabaseColor("window.frame.unfocusColor", "white", style
);
1106 resource
.wstyle
.f_unfocus
= BTexture("solid flat", getBaseDisplay(),
1107 getScreenNumber(), image_control
);
1108 resource
.wstyle
.f_unfocus
.setColor(color
);
1110 resource
.wstyle
.l_text_focus
=
1111 readDatabaseColor("window.label.focus.textColor", "black", style
);
1112 resource
.wstyle
.l_text_unfocus
=
1113 readDatabaseColor("window.label.unfocus.textColor", "white", style
);
1114 resource
.wstyle
.b_pic_focus
=
1115 readDatabaseColor("window.button.focus.picColor", "black", style
);
1116 resource
.wstyle
.b_pic_unfocus
=
1117 readDatabaseColor("window.button.unfocus.picColor", "white", style
);
1119 resource
.wstyle
.justify
= LeftJustify
;
1120 if (style
.getValue("window.justify", s
)) {
1121 if (s
== "right" || s
== "Right")
1122 resource
.wstyle
.justify
= RightJustify
;
1123 else if (s
== "center" || s
== "Center")
1124 resource
.wstyle
.justify
= CenterJustify
;
1128 if (resource
.wstyle
.t_focus
.texture() == BTexture::Parent_Relative
)
1129 resource
.wstyle
.t_focus
= resource
.wstyle
.f_focus
;
1130 if (resource
.wstyle
.t_unfocus
.texture() == BTexture::Parent_Relative
)
1131 resource
.wstyle
.t_unfocus
= resource
.wstyle
.f_unfocus
;
1132 if (resource
.wstyle
.h_focus
.texture() == BTexture::Parent_Relative
)
1133 resource
.wstyle
.h_focus
= resource
.wstyle
.f_focus
;
1134 if (resource
.wstyle
.h_unfocus
.texture() == BTexture::Parent_Relative
)
1135 resource
.wstyle
.h_unfocus
= resource
.wstyle
.f_unfocus
;
1137 // load toolbar config
1138 #ifdef BITMAPBUTTONS
1139 if (resource
.tstyle
.left_button
.mask
!= None
)
1140 XFreePixmap(blackbox
->getXDisplay(), resource
.tstyle
.left_button
.mask
);
1141 if (resource
.tstyle
.right_button
.mask
!= None
)
1142 XFreePixmap(blackbox
->getXDisplay(), resource
.tstyle
.right_button
.mask
);
1143 #endif // BITMAPBUTTONS
1145 resource
.tstyle
.toolbar
=
1146 readDatabaseTexture("toolbar", "black", style
);
1147 resource
.tstyle
.label
=
1148 readDatabaseTexture("toolbar.label", "black", style
);
1149 resource
.tstyle
.window
=
1150 readDatabaseTexture("toolbar.windowLabel", "black", style
);
1151 resource
.tstyle
.button
=
1152 readDatabaseTexture("toolbar.button", "white", style
);
1153 resource
.tstyle
.pressed
=
1154 readDatabaseTexture("toolbar.button.pressed", "black", style
);
1155 resource
.tstyle
.clock
=
1156 readDatabaseTexture("toolbar.clock", "black", style
);
1157 resource
.tstyle
.l_text
=
1158 readDatabaseColor("toolbar.label.textColor", "white", style
);
1159 resource
.tstyle
.w_text
=
1160 readDatabaseColor("toolbar.windowLabel.textColor", "white", style
);
1161 resource
.tstyle
.c_text
=
1162 readDatabaseColor("toolbar.clock.textColor", "white", style
);
1163 resource
.tstyle
.b_pic
=
1164 readDatabaseColor("toolbar.button.picColor", "black", style
);
1166 #ifdef BITMAPBUTTONS
1167 readDatabaseMask("toolbar.button.left.mask", resource
.tstyle
.left_button
,
1169 readDatabaseMask("toolbar.button.right.mask", resource
.tstyle
.right_button
,
1171 #endif // BITMAPBUTTONS
1173 resource
.tstyle
.justify
= LeftJustify
;
1174 if (style
.getValue("toolbar.justify", s
)) {
1175 if (s
== "right" || s
== "Right")
1176 resource
.tstyle
.justify
= RightJustify
;
1177 else if (s
== "center" || s
== "Center")
1178 resource
.tstyle
.justify
= CenterJustify
;
1182 if (resource
.tstyle
.toolbar
.texture() == BTexture::Parent_Relative
) {
1183 resource
.tstyle
.toolbar
= BTexture("solid flat", getBaseDisplay(),
1184 getScreenNumber(), image_control
);
1185 resource
.tstyle
.toolbar
.setColor(BColor("black", getBaseDisplay(),
1186 getScreenNumber()));
1190 #ifdef BITMAPBUTTONS
1191 if (resource
.mstyle
.bullet_image
.mask
!= None
)
1192 XFreePixmap(blackbox
->getXDisplay(), resource
.mstyle
.bullet_image
.mask
);
1193 if (resource
.mstyle
.tick_image
.mask
!= None
)
1194 XFreePixmap(blackbox
->getXDisplay(), resource
.mstyle
.tick_image
.mask
);
1195 #endif // BITMAPBUTTONS
1197 resource
.mstyle
.title
=
1198 readDatabaseTexture("menu.title", "white", style
);
1199 resource
.mstyle
.frame
=
1200 readDatabaseTexture("menu.frame", "black", style
);
1201 resource
.mstyle
.hilite
=
1202 readDatabaseTexture("menu.hilite", "white", style
);
1203 resource
.mstyle
.t_text
=
1204 readDatabaseColor("menu.title.textColor", "black", style
);
1205 resource
.mstyle
.f_text
=
1206 readDatabaseColor("menu.frame.textColor", "white", style
);
1207 resource
.mstyle
.d_text
=
1208 readDatabaseColor("menu.frame.disableColor", "black", style
);
1209 resource
.mstyle
.h_text
=
1210 readDatabaseColor("menu.hilite.textColor", "black", style
);
1212 #ifdef BITMAPBUTTONS
1213 readDatabaseMask("menu.arrow.mask", resource
.mstyle
.bullet_image
, style
);
1214 readDatabaseMask("menu.selected.mask", resource
.mstyle
.tick_image
, style
);
1215 #endif // BITMAPBUTTONS
1217 resource
.mstyle
.t_justify
= LeftJustify
;
1218 if (style
.getValue("menu.title.justify", s
)) {
1219 if (s
== "right" || s
== "Right")
1220 resource
.mstyle
.t_justify
= RightJustify
;
1221 else if (s
== "center" || s
== "Center")
1222 resource
.mstyle
.t_justify
= CenterJustify
;
1225 resource
.mstyle
.f_justify
= LeftJustify
;
1226 if (style
.getValue("menu.frame.justify", s
)) {
1227 if (s
== "right" || s
== "Right")
1228 resource
.mstyle
.f_justify
= RightJustify
;
1229 else if (s
== "center" || s
== "Center")
1230 resource
.mstyle
.f_justify
= CenterJustify
;
1233 resource
.mstyle
.bullet
= Basemenu::Triangle
;
1234 if (style
.getValue("menu.bullet", s
)) {
1235 if (s
== "empty" || s
== "Empty")
1236 resource
.mstyle
.bullet
= Basemenu::Empty
;
1237 else if (s
== "square" || s
== "Square")
1238 resource
.mstyle
.bullet
= Basemenu::Square
;
1239 else if (s
== "diamond" || s
== "Diamond")
1240 resource
.mstyle
.bullet
= Basemenu::Diamond
;
1243 resource
.mstyle
.bullet_pos
= Basemenu::Left
;
1244 if (style
.getValue("menu.bullet.position", s
)) {
1245 if (s
== "right" || s
== "Right")
1246 resource
.mstyle
.bullet_pos
= Basemenu::Right
;
1250 if (resource
.mstyle
.frame
.texture() == BTexture::Parent_Relative
) {
1251 resource
.mstyle
.frame
= BTexture("solid flat", getBaseDisplay(),
1252 getScreenNumber(), image_control
);
1253 resource
.mstyle
.frame
.setColor(BColor("black", getBaseDisplay(),
1254 getScreenNumber()));
1257 resource
.border_color
=
1258 readDatabaseColor("borderColor", "black", style
);
1260 // load bevel, border and handle widths
1261 if (! style
.getValue("handleWidth", resource
.handle_width
) ||
1262 resource
.handle_width
> (getWidth() / 2) || resource
.handle_width
== 0)
1263 resource
.handle_width
= 6;
1265 if (! style
.getValue("borderWidth", resource
.border_width
))
1266 resource
.border_width
= 1;
1268 if (! style
.getValue("bevelWidth", resource
.bevel_width
) ||
1269 resource
.bevel_width
> (getWidth() / 2) || resource
.bevel_width
== 0)
1270 resource
.bevel_width
= 3;
1272 if (! style
.getValue("frameWidth", resource
.frame_width
) ||
1273 resource
.frame_width
> (getWidth() / 2))
1274 resource
.frame_width
= resource
.bevel_width
;
1276 if (style
.getValue("rootCommand", s
))
1277 bexec(s
, displayString());
1281 void BScreen::addIcon(BlackboxWindow
*w
) {
1284 w
->setWorkspace(BSENTINEL
);
1285 w
->setWindowNumber(iconList
.size());
1287 iconList
.push_back(w
);
1289 const char* title
= w
->getIconTitle();
1290 iconmenu
->insert(title
);
1295 void BScreen::removeIcon(BlackboxWindow
*w
) {
1300 iconmenu
->remove(w
->getWindowNumber());
1303 BlackboxWindowList::iterator it
= iconList
.begin(),
1304 end
= iconList
.end();
1305 for (int i
= 0; it
!= end
; ++it
)
1306 (*it
)->setWindowNumber(i
++);
1310 BlackboxWindow
*BScreen::getIcon(unsigned int index
) {
1311 if (index
< iconList
.size()) {
1312 BlackboxWindowList::iterator it
= iconList
.begin();
1313 while (index
-- > 0) // increment to index
1318 return (BlackboxWindow
*) 0;
1322 unsigned int BScreen::addWorkspace(void) {
1323 Workspace
*wkspc
= new Workspace(this, workspacesList
.size());
1324 workspacesList
.push_back(wkspc
);
1325 saveWorkspaces(getWorkspaceCount());
1326 saveWorkspaceNames();
1328 workspacemenu
->insertWorkspace(wkspc
);
1329 workspacemenu
->update();
1331 toolbar
->reconfigure();
1333 updateNetizenWorkspaceCount();
1335 return workspacesList
.size();
1339 unsigned int BScreen::removeLastWorkspace(void) {
1340 if (workspacesList
.size() == 1)
1343 Workspace
*wkspc
= workspacesList
.back();
1345 if (current_workspace
->getID() == wkspc
->getID())
1346 changeWorkspaceID(current_workspace
->getID() - 1);
1350 workspacemenu
->removeWorkspace(wkspc
);
1351 workspacemenu
->update();
1353 workspacesList
.pop_back();
1356 saveWorkspaces(getWorkspaceCount());
1357 saveWorkspaceNames();
1359 toolbar
->reconfigure();
1361 updateNetizenWorkspaceCount();
1363 return workspacesList
.size();
1367 void BScreen::changeWorkspaceID(unsigned int id
) {
1368 if (! current_workspace
|| id
== current_workspace
->getID()) return;
1370 BlackboxWindow
*focused
= blackbox
->getFocusedWindow();
1371 if (focused
&& focused
->getScreen() == this) {
1372 assert(focused
->isStuck() ||
1373 focused
->getWorkspaceNumber() == current_workspace
->getID());
1375 current_workspace
->setLastFocusedWindow(focused
);
1377 // if no window had focus, no need to store a last focus
1378 current_workspace
->setLastFocusedWindow((BlackboxWindow
*) 0);
1381 // when we switch workspaces, unfocus whatever was focused if it is going
1383 if (focused
&& ! focused
->isStuck())
1384 blackbox
->setFocusedWindow((BlackboxWindow
*) 0);
1386 current_workspace
->hideAll();
1387 workspacemenu
->setItemSelected(current_workspace
->getID() + 2, False
);
1389 current_workspace
= getWorkspace(id
);
1391 xatom
->setValue(getRootWindow(), XAtom::net_current_desktop
,
1392 XAtom::cardinal
, id
);
1394 workspacemenu
->setItemSelected(current_workspace
->getID() + 2, True
);
1395 toolbar
->redrawWorkspaceLabel(True
);
1397 current_workspace
->showAll();
1402 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
1405 XSync(blackbox
->getXDisplay(), False
);
1407 // If sloppy focus and we can find the client window under the pointer,
1409 if (resource
.sloppy_focus
&&
1410 XQueryPointer(blackbox
->getXDisplay(), getRootWindow(), &r
, &c
,
1411 &rx
, &ry
, &x
, &y
, &m
) &&
1413 if ( (win
= blackbox
->searchWindow(c
)) )
1414 f
= win
->setInputFocus();
1417 // If that fails, and we're doing focus_last, try to focus the last window.
1418 if (! f
&& resource
.focus_last
&&
1419 (win
= current_workspace
->getLastFocusedWindow()))
1420 f
= win
->setInputFocus();
1423 if we found a focus target, then we set the focused window explicitly
1424 because it is possible to switch off this workspace before the x server
1425 generates the FocusIn event for the window. if that happens, openbox would
1426 lose track of what window was the 'LastFocused' window on the workspace.
1428 if we did not find a focus target, then set the current focused window to
1432 blackbox
->setFocusedWindow(win
);
1434 blackbox
->setFocusedWindow((BlackboxWindow
*) 0);
1436 updateNetizenCurrentWorkspace();
1441 * Set the _NET_CLIENT_LIST root window property.
1443 void BScreen::updateClientList(void) {
1444 if (windowList
.size() > 0) {
1445 Window
*windows
= new Window
[windowList
.size()];
1446 Window
*win_it
= windows
;
1447 BlackboxWindowList::iterator it
= windowList
.begin();
1448 const BlackboxWindowList::iterator end
= windowList
.end();
1449 for (; it
!= end
; ++it
, ++win_it
)
1450 *win_it
= (*it
)->getClientWindow();
1451 xatom
->setValue(getRootWindow(), XAtom::net_client_list
, XAtom::window
,
1452 windows
, windowList
.size());
1455 xatom
->setValue(getRootWindow(), XAtom::net_client_list
, XAtom::window
,
1458 updateStackingList();
1463 * Set the _NET_CLIENT_LIST_STACKING root window property.
1465 void BScreen::updateStackingList(void) {
1467 BlackboxWindowList stack_order
;
1470 * Get the stacking order from all of the workspaces.
1471 * We start with the current workspace so that the sticky windows will be
1472 * in the right order on the current workspace.
1473 * XXX: Do we need to have sticky windows in the list once for each workspace?
1475 getCurrentWorkspace()->appendStackOrder(stack_order
);
1476 for (unsigned int i
= 0; i
< getWorkspaceCount(); ++i
)
1477 if (i
!= getCurrentWorkspaceID())
1478 getWorkspace(i
)->appendStackOrder(stack_order
);
1480 if (stack_order
.size() > 0) {
1481 // set the client list atoms
1482 Window
*windows
= new Window
[stack_order
.size()];
1483 Window
*win_it
= windows
;
1484 BlackboxWindowList::iterator it
= stack_order
.begin(),
1485 end
= stack_order
.end();
1486 for (; it
!= end
; ++it
, ++win_it
)
1487 *win_it
= (*it
)->getClientWindow();
1488 xatom
->setValue(getRootWindow(), XAtom::net_client_list_stacking
,
1489 XAtom::window
, windows
, stack_order
.size());
1492 xatom
->setValue(getRootWindow(), XAtom::net_client_list_stacking
,
1493 XAtom::window
, 0, 0);
1497 void BScreen::addSystrayWindow(Window window
) {
1498 XGrabServer(blackbox
->getXDisplay());
1500 XSelectInput(blackbox
->getXDisplay(), window
, StructureNotifyMask
);
1501 systrayWindowList
.push_back(window
);
1502 xatom
->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows
,
1504 &systrayWindowList
[0], systrayWindowList
.size());
1505 blackbox
->saveSystrayWindowSearch(window
, this);
1507 XUngrabServer(blackbox
->getXDisplay());
1511 void BScreen::removeSystrayWindow(Window window
) {
1512 XGrabServer(blackbox
->getXDisplay());
1514 WindowList::iterator it
= systrayWindowList
.begin();
1515 const WindowList::iterator end
= systrayWindowList
.end();
1516 for (; it
!= end
; ++it
)
1517 if (*it
== window
) {
1518 systrayWindowList
.erase(it
);
1519 xatom
->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows
,
1521 &systrayWindowList
[0], systrayWindowList
.size());
1522 blackbox
->removeSystrayWindowSearch(window
);
1523 XSelectInput(blackbox
->getXDisplay(), window
, NoEventMask
);
1527 assert(it
!= end
); // not a systray window
1529 XUngrabServer(blackbox
->getXDisplay());
1533 void BScreen::manageWindow(Window w
) {
1534 // is the window a KDE systray window?
1536 if (xatom
->getValue(w
, XAtom::kde_net_wm_system_tray_window_for
,
1537 XAtom::window
, systray
) && systray
!= None
) {
1538 addSystrayWindow(w
);
1542 // is the window a docking app
1543 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), w
);
1544 if (wmhint
&& (wmhint
->flags
& StateHint
) &&
1545 wmhint
->initial_state
== WithdrawnState
) {
1550 new BlackboxWindow(blackbox
, w
, this);
1552 BlackboxWindow
*win
= blackbox
->searchWindow(w
);
1556 if (win
->isDesktop()) {
1557 desktopWindowList
.push_back(win
->getFrameWindow());
1558 } else { // if (win->isNormal()) {
1559 // don't list desktop windows as managed windows
1560 windowList
.push_back(win
);
1563 if (win
->isTopmost())
1564 specialWindowList
.push_back(win
->getFrameWindow());
1567 XMapRequestEvent mre
;
1569 if (blackbox
->isStartup() && win
->isNormal()) win
->restoreAttributes();
1570 win
->mapRequestEvent(&mre
);
1574 void BScreen::unmanageWindow(BlackboxWindow
*w
, bool remap
) {
1575 // is the window a KDE systray window?
1577 if (xatom
->getValue(w
->getClientWindow(),
1578 XAtom::kde_net_wm_system_tray_window_for
,
1579 XAtom::window
, systray
) && systray
!= None
) {
1580 removeSystrayWindow(w
->getClientWindow());
1586 // Remove the modality so that its parent won't try to re-focus the window
1587 if (w
->isModal()) w
->setModal(False
);
1589 if (w
->getWorkspaceNumber() != BSENTINEL
&&
1590 w
->getWindowNumber() != BSENTINEL
) {
1591 getWorkspace(w
->getWorkspaceNumber())->removeWindow(w
);
1593 for (unsigned int i
= 0; i
< getNumberOfWorkspaces(); ++i
)
1594 if (i
!= w
->getWorkspaceNumber())
1595 getWorkspace(i
)->removeWindow(w
, True
);
1597 } else if (w
->isIconic())
1600 if (w
->isDesktop()) {
1601 WindowList::iterator it
= desktopWindowList
.begin();
1602 const WindowList::iterator end
= desktopWindowList
.end();
1603 for (; it
!= end
; ++it
)
1604 if (*it
== w
->getFrameWindow()) {
1605 desktopWindowList
.erase(it
);
1608 assert(it
!= end
); // the window wasnt a desktop window?
1609 } else { // if (w->isNormal()) {
1610 // we don't list desktop windows as managed windows
1611 windowList
.remove(w
);
1614 if (w
->isTopmost()) {
1615 WindowList::iterator it
= specialWindowList
.begin();
1616 const WindowList::iterator end
= specialWindowList
.end();
1617 for (; it
!= end
; ++it
)
1618 if (*it
== w
->getFrameWindow()) {
1619 specialWindowList
.erase(it
);
1622 assert(it
!= end
); // the window wasnt a special window?
1626 if (blackbox
->getFocusedWindow() == w
)
1627 blackbox
->setFocusedWindow((BlackboxWindow
*) 0);
1629 removeNetizen(w
->getClientWindow());
1632 some managed windows can also be window group controllers. when
1633 unmanaging such windows, we should also delete the window group.
1635 BWindowGroup
*group
= blackbox
->searchGroup(w
->getClientWindow());
1642 void BScreen::addNetizen(Netizen
*n
) {
1643 netizenList
.push_back(n
);
1645 n
->sendWorkspaceCount();
1646 n
->sendCurrentWorkspace();
1648 WorkspaceList::iterator it
= workspacesList
.begin();
1649 const WorkspaceList::iterator end
= workspacesList
.end();
1650 for (; it
!= end
; ++it
)
1651 (*it
)->sendWindowList(*n
);
1653 Window f
= ((blackbox
->getFocusedWindow()) ?
1654 blackbox
->getFocusedWindow()->getClientWindow() : None
);
1655 n
->sendWindowFocus(f
);
1659 void BScreen::removeNetizen(Window w
) {
1660 NetizenList::iterator it
= netizenList
.begin();
1661 for (; it
!= netizenList
.end(); ++it
) {
1662 if ((*it
)->getWindowID() == w
) {
1664 netizenList
.erase(it
);
1671 void BScreen::updateWorkArea(void) {
1672 if (workspacesList
.size() > 0) {
1673 unsigned long *dims
= new unsigned long[4 * workspacesList
.size()];
1674 for (unsigned int i
= 0, m
= workspacesList
.size(); i
< m
; ++i
) {
1675 // XXX: this could be different for each workspace
1676 const Rect
&area
= availableArea();
1677 dims
[(i
* 4) + 0] = area
.x();
1678 dims
[(i
* 4) + 1] = area
.y();
1679 dims
[(i
* 4) + 2] = area
.width();
1680 dims
[(i
* 4) + 3] = area
.height();
1682 xatom
->setValue(getRootWindow(), XAtom::net_workarea
, XAtom::cardinal
,
1683 dims
, 4 * workspacesList
.size());
1686 xatom
->setValue(getRootWindow(), XAtom::net_workarea
, XAtom::cardinal
,
1691 void BScreen::updateNetizenCurrentWorkspace(void) {
1692 std::for_each(netizenList
.begin(), netizenList
.end(),
1693 std::mem_fun(&Netizen::sendCurrentWorkspace
));
1697 void BScreen::updateNetizenWorkspaceCount(void) {
1698 xatom
->setValue(getRootWindow(), XAtom::net_number_of_desktops
,
1699 XAtom::cardinal
, workspacesList
.size());
1703 std::for_each(netizenList
.begin(), netizenList
.end(),
1704 std::mem_fun(&Netizen::sendWorkspaceCount
));
1708 void BScreen::updateNetizenWindowFocus(void) {
1709 Window f
= ((blackbox
->getFocusedWindow()) ?
1710 blackbox
->getFocusedWindow()->getClientWindow() : None
);
1712 xatom
->setValue(getRootWindow(), XAtom::net_active_window
,
1715 NetizenList::iterator it
= netizenList
.begin();
1716 for (; it
!= netizenList
.end(); ++it
)
1717 (*it
)->sendWindowFocus(f
);
1721 void BScreen::updateNetizenWindowAdd(Window w
, unsigned long p
) {
1722 NetizenList::iterator it
= netizenList
.begin();
1723 for (; it
!= netizenList
.end(); ++it
) {
1724 (*it
)->sendWindowAdd(w
, p
);
1729 void BScreen::updateNetizenWindowDel(Window w
) {
1730 NetizenList::iterator it
= netizenList
.begin();
1731 for (; it
!= netizenList
.end(); ++it
)
1732 (*it
)->sendWindowDel(w
);
1736 void BScreen::updateNetizenWindowRaise(Window w
) {
1737 NetizenList::iterator it
= netizenList
.begin();
1738 for (; it
!= netizenList
.end(); ++it
)
1739 (*it
)->sendWindowRaise(w
);
1743 void BScreen::updateNetizenWindowLower(Window w
) {
1744 NetizenList::iterator it
= netizenList
.begin();
1745 for (; it
!= netizenList
.end(); ++it
)
1746 (*it
)->sendWindowLower(w
);
1750 void BScreen::updateNetizenConfigNotify(XEvent
*e
) {
1751 NetizenList::iterator it
= netizenList
.begin();
1752 for (; it
!= netizenList
.end(); ++it
)
1753 (*it
)->sendConfigNotify(e
);
1757 void BScreen::raiseWindows(Window
*workspace_stack
, unsigned int num
) {
1758 // the 13 represents the number of blackbox windows such as menus
1767 Window
*session_stack
= new
1768 Window
[(num
+ workspacesList
.size() + rootmenuList
.size() +
1769 specialWindowList
.size() + bbwins
)];
1770 unsigned int i
= 0, k
= num
;
1772 XRaiseWindow(blackbox
->getXDisplay(), iconmenu
->getWindowID());
1773 *(session_stack
+ i
++) = iconmenu
->getWindowID();
1775 WorkspaceList::iterator wit
= workspacesList
.begin();
1776 const WorkspaceList::iterator w_end
= workspacesList
.end();
1777 for (; wit
!= w_end
; ++wit
)
1778 *(session_stack
+ i
++) = (*wit
)->getMenu()->getWindowID();
1780 *(session_stack
+ i
++) = workspacemenu
->getWindowID();
1782 *(session_stack
+ i
++) = configmenu
->getFocusmenu()->getWindowID();
1783 *(session_stack
+ i
++) = configmenu
->getPlacementmenu()->getWindowID();
1784 *(session_stack
+ i
++) = configmenu
->getWindowSnapmenu()->getWindowID();
1785 *(session_stack
+ i
++) = configmenu
->getEdgeSnapmenu()->getWindowID();
1787 *(session_stack
+ i
++) = configmenu
->getXineramamenu()->getWindowID();
1790 *(session_stack
+ i
++) = configmenu
->getXftmenu()->getWindowID();
1792 *(session_stack
+ i
++) = configmenu
->getWindowID();
1794 *(session_stack
+ i
++) = slit
->getMenu()->getDirectionmenu()->getWindowID();
1795 *(session_stack
+ i
++) = slit
->getMenu()->getPlacementmenu()->getWindowID();
1796 *(session_stack
+ i
++) = slit
->getMenu()->getWindowID();
1798 *(session_stack
+ i
++) =
1799 toolbar
->getMenu()->getPlacementmenu()->getWindowID();
1800 *(session_stack
+ i
++) = toolbar
->getMenu()->getWindowID();
1802 RootmenuList::iterator rit
= rootmenuList
.begin();
1803 for (; rit
!= rootmenuList
.end(); ++rit
)
1804 *(session_stack
+ i
++) = (*rit
)->getWindowID();
1805 *(session_stack
+ i
++) = rootmenu
->getWindowID();
1807 if (toolbar
->isOnTop())
1808 *(session_stack
+ i
++) = toolbar
->getWindowID();
1810 if (slit
->isOnTop())
1811 *(session_stack
+ i
++) = slit
->getWindowID();
1813 WindowList::iterator sit
, send
= specialWindowList
.end();
1814 for (sit
= specialWindowList
.begin(); sit
!= send
; ++sit
)
1815 *(session_stack
+ i
++) = *sit
;
1818 *(session_stack
+ i
++) = *(workspace_stack
+ k
);
1820 XRestackWindows(blackbox
->getXDisplay(), session_stack
, i
);
1822 delete [] session_stack
;
1824 updateStackingList();
1828 void BScreen::lowerWindows(Window
*workspace_stack
, unsigned int num
) {
1829 assert(num
> 0); // this would cause trouble in the XRaiseWindow call
1831 Window
*session_stack
= new Window
[(num
+ desktopWindowList
.size())];
1832 unsigned int i
= 0, k
= num
;
1834 XLowerWindow(blackbox
->getXDisplay(), workspace_stack
[0]);
1837 *(session_stack
+ i
++) = *(workspace_stack
+ k
);
1839 WindowList::iterator dit
= desktopWindowList
.begin();
1840 const WindowList::iterator d_end
= desktopWindowList
.end();
1841 for (; dit
!= d_end
; ++dit
)
1842 *(session_stack
+ i
++) = *dit
;
1844 XRestackWindows(blackbox
->getXDisplay(), session_stack
, i
);
1846 delete [] session_stack
;
1848 updateStackingList();
1852 void BScreen::reassociateWindow(BlackboxWindow
*w
, unsigned int wkspc_id
,
1853 bool ignore_sticky
) {
1856 if (wkspc_id
== BSENTINEL
)
1857 wkspc_id
= current_workspace
->getID();
1859 if (w
->getWorkspaceNumber() == wkspc_id
)
1862 if (w
->isIconic()) {
1864 getWorkspace(wkspc_id
)->addWindow(w
);
1866 for (unsigned int i
= 0; i
< getNumberOfWorkspaces(); ++i
)
1867 if (i
!= w
->getWorkspaceNumber())
1868 getWorkspace(i
)->addWindow(w
, True
);
1869 } else if (ignore_sticky
|| ! w
->isStuck()) {
1872 getWorkspace(w
->getWorkspaceNumber())->removeWindow(w
);
1873 getWorkspace(wkspc_id
)->addWindow(w
);
1875 updateStackingList();
1879 void BScreen::propagateWindowName(const BlackboxWindow
*bw
) {
1880 if (bw
->isIconic()) {
1881 iconmenu
->changeItemLabel(bw
->getWindowNumber(), bw
->getIconTitle());
1884 Clientmenu
*clientmenu
= getWorkspace(bw
->getWorkspaceNumber())->getMenu();
1885 clientmenu
->changeItemLabel(bw
->getWindowNumber(), bw
->getTitle());
1886 clientmenu
->update();
1888 if (blackbox
->getFocusedWindow() == bw
)
1889 toolbar
->redrawWindowLabel(True
);
1894 void BScreen::nextFocus(void) const {
1895 BlackboxWindow
*focused
= blackbox
->getFocusedWindow(),
1899 focused
->getScreen()->getScreenNumber() == getScreenNumber() &&
1900 current_workspace
->getCount() > 1) {
1902 next
= current_workspace
->getNextWindowInList(next
);
1903 } while (next
!= focused
&& ! next
->setInputFocus());
1905 if (next
!= focused
)
1906 current_workspace
->raiseWindow(next
);
1907 } else if (current_workspace
->getCount() > 0) {
1908 next
= current_workspace
->getTopWindowOnStack();
1909 next
->setInputFocus();
1910 current_workspace
->raiseWindow(next
);
1915 void BScreen::prevFocus(void) const {
1916 BlackboxWindow
*focused
= blackbox
->getFocusedWindow(),
1920 // if window is not on this screen, ignore it
1921 if (focused
->getScreen()->getScreenNumber() != getScreenNumber())
1922 focused
= (BlackboxWindow
*) 0;
1926 focused
->getScreen()->getScreenNumber() == getScreenNumber() &&
1927 current_workspace
->getCount() > 1) {
1928 // next is the next window to receive focus, current is a place holder
1930 next
= current_workspace
->getPrevWindowInList(next
);
1931 } while (next
!= focused
&& ! next
->setInputFocus());
1933 if (next
!= focused
)
1934 current_workspace
->raiseWindow(next
);
1935 } else if (current_workspace
->getCount() > 0) {
1936 next
= current_workspace
->getTopWindowOnStack();
1937 next
->setInputFocus();
1938 current_workspace
->raiseWindow(next
);
1943 void BScreen::raiseFocus(void) const {
1944 BlackboxWindow
*focused
= blackbox
->getFocusedWindow();
1948 // if on this Screen, raise it
1949 if (focused
->getScreen()->getScreenNumber() == getScreenNumber()) {
1950 Workspace
*workspace
= getWorkspace(focused
->getWorkspaceNumber());
1951 workspace
->raiseWindow(focused
);
1956 void BScreen::InitMenu(void) {
1958 rootmenuList
.clear();
1960 while (rootmenu
->getCount())
1961 rootmenu
->remove(0);
1963 rootmenu
= new Rootmenu(this);
1965 bool defaultMenu
= True
;
1967 FILE *menu_file
= (FILE *) 0;
1968 const char *menu_filename
= blackbox
->getMenuFilename();
1971 if (! (menu_file
= fopen(menu_filename
, "r")))
1972 perror(menu_filename
);
1973 if (! menu_file
) { // opening the menu file failed, try the default menu
1974 menu_filename
= DEFAULTMENU
;
1975 if (! (menu_file
= fopen(menu_filename
, "r")))
1976 perror(menu_filename
);
1980 if (feof(menu_file
)) {
1981 fprintf(stderr
, i18n(ScreenSet
, ScreenEmptyMenuFile
,
1982 "%s: Empty menu file"),
1985 char line
[1024], label
[1024];
1986 memset(line
, 0, 1024);
1987 memset(label
, 0, 1024);
1989 while (fgets(line
, 1024, menu_file
) && ! feof(menu_file
)) {
1993 int i
, key
= 0, index
= -1, len
= strlen(line
);
1995 for (i
= 0; i
< len
; i
++) {
1996 if (line
[i
] == '[') index
= 0;
1997 else if (line
[i
] == ']') break;
1998 else if (line
[i
] != ' ')
2000 key
+= tolower(line
[i
]);
2003 if (key
== 517) { // [begin]
2005 for (i
= index
; i
< len
; i
++) {
2006 if (line
[i
] == '(') index
= 0;
2007 else if (line
[i
] == ')') break;
2008 else if (index
++ >= 0) {
2009 if (line
[i
] == '\\' && i
< len
- 1) i
++;
2010 label
[index
- 1] = line
[i
];
2014 if (index
== -1) index
= 0;
2015 label
[index
] = '\0';
2017 rootmenu
->setLabel(label
);
2018 defaultMenu
= parseMenuFile(menu_file
, rootmenu
);
2020 blackbox
->addMenuTimestamp(menu_filename
);
2029 rootmenu
->setInternalMenu();
2030 rootmenu
->insert(i18n(ScreenSet
, Screenxterm
, "xterm"),
2032 i18n(ScreenSet
, Screenxterm
, "xterm"));
2033 rootmenu
->insert(i18n(ScreenSet
, ScreenRestart
, "Restart"),
2035 rootmenu
->insert(i18n(ScreenSet
, ScreenExit
, "Exit"),
2037 rootmenu
->setLabel(i18n(BasemenuSet
, BasemenuBlackboxMenu
,
2044 size_t string_within(char begin
, char end
,
2045 const char *input
, size_t start_at
, size_t length
,
2049 size_t i
= start_at
;
2050 for (; i
< length
; ++i
) {
2051 if (input
[i
] == begin
) {
2053 } else if (input
[i
] == end
) {
2056 if (input
[i
] == '\\' && i
< length
- 1) i
++;
2057 output
[index
++] = input
[i
];
2062 output
[index
] = '\0';
2070 bool BScreen::parseMenuFile(FILE *file
, Rootmenu
*menu
) {
2071 char line
[1024], keyword
[1024], label
[1024], command
[1024];
2074 while (! (done
|| feof(file
))) {
2075 memset(line
, 0, 1024);
2076 memset(label
, 0, 1024);
2077 memset(command
, 0, 1024);
2079 if (! fgets(line
, 1024, file
))
2082 if (line
[0] == '#') // comment, skip it
2085 size_t line_length
= strlen(line
);
2086 unsigned int key
= 0;
2088 // get the keyword enclosed in []'s
2089 size_t pos
= string_within('[', ']', line
, 0, line_length
, keyword
);
2091 if (keyword
[0] == '\0') { // no keyword, no menu entry
2094 size_t len
= strlen(keyword
);
2095 for (size_t i
= 0; i
< len
; ++i
) {
2096 if (keyword
[i
] != ' ')
2097 key
+= tolower(keyword
[i
]);
2101 // get the label enclosed in ()'s
2102 pos
= string_within('(', ')', line
, pos
, line_length
, label
);
2104 // get the command enclosed in {}'s
2105 pos
= string_within('{', '}', line
, pos
, line_length
, command
);
2116 menu
->insert(label
);
2121 if (! (*label
&& *command
)) {
2122 fprintf(stderr
, i18n(ScreenSet
, ScreenEXECError
,
2123 "BScreen::parseMenuFile: [exec] error, "
2124 "no menu label and/or command defined\n"));
2128 menu
->insert(label
, BScreen::Execute
, command
);
2134 fprintf(stderr
, i18n(ScreenSet
, ScreenEXITError
,
2135 "BScreen::parseMenuFile: [exit] error, "
2136 "no menu label defined\n"));
2140 menu
->insert(label
, BScreen::Exit
);
2144 case 561: { // style
2145 if (! (*label
&& *command
)) {
2147 i18n(ScreenSet
, ScreenSTYLEError
,
2148 "BScreen::parseMenuFile: [style] error, "
2149 "no menu label and/or filename defined\n"));
2153 string style
= expandTilde(command
);
2155 menu
->insert(label
, BScreen::SetStyle
, style
.c_str());
2161 fprintf(stderr
, i18n(ScreenSet
, ScreenCONFIGError
,
2162 "BScreen::parseMenufile: [config] error, "
2163 "no label defined"));
2167 menu
->insert(label
, configmenu
);
2171 case 740: { // include
2173 fprintf(stderr
, i18n(ScreenSet
, ScreenINCLUDEError
,
2174 "BScreen::parseMenuFile: [include] error, "
2175 "no filename defined\n"));
2179 string newfile
= expandTilde(label
);
2180 FILE *submenufile
= fopen(newfile
.c_str(), "r");
2182 if (! submenufile
) {
2183 perror(newfile
.c_str());
2188 if (fstat(fileno(submenufile
), &buf
) ||
2189 ! S_ISREG(buf
.st_mode
)) {
2191 i18n(ScreenSet
, ScreenINCLUDEErrorReg
,
2192 "BScreen::parseMenuFile: [include] error: "
2193 "'%s' is not a regular file\n"), newfile
.c_str());
2197 if (! feof(submenufile
)) {
2198 if (! parseMenuFile(submenufile
, menu
))
2199 blackbox
->addMenuTimestamp(newfile
);
2201 fclose(submenufile
);
2207 case 767: { // submenu
2209 fprintf(stderr
, i18n(ScreenSet
, ScreenSUBMENUError
,
2210 "BScreen::parseMenuFile: [submenu] error, "
2211 "no menu label defined\n"));
2215 Rootmenu
*submenu
= new Rootmenu(this);
2218 submenu
->setLabel(command
);
2220 submenu
->setLabel(label
);
2222 parseMenuFile(file
, submenu
);
2224 menu
->insert(label
, submenu
);
2225 rootmenuList
.push_back(submenu
);
2230 case 773: { // restart
2232 fprintf(stderr
, i18n(ScreenSet
, ScreenRESTARTError
,
2233 "BScreen::parseMenuFile: [restart] error, "
2234 "no menu label defined\n"));
2239 menu
->insert(label
, BScreen::RestartOther
, command
);
2241 menu
->insert(label
, BScreen::Restart
);
2246 case 845: { // reconfig
2249 i18n(ScreenSet
, ScreenRECONFIGError
,
2250 "BScreen::parseMenuFile: [reconfig] error, "
2251 "no menu label defined\n"));
2255 menu
->insert(label
, BScreen::Reconfigure
);
2260 case 995: // stylesdir
2261 case 1113: { // stylesmenu
2262 bool newmenu
= ((key
== 1113) ? True
: False
);
2264 if (! *label
|| (! *command
&& newmenu
)) {
2266 i18n(ScreenSet
, ScreenSTYLESDIRError
,
2267 "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2268 " error, no directory defined\n"));
2272 char *directory
= ((newmenu
) ? command
: label
);
2274 string stylesdir
= expandTilde(directory
);
2276 struct stat statbuf
;
2278 if (stat(stylesdir
.c_str(), &statbuf
) == -1) {
2280 i18n(ScreenSet
, ScreenSTYLESDIRErrorNoExist
,
2281 "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
2282 " error, %s does not exist\n"), stylesdir
.c_str());
2285 if (! S_ISDIR(statbuf
.st_mode
)) {
2287 i18n(ScreenSet
, ScreenSTYLESDIRErrorNotDir
,
2288 "BScreen::parseMenuFile:"
2289 " [stylesdir/stylesmenu] error, %s is not a"
2290 " directory\n"), stylesdir
.c_str());
2294 Rootmenu
*stylesmenu
;
2297 stylesmenu
= new Rootmenu(this);
2301 DIR *d
= opendir(stylesdir
.c_str());
2303 std::vector
<string
> ls
;
2305 while((p
= readdir(d
)))
2306 ls
.push_back(p
->d_name
);
2310 std::sort(ls
.begin(), ls
.end());
2312 std::vector
<string
>::iterator it
= ls
.begin(),
2314 for (; it
!= end
; ++it
) {
2315 const string
& fname
= *it
;
2317 if (fname
[fname
.size()-1] == '~')
2320 string style
= stylesdir
;
2324 if (! stat(style
.c_str(), &statbuf
) && S_ISREG(statbuf
.st_mode
))
2325 stylesmenu
->insert(fname
, BScreen::SetStyle
, style
);
2328 stylesmenu
->update();
2331 stylesmenu
->setLabel(label
);
2332 menu
->insert(label
, stylesmenu
);
2333 rootmenuList
.push_back(stylesmenu
);
2336 blackbox
->addMenuTimestamp(stylesdir
);
2340 case 1090: { // workspaces
2343 i18n(ScreenSet
, ScreenWORKSPACESError
,
2344 "BScreen:parseMenuFile: [workspaces] error, "
2345 "no menu label defined\n"));
2349 menu
->insert(label
, workspacemenu
);
2355 return ((menu
->getCount() == 0) ? True
: False
);
2359 void BScreen::shutdown(void) {
2360 XSelectInput(blackbox
->getXDisplay(), getRootWindow(), NoEventMask
);
2361 XSync(blackbox
->getXDisplay(), False
);
2363 while(! windowList
.empty())
2364 unmanageWindow(windowList
.front(), True
);
2366 while(! desktopWindowList
.empty()) {
2367 BlackboxWindow
*win
= blackbox
->searchWindow(desktopWindowList
.front());
2369 unmanageWindow(win
, True
);
2376 void BScreen::showPosition(int x
, int y
) {
2377 if (! geom_visible
) {
2378 XMoveResizeWindow(blackbox
->getXDisplay(), geom_window
,
2379 (getWidth() - geom_w
) / 2,
2380 (getHeight() - geom_h
) / 2, geom_w
, geom_h
);
2381 XMapWindow(blackbox
->getXDisplay(), geom_window
);
2382 XRaiseWindow(blackbox
->getXDisplay(), geom_window
);
2384 geom_visible
= True
;
2389 sprintf(label
, i18n(ScreenSet
, ScreenPositionFormat
,
2390 "X: %4d x Y: %4d"), x
, y
);
2392 XClearWindow(blackbox
->getXDisplay(), geom_window
);
2394 resource
.wstyle
.font
->drawString(geom_window
,
2395 resource
.bevel_width
, resource
.bevel_width
,
2396 resource
.wstyle
.l_text_focus
,
2401 void BScreen::showGeometry(unsigned int gx
, unsigned int gy
) {
2402 if (! geom_visible
) {
2403 XMoveResizeWindow(blackbox
->getXDisplay(), geom_window
,
2404 (getWidth() - geom_w
) / 2,
2405 (getHeight() - geom_h
) / 2, geom_w
, geom_h
);
2406 XMapWindow(blackbox
->getXDisplay(), geom_window
);
2407 XRaiseWindow(blackbox
->getXDisplay(), geom_window
);
2409 geom_visible
= True
;
2414 sprintf(label
, i18n(ScreenSet
, ScreenGeometryFormat
,
2415 "W: %4d x H: %4d"), gx
, gy
);
2417 XClearWindow(blackbox
->getXDisplay(), geom_window
);
2419 resource
.wstyle
.font
->drawString(geom_window
,
2420 resource
.bevel_width
, resource
.bevel_width
,
2421 resource
.wstyle
.l_text_focus
,
2426 void BScreen::hideGeometry(void) {
2428 XUnmapWindow(blackbox
->getXDisplay(), geom_window
);
2429 geom_visible
= False
;
2434 void BScreen::addStrut(Strut
*strut
) {
2435 strutList
.push_back(strut
);
2439 void BScreen::removeStrut(Strut
*strut
) {
2440 strutList
.remove(strut
);
2444 const Rect
& BScreen::availableArea(void) const {
2446 return getRect(); // return the full screen
2452 const RectList
& BScreen::allAvailableAreas(void) const {
2453 assert(isXineramaActive());
2454 assert(xineramaUsableArea
.size() > 0);
2455 fprintf(stderr
, "1found x %d y %d w %d h %d\n",
2456 xineramaUsableArea
[0].x(), xineramaUsableArea
[0].y(),
2457 xineramaUsableArea
[0].width(), xineramaUsableArea
[0].height());
2458 return xineramaUsableArea
;
2463 void BScreen::updateAvailableArea(void) {
2464 Rect old_area
= usableArea
;
2465 usableArea
= getRect(); // reset to full screen
2468 // reset to the full areas
2469 if (isXineramaActive())
2470 xineramaUsableArea
= getXineramaAreas();
2473 /* these values represent offsets from the screen edge
2474 * we look for the biggest offset on each edge and then apply them
2476 * do not be confused by the similarity to the names of Rect's members
2478 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
2481 StrutList::const_iterator it
= strutList
.begin(), end
= strutList
.end();
2483 for(; it
!= end
; ++it
) {
2485 if (strut
->left
> current_left
)
2486 current_left
= strut
->left
;
2487 if (strut
->top
> current_top
)
2488 current_top
= strut
->top
;
2489 if (strut
->right
> current_right
)
2490 current_right
= strut
->right
;
2491 if (strut
->bottom
> current_bottom
)
2492 current_bottom
= strut
->bottom
;
2495 usableArea
.setPos(current_left
, current_top
);
2496 usableArea
.setSize(usableArea
.width() - (current_left
+ current_right
),
2497 usableArea
.height() - (current_top
+ current_bottom
));
2500 if (isXineramaActive()) {
2501 // keep each of the ximerama-defined areas inside the strut
2502 RectList::iterator xit
, xend
= xineramaUsableArea
.end();
2503 for (xit
= xineramaUsableArea
.begin(); xit
!= xend
; ++xit
) {
2504 if (xit
->x() < usableArea
.x()) {
2505 xit
->setX(usableArea
.x());
2506 xit
->setWidth(xit
->width() - usableArea
.x());
2508 if (xit
->y() < usableArea
.y()) {
2509 xit
->setY(usableArea
.y());
2510 xit
->setHeight(xit
->height() - usableArea
.y());
2512 if (xit
->x() + xit
->width() > usableArea
.width())
2513 xit
->setWidth(usableArea
.width() - xit
->x());
2514 if (xit
->y() + xit
->height() > usableArea
.height())
2515 xit
->setHeight(usableArea
.height() - xit
->y());
2520 if (old_area
!= usableArea
) {
2521 BlackboxWindowList::iterator it
= windowList
.begin(),
2522 end
= windowList
.end();
2523 for (; it
!= end
; ++it
)
2524 if ((*it
)->isMaximized()) (*it
)->remaximize();
2531 Workspace
* BScreen::getWorkspace(unsigned int index
) const {
2532 assert(index
< workspacesList
.size());
2533 return workspacesList
[index
];
2537 void BScreen::buttonPressEvent(const XButtonEvent
*xbutton
) {
2538 if (xbutton
->button
== 1) {
2539 if (! isRootColormapInstalled())
2540 image_control
->installRootColormap();
2542 if (workspacemenu
->isVisible())
2543 workspacemenu
->hide();
2545 if (rootmenu
->isVisible())
2548 } else if ((xbutton
->button
== 4 && resource
.root_scroll
== NormalScroll
) ||
2549 (xbutton
->button
== 5 && resource
.root_scroll
== ReverseScroll
)) {
2550 if (getCurrentWorkspaceID() >= getWorkspaceCount() - 1)
2551 changeWorkspaceID(0);
2553 changeWorkspaceID(getCurrentWorkspaceID() + 1);
2555 } else if ((xbutton
->button
== 5 && resource
.root_scroll
== NormalScroll
) ||
2556 (xbutton
->button
== 4 && resource
.root_scroll
== ReverseScroll
)) {
2557 if (getCurrentWorkspaceID() == 0)
2558 changeWorkspaceID(getWorkspaceCount() - 1);
2560 changeWorkspaceID(getCurrentWorkspaceID() - 1);
2563 if (resource
.root_menu_button
> 0 &&
2564 xbutton
->button
== resource
.root_menu_button
)
2565 showRootMenu(xbutton
->x_root
, xbutton
->y_root
);
2566 else if (resource
.workspace_menu_button
> 0 &&
2567 xbutton
->button
== resource
.workspace_menu_button
)
2568 showWorkspaceMenu(xbutton
->x_root
, xbutton
->y_root
);
2572 void BScreen::showWorkspaceMenu(int x
, int y
) {
2573 int mx
= x
- (workspacemenu
->getWidth() / 2);
2574 int my
= y
- (workspacemenu
->getTitleHeight() / 2);
2579 if (mx
+ workspacemenu
->getWidth() > getWidth())
2580 mx
= getWidth() - workspacemenu
->getWidth() - getBorderWidth();
2582 if (my
+ workspacemenu
->getHeight() > getHeight())
2583 my
= getHeight() - workspacemenu
->getHeight() - getBorderWidth();
2585 workspacemenu
->move(mx
, my
);
2587 if (! workspacemenu
->isVisible()) {
2588 workspacemenu
->removeParent();
2589 workspacemenu
->show();
2594 void BScreen::showRootMenu(int x
, int y
) {
2595 int mx
= x
- (rootmenu
->getWidth() / 2);
2596 int my
= y
- (rootmenu
->getTitleHeight() / 2);
2601 if (mx
+ rootmenu
->getWidth() > getWidth())
2602 mx
= getWidth() - rootmenu
->getWidth() - getBorderWidth();
2604 if (my
+ rootmenu
->getHeight() > getHeight())
2605 my
= getHeight() - rootmenu
->getHeight() - getBorderWidth();
2607 rootmenu
->move(mx
, my
);
2609 if (! rootmenu
->isVisible()) {
2610 blackbox
->checkMenu();
2616 void BScreen::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2617 if (pe
->atom
== xatom
->getAtom(XAtom::net_desktop_names
)) {
2618 // _NET_WM_DESKTOP_NAMES
2619 WorkspaceList::iterator it
= workspacesList
.begin();
2620 const WorkspaceList::iterator end
= workspacesList
.end();
2621 for (; it
!= end
; ++it
) {
2622 (*it
)->readName(); // re-read its name from the window property
2623 workspacemenu
->changeWorkspaceLabel((*it
)->getID(), (*it
)->getName());
2625 workspacemenu
->update();
2626 toolbar
->reconfigure();
2627 saveWorkspaceNames();
2632 void BScreen::toggleFocusModel(FocusModel model
) {
2633 std::for_each(windowList
.begin(), windowList
.end(),
2634 std::mem_fun(&BlackboxWindow::ungrabButtons
));
2636 if (model
== SloppyFocus
) {
2637 saveSloppyFocus(True
);
2639 // we're cheating here to save writing the config file 3 times
2640 resource
.auto_raise
= False
;
2641 resource
.click_raise
= False
;
2642 saveSloppyFocus(False
);
2645 std::for_each(windowList
.begin(), windowList
.end(),
2646 std::mem_fun(&BlackboxWindow::grabButtons
));
2649 #ifdef BITMAPBUTTONS
2650 void BScreen::readDatabaseMask(const string
&rname
, PixmapMask
&pixmapMask
,
2651 const Configuration
&style
) {
2653 int hx
, hy
; //ignored
2654 int ret
= BitmapOpenFailed
; //default to failure.
2656 if (style
.getValue(rname
, s
))
2658 if (s
[0] != '/' && s
[0] != '~')
2660 std::string xbmFile
= std::string("~/.openbox/buttons/") + s
;
2661 ret
= XReadBitmapFile(blackbox
->getXDisplay(), getRootWindow(),
2662 expandTilde(xbmFile
).c_str(), &pixmapMask
.w
,
2663 &pixmapMask
.h
, &pixmapMask
.mask
, &hx
, &hy
);
2665 ret
= XReadBitmapFile(blackbox
->getXDisplay(), getRootWindow(),
2666 expandTilde(s
).c_str(), &pixmapMask
.w
,
2667 &pixmapMask
.h
, &pixmapMask
.mask
, &hx
, &hy
);
2669 if (ret
== BitmapSuccess
)
2673 pixmapMask
.mask
= None
;
2674 pixmapMask
.w
= pixmapMask
.h
= 0;
2676 #endif // BITMAPSUCCESS
2678 BTexture
BScreen::readDatabaseTexture(const string
&rname
,
2679 const string
&default_color
,
2680 const Configuration
&style
,
2681 bool allowNoTexture
) {
2685 if (style
.getValue(rname
, s
))
2686 texture
= BTexture(s
);
2687 else if (allowNoTexture
) //no default
2688 texture
.setTexture(BTexture::NoTexture
);
2690 texture
.setTexture(BTexture::Solid
| BTexture::Flat
);
2692 // associate this texture with this screen
2693 texture
.setDisplay(getBaseDisplay(), getScreenNumber());
2694 texture
.setImageControl(image_control
);
2696 if (texture
.texture() != BTexture::NoTexture
) {
2697 texture
.setColor(readDatabaseColor(rname
+ ".color", default_color
,
2699 texture
.setColorTo(readDatabaseColor(rname
+ ".colorTo", default_color
,
2701 texture
.setBorderColor(readDatabaseColor(rname
+ ".borderColor",
2702 default_color
, style
));
2709 BColor
BScreen::readDatabaseColor(const string
&rname
,
2710 const string
&default_color
,
2711 const Configuration
&style
) {
2714 if (style
.getValue(rname
, s
))
2715 color
= BColor(s
, getBaseDisplay(), getScreenNumber());
2717 color
= BColor(default_color
, getBaseDisplay(), getScreenNumber());
2722 BFont
*BScreen::readDatabaseFont(const string
&rbasename
,
2723 const Configuration
&style
) {
2730 if (style
.getValue(rbasename
+ "xft.font", s
) &&
2731 style
.getValue(rbasename
+ "xft.size", i
)) {
2734 bool italic
= False
;
2735 bool dropShadow
= False
;
2737 if (style
.getValue(rbasename
+ "xft.flags", s
)) {
2738 if (s
.find("bold") != string::npos
)
2740 if (s
.find("italic") != string::npos
)
2742 if (s
.find("shadow") != string::npos
)
2746 unsigned char offset
= 1;
2747 if (style
.getValue(rbasename
+ "xft.shadow.offset", s
)) {
2748 offset
= atoi(s
.c_str()); //doesn't detect errors
2749 if (offset
> CHAR_MAX
)
2753 unsigned char tint
= 0x40;
2754 if (style
.getValue(rbasename
+ "xft.shadow.tint", s
)) {
2755 tint
= atoi(s
.c_str());
2759 BFont
*b
= new BFont(blackbox
->getXDisplay(), this, family
, i
, bold
,
2760 italic
, dropShadow
&& resource
.shadow_fonts
, offset
,
2761 tint
, resource
.aa_fonts
);
2765 delete b
; // fall back to the normal X font stuff
2769 style
.getValue(rbasename
+ "font", s
);
2770 // if this fails, a blank string will be used, which will cause the fallback
2773 BFont
*b
= new BFont(blackbox
->getXDisplay(), this, s
);
2775 exit(2); // can't continue without a font