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
99 #include "blackbox.hh"
100 #include "gccache.hh"
105 #include "workspace.hh"
111 Blackbox::Blackbox(char **m_argv
, char *dpy_name
, char *rc
)
112 : BaseDisplay(m_argv
[0], dpy_name
) {
113 if (! XSupportsLocale())
114 fprintf(stderr
, "X server does not support locale\n");
116 if (XSetLocaleModifiers("") == NULL
)
117 fprintf(stderr
, "cannot set locale modifiers\n");
122 // try to make sure the ~/.openbox directory exists
123 mkdir(expandTilde("~/.openbox").c_str(), S_IREAD
| S_IWRITE
| S_IEXEC
|
124 S_IRGRP
| S_IWGRP
| S_IXGRP
|
125 S_IROTH
| S_IWOTH
| S_IXOTH
);
127 if (! rc
) rc
= "~/.openbox/rc";
128 rc_file
= expandTilde(rc
);
129 config
.setFile(rc_file
);
133 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
= 0;
136 focused_window
= changing_window
= (BlackboxWindow
*) 0;
140 xatom
= new XAtom(getXDisplay());
142 cursor
.session
= XCreateFontCursor(getXDisplay(), XC_left_ptr
);
143 cursor
.move
= XCreateFontCursor(getXDisplay(), XC_fleur
);
144 cursor
.ll_angle
= XCreateFontCursor(getXDisplay(), XC_ll_angle
);
145 cursor
.lr_angle
= XCreateFontCursor(getXDisplay(), XC_lr_angle
);
146 cursor
.ul_angle
= XCreateFontCursor(getXDisplay(), XC_ul_angle
);
147 cursor
.ur_angle
= XCreateFontCursor(getXDisplay(), XC_ur_angle
);
149 for (unsigned int i
= 0; i
< getNumberOfScreens(); i
++) {
150 BScreen
*screen
= new BScreen(this, i
);
152 if (! screen
->isScreenManaged()) {
157 screenList
.push_back(screen
);
160 if (screenList
.empty()) {
162 "Blackbox::Blackbox: no managable screens found, aborting.\n");
166 // save current settings and default values
169 // set the screen with mouse to the first managed screen
170 active_screen
= screenList
.front();
173 XSynchronize(getXDisplay(), False
);
174 XSync(getXDisplay(), False
);
176 reconfigure_wait
= False
;
178 timer
= new BTimer(this, this);
179 timer
->setTimeout(0l);
183 Blackbox::~Blackbox(void) {
184 std::for_each(screenList
.begin(), screenList
.end(), PointerAssassin());
192 void Blackbox::process_event(XEvent
*e
) {
195 // strip the lock key modifiers
196 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
198 last_time
= e
->xbutton
.time
;
200 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
201 BScreen
*scrn
= (BScreen
*) 0;
203 if ((win
= searchWindow(e
->xbutton
.window
))) {
204 win
->buttonPressEvent(&e
->xbutton
);
206 /* XXX: is this sane on low colour desktops? */
207 if (e
->xbutton
.button
== 1)
208 win
->installColormap(True
);
209 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
210 scrn
->buttonPressEvent(&e
->xbutton
);
211 if (active_screen
!= scrn
) {
212 active_screen
= scrn
;
213 // first, set no focus window on the old screen
215 // and move focus to this screen
222 case ButtonRelease
: {
223 // strip the lock key modifiers
224 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
226 last_time
= e
->xbutton
.time
;
228 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
230 if ((win
= searchWindow(e
->xbutton
.window
)))
231 win
->buttonReleaseEvent(&e
->xbutton
);
236 case ConfigureRequest
: {
237 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
239 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
240 win
->configureRequestEvent(&e
->xconfigurerequest
);
242 if (validateWindow(e
->xconfigurerequest
.window
)) {
245 xwc
.x
= e
->xconfigurerequest
.x
;
246 xwc
.y
= e
->xconfigurerequest
.y
;
247 xwc
.width
= e
->xconfigurerequest
.width
;
248 xwc
.height
= e
->xconfigurerequest
.height
;
249 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
250 xwc
.sibling
= e
->xconfigurerequest
.above
;
251 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
253 XConfigureWindow(getXDisplay(), e
->xconfigurerequest
.window
,
254 e
->xconfigurerequest
.value_mask
, &xwc
);
263 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
264 e
->xmaprequest
.window
);
267 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
271 if (win
->isIconic()) {
275 if (win
->isShaded()) {
280 if (focus
&& (win
->isTransient() || win
->getScreen()->doFocusNew()) &&
282 win
->setInputFocus();
284 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
288 we got a map request for a window who's parent isn't root. this
289 can happen in only one circumstance:
291 a client window unmapped a managed window, and then remapped it
292 somewhere between unmapping the client window and reparenting it
295 regardless of how it happens, we need to find the screen that
298 XWindowAttributes wattrib
;
299 if (! XGetWindowAttributes(getXDisplay(), e
->xmaprequest
.window
,
301 // failed to get the window attributes, perhaps the window has
302 // now been destroyed?
306 screen
= searchScreen(wattrib
.root
);
307 assert(screen
!= 0); // this should never happen
310 screen
->manageWindow(e
->xmaprequest
.window
);
317 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
318 BScreen
*screen
= (BScreen
*) 0;
320 if ((win
= searchWindow(e
->xunmap
.window
))) {
321 win
->unmapNotifyEvent(&e
->xunmap
);
322 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
323 screen
->removeSystrayWindow(e
->xunmap
.window
);
329 case DestroyNotify
: {
330 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
331 BScreen
*screen
= (BScreen
*) 0;
332 BWindowGroup
*group
= (BWindowGroup
*) 0;
334 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
335 win
->destroyNotifyEvent(&e
->xdestroywindow
);
336 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
338 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
339 screen
->removeSystrayWindow(e
->xunmap
.window
);
345 case ReparentNotify
: {
347 this event is quite rare and is usually handled in unmapNotify
348 however, if the window is unmapped when the reparent event occurs
349 the window manager never sees it because an unmap event is not sent
350 to an already unmapped window.
352 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
354 win
->reparentNotifyEvent(&e
->xreparent
);
359 // motion notify compression...
362 while (XCheckTypedWindowEvent(getXDisplay(), e
->xmotion
.window
,
363 MotionNotify
, &realevent
)) {
367 // if we have compressed some motion events, use the last one
371 // the pointer is on the wrong screen
372 if (! e
->xmotion
.same_screen
)
375 // strip the lock key modifiers
376 e
->xmotion
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
378 last_time
= e
->xmotion
.time
;
380 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
382 if ((win
= searchWindow(e
->xmotion
.window
)))
383 win
->motionNotifyEvent(&e
->xmotion
);
388 case PropertyNotify
: {
389 last_time
= e
->xproperty
.time
;
391 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
392 BScreen
*screen
= (BScreen
*) 0;
394 if ((win
= searchWindow(e
->xproperty
.window
)))
395 win
->propertyNotifyEvent(&e
->xproperty
);
396 else if ((screen
= searchScreen(e
->xproperty
.window
)))
397 screen
->propertyNotifyEvent(&e
->xproperty
);
402 last_time
= e
->xcrossing
.time
;
404 BScreen
*screen
= (BScreen
*) 0;
405 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
407 if (e
->xcrossing
.mode
== NotifyGrab
) break;
409 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
410 (screen
= searchScreen(e
->xcrossing
.window
))) {
411 screen
->getImageControl()->installRootColormap();
412 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
414 win
->enterNotifyEvent(&e
->xcrossing
);
420 last_time
= e
->xcrossing
.time
;
422 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
424 if ((win
= searchWindow(e
->xcrossing
.window
)))
425 win
->leaveNotifyEvent(&e
->xcrossing
);
430 // compress expose events
433 int ex1
, ey1
, ex2
, ey2
;
436 ex2
= ex1
+ e
->xexpose
.width
- 1;
437 ey2
= ey1
+ e
->xexpose
.height
- 1;
438 while (XCheckTypedWindowEvent(getXDisplay(), e
->xexpose
.window
,
439 Expose
, &realevent
)) {
443 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
444 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
445 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
446 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
451 // use the merged area
454 e
->xexpose
.width
= ex2
- ex1
+ 1;
455 e
->xexpose
.height
= ey2
- ey1
+ 1;
457 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
459 if ((win
= searchWindow(e
->xexpose
.window
)))
460 win
->exposeEvent(&e
->xexpose
);
469 case ColormapNotify
: {
470 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
473 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
474 ColormapInstalled
) ? True
: False
);
480 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
481 e
->xfocus
.detail
!= NotifyAncestor
) {
483 don't process FocusIns when:
484 1. the new focus window isn't an ancestor or inferior of the old
485 focus window (NotifyNonlinear)
486 make sure to allow the FocusIn when the old focus window was an
487 ancestor but didn't have a parent, such as root (NotifyAncestor)
492 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
494 if (! win
->isFocused())
495 win
->setFocusFlag(True
);
498 set the event window to None. when the FocusOut event handler calls
499 this function recursively, it uses this as an indication that focus
500 has moved to a known window.
502 e
->xfocus
.window
= None
;
504 no_focus
= False
; // focusing is back on
511 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
513 don't process FocusOuts when:
514 2. the new focus window isn't an ancestor or inferior of the old
515 focus window (NotifyNonlinear)
520 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
521 if (win
&& win
->isFocused()) {
523 before we mark "win" as unfocused, we need to verify that focus is
524 going to a known location, is in a known location, or set focus
529 // don't check the current focus if FocusOut was generated during a grab
530 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
533 First, check if there is a pending FocusIn event waiting. if there
534 is, process it and determine if focus has moved to another window
535 (the FocusIn event handler sets the window in the event
536 structure to None to indicate this).
538 if (XCheckTypedEvent(getXDisplay(), FocusIn
, &event
)) {
540 process_event(&event
);
541 if (event
.xfocus
.window
== None
) {
549 Second, we query the X server for the current input focus.
550 to make sure that we keep a consistent state.
552 BlackboxWindow
*focus
;
555 XGetInputFocus(getXDisplay(), &w
, &revert
);
556 focus
= searchWindow(w
);
559 focus got from "win" to "focus" under some very strange
560 circumstances, and we need to make sure that the focus indication
563 setFocusedWindow(focus
);
565 // we have no idea where focus went... so we set it to somewhere
574 case ClientMessage
: {
575 if (e
->xclient
.format
== 32) {
576 if (e
->xclient
.message_type
== xatom
->getAtom(XAtom::wm_change_state
)) {
577 // WM_CHANGE_STATE message
578 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
579 if (! win
|| ! win
->validateClient()) return;
581 if (e
->xclient
.data
.l
[0] == IconicState
)
583 if (e
->xclient
.data
.l
[0] == NormalState
)
585 } else if (e
->xclient
.message_type
==
586 xatom
->getAtom(XAtom::blackbox_change_workspace
) ||
587 e
->xclient
.message_type
==
588 xatom
->getAtom(XAtom::net_current_desktop
)) {
589 // NET_CURRENT_DESKTOP message
590 BScreen
*screen
= searchScreen(e
->xclient
.window
);
592 unsigned int workspace
= e
->xclient
.data
.l
[0];
593 if (screen
&& workspace
< screen
->getWorkspaceCount())
594 screen
->changeWorkspaceID(workspace
);
595 } else if (e
->xclient
.message_type
==
596 xatom
->getAtom(XAtom::blackbox_change_window_focus
)) {
597 // TEMP HACK TO KEEP BBKEYS WORKING
598 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
600 if (win
&& win
->isVisible() && win
->setInputFocus())
601 win
->installColormap(True
);
602 } else if (e
->xclient
.message_type
==
603 xatom
->getAtom(XAtom::net_active_window
)) {
605 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
608 BScreen
*screen
= win
->getScreen();
611 win
->deiconify(False
, False
);
612 if (! win
->isStuck() &&
613 (win
->getWorkspaceNumber() != screen
->getCurrentWorkspaceID())) {
615 screen
->changeWorkspaceID(win
->getWorkspaceNumber());
617 if (win
->isVisible() && win
->setInputFocus()) {
618 win
->getScreen()->getWorkspace(win
->getWorkspaceNumber())->
620 win
->installColormap(True
);
623 } else if (e
->xclient
.message_type
==
624 xatom
->getAtom(XAtom::blackbox_cycle_window_focus
)) {
625 // BLACKBOX_CYCLE_WINDOW_FOCUS
626 BScreen
*screen
= searchScreen(e
->xclient
.window
);
629 if (! e
->xclient
.data
.l
[0])
634 } else if (e
->xclient
.message_type
==
635 xatom
->getAtom(XAtom::net_wm_desktop
)) {
637 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
640 BScreen
*screen
= win
->getScreen();
641 unsigned long wksp
= (unsigned) e
->xclient
.data
.l
[0];
642 if (wksp
< screen
->getWorkspaceCount()) {
643 if (win
->isIconic()) win
->deiconify(False
, True
);
644 if (win
->isStuck()) win
->stick();
645 if (wksp
!= screen
->getCurrentWorkspaceID())
649 screen
->reassociateWindow(win
, wksp
, True
);
650 } else if (wksp
== 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
651 wksp
== 0xffffffff) {
652 if (win
->isIconic()) win
->deiconify(False
, True
);
653 if (! win
->isStuck()) win
->stick();
654 if (! win
->isVisible()) win
->show();
657 } else if (e
->xclient
.message_type
==
658 xatom
->getAtom(XAtom::blackbox_change_attributes
)) {
659 // BLACKBOX_CHANGE_ATTRIBUTES
660 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
662 if (win
&& win
->validateClient()) {
664 net
.flags
= e
->xclient
.data
.l
[0];
665 net
.attrib
= e
->xclient
.data
.l
[1];
666 net
.workspace
= e
->xclient
.data
.l
[2];
667 net
.stack
= e
->xclient
.data
.l
[3];
668 net
.decoration
= e
->xclient
.data
.l
[4];
670 win
->changeBlackboxHints(&net
);
672 } else if (e
->xclient
.message_type
==
673 xatom
->getAtom(XAtom::net_number_of_desktops
)) {
674 // NET_NUMBER_OF_DESKTOPS
675 BScreen
*screen
= searchScreen(e
->xclient
.window
);
677 if (e
->xclient
.data
.l
[0] > 0)
678 screen
->changeWorkspaceCount((unsigned) e
->xclient
.data
.l
[0]);
679 } else if (e
->xclient
.message_type
==
680 xatom
->getAtom(XAtom::net_close_window
)) {
682 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
683 if (win
&& win
->validateClient())
684 win
->close(); // could this be smarter?
685 } else if (e
->xclient
.message_type
==
686 xatom
->getAtom(XAtom::net_wm_moveresize
)) {
688 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
689 if (win
&& win
->validateClient()) {
690 int x_root
= e
->xclient
.data
.l
[0],
691 y_root
= e
->xclient
.data
.l
[1];
692 if ((Atom
) e
->xclient
.data
.l
[2] ==
693 xatom
->getAtom(XAtom::net_wm_moveresize_move
)) {
694 win
->beginMove(x_root
, y_root
);
696 if ((Atom
) e
->xclient
.data
.l
[2] ==
697 xatom
->getAtom(XAtom::net_wm_moveresize_size_topleft
))
698 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopLeft
);
699 else if ((Atom
) e
->xclient
.data
.l
[2] ==
700 xatom
->getAtom(XAtom::net_wm_moveresize_size_topright
))
701 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopRight
);
702 else if ((Atom
) e
->xclient
.data
.l
[2] ==
703 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomleft
))
704 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomLeft
);
705 else if ((Atom
) e
->xclient
.data
.l
[2] ==
706 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomright
))
707 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomRight
);
710 } else if (e
->xclient
.message_type
==
711 xatom
->getAtom(XAtom::net_wm_state
)) {
713 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
714 if (win
&& win
->validateClient()) {
715 const Atom action
= (Atom
) e
->xclient
.data
.l
[0];
716 const Atom state
[] = { (Atom
) e
->xclient
.data
.l
[1],
717 (Atom
) e
->xclient
.data
.l
[2] };
719 for (int i
= 0; i
< 2; ++i
) {
723 if ((Atom
) e
->xclient
.data
.l
[0] == 1) {
725 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
727 } else if (state
[i
] ==
728 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
729 if (win
->isMaximizedHoriz()) {
730 win
->maximize(0); // unmaximize
731 win
->maximize(1); // full
732 } else if (! win
->isMaximized()) {
733 win
->maximize(2); // vert
735 } else if (state
[i
] ==
736 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
737 if (win
->isMaximizedVert()) {
738 win
->maximize(0); // unmaximize
739 win
->maximize(1); // full
740 } else if (! win
->isMaximized()) {
741 win
->maximize(3); // horiz
743 } else if (state
[i
] ==
744 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
745 if (! win
->isShaded())
747 } else if (state
[i
] ==
748 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
749 win
->setSkipTaskbar(True
);
750 } else if (state
[i
] ==
751 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
752 win
->setSkipPager(True
);
753 } else if (state
[i
] ==
754 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
755 win
->setFullscreen(True
);
757 } else if (action
== 0) {
759 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
760 win
->setModal(False
);
761 } else if (state
[i
] ==
762 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
763 if (win
->isMaximizedFull()) {
764 win
->maximize(0); // unmaximize
765 win
->maximize(3); // horiz
766 } else if (win
->isMaximizedVert()) {
767 win
->maximize(0); // unmaximize
769 } else if (state
[i
] ==
770 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
771 if (win
->isMaximizedFull()) {
772 win
->maximize(0); // unmaximize
773 win
->maximize(2); // vert
774 } else if (win
->isMaximizedHoriz()) {
775 win
->maximize(0); // unmaximize
777 } else if (state
[i
] ==
778 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
781 } else if (state
[i
] ==
782 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
783 win
->setSkipTaskbar(False
);
784 } else if (state
[i
] ==
785 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
786 win
->setSkipPager(False
);
787 } else if (state
[i
] ==
788 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
789 win
->setFullscreen(False
);
791 } else if (action
== 2) {
793 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
794 win
->setModal(! win
->isModal());
795 } else if (state
[i
] ==
796 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
797 if (win
->isMaximizedFull()) {
798 win
->maximize(0); // unmaximize
799 win
->maximize(3); // horiz
800 } else if (win
->isMaximizedVert()) {
801 win
->maximize(0); // unmaximize
802 } else if (win
->isMaximizedHoriz()) {
803 win
->maximize(0); // unmaximize
804 win
->maximize(1); // full
806 win
->maximize(2); // vert
808 } else if (state
[i
] ==
809 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
810 if (win
->isMaximizedFull()) {
811 win
->maximize(0); // unmaximize
812 win
->maximize(2); // vert
813 } else if (win
->isMaximizedHoriz()) {
814 win
->maximize(0); // unmaximize
815 } else if (win
->isMaximizedVert()) {
816 win
->maximize(0); // unmaximize
817 win
->maximize(1); // full
819 win
->maximize(3); // horiz
821 } else if (state
[i
] ==
822 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
824 } else if (state
[i
] ==
825 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
826 win
->setSkipTaskbar(! win
->skipTaskbar());
827 } else if (state
[i
] ==
828 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
829 win
->setSkipPager(! win
->skipPager());
830 } else if (state
[i
] ==
831 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
832 win
->setFullscreen(! win
->isFullscreen());
844 case ConfigureNotify
:
846 break; // not handled, just ignore
850 if (e
->type
== getShapeEventBase()) {
851 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
852 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
854 if (win
&& shape_event
->kind
== ShapeBounding
)
855 win
->shapeEvent(shape_event
);
863 bool Blackbox::handleSignal(int sig
) {
891 bool Blackbox::validateWindow(Window window
) {
893 if (XCheckTypedWindowEvent(getXDisplay(), window
, DestroyNotify
, &event
)) {
894 XPutBackEvent(getXDisplay(), &event
);
903 BScreen
*Blackbox::searchScreen(Window window
) {
904 ScreenList::iterator it
= screenList
.begin();
906 for (; it
!= screenList
.end(); ++it
) {
908 if (s
->getRootWindow() == window
)
912 return (BScreen
*) 0;
916 BScreen
*Blackbox::searchSystrayWindow(Window window
) {
917 WindowScreenLookup::iterator it
= systraySearchList
.find(window
);
918 if (it
!= systraySearchList
.end())
925 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
926 WindowLookup::iterator it
= windowSearchList
.find(window
);
927 if (it
!= windowSearchList
.end())
930 return (BlackboxWindow
*) 0;
934 BWindowGroup
*Blackbox::searchGroup(Window window
) {
935 GroupLookup::iterator it
= groupSearchList
.find(window
);
936 if (it
!= groupSearchList
.end())
939 return (BWindowGroup
*) 0;
943 void Blackbox::saveSystrayWindowSearch(Window window
, BScreen
*screen
) {
944 systraySearchList
.insert(WindowScreenLookupPair(window
, screen
));
948 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
949 windowSearchList
.insert(WindowLookupPair(window
, data
));
953 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
954 groupSearchList
.insert(GroupLookupPair(window
, data
));
958 void Blackbox::removeSystrayWindowSearch(Window window
) {
959 systraySearchList
.erase(window
);
963 void Blackbox::removeWindowSearch(Window window
) {
964 windowSearchList
.erase(window
);
968 void Blackbox::removeGroupSearch(Window window
) {
969 groupSearchList
.erase(window
);
973 void Blackbox::restart(const char *prog
) {
977 putenv(const_cast<char *>(screenList
.front()->displayString().c_str()));
978 execlp(prog
, prog
, NULL
);
982 // fall back in case the above execlp doesn't work
983 execvp(argv
[0], argv
);
984 string name
= basename(argv
[0]);
985 execvp(name
.c_str(), argv
);
989 void Blackbox::shutdown(void) {
990 BaseDisplay::shutdown();
992 XSetInputFocus(getXDisplay(), PointerRoot
, None
, CurrentTime
);
994 std::for_each(screenList
.begin(), screenList
.end(),
995 std::mem_fun(&BScreen::shutdown
));
997 XSync(getXDisplay(), False
);
1002 void Blackbox::saveXineramaPlacement(bool x
) {
1003 resource
.xinerama_placement
= x
;
1004 config
.setValue("session.xineramaSupport.windowPlacement",
1005 resource
.xinerama_placement
);
1006 reconfigure(); // make sure all screens get this change
1010 void Blackbox::saveXineramaMaximizing(bool x
) {
1011 resource
.xinerama_maximize
= x
;
1012 config
.setValue("session.xineramaSupport.windowMaximizing",
1013 resource
.xinerama_maximize
);
1014 reconfigure(); // make sure all screens get this change
1018 void Blackbox::saveXineramaSnapping(bool x
) {
1019 resource
.xinerama_snap
= x
;
1020 config
.setValue("session.xineramaSupport.windowSnapping",
1021 resource
.xinerama_snap
);
1022 reconfigure(); // make sure all screens get this change
1028 * Save all values as they are so that the defaults will be written to the rc
1031 void Blackbox::save_rc(void) {
1032 config
.setAutoSave(false);
1034 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
1035 config
.setValue("session.doubleClickInterval",
1036 resource
.double_click_interval
);
1037 config
.setValue("session.autoRaiseDelay",
1038 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
1039 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
1040 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
1041 config
.setValue("session.cacheMax", resource
.cache_max
);
1042 config
.setValue("session.styleFile", resource
.style_file
);
1043 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
1046 if (resource
.mod_mask
& Mod1Mask
) s
+= "Mod1-";
1047 if (resource
.mod_mask
& Mod2Mask
) s
+= "Mod2-";
1048 if (resource
.mod_mask
& Mod3Mask
) s
+= "Mod3-";
1049 if (resource
.mod_mask
& Mod4Mask
) s
+= "Mod4-";
1050 if (resource
.mod_mask
& Mod5Mask
) s
+= "Mod5-";
1051 if (resource
.mod_mask
& ShiftMask
) s
+= "Shift-";
1052 if (resource
.mod_mask
& ControlMask
) s
+= "Control-";
1053 s
.resize(s
.size() - 1); // drop the last '-'
1054 config
.setValue("session.modifierMask", s
);
1057 saveXineramaPlacement(resource
.xinerama_placement
);
1058 saveXineramaMaximizing(resource
.xinerama_maximize
);
1059 saveXineramaSnapping(resource
.xinerama_snap
);
1062 std::for_each(screenList
.begin(), screenList
.end(),
1063 std::mem_fun(&BScreen::save_rc
));
1065 config
.setAutoSave(true);
1070 void Blackbox::load_rc(void) {
1071 if (! config
.load())
1076 if (! config
.getValue("session.colorsPerChannel",
1077 resource
.colors_per_channel
))
1078 resource
.colors_per_channel
= 4;
1079 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
1080 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
1082 if (config
.getValue("session.styleFile", s
))
1083 resource
.style_file
= expandTilde(s
);
1085 resource
.style_file
= DEFAULTSTYLE
;
1087 if (! config
.getValue("session.doubleClickInterval",
1088 resource
.double_click_interval
));
1089 resource
.double_click_interval
= 250;
1091 if (! config
.getValue("session.autoRaiseDelay",
1092 resource
.auto_raise_delay
.tv_usec
))
1093 resource
.auto_raise_delay
.tv_usec
= 400;
1094 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
1095 resource
.auto_raise_delay
.tv_usec
-=
1096 (resource
.auto_raise_delay
.tv_sec
* 1000);
1097 resource
.auto_raise_delay
.tv_usec
*= 1000;
1099 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
1100 resource
.cache_life
= 5;
1101 resource
.cache_life
*= 60000;
1103 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
1104 resource
.cache_max
= 200;
1106 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
1107 resource
.titlebar_layout
= "ILMC";
1110 if (! config
.getValue("session.xineramaSupport.windowPlacement",
1111 resource
.xinerama_placement
))
1112 resource
.xinerama_placement
= false;
1114 if (! config
.getValue("session.xineramaSupport.windowMaximizing",
1115 resource
.xinerama_maximize
))
1116 resource
.xinerama_maximize
= false;
1118 if (! config
.getValue("session.xineramaSupport.windowSnapping",
1119 resource
.xinerama_snap
))
1120 resource
.xinerama_snap
= false;
1123 resource
.mod_mask
= 0;
1124 if (config
.getValue("session.modifierMask", s
)) {
1125 if (s
.find("Mod1") != string::npos
)
1126 resource
.mod_mask
|= Mod1Mask
;
1127 if (s
.find("Mod2") != string::npos
)
1128 resource
.mod_mask
|= Mod2Mask
;
1129 if (s
.find("Mod3") != string::npos
)
1130 resource
.mod_mask
|= Mod3Mask
;
1131 if (s
.find("Mod4") != string::npos
)
1132 resource
.mod_mask
|= Mod4Mask
;
1133 if (s
.find("Mod5") != string::npos
)
1134 resource
.mod_mask
|= Mod5Mask
;
1135 if (s
.find("Shift") != string::npos
)
1136 resource
.mod_mask
|= ShiftMask
;
1137 if (s
.find("Control") != string::npos
)
1138 resource
.mod_mask
|= ControlMask
;
1140 if (! resource
.mod_mask
)
1141 resource
.mod_mask
= Mod1Mask
;
1145 void Blackbox::reconfigure(void) {
1146 // don't reconfigure while saving the initial rc file, it's a waste and it
1147 // breaks somethings (workspace names)
1148 if (isStartup()) return;
1150 reconfigure_wait
= True
;
1152 if (! timer
->isTiming()) timer
->start();
1156 void Blackbox::real_reconfigure(void) {
1161 std::for_each(screenList
.begin(), screenList
.end(),
1162 std::mem_fun(&BScreen::reconfigure
));
1166 void Blackbox::saveStyleFilename(const string
& filename
) {
1167 assert(! filename
.empty());
1168 resource
.style_file
= filename
;
1169 config
.setValue("session.styleFile", resource
.style_file
);
1173 void Blackbox::timeout(void) {
1174 if (reconfigure_wait
)
1177 reconfigure_wait
= False
;
1181 void Blackbox::setChangingWindow(BlackboxWindow
*win
) {
1182 // make sure one of the two is null and the other isn't
1183 assert((! changing_window
&& win
) || (! win
&& changing_window
));
1184 changing_window
= win
;
1188 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1189 if (focused_window
&& focused_window
== win
) // nothing to do
1192 BScreen
*old_screen
= 0;
1194 if (focused_window
) {
1195 focused_window
->setFocusFlag(False
);
1196 old_screen
= focused_window
->getScreen();
1199 if (win
&& ! win
->isIconic()) {
1200 // the active screen is the one with the last focused window...
1201 // this will keep focus on this screen no matter where the mouse goes,
1202 // so multihead keybindings will continue to work on that screen until the
1203 // user focuses a window on a different screen.
1204 active_screen
= win
->getScreen();
1205 focused_window
= win
;
1209 if (active_screen
) {
1210 // set input focus to the toolbar of the screen with mouse
1211 XSetInputFocus(getXDisplay(),
1212 active_screen
->getRootWindow(),
1213 RevertToPointerRoot
, CurrentTime
);
1215 // set input focus to the toolbar of the first managed screen
1216 XSetInputFocus(getXDisplay(),
1217 screenList
.front()->getRootWindow(),
1218 RevertToPointerRoot
, CurrentTime
);
1221 // set input focus to the toolbar of the last screen
1222 XSetInputFocus(getXDisplay(), old_screen
->getRootWindow(),
1223 RevertToPointerRoot
, CurrentTime
);
1227 if (active_screen
&& active_screen
->isScreenManaged()) {
1228 active_screen
->updateNetizenWindowFocus();
1231 if (old_screen
&& old_screen
!= active_screen
) {
1232 old_screen
->updateNetizenWindowFocus();