1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // blackbox.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
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #include <X11/cursorfont.h>
33 #include <X11/keysym.h>
36 #include <X11/extensions/shape.h>
41 #endif // HAVE_STDIO_H
45 #endif // HAVE_STDLIB_H
49 #endif // HAVE_STRING_H
52 # include <sys/types.h>
54 #endif // HAVE_UNISTD_H
56 #ifdef HAVE_SYS_PARAM_H
57 # include <sys/param.h>
58 #endif // HAVE_SYS_PARAM_H
60 #ifdef HAVE_SYS_SELECT_H
61 # include <sys/select.h>
62 #endif // HAVE_SYS_SELECT_H
66 #endif // HAVE_SIGNAL_H
68 #ifdef HAVE_SYS_SIGNAL_H
69 # include <sys/signal.h>
70 #endif // HAVE_SYS_SIGNAL_H
72 #ifdef HAVE_SYS_STAT_H
73 # include <sys/types.h>
74 # include <sys/stat.h>
75 #endif // HAVE_SYS_STAT_H
77 #ifdef TIME_WITH_SYS_TIME
78 # include <sys/time.h>
80 #else // !TIME_WITH_SYS_TIME
81 # ifdef HAVE_SYS_TIME_H
82 # include <sys/time.h>
83 # else // !HAVE_SYS_TIME_H
85 # endif // HAVE_SYS_TIME_H
86 #endif // TIME_WITH_SYS_TIME
90 #endif // HAVE_LIBGEN_H
98 #include "blackbox.hh"
99 #include "Basemenu.hh"
100 #include "Clientmenu.hh"
101 #include "GCCache.hh"
103 #include "Rootmenu.hh"
106 #include "Toolbar.hh"
109 #include "Workspace.hh"
110 #include "Workspacemenu.hh"
113 // X event scanner for enter/leave notifies - adapted from twm
116 bool leave
, inferior
, enter
;
119 static Bool
queueScanner(Display
*, XEvent
*e
, char *args
) {
120 scanargs
*scan
= (scanargs
*) args
;
121 if ((e
->type
== LeaveNotify
) &&
122 (e
->xcrossing
.window
== scan
->w
) &&
123 (e
->xcrossing
.mode
== NotifyNormal
)) {
125 scan
->inferior
= (e
->xcrossing
.detail
== NotifyInferior
);
126 } else if ((e
->type
== EnterNotify
) && (e
->xcrossing
.mode
== NotifyUngrab
)) {
136 Blackbox::Blackbox(char **m_argv
, char *dpy_name
, char *rc
, char *menu
)
137 : BaseDisplay(m_argv
[0], dpy_name
) {
138 if (! XSupportsLocale())
139 fprintf(stderr
, "X server does not support locale\n");
141 if (XSetLocaleModifiers("") == NULL
)
142 fprintf(stderr
, "cannot set locale modifiers\n");
146 if (! rc
) rc
= "~/.openbox/rc";
147 rc_file
= expandTilde(rc
);
148 config
.setFile(rc_file
);
149 if (! menu
) menu
= "~/.openbox/menu";
150 menu_file
= expandTilde(menu
);
154 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
= 0;
157 focused_window
= (BlackboxWindow
*) 0;
162 xatom
= new XAtom(this);
164 cursor
.session
= XCreateFontCursor(getXDisplay(), XC_left_ptr
);
165 cursor
.move
= XCreateFontCursor(getXDisplay(), XC_fleur
);
166 cursor
.ll_angle
= XCreateFontCursor(getXDisplay(), XC_ll_angle
);
167 cursor
.lr_angle
= XCreateFontCursor(getXDisplay(), XC_lr_angle
);
169 for (unsigned int i
= 0; i
< getNumberOfScreens(); i
++) {
170 BScreen
*screen
= new BScreen(this, i
);
172 if (! screen
->isScreenManaged()) {
177 screenList
.push_back(screen
);
180 if (screenList
.empty()) {
182 i18n(blackboxSet
, blackboxNoManagableScreens
,
183 "Blackbox::Blackbox: no managable screens found, aborting.\n"));
187 // save current settings and default values
190 // set the screen with mouse to the first managed screen
191 active_screen
= screenList
.front();
194 XSynchronize(getXDisplay(), False
);
195 XSync(getXDisplay(), False
);
197 reconfigure_wait
= reread_menu_wait
= False
;
199 timer
= new BTimer(this, this);
200 timer
->setTimeout(0l);
204 Blackbox::~Blackbox(void) {
205 std::for_each(screenList
.begin(), screenList
.end(), PointerAssassin());
207 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
216 void Blackbox::process_event(XEvent
*e
) {
219 // strip the lock key modifiers
220 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
222 last_time
= e
->xbutton
.time
;
224 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
225 Basemenu
*menu
= (Basemenu
*) 0;
226 Slit
*slit
= (Slit
*) 0;
227 Toolbar
*tbar
= (Toolbar
*) 0;
228 BScreen
*scrn
= (BScreen
*) 0;
230 if ((win
= searchWindow(e
->xbutton
.window
))) {
231 win
->buttonPressEvent(&e
->xbutton
);
233 /* XXX: is this sane on low colour desktops? */
234 if (e
->xbutton
.button
== 1)
235 win
->installColormap(True
);
236 } else if ((menu
= searchMenu(e
->xbutton
.window
))) {
237 menu
->buttonPressEvent(&e
->xbutton
);
238 } else if ((slit
= searchSlit(e
->xbutton
.window
))) {
239 slit
->buttonPressEvent(&e
->xbutton
);
240 } else if ((tbar
= searchToolbar(e
->xbutton
.window
))) {
241 tbar
->buttonPressEvent(&e
->xbutton
);
242 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
243 scrn
->buttonPressEvent(&e
->xbutton
);
244 if (active_screen
!= scrn
) {
245 active_screen
= scrn
;
246 // first, set no focus window on the old screen
248 // and move focus to this screen
255 case ButtonRelease
: {
256 // strip the lock key modifiers
257 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
259 last_time
= e
->xbutton
.time
;
261 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
262 Basemenu
*menu
= (Basemenu
*) 0;
263 Toolbar
*tbar
= (Toolbar
*) 0;
265 if ((win
= searchWindow(e
->xbutton
.window
)))
266 win
->buttonReleaseEvent(&e
->xbutton
);
267 else if ((menu
= searchMenu(e
->xbutton
.window
)))
268 menu
->buttonReleaseEvent(&e
->xbutton
);
269 else if ((tbar
= searchToolbar(e
->xbutton
.window
)))
270 tbar
->buttonReleaseEvent(&e
->xbutton
);
275 case ConfigureRequest
: {
276 // compress configure requests...
279 while(XCheckTypedWindowEvent(getXDisplay(), e
->xconfigurerequest
.window
,
280 ConfigureRequest
, &realevent
)) {
286 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
287 Slit
*slit
= (Slit
*) 0;
289 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
290 win
->configureRequestEvent(&e
->xconfigurerequest
);
291 } else if ((slit
= searchSlit(e
->xconfigurerequest
.window
))) {
292 slit
->configureRequestEvent(&e
->xconfigurerequest
);
294 if (validateWindow(e
->xconfigurerequest
.window
)) {
297 xwc
.x
= e
->xconfigurerequest
.x
;
298 xwc
.y
= e
->xconfigurerequest
.y
;
299 xwc
.width
= e
->xconfigurerequest
.width
;
300 xwc
.height
= e
->xconfigurerequest
.height
;
301 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
302 xwc
.sibling
= e
->xconfigurerequest
.above
;
303 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
305 XConfigureWindow(getXDisplay(), e
->xconfigurerequest
.window
,
306 e
->xconfigurerequest
.value_mask
, &xwc
);
315 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
316 e
->xmaprequest
.window
);
319 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
322 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
326 we got a map request for a window who's parent isn't root. this
327 can happen in only one circumstance:
329 a client window unmapped a managed window, and then remapped it
330 somewhere between unmapping the client window and reparenting it
333 regardless of how it happens, we need to find the screen that
336 XWindowAttributes wattrib
;
337 if (! XGetWindowAttributes(getXDisplay(), e
->xmaprequest
.window
,
339 // failed to get the window attributes, perhaps the window has
340 // now been destroyed?
344 screen
= searchScreen(wattrib
.root
);
345 assert(screen
!= 0); // this should never happen
348 screen
->manageWindow(e
->xmaprequest
.window
);
355 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
356 Slit
*slit
= (Slit
*) 0;
358 if ((win
= searchWindow(e
->xunmap
.window
))) {
359 win
->unmapNotifyEvent(&e
->xunmap
);
360 } else if ((slit
= searchSlit(e
->xunmap
.window
))) {
361 slit
->unmapNotifyEvent(&e
->xunmap
);
367 case DestroyNotify
: {
368 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
369 Slit
*slit
= (Slit
*) 0;
370 BWindowGroup
*group
= (BWindowGroup
*) 0;
372 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
373 win
->destroyNotifyEvent(&e
->xdestroywindow
);
374 } else if ((slit
= searchSlit(e
->xdestroywindow
.window
))) {
375 slit
->removeClient(e
->xdestroywindow
.window
, False
);
376 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
383 case ReparentNotify
: {
385 this event is quite rare and is usually handled in unmapNotify
386 however, if the window is unmapped when the reparent event occurs
387 the window manager never sees it because an unmap event is not sent
388 to an already unmapped window.
390 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
392 win
->reparentNotifyEvent(&e
->xreparent
);
394 Slit
*slit
= searchSlit(e
->xreparent
.window
);
395 if (slit
&& slit
->getWindowID() != e
->xreparent
.parent
)
396 slit
->removeClient(e
->xreparent
.window
, True
);
402 // motion notify compression...
405 while (XCheckTypedWindowEvent(getXDisplay(), e
->xmotion
.window
,
406 MotionNotify
, &realevent
)) {
410 // if we have compressed some motion events, use the last one
414 // strip the lock key modifiers
415 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
417 last_time
= e
->xmotion
.time
;
419 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
420 Basemenu
*menu
= (Basemenu
*) 0;
422 if ((win
= searchWindow(e
->xmotion
.window
)))
423 win
->motionNotifyEvent(&e
->xmotion
);
424 else if ((menu
= searchMenu(e
->xmotion
.window
)))
425 menu
->motionNotifyEvent(&e
->xmotion
);
430 case PropertyNotify
: {
431 last_time
= e
->xproperty
.time
;
433 if (e
->xproperty
.state
!= PropertyDelete
) {
434 BlackboxWindow
*win
= searchWindow(e
->xproperty
.window
);
437 win
->propertyNotifyEvent(e
->xproperty
.atom
);
444 last_time
= e
->xcrossing
.time
;
446 BScreen
*screen
= (BScreen
*) 0;
447 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
448 Basemenu
*menu
= (Basemenu
*) 0;
449 Toolbar
*tbar
= (Toolbar
*) 0;
450 Slit
*slit
= (Slit
*) 0;
452 if (e
->xcrossing
.mode
== NotifyGrab
) break;
456 sa
.w
= e
->xcrossing
.window
;
457 sa
.enter
= sa
.leave
= False
;
458 XCheckIfEvent(getXDisplay(), &dummy
, queueScanner
, (char *) &sa
);
460 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
461 (screen
= searchScreen(e
->xcrossing
.window
))) {
462 screen
->getImageControl()->installRootColormap();
463 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
464 if (win
->getScreen()->isSloppyFocus() &&
465 (! win
->isFocused()) && (! no_focus
)) {
466 if (((! sa
.leave
) || sa
.inferior
) && win
->isVisible()) {
467 if (win
->setInputFocus())
468 win
->installColormap(True
); // XXX: shouldnt we honour no install?
471 } else if ((menu
= searchMenu(e
->xcrossing
.window
))) {
472 menu
->enterNotifyEvent(&e
->xcrossing
);
473 } else if ((tbar
= searchToolbar(e
->xcrossing
.window
))) {
474 tbar
->enterNotifyEvent(&e
->xcrossing
);
475 } else if ((slit
= searchSlit(e
->xcrossing
.window
))) {
476 slit
->enterNotifyEvent(&e
->xcrossing
);
482 last_time
= e
->xcrossing
.time
;
484 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
485 Basemenu
*menu
= (Basemenu
*) 0;
486 Toolbar
*tbar
= (Toolbar
*) 0;
487 Slit
*slit
= (Slit
*) 0;
489 if ((menu
= searchMenu(e
->xcrossing
.window
)))
490 menu
->leaveNotifyEvent(&e
->xcrossing
);
491 else if ((win
= searchWindow(e
->xcrossing
.window
)))
492 win
->installColormap(False
);
493 else if ((tbar
= searchToolbar(e
->xcrossing
.window
)))
494 tbar
->leaveNotifyEvent(&e
->xcrossing
);
495 else if ((slit
= searchSlit(e
->xcrossing
.window
)))
496 slit
->leaveNotifyEvent(&e
->xcrossing
);
501 // compress expose events
504 int ex1
, ey1
, ex2
, ey2
;
507 ex2
= ex1
+ e
->xexpose
.width
- 1;
508 ey2
= ey1
+ e
->xexpose
.height
- 1;
509 while (XCheckTypedWindowEvent(getXDisplay(), e
->xexpose
.window
,
510 Expose
, &realevent
)) {
514 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
515 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
516 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
517 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
522 // use the merged area
525 e
->xexpose
.width
= ex2
- ex1
+ 1;
526 e
->xexpose
.height
= ey2
- ey1
+ 1;
528 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
529 Basemenu
*menu
= (Basemenu
*) 0;
530 Toolbar
*tbar
= (Toolbar
*) 0;
532 if ((win
= searchWindow(e
->xexpose
.window
)))
533 win
->exposeEvent(&e
->xexpose
);
534 else if ((menu
= searchMenu(e
->xexpose
.window
)))
535 menu
->exposeEvent(&e
->xexpose
);
536 else if ((tbar
= searchToolbar(e
->xexpose
.window
)))
537 tbar
->exposeEvent(&e
->xexpose
);
543 Toolbar
*tbar
= searchToolbar(e
->xkey
.window
);
545 if (tbar
&& tbar
->isEditing())
546 tbar
->keyPressEvent(&e
->xkey
);
551 case ColormapNotify
: {
552 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
555 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
556 ColormapInstalled
) ? True
: False
);
562 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
563 e
->xfocus
.detail
!= NotifyAncestor
) {
565 don't process FocusIns when:
566 1. the new focus window isn't an ancestor or inferior of the old
567 focus window (NotifyNonlinear)
568 make sure to allow the FocusIn when the old focus window was an
569 ancestor but didn't have a parent, such as root (NotifyAncestor)
574 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
576 if (! win
->isFocused())
577 win
->setFocusFlag(True
);
580 set the event window to None. when the FocusOut event handler calls
581 this function recursively, it uses this as an indication that focus
582 has moved to a known window.
584 e
->xfocus
.window
= None
;
591 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
593 don't process FocusOuts when:
594 2. the new focus window isn't an ancestor or inferior of the old
595 focus window (NotifyNonlinear)
600 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
601 if (win
&& win
->isFocused()) {
603 before we mark "win" as unfocused, we need to verify that focus is
604 going to a known location, is in a known location, or set focus
609 // don't check the current focus if FocusOut was generated during a grab
610 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
613 First, check if there is a pending FocusIn event waiting. if there
614 is, process it and determine if focus has moved to another window
615 (the FocusIn event handler sets the window in the event
616 structure to None to indicate this).
618 if (XCheckTypedEvent(getXDisplay(), FocusIn
, &event
)) {
620 process_event(&event
);
621 if (event
.xfocus
.window
== None
) {
629 Second, we query the X server for the current input focus.
630 to make sure that we keep a consistent state.
632 BlackboxWindow
*focus
;
635 XGetInputFocus(getXDisplay(), &w
, &revert
);
636 focus
= searchWindow(w
);
639 focus got from "win" to "focus" under some very strange
640 circumstances, and we need to make sure that the focus indication
643 setFocusedWindow(focus
);
645 // we have no idea where focus went... so we set it to somewhere
654 case ClientMessage
: {
655 if (e
->xclient
.format
== 32) {
656 if (e
->xclient
.message_type
== xatom
->getAtom(XAtom::wm_change_state
)) {
657 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
658 if (! win
|| ! win
->validateClient()) return;
660 if (e
->xclient
.data
.l
[0] == IconicState
)
662 if (e
->xclient
.data
.l
[0] == NormalState
)
664 } else if(e
->xclient
.message_type
== getBlackboxChangeWorkspaceAtom()) {
665 BScreen
*screen
= searchScreen(e
->xclient
.window
);
667 if (screen
&& e
->xclient
.data
.l
[0] >= 0 &&
668 e
->xclient
.data
.l
[0] <
669 static_cast<signed>(screen
->getWorkspaceCount()))
670 screen
->changeWorkspaceID(e
->xclient
.data
.l
[0]);
671 } else if (e
->xclient
.message_type
== getBlackboxChangeWindowFocusAtom()) {
672 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
674 if (win
&& win
->isVisible() && win
->setInputFocus())
675 win
->installColormap(True
);
676 } else if (e
->xclient
.message_type
== getBlackboxCycleWindowFocusAtom()) {
677 BScreen
*screen
= searchScreen(e
->xclient
.window
);
680 if (! e
->xclient
.data
.l
[0])
685 } else if (e
->xclient
.message_type
== getBlackboxChangeAttributesAtom()) {
686 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
688 if (win
&& win
->validateClient()) {
690 net
.flags
= e
->xclient
.data
.l
[0];
691 net
.attrib
= e
->xclient
.data
.l
[1];
692 net
.workspace
= e
->xclient
.data
.l
[2];
693 net
.stack
= e
->xclient
.data
.l
[3];
694 net
.decoration
= e
->xclient
.data
.l
[4];
696 win
->changeBlackboxHints(&net
);
705 case ConfigureNotify
:
707 break; // not handled, just ignore
711 if (e
->type
== getShapeEventBase()) {
712 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
713 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
716 win
->shapeEvent(shape_event
);
724 bool Blackbox::handleSignal(int sig
) {
750 bool Blackbox::validateWindow(Window window
) {
752 if (XCheckTypedWindowEvent(getXDisplay(), window
, DestroyNotify
, &event
)) {
753 XPutBackEvent(getXDisplay(), &event
);
762 BScreen
*Blackbox::searchScreen(Window window
) {
763 ScreenList::iterator it
= screenList
.begin();
765 for (; it
!= screenList
.end(); ++it
) {
767 if (s
->getRootWindow() == window
)
771 return (BScreen
*) 0;
775 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
776 WindowLookup::iterator it
= windowSearchList
.find(window
);
777 if (it
!= windowSearchList
.end())
780 return (BlackboxWindow
*) 0;
784 BWindowGroup
*Blackbox::searchGroup(Window window
) {
785 GroupLookup::iterator it
= groupSearchList
.find(window
);
786 if (it
!= groupSearchList
.end())
789 return (BWindowGroup
*) 0;
793 Basemenu
*Blackbox::searchMenu(Window window
) {
794 MenuLookup::iterator it
= menuSearchList
.find(window
);
795 if (it
!= menuSearchList
.end())
798 return (Basemenu
*) 0;
802 Toolbar
*Blackbox::searchToolbar(Window window
) {
803 ToolbarLookup::iterator it
= toolbarSearchList
.find(window
);
804 if (it
!= toolbarSearchList
.end())
811 Slit
*Blackbox::searchSlit(Window window
) {
812 SlitLookup::iterator it
= slitSearchList
.find(window
);
813 if (it
!= slitSearchList
.end())
820 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
821 windowSearchList
.insert(WindowLookupPair(window
, data
));
825 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
826 groupSearchList
.insert(GroupLookupPair(window
, data
));
830 void Blackbox::saveMenuSearch(Window window
, Basemenu
*data
) {
831 menuSearchList
.insert(MenuLookupPair(window
, data
));
835 void Blackbox::saveToolbarSearch(Window window
, Toolbar
*data
) {
836 toolbarSearchList
.insert(ToolbarLookupPair(window
, data
));
840 void Blackbox::saveSlitSearch(Window window
, Slit
*data
) {
841 slitSearchList
.insert(SlitLookupPair(window
, data
));
845 void Blackbox::removeWindowSearch(Window window
) {
846 windowSearchList
.erase(window
);
850 void Blackbox::removeGroupSearch(Window window
) {
851 groupSearchList
.erase(window
);
855 void Blackbox::removeMenuSearch(Window window
) {
856 menuSearchList
.erase(window
);
860 void Blackbox::removeToolbarSearch(Window window
) {
861 toolbarSearchList
.erase(window
);
865 void Blackbox::removeSlitSearch(Window window
) {
866 slitSearchList
.erase(window
);
870 void Blackbox::restart(const char *prog
) {
874 execlp(prog
, prog
, NULL
);
878 // fall back in case the above execlp doesn't work
879 execvp(argv
[0], argv
);
880 string name
= basename(argv
[0]);
881 execvp(name
.c_str(), argv
);
885 void Blackbox::shutdown(void) {
886 BaseDisplay::shutdown();
888 XSetInputFocus(getXDisplay(), PointerRoot
, None
, CurrentTime
);
890 std::for_each(screenList
.begin(), screenList
.end(),
891 std::mem_fun(&BScreen::shutdown
));
893 XSync(getXDisplay(), False
);
898 * Save all values as they are so that the defaults will be written to the rc
901 void Blackbox::save_rc(void) {
902 config
.setAutoSave(false);
904 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
905 config
.setValue("session.doubleClickInterval",
906 resource
.double_click_interval
);
907 config
.setValue("session.autoRaiseDelay",
908 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
909 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
910 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
911 config
.setValue("session.cacheMax", resource
.cache_max
);
912 config
.setValue("session.styleFile", resource
.style_file
);
913 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
915 std::for_each(screenList
.begin(), screenList
.end(),
916 std::mem_fun(&BScreen::save_rc
));
918 config
.setAutoSave(true);
923 void Blackbox::load_rc(void) {
929 if (! config
.getValue("session.colorsPerChannel",
930 resource
.colors_per_channel
))
931 resource
.colors_per_channel
= 4;
932 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
933 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
935 if (config
.getValue("session.styleFile", s
))
936 resource
.style_file
= expandTilde(s
);
938 resource
.style_file
= DEFAULTSTYLE
;
940 if (! config
.getValue("session.doubleClickInterval",
941 resource
.double_click_interval
));
942 resource
.double_click_interval
= 250;
944 if (! config
.getValue("session.autoRaiseDelay",
945 resource
.auto_raise_delay
.tv_usec
))
946 resource
.auto_raise_delay
.tv_usec
= 400;
947 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
948 resource
.auto_raise_delay
.tv_usec
-=
949 (resource
.auto_raise_delay
.tv_sec
* 1000);
950 resource
.auto_raise_delay
.tv_usec
*= 1000;
952 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
953 resource
.cache_life
= 5;
954 resource
.cache_life
*= 60000;
956 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
957 resource
.cache_max
= 200;
959 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
960 resource
.titlebar_layout
= "ILMC";
964 void Blackbox::reconfigure(void) {
965 reconfigure_wait
= True
;
967 if (! timer
->isTiming()) timer
->start();
971 void Blackbox::real_reconfigure(void) {
974 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
976 menuTimestamps
.clear();
980 std::for_each(screenList
.begin(), screenList
.end(),
981 std::mem_fun(&BScreen::reconfigure
));
985 void Blackbox::checkMenu(void) {
987 MenuTimestampList::iterator it
= menuTimestamps
.begin();
988 for(; it
!= menuTimestamps
.end(); ++it
) {
989 MenuTimestamp
*tmp
= *it
;
992 if (! stat(tmp
->filename
.c_str(), &buf
)) {
993 if (tmp
->timestamp
!= buf
.st_ctime
)
1000 if (reread
) rereadMenu();
1004 void Blackbox::rereadMenu(void) {
1005 reread_menu_wait
= True
;
1007 if (! timer
->isTiming()) timer
->start();
1011 void Blackbox::real_rereadMenu(void) {
1012 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
1014 menuTimestamps
.clear();
1016 std::for_each(screenList
.begin(), screenList
.end(),
1017 std::mem_fun(&BScreen::rereadMenu
));
1021 void Blackbox::saveStyleFilename(const string
& filename
) {
1022 assert(! filename
.empty());
1023 resource
.style_file
= filename
;
1024 config
.setValue("session.styleFile", resource
.style_file
);
1028 void Blackbox::addMenuTimestamp(const string
& filename
) {
1029 assert(! filename
.empty());
1032 MenuTimestampList::iterator it
= menuTimestamps
.begin();
1033 for (; it
!= menuTimestamps
.end() && ! found
; ++it
) {
1034 if ((*it
)->filename
== filename
) found
= True
;
1039 if (! stat(filename
.c_str(), &buf
)) {
1040 MenuTimestamp
*ts
= new MenuTimestamp
;
1042 ts
->filename
= filename
;
1043 ts
->timestamp
= buf
.st_ctime
;
1045 menuTimestamps
.push_back(ts
);
1051 void Blackbox::timeout(void) {
1052 if (reconfigure_wait
)
1055 if (reread_menu_wait
)
1058 reconfigure_wait
= reread_menu_wait
= False
;
1062 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1063 if (focused_window
&& focused_window
== win
) // nothing to do
1066 BScreen
*old_screen
= 0;
1068 if (focused_window
) {
1069 focused_window
->setFocusFlag(False
);
1070 old_screen
= focused_window
->getScreen();
1073 if (win
&& ! win
->isIconic()) {
1074 // the active screen is the one with the last focused window...
1075 // this will keep focus on this screen no matter where the mouse goes,
1076 // so multihead keybindings will continue to work on that screen until the
1077 // user focuses a window on a different screen.
1078 active_screen
= win
->getScreen();
1079 focused_window
= win
;
1083 if (active_screen
) {
1084 // set input focus to the toolbar of the screen with mouse
1085 XSetInputFocus(getXDisplay(),
1086 active_screen
->getRootWindow(),
1087 RevertToPointerRoot
, CurrentTime
);
1089 // set input focus to the toolbar of the first managed screen
1090 XSetInputFocus(getXDisplay(),
1091 screenList
.front()->getRootWindow(),
1092 RevertToPointerRoot
, CurrentTime
);
1095 // set input focus to the toolbar of the last screen
1096 XSetInputFocus(getXDisplay(), old_screen
->getRootWindow(),
1097 RevertToPointerRoot
, CurrentTime
);
1101 if (active_screen
&& active_screen
->isScreenManaged()) {
1102 active_screen
->getToolbar()->redrawWindowLabel(True
);
1103 active_screen
->updateNetizenWindowFocus();
1106 if (old_screen
&& old_screen
!= active_screen
) {
1107 old_screen
->getToolbar()->redrawWindowLabel(True
);
1108 old_screen
->updateNetizenWindowFocus();