1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
5 #endif // HAVE_CONFIG_H
10 #include <X11/Xatom.h>
11 #include <X11/cursorfont.h>
12 #include <X11/keysym.h>
15 #include <X11/extensions/shape.h>
20 #endif // HAVE_STDIO_H
24 #endif // HAVE_STDLIB_H
28 #endif // HAVE_STRING_H
31 # include <sys/types.h>
33 #endif // HAVE_UNISTD_H
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif // HAVE_SYS_PARAM_H
39 #ifdef HAVE_SYS_SELECT_H
40 # include <sys/select.h>
41 #endif // HAVE_SYS_SELECT_H
45 #endif // HAVE_SIGNAL_H
47 #ifdef HAVE_SYS_SIGNAL_H
48 # include <sys/signal.h>
49 #endif // HAVE_SYS_SIGNAL_H
51 #ifdef HAVE_SYS_STAT_H
52 # include <sys/types.h>
53 # include <sys/stat.h>
54 #endif // HAVE_SYS_STAT_H
56 #ifdef TIME_WITH_SYS_TIME
57 # include <sys/time.h>
59 #else // !TIME_WITH_SYS_TIME
60 # ifdef HAVE_SYS_TIME_H
61 # include <sys/time.h>
62 # else // !HAVE_SYS_TIME_H
64 # endif // HAVE_SYS_TIME_H
65 #endif // TIME_WITH_SYS_TIME
69 #endif // HAVE_LIBGEN_H
78 #include "blackbox.hh"
84 #include "workspace.hh"
90 Blackbox::Blackbox(char **m_argv
, char *dpy_name
, char *rc
)
91 : BaseDisplay(m_argv
[0], dpy_name
) {
93 if (! XSupportsLocale())
94 fprintf(stderr
, "X server does not support locale\n");
96 if (XSetLocaleModifiers("") == NULL
)
97 fprintf(stderr
, "cannot set locale modifiers\n");
102 // try to make sure the ~/.openbox directory exists
103 mkdir(expandTilde("~/.openbox").c_str(), S_IREAD
| S_IWRITE
| S_IEXEC
|
104 S_IRGRP
| S_IWGRP
| S_IXGRP
|
105 S_IROTH
| S_IWOTH
| S_IXOTH
);
107 if (! rc
) rc
= "~/.openbox/rc";
108 rc_file
= expandTilde(rc
);
109 config
.setFile(rc_file
);
113 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
= 0;
116 focused_window
= changing_window
= (BlackboxWindow
*) 0;
120 xatom
= new XAtom(getXDisplay());
122 cursor
.session
= XCreateFontCursor(getXDisplay(), XC_left_ptr
);
123 cursor
.move
= XCreateFontCursor(getXDisplay(), XC_fleur
);
124 cursor
.ll_angle
= XCreateFontCursor(getXDisplay(), XC_ll_angle
);
125 cursor
.lr_angle
= XCreateFontCursor(getXDisplay(), XC_lr_angle
);
126 cursor
.ul_angle
= XCreateFontCursor(getXDisplay(), XC_ul_angle
);
127 cursor
.ur_angle
= XCreateFontCursor(getXDisplay(), XC_ur_angle
);
129 for (unsigned int i
= 0; i
< getNumberOfScreens(); i
++) {
130 BScreen
*screen
= new BScreen(this, i
);
132 if (! screen
->isScreenManaged()) {
137 screenList
.push_back(screen
);
140 if (screenList
.empty()) {
142 "Blackbox::Blackbox: no managable screens found, aborting.\n");
146 // save current settings and default values
149 // set the screen with mouse to the first managed screen
150 active_screen
= screenList
.front();
153 XSynchronize(getXDisplay(), False
);
154 XSync(getXDisplay(), False
);
156 reconfigure_wait
= False
;
158 timer
= new BTimer(this, this);
159 timer
->setTimeout(0l);
163 Blackbox::~Blackbox(void) {
164 std::for_each(screenList
.begin(), screenList
.end(), PointerAssassin());
172 void Blackbox::process_event(XEvent
*e
) {
175 // strip the lock key modifiers
176 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
178 last_time
= e
->xbutton
.time
;
180 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
181 BScreen
*scrn
= (BScreen
*) 0;
183 if ((win
= searchWindow(e
->xbutton
.window
))) {
184 win
->buttonPressEvent(&e
->xbutton
);
186 /* XXX: is this sane on low colour desktops? */
187 if (e
->xbutton
.button
== 1)
188 win
->installColormap(True
);
189 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
190 scrn
->buttonPressEvent(&e
->xbutton
);
191 if (active_screen
!= scrn
) {
192 active_screen
= scrn
;
193 // first, set no focus window on the old screen
195 // and move focus to this screen
202 case ButtonRelease
: {
203 // strip the lock key modifiers
204 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
206 last_time
= e
->xbutton
.time
;
208 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
210 if ((win
= searchWindow(e
->xbutton
.window
)))
211 win
->buttonReleaseEvent(&e
->xbutton
);
216 case ConfigureRequest
: {
217 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
219 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
220 win
->configureRequestEvent(&e
->xconfigurerequest
);
222 if (validateWindow(e
->xconfigurerequest
.window
)) {
225 xwc
.x
= e
->xconfigurerequest
.x
;
226 xwc
.y
= e
->xconfigurerequest
.y
;
227 xwc
.width
= e
->xconfigurerequest
.width
;
228 xwc
.height
= e
->xconfigurerequest
.height
;
229 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
230 xwc
.sibling
= e
->xconfigurerequest
.above
;
231 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
233 XConfigureWindow(getXDisplay(), e
->xconfigurerequest
.window
,
234 e
->xconfigurerequest
.value_mask
, &xwc
);
243 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
244 e
->xmaprequest
.window
);
247 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
251 if (win
->isIconic()) {
255 if (win
->isShaded()) {
260 if (focus
&& (win
->isTransient() || win
->getScreen()->doFocusNew()) &&
262 win
->setInputFocus();
264 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
268 we got a map request for a window who's parent isn't root. this
269 can happen in only one circumstance:
271 a client window unmapped a managed window, and then remapped it
272 somewhere between unmapping the client window and reparenting it
275 regardless of how it happens, we need to find the screen that
278 XWindowAttributes wattrib
;
279 if (! XGetWindowAttributes(getXDisplay(), e
->xmaprequest
.window
,
281 // failed to get the window attributes, perhaps the window has
282 // now been destroyed?
286 screen
= searchScreen(wattrib
.root
);
287 assert(screen
!= 0); // this should never happen
290 screen
->manageWindow(e
->xmaprequest
.window
);
297 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
298 BScreen
*screen
= (BScreen
*) 0;
300 if ((win
= searchWindow(e
->xunmap
.window
))) {
301 win
->unmapNotifyEvent(&e
->xunmap
);
302 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
303 screen
->removeSystrayWindow(e
->xunmap
.window
);
309 case DestroyNotify
: {
310 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
311 BScreen
*screen
= (BScreen
*) 0;
312 BWindowGroup
*group
= (BWindowGroup
*) 0;
314 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
315 win
->destroyNotifyEvent(&e
->xdestroywindow
);
316 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
318 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
319 screen
->removeSystrayWindow(e
->xunmap
.window
);
325 case ReparentNotify
: {
327 this event is quite rare and is usually handled in unmapNotify
328 however, if the window is unmapped when the reparent event occurs
329 the window manager never sees it because an unmap event is not sent
330 to an already unmapped window.
332 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
334 win
->reparentNotifyEvent(&e
->xreparent
);
339 // motion notify compression...
342 while (XCheckTypedWindowEvent(getXDisplay(), e
->xmotion
.window
,
343 MotionNotify
, &realevent
)) {
347 // if we have compressed some motion events, use the last one
351 // the pointer is on the wrong screen
352 if (! e
->xmotion
.same_screen
)
355 // strip the lock key modifiers
356 e
->xmotion
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
358 last_time
= e
->xmotion
.time
;
360 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
362 if ((win
= searchWindow(e
->xmotion
.window
)))
363 win
->motionNotifyEvent(&e
->xmotion
);
368 case PropertyNotify
: {
369 last_time
= e
->xproperty
.time
;
371 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
372 BScreen
*screen
= (BScreen
*) 0;
374 if ((win
= searchWindow(e
->xproperty
.window
)))
375 win
->propertyNotifyEvent(&e
->xproperty
);
376 else if ((screen
= searchScreen(e
->xproperty
.window
)))
377 screen
->propertyNotifyEvent(&e
->xproperty
);
382 last_time
= e
->xcrossing
.time
;
384 BScreen
*screen
= (BScreen
*) 0;
385 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
387 if (e
->xcrossing
.mode
== NotifyGrab
) break;
389 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
390 (screen
= searchScreen(e
->xcrossing
.window
))) {
391 screen
->getImageControl()->installRootColormap();
392 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
394 win
->enterNotifyEvent(&e
->xcrossing
);
400 last_time
= e
->xcrossing
.time
;
402 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
404 if ((win
= searchWindow(e
->xcrossing
.window
)))
405 win
->leaveNotifyEvent(&e
->xcrossing
);
410 // compress expose events
413 int ex1
, ey1
, ex2
, ey2
;
416 ex2
= ex1
+ e
->xexpose
.width
- 1;
417 ey2
= ey1
+ e
->xexpose
.height
- 1;
418 while (XCheckTypedWindowEvent(getXDisplay(), e
->xexpose
.window
,
419 Expose
, &realevent
)) {
423 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
424 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
425 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
426 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
431 // use the merged area
434 e
->xexpose
.width
= ex2
- ex1
+ 1;
435 e
->xexpose
.height
= ey2
- ey1
+ 1;
437 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
439 if ((win
= searchWindow(e
->xexpose
.window
)))
440 win
->exposeEvent(&e
->xexpose
);
449 case ColormapNotify
: {
450 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
453 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
454 ColormapInstalled
) ? True
: False
);
460 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
461 e
->xfocus
.detail
!= NotifyAncestor
) {
463 don't process FocusIns when:
464 1. the new focus window isn't an ancestor or inferior of the old
465 focus window (NotifyNonlinear)
466 make sure to allow the FocusIn when the old focus window was an
467 ancestor but didn't have a parent, such as root (NotifyAncestor)
472 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
474 if (! win
->isFocused())
475 win
->setFocusFlag(True
);
478 set the event window to None. when the FocusOut event handler calls
479 this function recursively, it uses this as an indication that focus
480 has moved to a known window.
482 e
->xfocus
.window
= None
;
484 no_focus
= False
; // focusing is back on
491 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
493 don't process FocusOuts when:
494 2. the new focus window isn't an ancestor or inferior of the old
495 focus window (NotifyNonlinear)
500 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
501 if (win
&& win
->isFocused()) {
503 before we mark "win" as unfocused, we need to verify that focus is
504 going to a known location, is in a known location, or set focus
509 // don't check the current focus if FocusOut was generated during a grab
510 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
513 First, check if there is a pending FocusIn event waiting. if there
514 is, process it and determine if focus has moved to another window
515 (the FocusIn event handler sets the window in the event
516 structure to None to indicate this).
518 if (XCheckTypedEvent(getXDisplay(), FocusIn
, &event
)) {
520 process_event(&event
);
521 if (event
.xfocus
.window
== None
) {
529 Second, we query the X server for the current input focus.
530 to make sure that we keep a consistent state.
532 BlackboxWindow
*focus
;
535 XGetInputFocus(getXDisplay(), &w
, &revert
);
536 focus
= searchWindow(w
);
539 focus got from "win" to "focus" under some very strange
540 circumstances, and we need to make sure that the focus indication
543 setFocusedWindow(focus
);
545 // we have no idea where focus went... so we set it to somewhere
554 case ClientMessage
: {
555 if (e
->xclient
.format
== 32) {
556 if (e
->xclient
.message_type
== xatom
->getAtom(XAtom::wm_change_state
)) {
557 // WM_CHANGE_STATE message
558 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
559 if (! win
|| ! win
->validateClient()) return;
561 if (e
->xclient
.data
.l
[0] == IconicState
)
563 if (e
->xclient
.data
.l
[0] == NormalState
)
565 } else if (e
->xclient
.message_type
==
566 xatom
->getAtom(XAtom::blackbox_change_workspace
) ||
567 e
->xclient
.message_type
==
568 xatom
->getAtom(XAtom::net_current_desktop
)) {
569 // NET_CURRENT_DESKTOP message
570 BScreen
*screen
= searchScreen(e
->xclient
.window
);
572 unsigned int workspace
= e
->xclient
.data
.l
[0];
573 if (screen
&& workspace
< screen
->getWorkspaceCount())
574 screen
->changeWorkspaceID(workspace
);
575 } else if (e
->xclient
.message_type
==
576 xatom
->getAtom(XAtom::blackbox_change_window_focus
)) {
577 // TEMP HACK TO KEEP BBKEYS WORKING
578 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
580 if (win
&& win
->isVisible() && win
->setInputFocus())
581 win
->installColormap(True
);
582 } else if (e
->xclient
.message_type
==
583 xatom
->getAtom(XAtom::net_active_window
)) {
585 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
588 BScreen
*screen
= win
->getScreen();
591 win
->deiconify(False
, False
);
592 if (! win
->isStuck() &&
593 (win
->getWorkspaceNumber() != screen
->getCurrentWorkspaceID())) {
595 screen
->changeWorkspaceID(win
->getWorkspaceNumber());
597 if (win
->isVisible() && win
->setInputFocus()) {
598 win
->getScreen()->getWorkspace(win
->getWorkspaceNumber())->
600 win
->installColormap(True
);
603 } else if (e
->xclient
.message_type
==
604 xatom
->getAtom(XAtom::blackbox_cycle_window_focus
)) {
605 // BLACKBOX_CYCLE_WINDOW_FOCUS
606 BScreen
*screen
= searchScreen(e
->xclient
.window
);
609 if (! e
->xclient
.data
.l
[0])
614 } else if (e
->xclient
.message_type
==
615 xatom
->getAtom(XAtom::net_wm_desktop
)) {
617 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
620 BScreen
*screen
= win
->getScreen();
621 unsigned long wksp
= (unsigned) e
->xclient
.data
.l
[0];
622 if (wksp
< screen
->getWorkspaceCount()) {
623 if (win
->isIconic()) win
->deiconify(False
, True
);
624 if (win
->isStuck()) win
->stick();
625 if (wksp
!= screen
->getCurrentWorkspaceID())
629 screen
->reassociateWindow(win
, wksp
, True
);
630 } else if (wksp
== 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
631 wksp
== 0xffffffff) {
632 if (win
->isIconic()) win
->deiconify(False
, True
);
633 if (! win
->isStuck()) win
->stick();
634 if (! win
->isVisible()) win
->show();
637 } else if (e
->xclient
.message_type
==
638 xatom
->getAtom(XAtom::blackbox_change_attributes
)) {
639 // BLACKBOX_CHANGE_ATTRIBUTES
640 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
642 if (win
&& win
->validateClient()) {
644 net
.flags
= e
->xclient
.data
.l
[0];
645 net
.attrib
= e
->xclient
.data
.l
[1];
646 net
.workspace
= e
->xclient
.data
.l
[2];
647 net
.stack
= e
->xclient
.data
.l
[3];
648 net
.decoration
= e
->xclient
.data
.l
[4];
650 win
->changeBlackboxHints(&net
);
652 } else if (e
->xclient
.message_type
==
653 xatom
->getAtom(XAtom::net_number_of_desktops
)) {
654 // NET_NUMBER_OF_DESKTOPS
655 BScreen
*screen
= searchScreen(e
->xclient
.window
);
657 if (e
->xclient
.data
.l
[0] > 0)
658 screen
->changeWorkspaceCount((unsigned) e
->xclient
.data
.l
[0]);
659 } else if (e
->xclient
.message_type
==
660 xatom
->getAtom(XAtom::net_close_window
)) {
662 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
663 if (win
&& win
->validateClient())
664 win
->close(); // could this be smarter?
665 } else if (e
->xclient
.message_type
==
666 xatom
->getAtom(XAtom::net_wm_moveresize
)) {
668 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
669 if (win
&& win
->validateClient()) {
670 int x_root
= e
->xclient
.data
.l
[0],
671 y_root
= e
->xclient
.data
.l
[1];
672 if ((Atom
) e
->xclient
.data
.l
[2] ==
673 xatom
->getAtom(XAtom::net_wm_moveresize_move
)) {
674 win
->beginMove(x_root
, y_root
);
676 if ((Atom
) e
->xclient
.data
.l
[2] ==
677 xatom
->getAtom(XAtom::net_wm_moveresize_size_topleft
))
678 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopLeft
);
679 else if ((Atom
) e
->xclient
.data
.l
[2] ==
680 xatom
->getAtom(XAtom::net_wm_moveresize_size_topright
))
681 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopRight
);
682 else if ((Atom
) e
->xclient
.data
.l
[2] ==
683 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomleft
))
684 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomLeft
);
685 else if ((Atom
) e
->xclient
.data
.l
[2] ==
686 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomright
))
687 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomRight
);
690 } else if (e
->xclient
.message_type
==
691 xatom
->getAtom(XAtom::net_wm_state
)) {
693 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
694 if (win
&& win
->validateClient()) {
695 const Atom action
= (Atom
) e
->xclient
.data
.l
[0];
696 const Atom state
[] = { (Atom
) e
->xclient
.data
.l
[1],
697 (Atom
) e
->xclient
.data
.l
[2] };
699 for (int i
= 0; i
< 2; ++i
) {
703 if ((Atom
) e
->xclient
.data
.l
[0] == 1) {
705 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
707 } else if (state
[i
] ==
708 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
709 if (win
->isMaximizedHoriz()) {
710 win
->maximize(0); // unmaximize
711 win
->maximize(1); // full
712 } else if (! win
->isMaximized()) {
713 win
->maximize(2); // vert
715 } else if (state
[i
] ==
716 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
717 if (win
->isMaximizedVert()) {
718 win
->maximize(0); // unmaximize
719 win
->maximize(1); // full
720 } else if (! win
->isMaximized()) {
721 win
->maximize(3); // horiz
723 } else if (state
[i
] ==
724 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
725 if (! win
->isShaded())
727 } else if (state
[i
] ==
728 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
729 win
->setSkipTaskbar(True
);
730 } else if (state
[i
] ==
731 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
732 win
->setSkipPager(True
);
733 } else if (state
[i
] ==
734 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
735 win
->setFullscreen(True
);
737 } else if (action
== 0) {
739 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
740 win
->setModal(False
);
741 } else if (state
[i
] ==
742 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
743 if (win
->isMaximizedFull()) {
744 win
->maximize(0); // unmaximize
745 win
->maximize(3); // horiz
746 } else if (win
->isMaximizedVert()) {
747 win
->maximize(0); // unmaximize
749 } else if (state
[i
] ==
750 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
751 if (win
->isMaximizedFull()) {
752 win
->maximize(0); // unmaximize
753 win
->maximize(2); // vert
754 } else if (win
->isMaximizedHoriz()) {
755 win
->maximize(0); // unmaximize
757 } else if (state
[i
] ==
758 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
761 } else if (state
[i
] ==
762 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
763 win
->setSkipTaskbar(False
);
764 } else if (state
[i
] ==
765 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
766 win
->setSkipPager(False
);
767 } else if (state
[i
] ==
768 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
769 win
->setFullscreen(False
);
771 } else if (action
== 2) {
773 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
774 win
->setModal(! win
->isModal());
775 } else if (state
[i
] ==
776 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
777 if (win
->isMaximizedFull()) {
778 win
->maximize(0); // unmaximize
779 win
->maximize(3); // horiz
780 } else if (win
->isMaximizedVert()) {
781 win
->maximize(0); // unmaximize
782 } else if (win
->isMaximizedHoriz()) {
783 win
->maximize(0); // unmaximize
784 win
->maximize(1); // full
786 win
->maximize(2); // vert
788 } else if (state
[i
] ==
789 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
790 if (win
->isMaximizedFull()) {
791 win
->maximize(0); // unmaximize
792 win
->maximize(2); // vert
793 } else if (win
->isMaximizedHoriz()) {
794 win
->maximize(0); // unmaximize
795 } else if (win
->isMaximizedVert()) {
796 win
->maximize(0); // unmaximize
797 win
->maximize(1); // full
799 win
->maximize(3); // horiz
801 } else if (state
[i
] ==
802 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
804 } else if (state
[i
] ==
805 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
806 win
->setSkipTaskbar(! win
->skipTaskbar());
807 } else if (state
[i
] ==
808 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
809 win
->setSkipPager(! win
->skipPager());
810 } else if (state
[i
] ==
811 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
812 win
->setFullscreen(! win
->isFullscreen());
824 case ConfigureNotify
:
826 break; // not handled, just ignore
830 if (e
->type
== getShapeEventBase()) {
831 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
832 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
834 if (win
&& shape_event
->kind
== ShapeBounding
)
835 win
->shapeEvent(shape_event
);
843 bool Blackbox::handleSignal(int sig
) {
871 bool Blackbox::validateWindow(Window window
) {
873 if (XCheckTypedWindowEvent(getXDisplay(), window
, DestroyNotify
, &event
)) {
874 XPutBackEvent(getXDisplay(), &event
);
883 BScreen
*Blackbox::searchScreen(Window window
) {
884 ScreenList::iterator it
= screenList
.begin();
886 for (; it
!= screenList
.end(); ++it
) {
888 if (s
->getRootWindow() == window
)
892 return (BScreen
*) 0;
896 BScreen
*Blackbox::searchSystrayWindow(Window window
) {
897 WindowScreenLookup::iterator it
= systraySearchList
.find(window
);
898 if (it
!= systraySearchList
.end())
905 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
906 WindowLookup::iterator it
= windowSearchList
.find(window
);
907 if (it
!= windowSearchList
.end())
910 return (BlackboxWindow
*) 0;
914 BWindowGroup
*Blackbox::searchGroup(Window window
) {
915 GroupLookup::iterator it
= groupSearchList
.find(window
);
916 if (it
!= groupSearchList
.end())
919 return (BWindowGroup
*) 0;
923 void Blackbox::saveSystrayWindowSearch(Window window
, BScreen
*screen
) {
924 systraySearchList
.insert(WindowScreenLookupPair(window
, screen
));
928 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
929 windowSearchList
.insert(WindowLookupPair(window
, data
));
933 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
934 groupSearchList
.insert(GroupLookupPair(window
, data
));
938 void Blackbox::removeSystrayWindowSearch(Window window
) {
939 systraySearchList
.erase(window
);
943 void Blackbox::removeWindowSearch(Window window
) {
944 windowSearchList
.erase(window
);
948 void Blackbox::removeGroupSearch(Window window
) {
949 groupSearchList
.erase(window
);
953 void Blackbox::restart(const char *prog
) {
957 putenv(const_cast<char *>(screenList
.front()->displayString().c_str()));
958 execlp(prog
, prog
, NULL
);
962 // fall back in case the above execlp doesn't work
963 execvp(argv
[0], argv
);
964 string name
= basename(argv
[0]);
965 execvp(name
.c_str(), argv
);
969 void Blackbox::shutdown(void) {
970 BaseDisplay::shutdown();
972 XSetInputFocus(getXDisplay(), PointerRoot
, None
, CurrentTime
);
974 std::for_each(screenList
.begin(), screenList
.end(),
975 std::mem_fun(&BScreen::shutdown
));
977 XSync(getXDisplay(), False
);
982 void Blackbox::saveXineramaPlacement(bool x
) {
983 resource
.xinerama_placement
= x
;
984 config
.setValue("session.xineramaSupport.windowPlacement",
985 resource
.xinerama_placement
);
986 reconfigure(); // make sure all screens get this change
990 void Blackbox::saveXineramaMaximizing(bool x
) {
991 resource
.xinerama_maximize
= x
;
992 config
.setValue("session.xineramaSupport.windowMaximizing",
993 resource
.xinerama_maximize
);
994 reconfigure(); // make sure all screens get this change
998 void Blackbox::saveXineramaSnapping(bool x
) {
999 resource
.xinerama_snap
= x
;
1000 config
.setValue("session.xineramaSupport.windowSnapping",
1001 resource
.xinerama_snap
);
1002 reconfigure(); // make sure all screens get this change
1008 * Save all values as they are so that the defaults will be written to the rc
1011 void Blackbox::save_rc(void) {
1012 config
.setAutoSave(false);
1014 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
1015 config
.setValue("session.doubleClickInterval",
1016 resource
.double_click_interval
);
1017 config
.setValue("session.autoRaiseDelay",
1018 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
1019 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
1020 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
1021 config
.setValue("session.cacheMax", resource
.cache_max
);
1022 config
.setValue("session.styleFile", resource
.style_file
);
1023 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
1026 if (resource
.mod_mask
& Mod1Mask
) s
+= "Mod1-";
1027 if (resource
.mod_mask
& Mod2Mask
) s
+= "Mod2-";
1028 if (resource
.mod_mask
& Mod3Mask
) s
+= "Mod3-";
1029 if (resource
.mod_mask
& Mod4Mask
) s
+= "Mod4-";
1030 if (resource
.mod_mask
& Mod5Mask
) s
+= "Mod5-";
1031 if (resource
.mod_mask
& ShiftMask
) s
+= "Shift-";
1032 if (resource
.mod_mask
& ControlMask
) s
+= "Control-";
1033 s
.resize(s
.size() - 1); // drop the last '-'
1034 config
.setValue("session.modifierMask", s
);
1037 saveXineramaPlacement(resource
.xinerama_placement
);
1038 saveXineramaMaximizing(resource
.xinerama_maximize
);
1039 saveXineramaSnapping(resource
.xinerama_snap
);
1042 std::for_each(screenList
.begin(), screenList
.end(),
1043 std::mem_fun(&BScreen::save_rc
));
1045 config
.setAutoSave(true);
1050 void Blackbox::load_rc(void) {
1051 if (! config
.load())
1056 if (! config
.getValue("session.colorsPerChannel",
1057 resource
.colors_per_channel
))
1058 resource
.colors_per_channel
= 4;
1059 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
1060 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
1062 if (config
.getValue("session.styleFile", s
))
1063 resource
.style_file
= expandTilde(s
);
1065 resource
.style_file
= DEFAULTSTYLE
;
1067 if (! config
.getValue("session.doubleClickInterval",
1068 resource
.double_click_interval
));
1069 resource
.double_click_interval
= 250;
1071 if (! config
.getValue("session.autoRaiseDelay",
1072 resource
.auto_raise_delay
.tv_usec
))
1073 resource
.auto_raise_delay
.tv_usec
= 400;
1074 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
1075 resource
.auto_raise_delay
.tv_usec
-=
1076 (resource
.auto_raise_delay
.tv_sec
* 1000);
1077 resource
.auto_raise_delay
.tv_usec
*= 1000;
1079 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
1080 resource
.cache_life
= 5;
1081 resource
.cache_life
*= 60000;
1083 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
1084 resource
.cache_max
= 200;
1086 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
1087 resource
.titlebar_layout
= "ILMC";
1090 if (! config
.getValue("session.xineramaSupport.windowPlacement",
1091 resource
.xinerama_placement
))
1092 resource
.xinerama_placement
= false;
1094 if (! config
.getValue("session.xineramaSupport.windowMaximizing",
1095 resource
.xinerama_maximize
))
1096 resource
.xinerama_maximize
= false;
1098 if (! config
.getValue("session.xineramaSupport.windowSnapping",
1099 resource
.xinerama_snap
))
1100 resource
.xinerama_snap
= false;
1103 resource
.mod_mask
= 0;
1104 if (config
.getValue("session.modifierMask", s
)) {
1105 if (s
.find("Mod1") != string::npos
)
1106 resource
.mod_mask
|= Mod1Mask
;
1107 if (s
.find("Mod2") != string::npos
)
1108 resource
.mod_mask
|= Mod2Mask
;
1109 if (s
.find("Mod3") != string::npos
)
1110 resource
.mod_mask
|= Mod3Mask
;
1111 if (s
.find("Mod4") != string::npos
)
1112 resource
.mod_mask
|= Mod4Mask
;
1113 if (s
.find("Mod5") != string::npos
)
1114 resource
.mod_mask
|= Mod5Mask
;
1115 if (s
.find("Shift") != string::npos
)
1116 resource
.mod_mask
|= ShiftMask
;
1117 if (s
.find("Control") != string::npos
)
1118 resource
.mod_mask
|= ControlMask
;
1120 if (! resource
.mod_mask
)
1121 resource
.mod_mask
= Mod1Mask
;
1125 void Blackbox::reconfigure(void) {
1126 // don't reconfigure while saving the initial rc file, it's a waste and it
1127 // breaks somethings (workspace names)
1128 if (isStartup()) return;
1130 reconfigure_wait
= True
;
1132 if (! timer
->isTiming()) timer
->start();
1136 void Blackbox::real_reconfigure(void) {
1141 std::for_each(screenList
.begin(), screenList
.end(),
1142 std::mem_fun(&BScreen::reconfigure
));
1146 void Blackbox::saveStyleFilename(const string
& filename
) {
1147 assert(! filename
.empty());
1148 resource
.style_file
= filename
;
1149 config
.setValue("session.styleFile", resource
.style_file
);
1153 void Blackbox::timeout(void) {
1154 if (reconfigure_wait
)
1157 reconfigure_wait
= False
;
1161 void Blackbox::setChangingWindow(BlackboxWindow
*win
) {
1162 // make sure one of the two is null and the other isn't
1163 assert((! changing_window
&& win
) || (! win
&& changing_window
));
1164 changing_window
= win
;
1168 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1169 if (focused_window
&& focused_window
== win
) // nothing to do
1172 BScreen
*old_screen
= 0;
1174 if (focused_window
) {
1175 focused_window
->setFocusFlag(False
);
1176 old_screen
= focused_window
->getScreen();
1179 if (win
&& ! win
->isIconic()) {
1180 // the active screen is the one with the last focused window...
1181 // this will keep focus on this screen no matter where the mouse goes,
1182 // so multihead keybindings will continue to work on that screen until the
1183 // user focuses a window on a different screen.
1184 active_screen
= win
->getScreen();
1185 focused_window
= win
;
1189 if (active_screen
) {
1190 // set input focus to the toolbar of the screen with mouse
1191 XSetInputFocus(getXDisplay(),
1192 active_screen
->getRootWindow(),
1193 RevertToPointerRoot
, CurrentTime
);
1195 // set input focus to the toolbar of the first managed screen
1196 XSetInputFocus(getXDisplay(),
1197 screenList
.front()->getRootWindow(),
1198 RevertToPointerRoot
, CurrentTime
);
1201 // set input focus to the toolbar of the last screen
1202 XSetInputFocus(getXDisplay(), old_screen
->getRootWindow(),
1203 RevertToPointerRoot
, CurrentTime
);
1207 if (active_screen
&& active_screen
->isScreenManaged()) {
1208 active_screen
->updateNetizenWindowFocus();
1211 if (old_screen
&& old_screen
!= active_screen
) {
1212 old_screen
->updateNetizenWindowFocus();