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
) {
92 if (! XSupportsLocale())
93 fprintf(stderr
, "X server does not support locale\n");
95 if (XSetLocaleModifiers("") == NULL
)
96 fprintf(stderr
, "cannot set locale modifiers\n");
101 // try to make sure the ~/.openbox directory exists
102 mkdir(expandTilde("~/.openbox").c_str(), S_IREAD
| S_IWRITE
| S_IEXEC
|
103 S_IRGRP
| S_IWGRP
| S_IXGRP
|
104 S_IROTH
| S_IWOTH
| S_IXOTH
);
106 if (! rc
) rc
= "~/.openbox/rc";
107 rc_file
= expandTilde(rc
);
108 config
.setFile(rc_file
);
112 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
= 0;
115 focused_window
= changing_window
= (BlackboxWindow
*) 0;
119 xatom
= new XAtom(getXDisplay());
121 cursor
.session
= XCreateFontCursor(getXDisplay(), XC_left_ptr
);
122 cursor
.move
= XCreateFontCursor(getXDisplay(), XC_fleur
);
123 cursor
.ll_angle
= XCreateFontCursor(getXDisplay(), XC_ll_angle
);
124 cursor
.lr_angle
= XCreateFontCursor(getXDisplay(), XC_lr_angle
);
125 cursor
.ul_angle
= XCreateFontCursor(getXDisplay(), XC_ul_angle
);
126 cursor
.ur_angle
= XCreateFontCursor(getXDisplay(), XC_ur_angle
);
128 for (unsigned int i
= 0; i
< getNumberOfScreens(); i
++) {
129 BScreen
*screen
= new BScreen(this, i
);
131 if (! screen
->isScreenManaged()) {
136 screenList
.push_back(screen
);
139 if (screenList
.empty()) {
141 "Blackbox::Blackbox: no managable screens found, aborting.\n");
145 // save current settings and default values
148 // set the screen with mouse to the first managed screen
149 active_screen
= screenList
.front();
152 XSynchronize(getXDisplay(), False
);
153 XSync(getXDisplay(), False
);
155 reconfigure_wait
= False
;
157 timer
= new BTimer(this, this);
158 timer
->setTimeout(0l);
162 Blackbox::~Blackbox(void) {
163 std::for_each(screenList
.begin(), screenList
.end(), PointerAssassin());
171 void Blackbox::process_event(XEvent
*e
) {
174 // strip the lock key modifiers
175 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
177 last_time
= e
->xbutton
.time
;
179 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
180 BScreen
*scrn
= (BScreen
*) 0;
182 if ((win
= searchWindow(e
->xbutton
.window
))) {
183 win
->buttonPressEvent(&e
->xbutton
);
185 /* XXX: is this sane on low colour desktops? */
186 if (e
->xbutton
.button
== 1)
187 win
->installColormap(True
);
188 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
189 scrn
->buttonPressEvent(&e
->xbutton
);
190 if (active_screen
!= scrn
) {
191 active_screen
= scrn
;
192 // first, set no focus window on the old screen
194 // and move focus to this screen
201 case ButtonRelease
: {
202 // strip the lock key modifiers
203 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
205 last_time
= e
->xbutton
.time
;
207 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
209 if ((win
= searchWindow(e
->xbutton
.window
)))
210 win
->buttonReleaseEvent(&e
->xbutton
);
215 case ConfigureRequest
: {
216 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
218 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
219 win
->configureRequestEvent(&e
->xconfigurerequest
);
221 if (validateWindow(e
->xconfigurerequest
.window
)) {
224 xwc
.x
= e
->xconfigurerequest
.x
;
225 xwc
.y
= e
->xconfigurerequest
.y
;
226 xwc
.width
= e
->xconfigurerequest
.width
;
227 xwc
.height
= e
->xconfigurerequest
.height
;
228 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
229 xwc
.sibling
= e
->xconfigurerequest
.above
;
230 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
232 XConfigureWindow(getXDisplay(), e
->xconfigurerequest
.window
,
233 e
->xconfigurerequest
.value_mask
, &xwc
);
242 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
243 e
->xmaprequest
.window
);
246 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
250 if (win
->isIconic()) {
254 if (win
->isShaded()) {
259 if (focus
&& (win
->isTransient() || win
->getScreen()->doFocusNew()) &&
261 win
->setInputFocus();
263 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
267 we got a map request for a window who's parent isn't root. this
268 can happen in only one circumstance:
270 a client window unmapped a managed window, and then remapped it
271 somewhere between unmapping the client window and reparenting it
274 regardless of how it happens, we need to find the screen that
277 XWindowAttributes wattrib
;
278 if (! XGetWindowAttributes(getXDisplay(), e
->xmaprequest
.window
,
280 // failed to get the window attributes, perhaps the window has
281 // now been destroyed?
285 screen
= searchScreen(wattrib
.root
);
286 assert(screen
!= 0); // this should never happen
289 screen
->manageWindow(e
->xmaprequest
.window
);
296 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
297 BScreen
*screen
= (BScreen
*) 0;
299 if ((win
= searchWindow(e
->xunmap
.window
))) {
300 win
->unmapNotifyEvent(&e
->xunmap
);
301 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
302 screen
->removeSystrayWindow(e
->xunmap
.window
);
308 case DestroyNotify
: {
309 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
310 BScreen
*screen
= (BScreen
*) 0;
311 BWindowGroup
*group
= (BWindowGroup
*) 0;
313 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
314 win
->destroyNotifyEvent(&e
->xdestroywindow
);
315 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
317 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
318 screen
->removeSystrayWindow(e
->xunmap
.window
);
324 case ReparentNotify
: {
326 this event is quite rare and is usually handled in unmapNotify
327 however, if the window is unmapped when the reparent event occurs
328 the window manager never sees it because an unmap event is not sent
329 to an already unmapped window.
331 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
333 win
->reparentNotifyEvent(&e
->xreparent
);
338 // motion notify compression...
341 while (XCheckTypedWindowEvent(getXDisplay(), e
->xmotion
.window
,
342 MotionNotify
, &realevent
)) {
346 // if we have compressed some motion events, use the last one
350 // the pointer is on the wrong screen
351 if (! e
->xmotion
.same_screen
)
354 // strip the lock key modifiers
355 e
->xmotion
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
357 last_time
= e
->xmotion
.time
;
359 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
361 if ((win
= searchWindow(e
->xmotion
.window
)))
362 win
->motionNotifyEvent(&e
->xmotion
);
367 case PropertyNotify
: {
368 last_time
= e
->xproperty
.time
;
370 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
371 BScreen
*screen
= (BScreen
*) 0;
373 if ((win
= searchWindow(e
->xproperty
.window
)))
374 win
->propertyNotifyEvent(&e
->xproperty
);
375 else if ((screen
= searchScreen(e
->xproperty
.window
)))
376 screen
->propertyNotifyEvent(&e
->xproperty
);
381 last_time
= e
->xcrossing
.time
;
383 BScreen
*screen
= (BScreen
*) 0;
384 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
386 if (e
->xcrossing
.mode
== NotifyGrab
) break;
388 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
389 (screen
= searchScreen(e
->xcrossing
.window
))) {
390 screen
->getImageControl()->installRootColormap();
391 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
393 win
->enterNotifyEvent(&e
->xcrossing
);
399 last_time
= e
->xcrossing
.time
;
401 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
403 if ((win
= searchWindow(e
->xcrossing
.window
)))
404 win
->leaveNotifyEvent(&e
->xcrossing
);
409 // compress expose events
412 int ex1
, ey1
, ex2
, ey2
;
415 ex2
= ex1
+ e
->xexpose
.width
- 1;
416 ey2
= ey1
+ e
->xexpose
.height
- 1;
417 while (XCheckTypedWindowEvent(getXDisplay(), e
->xexpose
.window
,
418 Expose
, &realevent
)) {
422 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
423 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
424 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
425 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
430 // use the merged area
433 e
->xexpose
.width
= ex2
- ex1
+ 1;
434 e
->xexpose
.height
= ey2
- ey1
+ 1;
436 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
438 if ((win
= searchWindow(e
->xexpose
.window
)))
439 win
->exposeEvent(&e
->xexpose
);
448 case ColormapNotify
: {
449 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
452 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
453 ColormapInstalled
) ? True
: False
);
459 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
460 e
->xfocus
.detail
!= NotifyAncestor
) {
462 don't process FocusIns when:
463 1. the new focus window isn't an ancestor or inferior of the old
464 focus window (NotifyNonlinear)
465 make sure to allow the FocusIn when the old focus window was an
466 ancestor but didn't have a parent, such as root (NotifyAncestor)
471 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
473 if (! win
->isFocused())
474 win
->setFocusFlag(True
);
477 set the event window to None. when the FocusOut event handler calls
478 this function recursively, it uses this as an indication that focus
479 has moved to a known window.
481 e
->xfocus
.window
= None
;
483 no_focus
= False
; // focusing is back on
490 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
492 don't process FocusOuts when:
493 2. the new focus window isn't an ancestor or inferior of the old
494 focus window (NotifyNonlinear)
499 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
500 if (win
&& win
->isFocused()) {
502 before we mark "win" as unfocused, we need to verify that focus is
503 going to a known location, is in a known location, or set focus
508 // don't check the current focus if FocusOut was generated during a grab
509 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
512 First, check if there is a pending FocusIn event waiting. if there
513 is, process it and determine if focus has moved to another window
514 (the FocusIn event handler sets the window in the event
515 structure to None to indicate this).
517 if (XCheckTypedEvent(getXDisplay(), FocusIn
, &event
)) {
519 process_event(&event
);
520 if (event
.xfocus
.window
== None
) {
528 Second, we query the X server for the current input focus.
529 to make sure that we keep a consistent state.
531 BlackboxWindow
*focus
;
534 XGetInputFocus(getXDisplay(), &w
, &revert
);
535 focus
= searchWindow(w
);
538 focus got from "win" to "focus" under some very strange
539 circumstances, and we need to make sure that the focus indication
542 setFocusedWindow(focus
);
544 // we have no idea where focus went... so we set it to somewhere
553 case ClientMessage
: {
554 if (e
->xclient
.format
== 32) {
555 if (e
->xclient
.message_type
== xatom
->getAtom(XAtom::wm_change_state
)) {
556 // WM_CHANGE_STATE message
557 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
558 if (! win
|| ! win
->validateClient()) return;
560 if (e
->xclient
.data
.l
[0] == IconicState
)
562 if (e
->xclient
.data
.l
[0] == NormalState
)
564 } else if (e
->xclient
.message_type
==
565 xatom
->getAtom(XAtom::blackbox_change_workspace
) ||
566 e
->xclient
.message_type
==
567 xatom
->getAtom(XAtom::net_current_desktop
)) {
568 // NET_CURRENT_DESKTOP message
569 BScreen
*screen
= searchScreen(e
->xclient
.window
);
571 unsigned int workspace
= e
->xclient
.data
.l
[0];
572 if (screen
&& workspace
< screen
->getWorkspaceCount())
573 screen
->changeWorkspaceID(workspace
);
574 } else if (e
->xclient
.message_type
==
575 xatom
->getAtom(XAtom::blackbox_change_window_focus
)) {
576 // TEMP HACK TO KEEP BBKEYS WORKING
577 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
579 if (win
&& win
->isVisible() && win
->setInputFocus())
580 win
->installColormap(True
);
581 } else if (e
->xclient
.message_type
==
582 xatom
->getAtom(XAtom::net_active_window
)) {
584 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
587 BScreen
*screen
= win
->getScreen();
590 win
->deiconify(False
, False
);
591 if (! win
->isStuck() &&
592 (win
->getWorkspaceNumber() != screen
->getCurrentWorkspaceID())) {
594 screen
->changeWorkspaceID(win
->getWorkspaceNumber());
596 if (win
->isVisible() && win
->setInputFocus()) {
597 win
->getScreen()->getWorkspace(win
->getWorkspaceNumber())->
599 win
->installColormap(True
);
602 } else if (e
->xclient
.message_type
==
603 xatom
->getAtom(XAtom::blackbox_cycle_window_focus
)) {
604 // BLACKBOX_CYCLE_WINDOW_FOCUS
605 BScreen
*screen
= searchScreen(e
->xclient
.window
);
608 if (! e
->xclient
.data
.l
[0])
613 } else if (e
->xclient
.message_type
==
614 xatom
->getAtom(XAtom::net_wm_desktop
)) {
616 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
619 BScreen
*screen
= win
->getScreen();
620 unsigned long wksp
= (unsigned) e
->xclient
.data
.l
[0];
621 if (wksp
< screen
->getWorkspaceCount()) {
622 if (win
->isIconic()) win
->deiconify(False
, True
);
623 if (win
->isStuck()) win
->stick();
624 if (wksp
!= screen
->getCurrentWorkspaceID())
628 screen
->reassociateWindow(win
, wksp
, True
);
629 } else if (wksp
== 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
630 wksp
== 0xffffffff) {
631 if (win
->isIconic()) win
->deiconify(False
, True
);
632 if (! win
->isStuck()) win
->stick();
633 if (! win
->isVisible()) win
->show();
636 } else if (e
->xclient
.message_type
==
637 xatom
->getAtom(XAtom::blackbox_change_attributes
)) {
638 // BLACKBOX_CHANGE_ATTRIBUTES
639 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
641 if (win
&& win
->validateClient()) {
643 net
.flags
= e
->xclient
.data
.l
[0];
644 net
.attrib
= e
->xclient
.data
.l
[1];
645 net
.workspace
= e
->xclient
.data
.l
[2];
646 net
.stack
= e
->xclient
.data
.l
[3];
647 net
.decoration
= e
->xclient
.data
.l
[4];
649 win
->changeBlackboxHints(&net
);
651 } else if (e
->xclient
.message_type
==
652 xatom
->getAtom(XAtom::net_number_of_desktops
)) {
653 // NET_NUMBER_OF_DESKTOPS
654 BScreen
*screen
= searchScreen(e
->xclient
.window
);
656 if (e
->xclient
.data
.l
[0] > 0)
657 screen
->changeWorkspaceCount((unsigned) e
->xclient
.data
.l
[0]);
658 } else if (e
->xclient
.message_type
==
659 xatom
->getAtom(XAtom::net_close_window
)) {
661 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
662 if (win
&& win
->validateClient())
663 win
->close(); // could this be smarter?
664 } else if (e
->xclient
.message_type
==
665 xatom
->getAtom(XAtom::net_wm_moveresize
)) {
667 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
668 if (win
&& win
->validateClient()) {
669 int x_root
= e
->xclient
.data
.l
[0],
670 y_root
= e
->xclient
.data
.l
[1];
671 if ((Atom
) e
->xclient
.data
.l
[2] ==
672 xatom
->getAtom(XAtom::net_wm_moveresize_move
)) {
673 win
->beginMove(x_root
, y_root
);
675 if ((Atom
) e
->xclient
.data
.l
[2] ==
676 xatom
->getAtom(XAtom::net_wm_moveresize_size_topleft
))
677 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopLeft
);
678 else if ((Atom
) e
->xclient
.data
.l
[2] ==
679 xatom
->getAtom(XAtom::net_wm_moveresize_size_topright
))
680 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopRight
);
681 else if ((Atom
) e
->xclient
.data
.l
[2] ==
682 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomleft
))
683 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomLeft
);
684 else if ((Atom
) e
->xclient
.data
.l
[2] ==
685 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomright
))
686 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomRight
);
689 } else if (e
->xclient
.message_type
==
690 xatom
->getAtom(XAtom::net_wm_state
)) {
692 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
693 if (win
&& win
->validateClient()) {
694 const Atom action
= (Atom
) e
->xclient
.data
.l
[0];
695 const Atom state
[] = { (Atom
) e
->xclient
.data
.l
[1],
696 (Atom
) e
->xclient
.data
.l
[2] };
698 for (int i
= 0; i
< 2; ++i
) {
702 if ((Atom
) e
->xclient
.data
.l
[0] == 1) {
704 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
706 } else if (state
[i
] ==
707 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
708 if (win
->isMaximizedHoriz()) {
709 win
->maximize(0); // unmaximize
710 win
->maximize(1); // full
711 } else if (! win
->isMaximized()) {
712 win
->maximize(2); // vert
714 } else if (state
[i
] ==
715 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
716 if (win
->isMaximizedVert()) {
717 win
->maximize(0); // unmaximize
718 win
->maximize(1); // full
719 } else if (! win
->isMaximized()) {
720 win
->maximize(3); // horiz
722 } else if (state
[i
] ==
723 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
724 if (! win
->isShaded())
726 } else if (state
[i
] ==
727 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
728 win
->setSkipTaskbar(True
);
729 } else if (state
[i
] ==
730 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
731 win
->setSkipPager(True
);
732 } else if (state
[i
] ==
733 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
734 win
->setFullscreen(True
);
736 } else if (action
== 0) {
738 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
739 win
->setModal(False
);
740 } else if (state
[i
] ==
741 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
742 if (win
->isMaximizedFull()) {
743 win
->maximize(0); // unmaximize
744 win
->maximize(3); // horiz
745 } else if (win
->isMaximizedVert()) {
746 win
->maximize(0); // unmaximize
748 } else if (state
[i
] ==
749 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
750 if (win
->isMaximizedFull()) {
751 win
->maximize(0); // unmaximize
752 win
->maximize(2); // vert
753 } else if (win
->isMaximizedHoriz()) {
754 win
->maximize(0); // unmaximize
756 } else if (state
[i
] ==
757 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
760 } else if (state
[i
] ==
761 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
762 win
->setSkipTaskbar(False
);
763 } else if (state
[i
] ==
764 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
765 win
->setSkipPager(False
);
766 } else if (state
[i
] ==
767 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
768 win
->setFullscreen(False
);
770 } else if (action
== 2) {
772 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
773 win
->setModal(! win
->isModal());
774 } else if (state
[i
] ==
775 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
776 if (win
->isMaximizedFull()) {
777 win
->maximize(0); // unmaximize
778 win
->maximize(3); // horiz
779 } else if (win
->isMaximizedVert()) {
780 win
->maximize(0); // unmaximize
781 } else if (win
->isMaximizedHoriz()) {
782 win
->maximize(0); // unmaximize
783 win
->maximize(1); // full
785 win
->maximize(2); // vert
787 } else if (state
[i
] ==
788 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
789 if (win
->isMaximizedFull()) {
790 win
->maximize(0); // unmaximize
791 win
->maximize(2); // vert
792 } else if (win
->isMaximizedHoriz()) {
793 win
->maximize(0); // unmaximize
794 } else if (win
->isMaximizedVert()) {
795 win
->maximize(0); // unmaximize
796 win
->maximize(1); // full
798 win
->maximize(3); // horiz
800 } else if (state
[i
] ==
801 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
803 } else if (state
[i
] ==
804 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
805 win
->setSkipTaskbar(! win
->skipTaskbar());
806 } else if (state
[i
] ==
807 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
808 win
->setSkipPager(! win
->skipPager());
809 } else if (state
[i
] ==
810 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
811 win
->setFullscreen(! win
->isFullscreen());
823 case ConfigureNotify
:
825 break; // not handled, just ignore
829 if (e
->type
== getShapeEventBase()) {
830 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
831 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
833 if (win
&& shape_event
->kind
== ShapeBounding
)
834 win
->shapeEvent(shape_event
);
842 bool Blackbox::handleSignal(int sig
) {
870 bool Blackbox::validateWindow(Window window
) {
872 if (XCheckTypedWindowEvent(getXDisplay(), window
, DestroyNotify
, &event
)) {
873 XPutBackEvent(getXDisplay(), &event
);
882 BScreen
*Blackbox::searchScreen(Window window
) {
883 ScreenList::iterator it
= screenList
.begin();
885 for (; it
!= screenList
.end(); ++it
) {
887 if (s
->getRootWindow() == window
)
891 return (BScreen
*) 0;
895 BScreen
*Blackbox::searchSystrayWindow(Window window
) {
896 WindowScreenLookup::iterator it
= systraySearchList
.find(window
);
897 if (it
!= systraySearchList
.end())
904 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
905 WindowLookup::iterator it
= windowSearchList
.find(window
);
906 if (it
!= windowSearchList
.end())
909 return (BlackboxWindow
*) 0;
913 BWindowGroup
*Blackbox::searchGroup(Window window
) {
914 GroupLookup::iterator it
= groupSearchList
.find(window
);
915 if (it
!= groupSearchList
.end())
918 return (BWindowGroup
*) 0;
922 void Blackbox::saveSystrayWindowSearch(Window window
, BScreen
*screen
) {
923 systraySearchList
.insert(WindowScreenLookupPair(window
, screen
));
927 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
928 windowSearchList
.insert(WindowLookupPair(window
, data
));
932 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
933 groupSearchList
.insert(GroupLookupPair(window
, data
));
937 void Blackbox::removeSystrayWindowSearch(Window window
) {
938 systraySearchList
.erase(window
);
942 void Blackbox::removeWindowSearch(Window window
) {
943 windowSearchList
.erase(window
);
947 void Blackbox::removeGroupSearch(Window window
) {
948 groupSearchList
.erase(window
);
952 void Blackbox::restart(const char *prog
) {
956 putenv(const_cast<char *>(screenList
.front()->displayString().c_str()));
957 execlp(prog
, prog
, NULL
);
961 // fall back in case the above execlp doesn't work
962 execvp(argv
[0], argv
);
963 string name
= basename(argv
[0]);
964 execvp(name
.c_str(), argv
);
968 void Blackbox::shutdown(void) {
969 BaseDisplay::shutdown();
971 XSetInputFocus(getXDisplay(), PointerRoot
, None
, CurrentTime
);
973 std::for_each(screenList
.begin(), screenList
.end(),
974 std::mem_fun(&BScreen::shutdown
));
976 XSync(getXDisplay(), False
);
981 void Blackbox::saveXineramaPlacement(bool x
) {
982 resource
.xinerama_placement
= x
;
983 config
.setValue("session.xineramaSupport.windowPlacement",
984 resource
.xinerama_placement
);
985 reconfigure(); // make sure all screens get this change
989 void Blackbox::saveXineramaMaximizing(bool x
) {
990 resource
.xinerama_maximize
= x
;
991 config
.setValue("session.xineramaSupport.windowMaximizing",
992 resource
.xinerama_maximize
);
993 reconfigure(); // make sure all screens get this change
997 void Blackbox::saveXineramaSnapping(bool x
) {
998 resource
.xinerama_snap
= x
;
999 config
.setValue("session.xineramaSupport.windowSnapping",
1000 resource
.xinerama_snap
);
1001 reconfigure(); // make sure all screens get this change
1007 * Save all values as they are so that the defaults will be written to the rc
1010 void Blackbox::save_rc(void) {
1011 config
.setAutoSave(false);
1013 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
1014 config
.setValue("session.doubleClickInterval",
1015 resource
.double_click_interval
);
1016 config
.setValue("session.autoRaiseDelay",
1017 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
1018 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
1019 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
1020 config
.setValue("session.cacheMax", resource
.cache_max
);
1021 config
.setValue("session.styleFile", resource
.style_file
);
1022 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
1025 if (resource
.mod_mask
& Mod1Mask
) s
+= "Mod1-";
1026 if (resource
.mod_mask
& Mod2Mask
) s
+= "Mod2-";
1027 if (resource
.mod_mask
& Mod3Mask
) s
+= "Mod3-";
1028 if (resource
.mod_mask
& Mod4Mask
) s
+= "Mod4-";
1029 if (resource
.mod_mask
& Mod5Mask
) s
+= "Mod5-";
1030 if (resource
.mod_mask
& ShiftMask
) s
+= "Shift-";
1031 if (resource
.mod_mask
& ControlMask
) s
+= "Control-";
1032 s
.resize(s
.size() - 1); // drop the last '-'
1033 config
.setValue("session.modifierMask", s
);
1036 saveXineramaPlacement(resource
.xinerama_placement
);
1037 saveXineramaMaximizing(resource
.xinerama_maximize
);
1038 saveXineramaSnapping(resource
.xinerama_snap
);
1041 std::for_each(screenList
.begin(), screenList
.end(),
1042 std::mem_fun(&BScreen::save_rc
));
1044 config
.setAutoSave(true);
1049 void Blackbox::load_rc(void) {
1050 if (! config
.load())
1055 if (! config
.getValue("session.colorsPerChannel",
1056 resource
.colors_per_channel
))
1057 resource
.colors_per_channel
= 4;
1058 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
1059 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
1061 if (config
.getValue("session.styleFile", s
))
1062 resource
.style_file
= expandTilde(s
);
1064 resource
.style_file
= DEFAULTSTYLE
;
1066 if (! config
.getValue("session.doubleClickInterval",
1067 resource
.double_click_interval
));
1068 resource
.double_click_interval
= 250;
1070 if (! config
.getValue("session.autoRaiseDelay",
1071 resource
.auto_raise_delay
.tv_usec
))
1072 resource
.auto_raise_delay
.tv_usec
= 400;
1073 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
1074 resource
.auto_raise_delay
.tv_usec
-=
1075 (resource
.auto_raise_delay
.tv_sec
* 1000);
1076 resource
.auto_raise_delay
.tv_usec
*= 1000;
1078 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
1079 resource
.cache_life
= 5;
1080 resource
.cache_life
*= 60000;
1082 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
1083 resource
.cache_max
= 200;
1085 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
1086 resource
.titlebar_layout
= "ILMC";
1089 if (! config
.getValue("session.xineramaSupport.windowPlacement",
1090 resource
.xinerama_placement
))
1091 resource
.xinerama_placement
= false;
1093 if (! config
.getValue("session.xineramaSupport.windowMaximizing",
1094 resource
.xinerama_maximize
))
1095 resource
.xinerama_maximize
= false;
1097 if (! config
.getValue("session.xineramaSupport.windowSnapping",
1098 resource
.xinerama_snap
))
1099 resource
.xinerama_snap
= false;
1102 resource
.mod_mask
= 0;
1103 if (config
.getValue("session.modifierMask", s
)) {
1104 if (s
.find("Mod1") != string::npos
)
1105 resource
.mod_mask
|= Mod1Mask
;
1106 if (s
.find("Mod2") != string::npos
)
1107 resource
.mod_mask
|= Mod2Mask
;
1108 if (s
.find("Mod3") != string::npos
)
1109 resource
.mod_mask
|= Mod3Mask
;
1110 if (s
.find("Mod4") != string::npos
)
1111 resource
.mod_mask
|= Mod4Mask
;
1112 if (s
.find("Mod5") != string::npos
)
1113 resource
.mod_mask
|= Mod5Mask
;
1114 if (s
.find("Shift") != string::npos
)
1115 resource
.mod_mask
|= ShiftMask
;
1116 if (s
.find("Control") != string::npos
)
1117 resource
.mod_mask
|= ControlMask
;
1119 if (! resource
.mod_mask
)
1120 resource
.mod_mask
= Mod1Mask
;
1124 void Blackbox::reconfigure(void) {
1125 // don't reconfigure while saving the initial rc file, it's a waste and it
1126 // breaks somethings (workspace names)
1127 if (isStartup()) return;
1129 reconfigure_wait
= True
;
1131 if (! timer
->isTiming()) timer
->start();
1135 void Blackbox::real_reconfigure(void) {
1140 std::for_each(screenList
.begin(), screenList
.end(),
1141 std::mem_fun(&BScreen::reconfigure
));
1145 void Blackbox::saveStyleFilename(const string
& filename
) {
1146 assert(! filename
.empty());
1147 resource
.style_file
= filename
;
1148 config
.setValue("session.styleFile", resource
.style_file
);
1152 void Blackbox::timeout(void) {
1153 if (reconfigure_wait
)
1156 reconfigure_wait
= False
;
1160 void Blackbox::setChangingWindow(BlackboxWindow
*win
) {
1161 // make sure one of the two is null and the other isn't
1162 assert((! changing_window
&& win
) || (! win
&& changing_window
));
1163 changing_window
= win
;
1167 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1168 if (focused_window
&& focused_window
== win
) // nothing to do
1171 BScreen
*old_screen
= 0;
1173 if (focused_window
) {
1174 focused_window
->setFocusFlag(False
);
1175 old_screen
= focused_window
->getScreen();
1178 if (win
&& ! win
->isIconic()) {
1179 // the active screen is the one with the last focused window...
1180 // this will keep focus on this screen no matter where the mouse goes,
1181 // so multihead keybindings will continue to work on that screen until the
1182 // user focuses a window on a different screen.
1183 active_screen
= win
->getScreen();
1184 focused_window
= win
;
1188 if (active_screen
) {
1189 // set input focus to the toolbar of the screen with mouse
1190 XSetInputFocus(getXDisplay(),
1191 active_screen
->getRootWindow(),
1192 RevertToPointerRoot
, CurrentTime
);
1194 // set input focus to the toolbar of the first managed screen
1195 XSetInputFocus(getXDisplay(),
1196 screenList
.front()->getRootWindow(),
1197 RevertToPointerRoot
, CurrentTime
);
1200 // set input focus to the toolbar of the last screen
1201 XSetInputFocus(getXDisplay(), old_screen
->getRootWindow(),
1202 RevertToPointerRoot
, CurrentTime
);
1206 if (active_screen
&& active_screen
->isScreenManaged()) {
1207 active_screen
->updateNetizenWindowFocus();
1210 if (old_screen
&& old_screen
!= active_screen
) {
1211 old_screen
->updateNetizenWindowFocus();