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
) {
564 don't process FocusIns when:
565 1. the new focus window isn't an ancestor or inferior of the old
566 focus window (NotifyNonlinear)
571 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
573 if (! win
->isFocused())
574 win
->setFocusFlag(True
);
577 set the event window to None. when the FocusOut event handler calls
578 this function recursively, it uses this as an indication that focus
579 has moved to a known window.
581 e
->xfocus
.window
= None
;
588 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
590 don't process FocusOuts when:
591 2. the new focus window isn't an ancestor or inferior of the old
592 focus window (NotifyNonlinear)
597 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
598 if (win
&& win
->isFocused()) {
600 before we mark "win" as unfocused, we need to verify that focus is
601 going to a known location, is in a known location, or set focus
606 // don't check the current focus if FocusOut was generated during a grab
607 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
610 First, check if there is a pending FocusIn event waiting. if there
611 is, process it and determine if focus has moved to another window
612 (the FocusIn event handler sets the window in the event
613 structure to None to indicate this).
615 if (XCheckTypedEvent(getXDisplay(), FocusIn
, &event
)) {
617 process_event(&event
);
618 if (event
.xfocus
.window
== None
) {
626 Second, we query the X server for the current input focus.
627 to make sure that we keep a consistent state.
629 BlackboxWindow
*focus
;
632 XGetInputFocus(getXDisplay(), &w
, &revert
);
633 focus
= searchWindow(w
);
636 focus got from "win" to "focus" under some very strange
637 circumstances, and we need to make sure that the focus indication
640 setFocusedWindow(focus
);
642 // we have no idea where focus went... so we set it to somewhere
651 case ClientMessage
: {
652 if (e
->xclient
.format
== 32) {
653 if (e
->xclient
.message_type
== getWMChangeStateAtom()) {
654 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
655 if (! win
|| ! win
->validateClient()) return;
657 if (e
->xclient
.data
.l
[0] == IconicState
)
659 if (e
->xclient
.data
.l
[0] == NormalState
)
661 } else if(e
->xclient
.message_type
== getBlackboxChangeWorkspaceAtom()) {
662 BScreen
*screen
= searchScreen(e
->xclient
.window
);
664 if (screen
&& e
->xclient
.data
.l
[0] >= 0 &&
665 e
->xclient
.data
.l
[0] <
666 static_cast<signed>(screen
->getWorkspaceCount()))
667 screen
->changeWorkspaceID(e
->xclient
.data
.l
[0]);
668 } else if (e
->xclient
.message_type
== getBlackboxChangeWindowFocusAtom()) {
669 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
671 if (win
&& win
->isVisible() && win
->setInputFocus())
672 win
->installColormap(True
);
673 } else if (e
->xclient
.message_type
== getBlackboxCycleWindowFocusAtom()) {
674 BScreen
*screen
= searchScreen(e
->xclient
.window
);
677 if (! e
->xclient
.data
.l
[0])
682 } else if (e
->xclient
.message_type
== getBlackboxChangeAttributesAtom()) {
683 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
685 if (win
&& win
->validateClient()) {
687 net
.flags
= e
->xclient
.data
.l
[0];
688 net
.attrib
= e
->xclient
.data
.l
[1];
689 net
.workspace
= e
->xclient
.data
.l
[2];
690 net
.stack
= e
->xclient
.data
.l
[3];
691 net
.decoration
= e
->xclient
.data
.l
[4];
693 win
->changeBlackboxHints(&net
);
702 case ConfigureNotify
:
704 break; // not handled, just ignore
708 if (e
->type
== getShapeEventBase()) {
709 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
710 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
713 win
->shapeEvent(shape_event
);
721 bool Blackbox::handleSignal(int sig
) {
747 bool Blackbox::validateWindow(Window window
) {
749 if (XCheckTypedWindowEvent(getXDisplay(), window
, DestroyNotify
, &event
)) {
750 XPutBackEvent(getXDisplay(), &event
);
759 BScreen
*Blackbox::searchScreen(Window window
) {
760 ScreenList::iterator it
= screenList
.begin();
762 for (; it
!= screenList
.end(); ++it
) {
764 if (s
->getRootWindow() == window
)
768 return (BScreen
*) 0;
772 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
773 WindowLookup::iterator it
= windowSearchList
.find(window
);
774 if (it
!= windowSearchList
.end())
777 return (BlackboxWindow
*) 0;
781 BWindowGroup
*Blackbox::searchGroup(Window window
) {
782 GroupLookup::iterator it
= groupSearchList
.find(window
);
783 if (it
!= groupSearchList
.end())
786 return (BWindowGroup
*) 0;
790 Basemenu
*Blackbox::searchMenu(Window window
) {
791 MenuLookup::iterator it
= menuSearchList
.find(window
);
792 if (it
!= menuSearchList
.end())
795 return (Basemenu
*) 0;
799 Toolbar
*Blackbox::searchToolbar(Window window
) {
800 ToolbarLookup::iterator it
= toolbarSearchList
.find(window
);
801 if (it
!= toolbarSearchList
.end())
808 Slit
*Blackbox::searchSlit(Window window
) {
809 SlitLookup::iterator it
= slitSearchList
.find(window
);
810 if (it
!= slitSearchList
.end())
817 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
818 windowSearchList
.insert(WindowLookupPair(window
, data
));
822 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
823 groupSearchList
.insert(GroupLookupPair(window
, data
));
827 void Blackbox::saveMenuSearch(Window window
, Basemenu
*data
) {
828 menuSearchList
.insert(MenuLookupPair(window
, data
));
832 void Blackbox::saveToolbarSearch(Window window
, Toolbar
*data
) {
833 toolbarSearchList
.insert(ToolbarLookupPair(window
, data
));
837 void Blackbox::saveSlitSearch(Window window
, Slit
*data
) {
838 slitSearchList
.insert(SlitLookupPair(window
, data
));
842 void Blackbox::removeWindowSearch(Window window
) {
843 windowSearchList
.erase(window
);
847 void Blackbox::removeGroupSearch(Window window
) {
848 groupSearchList
.erase(window
);
852 void Blackbox::removeMenuSearch(Window window
) {
853 menuSearchList
.erase(window
);
857 void Blackbox::removeToolbarSearch(Window window
) {
858 toolbarSearchList
.erase(window
);
862 void Blackbox::removeSlitSearch(Window window
) {
863 slitSearchList
.erase(window
);
867 void Blackbox::restart(const char *prog
) {
871 execlp(prog
, prog
, NULL
);
875 // fall back in case the above execlp doesn't work
876 execvp(argv
[0], argv
);
877 string name
= basename(argv
[0]);
878 execvp(name
.c_str(), argv
);
882 void Blackbox::shutdown(void) {
883 BaseDisplay::shutdown();
885 XSetInputFocus(getXDisplay(), PointerRoot
, None
, CurrentTime
);
887 std::for_each(screenList
.begin(), screenList
.end(),
888 std::mem_fun(&BScreen::shutdown
));
890 XSync(getXDisplay(), False
);
895 * Save all values as they are so that the defaults will be written to the rc
898 void Blackbox::save_rc(void) {
899 config
.setAutoSave(false);
901 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
902 config
.setValue("session.doubleClickInterval",
903 resource
.double_click_interval
);
904 config
.setValue("session.autoRaiseDelay",
905 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
906 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
907 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
908 config
.setValue("session.cacheMax", resource
.cache_max
);
909 config
.setValue("session.styleFile", resource
.style_file
);
910 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
912 std::for_each(screenList
.begin(), screenList
.end(),
913 std::mem_fun(&BScreen::save_rc
));
915 config
.setAutoSave(true);
920 void Blackbox::load_rc(void) {
926 if (! config
.getValue("session.colorsPerChannel",
927 resource
.colors_per_channel
))
928 resource
.colors_per_channel
= 4;
929 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
930 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
932 if (config
.getValue("session.styleFile", s
))
933 resource
.style_file
= expandTilde(s
);
935 resource
.style_file
= DEFAULTSTYLE
;
937 if (! config
.getValue("session.doubleClickInterval",
938 resource
.double_click_interval
));
939 resource
.double_click_interval
= 250;
941 if (! config
.getValue("session.autoRaiseDelay",
942 resource
.auto_raise_delay
.tv_usec
))
943 resource
.auto_raise_delay
.tv_usec
= 400;
944 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
945 resource
.auto_raise_delay
.tv_usec
-=
946 (resource
.auto_raise_delay
.tv_sec
* 1000);
947 resource
.auto_raise_delay
.tv_usec
*= 1000;
949 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
950 resource
.cache_life
= 5;
951 resource
.cache_life
*= 60000;
953 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
954 resource
.cache_max
= 200;
956 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
957 resource
.titlebar_layout
= "ILMC";
961 void Blackbox::reconfigure(void) {
962 reconfigure_wait
= True
;
964 if (! timer
->isTiming()) timer
->start();
968 void Blackbox::real_reconfigure(void) {
971 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
973 menuTimestamps
.clear();
977 std::for_each(screenList
.begin(), screenList
.end(),
978 std::mem_fun(&BScreen::reconfigure
));
982 void Blackbox::checkMenu(void) {
984 MenuTimestampList::iterator it
= menuTimestamps
.begin();
985 for(; it
!= menuTimestamps
.end(); ++it
) {
986 MenuTimestamp
*tmp
= *it
;
989 if (! stat(tmp
->filename
.c_str(), &buf
)) {
990 if (tmp
->timestamp
!= buf
.st_ctime
)
997 if (reread
) rereadMenu();
1001 void Blackbox::rereadMenu(void) {
1002 reread_menu_wait
= True
;
1004 if (! timer
->isTiming()) timer
->start();
1008 void Blackbox::real_rereadMenu(void) {
1009 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
1011 menuTimestamps
.clear();
1013 std::for_each(screenList
.begin(), screenList
.end(),
1014 std::mem_fun(&BScreen::rereadMenu
));
1018 void Blackbox::saveStyleFilename(const string
& filename
) {
1019 assert(! filename
.empty());
1020 resource
.style_file
= filename
;
1021 config
.setValue("session.styleFile", resource
.style_file
);
1025 void Blackbox::addMenuTimestamp(const string
& filename
) {
1026 assert(! filename
.empty());
1029 MenuTimestampList::iterator it
= menuTimestamps
.begin();
1030 for (; it
!= menuTimestamps
.end() && ! found
; ++it
) {
1031 if ((*it
)->filename
== filename
) found
= True
;
1036 if (! stat(filename
.c_str(), &buf
)) {
1037 MenuTimestamp
*ts
= new MenuTimestamp
;
1039 ts
->filename
= filename
;
1040 ts
->timestamp
= buf
.st_ctime
;
1042 menuTimestamps
.push_back(ts
);
1048 void Blackbox::timeout(void) {
1049 if (reconfigure_wait
)
1052 if (reread_menu_wait
)
1055 reconfigure_wait
= reread_menu_wait
= False
;
1059 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1060 if (focused_window
&& focused_window
== win
) // nothing to do
1063 BScreen
*old_screen
= 0;
1065 if (focused_window
) {
1066 focused_window
->setFocusFlag(False
);
1067 old_screen
= focused_window
->getScreen();
1070 if (win
&& ! win
->isIconic()) {
1071 // the active screen is the one with the last focused window...
1072 // this will keep focus on this screen no matter where the mouse goes,
1073 // so multihead keybindings will continue to work on that screen until the
1074 // user focuses a window on a different screen.
1075 active_screen
= win
->getScreen();
1076 focused_window
= win
;
1080 if (active_screen
) {
1081 // set input focus to the toolbar of the screen with mouse
1082 XSetInputFocus(getXDisplay(),
1083 active_screen
->getRootWindow(),
1084 RevertToPointerRoot
, CurrentTime
);
1086 // set input focus to the toolbar of the first managed screen
1087 XSetInputFocus(getXDisplay(),
1088 screenList
.front()->getRootWindow(),
1089 RevertToPointerRoot
, CurrentTime
);
1092 // set input focus to the toolbar of the last screen
1093 XSetInputFocus(getXDisplay(), old_screen
->getRootWindow(),
1094 RevertToPointerRoot
, CurrentTime
);
1098 if (active_screen
&& active_screen
->isScreenManaged()) {
1099 active_screen
->getToolbar()->redrawWindowLabel(True
);
1100 active_screen
->updateNetizenWindowFocus();
1103 if (old_screen
&& old_screen
!= active_screen
) {
1104 old_screen
->getToolbar()->redrawWindowLabel(True
);
1105 old_screen
->updateNetizenWindowFocus();