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
100 #include "blackbox.hh"
101 #include "Basemenu.hh"
102 #include "Clientmenu.hh"
103 #include "GCCache.hh"
105 #include "Rootmenu.hh"
108 #include "Toolbar.hh"
111 #include "Workspace.hh"
112 #include "Workspacemenu.hh"
115 // X event scanner for enter/leave notifies - adapted from twm
118 bool leave
, inferior
, enter
;
121 static Bool
queueScanner(Display
*, XEvent
*e
, char *args
) {
122 scanargs
*scan
= (scanargs
*) args
;
123 if ((e
->type
== LeaveNotify
) &&
124 (e
->xcrossing
.window
== scan
->w
) &&
125 (e
->xcrossing
.mode
== NotifyNormal
)) {
127 scan
->inferior
= (e
->xcrossing
.detail
== NotifyInferior
);
128 } else if ((e
->type
== EnterNotify
) && (e
->xcrossing
.mode
== NotifyUngrab
)) {
138 Blackbox::Blackbox(char **m_argv
, char *dpy_name
, char *rc
, char *menu
)
139 : BaseDisplay(m_argv
[0], dpy_name
) {
140 if (! XSupportsLocale())
141 fprintf(stderr
, "X server does not support locale\n");
143 if (XSetLocaleModifiers("") == NULL
)
144 fprintf(stderr
, "cannot set locale modifiers\n");
148 if (! rc
) rc
= "~/.openbox/rc";
149 rc_file
= expandTilde(rc
);
150 config
.setFile(rc_file
);
151 if (! menu
) menu
= "~/.openbox/menu";
152 menu_file
= expandTilde(menu
);
156 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
= 0;
159 focused_window
= (BlackboxWindow
*) 0;
164 xatom
= new XAtom(this);
166 cursor
.session
= XCreateFontCursor(getXDisplay(), XC_left_ptr
);
167 cursor
.move
= XCreateFontCursor(getXDisplay(), XC_fleur
);
168 cursor
.ll_angle
= XCreateFontCursor(getXDisplay(), XC_ll_angle
);
169 cursor
.lr_angle
= XCreateFontCursor(getXDisplay(), XC_lr_angle
);
171 for (unsigned int i
= 0; i
< getNumberOfScreens(); i
++) {
172 BScreen
*screen
= new BScreen(this, i
);
174 if (! screen
->isScreenManaged()) {
179 screenList
.push_back(screen
);
182 if (screenList
.empty()) {
184 i18n(blackboxSet
, blackboxNoManagableScreens
,
185 "Blackbox::Blackbox: no managable screens found, aborting.\n"));
189 // save current settings and default values
192 // set the screen with mouse to the first managed screen
193 active_screen
= screenList
.front();
196 XSynchronize(getXDisplay(), False
);
197 XSync(getXDisplay(), False
);
199 reconfigure_wait
= reread_menu_wait
= False
;
201 timer
= new BTimer(this, this);
202 timer
->setTimeout(0l);
206 Blackbox::~Blackbox(void) {
207 std::for_each(screenList
.begin(), screenList
.end(), PointerAssassin());
209 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
218 void Blackbox::process_event(XEvent
*e
) {
221 // strip the lock key modifiers
222 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
224 last_time
= e
->xbutton
.time
;
226 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
227 Basemenu
*menu
= (Basemenu
*) 0;
228 Slit
*slit
= (Slit
*) 0;
229 Toolbar
*tbar
= (Toolbar
*) 0;
230 BScreen
*scrn
= (BScreen
*) 0;
232 if ((win
= searchWindow(e
->xbutton
.window
))) {
233 win
->buttonPressEvent(&e
->xbutton
);
235 /* XXX: is this sane on low colour desktops? */
236 if (e
->xbutton
.button
== 1)
237 win
->installColormap(True
);
238 } else if ((menu
= searchMenu(e
->xbutton
.window
))) {
239 menu
->buttonPressEvent(&e
->xbutton
);
240 } else if ((slit
= searchSlit(e
->xbutton
.window
))) {
241 slit
->buttonPressEvent(&e
->xbutton
);
242 } else if ((tbar
= searchToolbar(e
->xbutton
.window
))) {
243 tbar
->buttonPressEvent(&e
->xbutton
);
244 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
245 scrn
->buttonPressEvent(&e
->xbutton
);
246 if (active_screen
!= scrn
) {
247 active_screen
= scrn
;
248 // first, set no focus window on the old screen
250 // and move focus to this screen
257 case ButtonRelease
: {
258 // strip the lock key modifiers
259 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
261 last_time
= e
->xbutton
.time
;
263 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
264 Basemenu
*menu
= (Basemenu
*) 0;
265 Toolbar
*tbar
= (Toolbar
*) 0;
267 if ((win
= searchWindow(e
->xbutton
.window
)))
268 win
->buttonReleaseEvent(&e
->xbutton
);
269 else if ((menu
= searchMenu(e
->xbutton
.window
)))
270 menu
->buttonReleaseEvent(&e
->xbutton
);
271 else if ((tbar
= searchToolbar(e
->xbutton
.window
)))
272 tbar
->buttonReleaseEvent(&e
->xbutton
);
277 case ConfigureRequest
: {
278 // compress configure requests...
281 while(XCheckTypedWindowEvent(getXDisplay(), e
->xconfigurerequest
.window
,
282 ConfigureRequest
, &realevent
)) {
288 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
289 Slit
*slit
= (Slit
*) 0;
291 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
292 win
->configureRequestEvent(&e
->xconfigurerequest
);
293 } else if ((slit
= searchSlit(e
->xconfigurerequest
.window
))) {
294 slit
->configureRequestEvent(&e
->xconfigurerequest
);
296 if (validateWindow(e
->xconfigurerequest
.window
)) {
299 xwc
.x
= e
->xconfigurerequest
.x
;
300 xwc
.y
= e
->xconfigurerequest
.y
;
301 xwc
.width
= e
->xconfigurerequest
.width
;
302 xwc
.height
= e
->xconfigurerequest
.height
;
303 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
304 xwc
.sibling
= e
->xconfigurerequest
.above
;
305 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
307 XConfigureWindow(getXDisplay(), e
->xconfigurerequest
.window
,
308 e
->xconfigurerequest
.value_mask
, &xwc
);
317 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
318 e
->xmaprequest
.window
);
321 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
324 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
328 we got a map request for a window who's parent isn't root. this
329 can happen in only one circumstance:
331 a client window unmapped a managed window, and then remapped it
332 somewhere between unmapping the client window and reparenting it
335 regardless of how it happens, we need to find the screen that
338 XWindowAttributes wattrib
;
339 if (! XGetWindowAttributes(getXDisplay(), e
->xmaprequest
.window
,
341 // failed to get the window attributes, perhaps the window has
342 // now been destroyed?
346 screen
= searchScreen(wattrib
.root
);
347 assert(screen
!= 0); // this should never happen
350 screen
->manageWindow(e
->xmaprequest
.window
);
357 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
358 Slit
*slit
= (Slit
*) 0;
360 if ((win
= searchWindow(e
->xunmap
.window
))) {
361 win
->unmapNotifyEvent(&e
->xunmap
);
362 } else if ((slit
= searchSlit(e
->xunmap
.window
))) {
363 slit
->unmapNotifyEvent(&e
->xunmap
);
369 case DestroyNotify
: {
370 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
371 Slit
*slit
= (Slit
*) 0;
372 BWindowGroup
*group
= (BWindowGroup
*) 0;
374 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
375 win
->destroyNotifyEvent(&e
->xdestroywindow
);
376 } else if ((slit
= searchSlit(e
->xdestroywindow
.window
))) {
377 slit
->removeClient(e
->xdestroywindow
.window
, False
);
378 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
385 case ReparentNotify
: {
387 this event is quite rare and is usually handled in unmapNotify
388 however, if the window is unmapped when the reparent event occurs
389 the window manager never sees it because an unmap event is not sent
390 to an already unmapped window.
392 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
394 win
->reparentNotifyEvent(&e
->xreparent
);
396 Slit
*slit
= searchSlit(e
->xreparent
.window
);
397 if (slit
&& slit
->getWindowID() != e
->xreparent
.parent
)
398 slit
->removeClient(e
->xreparent
.window
, True
);
404 // motion notify compression...
407 while (XCheckTypedWindowEvent(getXDisplay(), e
->xmotion
.window
,
408 MotionNotify
, &realevent
)) {
412 // if we have compressed some motion events, use the last one
416 // strip the lock key modifiers
417 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
419 last_time
= e
->xmotion
.time
;
421 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
422 Basemenu
*menu
= (Basemenu
*) 0;
424 if ((win
= searchWindow(e
->xmotion
.window
)))
425 win
->motionNotifyEvent(&e
->xmotion
);
426 else if ((menu
= searchMenu(e
->xmotion
.window
)))
427 menu
->motionNotifyEvent(&e
->xmotion
);
432 case PropertyNotify
: {
433 last_time
= e
->xproperty
.time
;
435 if (e
->xproperty
.state
!= PropertyDelete
) {
436 BlackboxWindow
*win
= searchWindow(e
->xproperty
.window
);
439 win
->propertyNotifyEvent(e
->xproperty
.atom
);
446 last_time
= e
->xcrossing
.time
;
448 BScreen
*screen
= (BScreen
*) 0;
449 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
450 Basemenu
*menu
= (Basemenu
*) 0;
451 Toolbar
*tbar
= (Toolbar
*) 0;
452 Slit
*slit
= (Slit
*) 0;
454 if (e
->xcrossing
.mode
== NotifyGrab
) break;
458 sa
.w
= e
->xcrossing
.window
;
459 sa
.enter
= sa
.leave
= False
;
460 XCheckIfEvent(getXDisplay(), &dummy
, queueScanner
, (char *) &sa
);
462 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
463 (screen
= searchScreen(e
->xcrossing
.window
))) {
464 screen
->getImageControl()->installRootColormap();
465 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
466 if (win
->getScreen()->isSloppyFocus() &&
467 (! win
->isFocused()) && (! no_focus
)) {
468 if (((! sa
.leave
) || sa
.inferior
) && win
->isVisible()) {
469 if (win
->setInputFocus())
470 win
->installColormap(True
); // XXX: shouldnt we honour no install?
473 } else if ((menu
= searchMenu(e
->xcrossing
.window
))) {
474 menu
->enterNotifyEvent(&e
->xcrossing
);
475 } else if ((tbar
= searchToolbar(e
->xcrossing
.window
))) {
476 tbar
->enterNotifyEvent(&e
->xcrossing
);
477 } else if ((slit
= searchSlit(e
->xcrossing
.window
))) {
478 slit
->enterNotifyEvent(&e
->xcrossing
);
484 last_time
= e
->xcrossing
.time
;
486 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
487 Basemenu
*menu
= (Basemenu
*) 0;
488 Toolbar
*tbar
= (Toolbar
*) 0;
489 Slit
*slit
= (Slit
*) 0;
491 if ((menu
= searchMenu(e
->xcrossing
.window
)))
492 menu
->leaveNotifyEvent(&e
->xcrossing
);
493 else if ((win
= searchWindow(e
->xcrossing
.window
)))
494 win
->installColormap(False
);
495 else if ((tbar
= searchToolbar(e
->xcrossing
.window
)))
496 tbar
->leaveNotifyEvent(&e
->xcrossing
);
497 else if ((slit
= searchSlit(e
->xcrossing
.window
)))
498 slit
->leaveNotifyEvent(&e
->xcrossing
);
503 // compress expose events
506 int ex1
, ey1
, ex2
, ey2
;
509 ex2
= ex1
+ e
->xexpose
.width
- 1;
510 ey2
= ey1
+ e
->xexpose
.height
- 1;
511 while (XCheckTypedWindowEvent(getXDisplay(), e
->xexpose
.window
,
512 Expose
, &realevent
)) {
516 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
517 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
518 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
519 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
524 // use the merged area
527 e
->xexpose
.width
= ex2
- ex1
+ 1;
528 e
->xexpose
.height
= ey2
- ey1
+ 1;
530 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
531 Basemenu
*menu
= (Basemenu
*) 0;
532 Toolbar
*tbar
= (Toolbar
*) 0;
534 if ((win
= searchWindow(e
->xexpose
.window
)))
535 win
->exposeEvent(&e
->xexpose
);
536 else if ((menu
= searchMenu(e
->xexpose
.window
)))
537 menu
->exposeEvent(&e
->xexpose
);
538 else if ((tbar
= searchToolbar(e
->xexpose
.window
)))
539 tbar
->exposeEvent(&e
->xexpose
);
545 Toolbar
*tbar
= searchToolbar(e
->xkey
.window
);
547 if (tbar
&& tbar
->isEditing())
548 tbar
->keyPressEvent(&e
->xkey
);
553 case ColormapNotify
: {
554 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
557 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
558 ColormapInstalled
) ? True
: False
);
564 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
565 e
->xfocus
.detail
!= NotifyAncestor
) {
567 don't process FocusIns when:
568 1. the new focus window isn't an ancestor or inferior of the old
569 focus window (NotifyNonlinear)
570 make sure to allow the FocusIn when the old focus window was an
571 ancestor but didn't have a parent, such as root (NotifyAncestor)
576 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
578 if (! win
->isFocused())
579 win
->setFocusFlag(True
);
582 set the event window to None. when the FocusOut event handler calls
583 this function recursively, it uses this as an indication that focus
584 has moved to a known window.
586 e
->xfocus
.window
= None
;
593 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
595 don't process FocusOuts when:
596 2. the new focus window isn't an ancestor or inferior of the old
597 focus window (NotifyNonlinear)
602 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
603 if (win
&& win
->isFocused()) {
605 before we mark "win" as unfocused, we need to verify that focus is
606 going to a known location, is in a known location, or set focus
611 // don't check the current focus if FocusOut was generated during a grab
612 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
615 First, check if there is a pending FocusIn event waiting. if there
616 is, process it and determine if focus has moved to another window
617 (the FocusIn event handler sets the window in the event
618 structure to None to indicate this).
620 if (XCheckTypedEvent(getXDisplay(), FocusIn
, &event
)) {
622 process_event(&event
);
623 if (event
.xfocus
.window
== None
) {
631 Second, we query the X server for the current input focus.
632 to make sure that we keep a consistent state.
634 BlackboxWindow
*focus
;
637 XGetInputFocus(getXDisplay(), &w
, &revert
);
638 focus
= searchWindow(w
);
641 focus got from "win" to "focus" under some very strange
642 circumstances, and we need to make sure that the focus indication
645 setFocusedWindow(focus
);
647 // we have no idea where focus went... so we set it to somewhere
656 case ClientMessage
: {
657 if (e
->xclient
.format
== 32) {
658 if (e
->xclient
.message_type
== xatom
->getAtom(XAtom::wm_change_state
)) {
659 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
660 if (! win
|| ! win
->validateClient()) return;
662 if (e
->xclient
.data
.l
[0] == IconicState
)
664 if (e
->xclient
.data
.l
[0] == NormalState
)
666 } else if(e
->xclient
.message_type
== getBlackboxChangeWorkspaceAtom()) {
667 BScreen
*screen
= searchScreen(e
->xclient
.window
);
669 if (screen
&& e
->xclient
.data
.l
[0] >= 0 &&
670 e
->xclient
.data
.l
[0] <
671 static_cast<signed>(screen
->getWorkspaceCount()))
672 screen
->changeWorkspaceID(e
->xclient
.data
.l
[0]);
673 } else if (e
->xclient
.message_type
== getBlackboxChangeWindowFocusAtom()) {
674 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
676 if (win
&& win
->isVisible() && win
->setInputFocus())
677 win
->installColormap(True
);
678 } else if (e
->xclient
.message_type
== getBlackboxCycleWindowFocusAtom()) {
679 BScreen
*screen
= searchScreen(e
->xclient
.window
);
682 if (! e
->xclient
.data
.l
[0])
687 } else if (e
->xclient
.message_type
== getBlackboxChangeAttributesAtom()) {
688 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
690 if (win
&& win
->validateClient()) {
692 net
.flags
= e
->xclient
.data
.l
[0];
693 net
.attrib
= e
->xclient
.data
.l
[1];
694 net
.workspace
= e
->xclient
.data
.l
[2];
695 net
.stack
= e
->xclient
.data
.l
[3];
696 net
.decoration
= e
->xclient
.data
.l
[4];
698 win
->changeBlackboxHints(&net
);
707 case ConfigureNotify
:
709 break; // not handled, just ignore
713 if (e
->type
== getShapeEventBase()) {
714 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
715 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
718 win
->shapeEvent(shape_event
);
726 bool Blackbox::handleSignal(int sig
) {
752 bool Blackbox::validateWindow(Window window
) {
754 if (XCheckTypedWindowEvent(getXDisplay(), window
, DestroyNotify
, &event
)) {
755 XPutBackEvent(getXDisplay(), &event
);
764 BScreen
*Blackbox::searchScreen(Window window
) {
765 ScreenList::iterator it
= screenList
.begin();
767 for (; it
!= screenList
.end(); ++it
) {
769 if (s
->getRootWindow() == window
)
773 return (BScreen
*) 0;
777 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
778 WindowLookup::iterator it
= windowSearchList
.find(window
);
779 if (it
!= windowSearchList
.end())
782 return (BlackboxWindow
*) 0;
786 BWindowGroup
*Blackbox::searchGroup(Window window
) {
787 GroupLookup::iterator it
= groupSearchList
.find(window
);
788 if (it
!= groupSearchList
.end())
791 return (BWindowGroup
*) 0;
795 Basemenu
*Blackbox::searchMenu(Window window
) {
796 MenuLookup::iterator it
= menuSearchList
.find(window
);
797 if (it
!= menuSearchList
.end())
800 return (Basemenu
*) 0;
804 Toolbar
*Blackbox::searchToolbar(Window window
) {
805 ToolbarLookup::iterator it
= toolbarSearchList
.find(window
);
806 if (it
!= toolbarSearchList
.end())
813 Slit
*Blackbox::searchSlit(Window window
) {
814 SlitLookup::iterator it
= slitSearchList
.find(window
);
815 if (it
!= slitSearchList
.end())
822 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
823 windowSearchList
.insert(WindowLookupPair(window
, data
));
827 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
828 groupSearchList
.insert(GroupLookupPair(window
, data
));
832 void Blackbox::saveMenuSearch(Window window
, Basemenu
*data
) {
833 menuSearchList
.insert(MenuLookupPair(window
, data
));
837 void Blackbox::saveToolbarSearch(Window window
, Toolbar
*data
) {
838 toolbarSearchList
.insert(ToolbarLookupPair(window
, data
));
842 void Blackbox::saveSlitSearch(Window window
, Slit
*data
) {
843 slitSearchList
.insert(SlitLookupPair(window
, data
));
847 void Blackbox::removeWindowSearch(Window window
) {
848 windowSearchList
.erase(window
);
852 void Blackbox::removeGroupSearch(Window window
) {
853 groupSearchList
.erase(window
);
857 void Blackbox::removeMenuSearch(Window window
) {
858 menuSearchList
.erase(window
);
862 void Blackbox::removeToolbarSearch(Window window
) {
863 toolbarSearchList
.erase(window
);
867 void Blackbox::removeSlitSearch(Window window
) {
868 slitSearchList
.erase(window
);
872 void Blackbox::restart(const char *prog
) {
876 execlp(prog
, prog
, NULL
);
880 // fall back in case the above execlp doesn't work
881 execvp(argv
[0], argv
);
882 string name
= basename(argv
[0]);
883 execvp(name
.c_str(), argv
);
887 void Blackbox::shutdown(void) {
888 BaseDisplay::shutdown();
890 XSetInputFocus(getXDisplay(), PointerRoot
, None
, CurrentTime
);
892 std::for_each(screenList
.begin(), screenList
.end(),
893 std::mem_fun(&BScreen::shutdown
));
895 XSync(getXDisplay(), False
);
899 void Blackbox::saveWindowToWindowSnap(bool s
) {
900 resource
.window_to_window_snap
= s
;
901 config
.setValue("session.windowToWindowSnap", resource
.window_to_window_snap
);
905 void Blackbox::saveWindowCornerSnap(bool s
) {
906 resource
.window_corner_snap
= s
;
907 config
.setValue("session.windowCornerSnap", resource
.window_corner_snap
);
912 * Save all values as they are so that the defaults will be written to the rc
915 void Blackbox::save_rc(void) {
916 config
.setAutoSave(false);
918 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
919 config
.setValue("session.doubleClickInterval",
920 resource
.double_click_interval
);
921 config
.setValue("session.autoRaiseDelay",
922 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
923 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
924 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
925 config
.setValue("session.cacheMax", resource
.cache_max
);
926 config
.setValue("session.styleFile", resource
.style_file
);
927 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
928 saveWindowToWindowSnap(resource
.window_to_window_snap
);
929 saveWindowCornerSnap(resource
.window_corner_snap
);
931 std::for_each(screenList
.begin(), screenList
.end(),
932 std::mem_fun(&BScreen::save_rc
));
934 config
.setAutoSave(true);
939 void Blackbox::load_rc(void) {
945 if (! config
.getValue("session.colorsPerChannel",
946 resource
.colors_per_channel
))
947 resource
.colors_per_channel
= 4;
948 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
949 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
951 if (config
.getValue("session.styleFile", s
))
952 resource
.style_file
= expandTilde(s
);
954 resource
.style_file
= DEFAULTSTYLE
;
956 if (! config
.getValue("session.doubleClickInterval",
957 resource
.double_click_interval
));
958 resource
.double_click_interval
= 250;
960 if (! config
.getValue("session.autoRaiseDelay",
961 resource
.auto_raise_delay
.tv_usec
))
962 resource
.auto_raise_delay
.tv_usec
= 400;
963 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
964 resource
.auto_raise_delay
.tv_usec
-=
965 (resource
.auto_raise_delay
.tv_sec
* 1000);
966 resource
.auto_raise_delay
.tv_usec
*= 1000;
968 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
969 resource
.cache_life
= 5;
970 resource
.cache_life
*= 60000;
972 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
973 resource
.cache_max
= 200;
975 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
976 resource
.titlebar_layout
= "ILMC";
978 if (! config
.getValue("session.windowToWindowSnap",
979 resource
.window_to_window_snap
))
980 resource
.window_to_window_snap
= true;
982 if (! config
.getValue("session.windowCornerSnap",
983 resource
.window_corner_snap
))
984 resource
.window_corner_snap
= true;
988 void Blackbox::reconfigure(void) {
989 reconfigure_wait
= True
;
991 if (! timer
->isTiming()) timer
->start();
995 void Blackbox::real_reconfigure(void) {
998 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
1000 menuTimestamps
.clear();
1004 std::for_each(screenList
.begin(), screenList
.end(),
1005 std::mem_fun(&BScreen::reconfigure
));
1009 void Blackbox::checkMenu(void) {
1010 bool reread
= False
;
1011 MenuTimestampList::iterator it
= menuTimestamps
.begin();
1012 for(; it
!= menuTimestamps
.end(); ++it
) {
1013 MenuTimestamp
*tmp
= *it
;
1016 if (! stat(tmp
->filename
.c_str(), &buf
)) {
1017 if (tmp
->timestamp
!= buf
.st_ctime
)
1024 if (reread
) rereadMenu();
1028 void Blackbox::rereadMenu(void) {
1029 reread_menu_wait
= True
;
1031 if (! timer
->isTiming()) timer
->start();
1035 void Blackbox::real_rereadMenu(void) {
1036 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
1038 menuTimestamps
.clear();
1040 std::for_each(screenList
.begin(), screenList
.end(),
1041 std::mem_fun(&BScreen::rereadMenu
));
1045 void Blackbox::saveStyleFilename(const string
& filename
) {
1046 assert(! filename
.empty());
1047 resource
.style_file
= filename
;
1048 config
.setValue("session.styleFile", resource
.style_file
);
1052 void Blackbox::addMenuTimestamp(const string
& filename
) {
1053 assert(! filename
.empty());
1056 MenuTimestampList::iterator it
= menuTimestamps
.begin();
1057 for (; it
!= menuTimestamps
.end() && ! found
; ++it
) {
1058 if ((*it
)->filename
== filename
) found
= True
;
1063 if (! stat(filename
.c_str(), &buf
)) {
1064 MenuTimestamp
*ts
= new MenuTimestamp
;
1066 ts
->filename
= filename
;
1067 ts
->timestamp
= buf
.st_ctime
;
1069 menuTimestamps
.push_back(ts
);
1075 void Blackbox::timeout(void) {
1076 if (reconfigure_wait
)
1079 if (reread_menu_wait
)
1082 reconfigure_wait
= reread_menu_wait
= False
;
1086 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1087 if (focused_window
&& focused_window
== win
) // nothing to do
1090 BScreen
*old_screen
= 0;
1092 if (focused_window
) {
1093 focused_window
->setFocusFlag(False
);
1094 old_screen
= focused_window
->getScreen();
1097 if (win
&& ! win
->isIconic()) {
1098 // the active screen is the one with the last focused window...
1099 // this will keep focus on this screen no matter where the mouse goes,
1100 // so multihead keybindings will continue to work on that screen until the
1101 // user focuses a window on a different screen.
1102 active_screen
= win
->getScreen();
1103 focused_window
= win
;
1107 if (active_screen
) {
1108 // set input focus to the toolbar of the screen with mouse
1109 XSetInputFocus(getXDisplay(),
1110 active_screen
->getRootWindow(),
1111 RevertToPointerRoot
, CurrentTime
);
1113 // set input focus to the toolbar of the first managed screen
1114 XSetInputFocus(getXDisplay(),
1115 screenList
.front()->getRootWindow(),
1116 RevertToPointerRoot
, CurrentTime
);
1119 // set input focus to the toolbar of the last screen
1120 XSetInputFocus(getXDisplay(), old_screen
->getRootWindow(),
1121 RevertToPointerRoot
, CurrentTime
);
1125 if (active_screen
&& active_screen
->isScreenManaged()) {
1126 active_screen
->getToolbar()->redrawWindowLabel(True
);
1127 active_screen
->updateNetizenWindowFocus();
1130 if (old_screen
&& old_screen
!= active_screen
) {
1131 old_screen
->getToolbar()->redrawWindowLabel(True
);
1132 old_screen
->updateNetizenWindowFocus();