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"
79 #include "otk/gccache.hh"
80 #include "otk/image.hh"
81 #include "otk/assassin.hh"
85 #include "workspace.hh"
93 Blackbox::Blackbox(int argc
, char **m_argv
, char *rc
)
94 : Openbox(argc
, m_argv
) {
96 if (! XSupportsLocale())
97 fprintf(stderr
, "X server does not support locale\n");
99 if (XSetLocaleModifiers("") == NULL
)
100 fprintf(stderr
, "cannot set locale modifiers\n");
105 // try to make sure the ~/.openbox directory exists
106 mkdir(expandTilde("~/.openbox").c_str(), S_IREAD
| S_IWRITE
| S_IEXEC
|
107 S_IRGRP
| S_IWGRP
| S_IXGRP
|
108 S_IROTH
| S_IWOTH
| S_IXOTH
);
110 if (! rc
) rc
= "~/.openbox/rc3";
111 rc_file
= expandTilde(rc
);
112 config
.setFile(rc_file
);
116 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
= 0;
119 focused_window
= changing_window
= (BlackboxWindow
*) 0;
123 xatom
= new XAtom(otk::OBDisplay::display
);
125 cursor
.session
= XCreateFontCursor(otk::OBDisplay::display
, XC_left_ptr
);
126 cursor
.move
= XCreateFontCursor(otk::OBDisplay::display
, XC_fleur
);
127 cursor
.ll_angle
= XCreateFontCursor(otk::OBDisplay::display
, XC_ll_angle
);
128 cursor
.lr_angle
= XCreateFontCursor(otk::OBDisplay::display
, XC_lr_angle
);
129 cursor
.ul_angle
= XCreateFontCursor(otk::OBDisplay::display
, XC_ul_angle
);
130 cursor
.ur_angle
= XCreateFontCursor(otk::OBDisplay::display
, XC_ur_angle
);
132 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); i
++) {
133 BScreen
*screen
= new BScreen(this, i
);
135 if (! screen
->isScreenManaged()) {
140 screenList
.push_back(screen
);
143 if (screenList
.empty()) {
145 "Blackbox::Blackbox: no managable screens found, aborting.\n");
149 // save current settings and default values
152 // set the screen with mouse to the first managed screen
153 active_screen
= screenList
.front();
156 XSynchronize(otk::OBDisplay::display
, False
);
157 XSync(otk::OBDisplay::display
, False
);
159 reconfigure_wait
= False
;
161 timer
= new otk::OBTimer(Openbox::instance
->timerManager(),
162 (otk::OBTimeoutHandler
)timeout
,
164 timer
->setTimeout(0l);
168 Blackbox::~Blackbox(void) {
169 std::for_each(screenList
.begin(), screenList
.end(), otk::PointerAssassin());
177 void Blackbox::process_event(XEvent
*e
) {
180 // strip the lock key modifiers
181 //e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
183 last_time
= e
->xbutton
.time
;
185 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
186 BScreen
*scrn
= (BScreen
*) 0;
188 if ((win
= searchWindow(e
->xbutton
.window
))) {
189 win
->buttonPressEvent(&e
->xbutton
);
191 /* XXX: is this sane on low colour desktops? */
192 if (e
->xbutton
.button
== 1)
193 win
->installColormap(True
);
194 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
195 scrn
->buttonPressEvent(&e
->xbutton
);
196 if (active_screen
!= scrn
) {
197 active_screen
= scrn
;
198 // first, set no focus window on the old screen
200 // and move focus to this screen
207 case ButtonRelease
: {
208 // strip the lock key modifiers
209 //e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
211 last_time
= e
->xbutton
.time
;
213 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
215 if ((win
= searchWindow(e
->xbutton
.window
)))
216 win
->buttonReleaseEvent(&e
->xbutton
);
221 case ConfigureRequest
: {
222 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
224 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
225 win
->configureRequestEvent(&e
->xconfigurerequest
);
227 if (validateWindow(e
->xconfigurerequest
.window
)) {
230 xwc
.x
= e
->xconfigurerequest
.x
;
231 xwc
.y
= e
->xconfigurerequest
.y
;
232 xwc
.width
= e
->xconfigurerequest
.width
;
233 xwc
.height
= e
->xconfigurerequest
.height
;
234 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
235 xwc
.sibling
= e
->xconfigurerequest
.above
;
236 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
238 XConfigureWindow(otk::OBDisplay::display
, e
->xconfigurerequest
.window
,
239 e
->xconfigurerequest
.value_mask
, &xwc
);
248 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
249 e
->xmaprequest
.window
);
252 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
256 if (win
->isIconic()) {
260 if (win
->isShaded()) {
265 if (focus
&& (win
->isTransient() || win
->getScreen()->doFocusNew()) &&
267 win
->setInputFocus();
269 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
273 we got a map request for a window who's parent isn't root. this
274 can happen in only one circumstance:
276 a client window unmapped a managed window, and then remapped it
277 somewhere between unmapping the client window and reparenting it
280 regardless of how it happens, we need to find the screen that
283 XWindowAttributes wattrib
;
284 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
->xmaprequest
.window
,
286 // failed to get the window attributes, perhaps the window has
287 // now been destroyed?
291 screen
= searchScreen(wattrib
.root
);
292 assert(screen
!= 0); // this should never happen
295 screen
->manageWindow(e
->xmaprequest
.window
);
302 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
303 BScreen
*screen
= (BScreen
*) 0;
305 if ((win
= searchWindow(e
->xunmap
.window
))) {
306 win
->unmapNotifyEvent(&e
->xunmap
);
307 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
308 screen
->removeSystrayWindow(e
->xunmap
.window
);
314 case DestroyNotify
: {
315 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
316 BScreen
*screen
= (BScreen
*) 0;
317 BWindowGroup
*group
= (BWindowGroup
*) 0;
319 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
320 win
->destroyNotifyEvent(&e
->xdestroywindow
);
321 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
323 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
324 screen
->removeSystrayWindow(e
->xunmap
.window
);
330 case ReparentNotify
: {
332 this event is quite rare and is usually handled in unmapNotify
333 however, if the window is unmapped when the reparent event occurs
334 the window manager never sees it because an unmap event is not sent
335 to an already unmapped window.
337 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
339 win
->reparentNotifyEvent(&e
->xreparent
);
344 // motion notify compression...
347 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, e
->xmotion
.window
,
348 MotionNotify
, &realevent
)) {
352 // if we have compressed some motion events, use the last one
356 // the pointer is on the wrong screen
357 if (! e
->xmotion
.same_screen
)
360 // strip the lock key modifiers
361 //e->xmotion.state &= ~(NumLockMask | ScrollLockMask | LockMask);
363 last_time
= e
->xmotion
.time
;
365 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
367 if ((win
= searchWindow(e
->xmotion
.window
)))
368 win
->motionNotifyEvent(&e
->xmotion
);
373 case PropertyNotify
: {
374 last_time
= e
->xproperty
.time
;
376 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
377 BScreen
*screen
= (BScreen
*) 0;
379 if ((win
= searchWindow(e
->xproperty
.window
)))
380 win
->propertyNotifyEvent(&e
->xproperty
);
381 else if ((screen
= searchScreen(e
->xproperty
.window
)))
382 screen
->propertyNotifyEvent(&e
->xproperty
);
387 last_time
= e
->xcrossing
.time
;
389 BScreen
*screen
= (BScreen
*) 0;
390 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
392 if (e
->xcrossing
.mode
== NotifyGrab
) break;
394 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
395 (screen
= searchScreen(e
->xcrossing
.window
))) {
396 screen
->getImageControl()->installRootColormap();
397 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
399 win
->enterNotifyEvent(&e
->xcrossing
);
405 last_time
= e
->xcrossing
.time
;
407 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
409 if ((win
= searchWindow(e
->xcrossing
.window
)))
410 win
->leaveNotifyEvent(&e
->xcrossing
);
415 // compress expose events
418 int ex1
, ey1
, ex2
, ey2
;
421 ex2
= ex1
+ e
->xexpose
.width
- 1;
422 ey2
= ey1
+ e
->xexpose
.height
- 1;
423 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, e
->xexpose
.window
,
424 Expose
, &realevent
)) {
428 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
429 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
430 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
431 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
436 // use the merged area
439 e
->xexpose
.width
= ex2
- ex1
+ 1;
440 e
->xexpose
.height
= ey2
- ey1
+ 1;
442 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
444 if ((win
= searchWindow(e
->xexpose
.window
)))
445 win
->exposeEvent(&e
->xexpose
);
454 case ColormapNotify
: {
455 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
458 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
459 ColormapInstalled
) ? True
: False
);
465 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
466 e
->xfocus
.detail
!= NotifyAncestor
) {
468 don't process FocusIns when:
469 1. the new focus window isn't an ancestor or inferior of the old
470 focus window (NotifyNonlinear)
471 make sure to allow the FocusIn when the old focus window was an
472 ancestor but didn't have a parent, such as root (NotifyAncestor)
477 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
479 if (! win
->isFocused())
480 win
->setFocusFlag(True
);
483 set the event window to None. when the FocusOut event handler calls
484 this function recursively, it uses this as an indication that focus
485 has moved to a known window.
487 e
->xfocus
.window
= None
;
489 no_focus
= False
; // focusing is back on
496 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
498 don't process FocusOuts when:
499 2. the new focus window isn't an ancestor or inferior of the old
500 focus window (NotifyNonlinear)
505 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
506 if (win
&& win
->isFocused()) {
508 before we mark "win" as unfocused, we need to verify that focus is
509 going to a known location, is in a known location, or set focus
514 // don't check the current focus if FocusOut was generated during a grab
515 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
518 First, check if there is a pending FocusIn event waiting. if there
519 is, process it and determine if focus has moved to another window
520 (the FocusIn event handler sets the window in the event
521 structure to None to indicate this).
523 if (XCheckTypedEvent(otk::OBDisplay::display
, FocusIn
, &event
)) {
525 process_event(&event
);
526 if (event
.xfocus
.window
== None
) {
534 Second, we query the X server for the current input focus.
535 to make sure that we keep a consistent state.
537 BlackboxWindow
*focus
;
540 XGetInputFocus(otk::OBDisplay::display
, &w
, &revert
);
541 focus
= searchWindow(w
);
544 focus got from "win" to "focus" under some very strange
545 circumstances, and we need to make sure that the focus indication
548 setFocusedWindow(focus
);
550 // we have no idea where focus went... so we set it to somewhere
559 case ClientMessage
: {
560 if (e
->xclient
.format
== 32) {
561 if (e
->xclient
.message_type
== xatom
->getAtom(XAtom::wm_change_state
)) {
562 // WM_CHANGE_STATE message
563 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
564 if (! win
|| ! win
->validateClient()) return;
566 if (e
->xclient
.data
.l
[0] == IconicState
)
568 if (e
->xclient
.data
.l
[0] == NormalState
)
570 } else if (e
->xclient
.message_type
==
571 xatom
->getAtom(XAtom::blackbox_change_workspace
) ||
572 e
->xclient
.message_type
==
573 xatom
->getAtom(XAtom::net_current_desktop
)) {
574 // NET_CURRENT_DESKTOP message
575 BScreen
*screen
= searchScreen(e
->xclient
.window
);
577 unsigned int workspace
= e
->xclient
.data
.l
[0];
578 if (screen
&& workspace
< screen
->getWorkspaceCount())
579 screen
->changeWorkspaceID(workspace
);
580 } else if (e
->xclient
.message_type
==
581 xatom
->getAtom(XAtom::blackbox_change_window_focus
)) {
582 // TEMP HACK TO KEEP BBKEYS WORKING
583 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
585 if (win
&& win
->isVisible() && win
->setInputFocus())
586 win
->installColormap(True
);
587 } else if (e
->xclient
.message_type
==
588 xatom
->getAtom(XAtom::net_active_window
)) {
590 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
593 BScreen
*screen
= win
->getScreen();
596 win
->deiconify(False
, False
);
597 if (! win
->isStuck() &&
598 (win
->getWorkspaceNumber() != screen
->getCurrentWorkspaceID())) {
600 screen
->changeWorkspaceID(win
->getWorkspaceNumber());
602 if (win
->isVisible() && win
->setInputFocus()) {
603 win
->getScreen()->getWorkspace(win
->getWorkspaceNumber())->
605 win
->installColormap(True
);
608 } else if (e
->xclient
.message_type
==
609 xatom
->getAtom(XAtom::blackbox_cycle_window_focus
)) {
610 // BLACKBOX_CYCLE_WINDOW_FOCUS
611 BScreen
*screen
= searchScreen(e
->xclient
.window
);
614 if (! e
->xclient
.data
.l
[0])
619 } else if (e
->xclient
.message_type
==
620 xatom
->getAtom(XAtom::net_wm_desktop
)) {
622 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
625 BScreen
*screen
= win
->getScreen();
626 unsigned long wksp
= (unsigned) e
->xclient
.data
.l
[0];
627 if (wksp
< screen
->getWorkspaceCount()) {
628 if (win
->isIconic()) win
->deiconify(False
, True
);
629 if (win
->isStuck()) win
->stick();
630 if (wksp
!= screen
->getCurrentWorkspaceID())
634 screen
->reassociateWindow(win
, wksp
, True
);
635 } else if (wksp
== 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
636 wksp
== 0xffffffff) {
637 if (win
->isIconic()) win
->deiconify(False
, True
);
638 if (! win
->isStuck()) win
->stick();
639 if (! win
->isVisible()) win
->show();
642 } else if (e
->xclient
.message_type
==
643 xatom
->getAtom(XAtom::blackbox_change_attributes
)) {
644 // BLACKBOX_CHANGE_ATTRIBUTES
645 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
647 if (win
&& win
->validateClient()) {
649 net
.flags
= e
->xclient
.data
.l
[0];
650 net
.attrib
= e
->xclient
.data
.l
[1];
651 net
.workspace
= e
->xclient
.data
.l
[2];
652 net
.stack
= e
->xclient
.data
.l
[3];
653 net
.decoration
= e
->xclient
.data
.l
[4];
655 win
->changeBlackboxHints(&net
);
657 } else if (e
->xclient
.message_type
==
658 xatom
->getAtom(XAtom::net_number_of_desktops
)) {
659 // NET_NUMBER_OF_DESKTOPS
660 BScreen
*screen
= searchScreen(e
->xclient
.window
);
662 if (e
->xclient
.data
.l
[0] > 0)
663 screen
->changeWorkspaceCount((unsigned) e
->xclient
.data
.l
[0]);
664 } else if (e
->xclient
.message_type
==
665 xatom
->getAtom(XAtom::net_close_window
)) {
667 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
668 if (win
&& win
->validateClient())
669 win
->close(); // could this be smarter?
670 } else if (e
->xclient
.message_type
==
671 xatom
->getAtom(XAtom::net_wm_moveresize
)) {
673 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
674 if (win
&& win
->validateClient()) {
675 int x_root
= e
->xclient
.data
.l
[0],
676 y_root
= e
->xclient
.data
.l
[1];
677 if ((Atom
) e
->xclient
.data
.l
[2] ==
678 xatom
->getAtom(XAtom::net_wm_moveresize_move
)) {
679 win
->beginMove(x_root
, y_root
);
681 if ((Atom
) e
->xclient
.data
.l
[2] ==
682 xatom
->getAtom(XAtom::net_wm_moveresize_size_topleft
))
683 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopLeft
);
684 else if ((Atom
) e
->xclient
.data
.l
[2] ==
685 xatom
->getAtom(XAtom::net_wm_moveresize_size_topright
))
686 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopRight
);
687 else if ((Atom
) e
->xclient
.data
.l
[2] ==
688 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomleft
))
689 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomLeft
);
690 else if ((Atom
) e
->xclient
.data
.l
[2] ==
691 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomright
))
692 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomRight
);
695 } else if (e
->xclient
.message_type
==
696 xatom
->getAtom(XAtom::net_wm_state
)) {
698 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
699 if (win
&& win
->validateClient()) {
700 const Atom action
= (Atom
) e
->xclient
.data
.l
[0];
701 const Atom state
[] = { (Atom
) e
->xclient
.data
.l
[1],
702 (Atom
) e
->xclient
.data
.l
[2] };
704 for (int i
= 0; i
< 2; ++i
) {
708 if ((Atom
) e
->xclient
.data
.l
[0] == 1) {
710 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
712 } else if (state
[i
] ==
713 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
714 if (win
->isMaximizedHoriz()) {
715 win
->maximize(0); // unmaximize
716 win
->maximize(1); // full
717 } else if (! win
->isMaximized()) {
718 win
->maximize(2); // vert
720 } else if (state
[i
] ==
721 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
722 if (win
->isMaximizedVert()) {
723 win
->maximize(0); // unmaximize
724 win
->maximize(1); // full
725 } else if (! win
->isMaximized()) {
726 win
->maximize(3); // horiz
728 } else if (state
[i
] ==
729 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
730 if (! win
->isShaded())
732 } else if (state
[i
] ==
733 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
734 win
->setSkipTaskbar(True
);
735 } else if (state
[i
] ==
736 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
737 win
->setSkipPager(True
);
738 } else if (state
[i
] ==
739 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
740 win
->setFullscreen(True
);
742 } else if (action
== 0) {
744 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
745 win
->setModal(False
);
746 } else if (state
[i
] ==
747 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
748 if (win
->isMaximizedFull()) {
749 win
->maximize(0); // unmaximize
750 win
->maximize(3); // horiz
751 } else if (win
->isMaximizedVert()) {
752 win
->maximize(0); // unmaximize
754 } else if (state
[i
] ==
755 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
756 if (win
->isMaximizedFull()) {
757 win
->maximize(0); // unmaximize
758 win
->maximize(2); // vert
759 } else if (win
->isMaximizedHoriz()) {
760 win
->maximize(0); // unmaximize
762 } else if (state
[i
] ==
763 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
766 } else if (state
[i
] ==
767 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
768 win
->setSkipTaskbar(False
);
769 } else if (state
[i
] ==
770 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
771 win
->setSkipPager(False
);
772 } else if (state
[i
] ==
773 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
774 win
->setFullscreen(False
);
776 } else if (action
== 2) {
778 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
779 win
->setModal(! win
->isModal());
780 } else if (state
[i
] ==
781 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
782 if (win
->isMaximizedFull()) {
783 win
->maximize(0); // unmaximize
784 win
->maximize(3); // horiz
785 } else if (win
->isMaximizedVert()) {
786 win
->maximize(0); // unmaximize
787 } else if (win
->isMaximizedHoriz()) {
788 win
->maximize(0); // unmaximize
789 win
->maximize(1); // full
791 win
->maximize(2); // vert
793 } else if (state
[i
] ==
794 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
795 if (win
->isMaximizedFull()) {
796 win
->maximize(0); // unmaximize
797 win
->maximize(2); // vert
798 } else if (win
->isMaximizedHoriz()) {
799 win
->maximize(0); // unmaximize
800 } else if (win
->isMaximizedVert()) {
801 win
->maximize(0); // unmaximize
802 win
->maximize(1); // full
804 win
->maximize(3); // horiz
806 } else if (state
[i
] ==
807 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
809 } else if (state
[i
] ==
810 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
811 win
->setSkipTaskbar(! win
->skipTaskbar());
812 } else if (state
[i
] ==
813 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
814 win
->setSkipPager(! win
->skipPager());
815 } else if (state
[i
] ==
816 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
817 win
->setFullscreen(! win
->isFullscreen());
829 case ConfigureNotify
:
831 break; // not handled, just ignore
835 if (e
->type
== getShapeEventBase()) {
836 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
837 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
839 if (win
&& shape_event
->kind
== ShapeBounding
)
840 win
->shapeEvent(shape_event
);
848 bool Blackbox::handleSignal(int sig
) {
876 bool Blackbox::validateWindow(Window window
) {
878 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, window
, DestroyNotify
, &event
)) {
879 XPutBackEvent(otk::OBDisplay::display
, &event
);
888 BScreen
*Blackbox::searchScreen(Window window
) {
889 ScreenList::iterator it
= screenList
.begin();
891 for (; it
!= screenList
.end(); ++it
) {
893 if (s
->getRootWindow() == window
)
897 return (BScreen
*) 0;
901 BScreen
*Blackbox::searchSystrayWindow(Window window
) {
902 WindowScreenLookup::iterator it
= systraySearchList
.find(window
);
903 if (it
!= systraySearchList
.end())
910 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
911 WindowLookup::iterator it
= windowSearchList
.find(window
);
912 if (it
!= windowSearchList
.end())
915 return (BlackboxWindow
*) 0;
919 BWindowGroup
*Blackbox::searchGroup(Window window
) {
920 GroupLookup::iterator it
= groupSearchList
.find(window
);
921 if (it
!= groupSearchList
.end())
924 return (BWindowGroup
*) 0;
928 void Blackbox::saveSystrayWindowSearch(Window window
, BScreen
*screen
) {
929 systraySearchList
.insert(WindowScreenLookupPair(window
, screen
));
933 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
934 windowSearchList
.insert(WindowLookupPair(window
, data
));
938 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
939 groupSearchList
.insert(GroupLookupPair(window
, data
));
943 void Blackbox::removeSystrayWindowSearch(Window window
) {
944 systraySearchList
.erase(window
);
948 void Blackbox::removeWindowSearch(Window window
) {
949 windowSearchList
.erase(window
);
953 void Blackbox::removeGroupSearch(Window window
) {
954 groupSearchList
.erase(window
);
958 void Blackbox::restart(const char *prog
) {
962 putenv(const_cast<char *>(screenList
.front()->displayString().c_str()));
963 execlp(prog
, prog
, NULL
);
967 // fall back in case the above execlp doesn't work
968 execvp(argv
[0], argv
);
969 string name
= ::basename(argv
[0]);
970 execvp(name
.c_str(), argv
);
974 void Blackbox::shutdown(void) {
977 XSetInputFocus(otk::OBDisplay::display
, PointerRoot
, None
, CurrentTime
);
979 std::for_each(screenList
.begin(), screenList
.end(),
980 std::mem_fun(&BScreen::shutdown
));
982 XSync(otk::OBDisplay::display
, False
);
987 void Blackbox::saveXineramaPlacement(bool x
) {
988 resource
.xinerama_placement
= x
;
989 config
.setValue("session.xineramaSupport.windowPlacement",
990 resource
.xinerama_placement
);
991 reconfigure(); // make sure all screens get this
993 void Blackbox::saveXineramaMaximizing(bool x
) {
994 resource
.xinerama_maximize
= x
;
995 config
.setValue("session.xineramaSupport.windowMaximizing",
996 resource
.xinerama_maximize
);
997 reconfigure(); // make sure all screens get this change
1001 void Blackbox::saveXineramaSnapping(bool x
) {
1002 resource
.xinerama_snap
= x
;
1003 config
.setValue("session.xineramaSupport.windowSnapping",
1004 resource
.xinerama_snap
);
1005 reconfigure(); // make sure all screens get this change
1011 * Save all values as they are so that the defaults will be written to the rc
1014 void Blackbox::save_rc(void) {
1015 config
.setAutoSave(false);
1017 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
1018 config
.setValue("session.doubleClickInterval",
1019 resource
.double_click_interval
);
1020 config
.setValue("session.autoRaiseDelay",
1021 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
1022 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
1023 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
1024 config
.setValue("session.cacheMax", resource
.cache_max
);
1025 config
.setValue("session.styleFile", resource
.style_file
);
1026 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
1029 if (resource
.mod_mask
& Mod1Mask
) s
+= "Mod1-";
1030 if (resource
.mod_mask
& Mod2Mask
) s
+= "Mod2-";
1031 if (resource
.mod_mask
& Mod3Mask
) s
+= "Mod3-";
1032 if (resource
.mod_mask
& Mod4Mask
) s
+= "Mod4-";
1033 if (resource
.mod_mask
& Mod5Mask
) s
+= "Mod5-";
1034 if (resource
.mod_mask
& ShiftMask
) s
+= "Shift-";
1035 if (resource
.mod_mask
& ControlMask
) s
+= "Control-";
1036 s
.resize(s
.size() - 1); // drop the last '-'
1037 config
.setValue("session.modifierMask", s
);
1040 saveXineramaPlacement(resource
.xinerama_placement
);
1041 saveXineramaMaximizing(resource
.xinerama_maximize
);
1042 saveXineramaSnapping(resource
.xinerama_snap
);
1045 std::for_each(screenList
.begin(), screenList
.end(),
1046 std::mem_fun(&BScreen::save_rc
));
1048 config
.setAutoSave(true);
1053 void Blackbox::load_rc(void) {
1054 if (! config
.load())
1059 if (! config
.getValue("session.colorsPerChannel",
1060 resource
.colors_per_channel
))
1061 resource
.colors_per_channel
= 4;
1062 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
1063 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
1065 if (config
.getValue("session.styleFile", s
))
1066 resource
.style_file
= expandTilde(s
);
1068 resource
.style_file
= DEFAULTSTYLE
;
1070 if (! config
.getValue("session.doubleClickInterval",
1071 resource
.double_click_interval
));
1072 resource
.double_click_interval
= 250;
1074 if (! config
.getValue("session.autoRaiseDelay",
1075 resource
.auto_raise_delay
.tv_usec
))
1076 resource
.auto_raise_delay
.tv_usec
= 400;
1077 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
1078 resource
.auto_raise_delay
.tv_usec
-=
1079 (resource
.auto_raise_delay
.tv_sec
* 1000);
1080 resource
.auto_raise_delay
.tv_usec
*= 1000;
1082 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
1083 resource
.cache_life
= 5;
1084 resource
.cache_life
*= 60000;
1086 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
1087 resource
.cache_max
= 200;
1089 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
1090 resource
.titlebar_layout
= "ILMC";
1093 if (! config
.getValue("session.xineramaSupport.windowPlacement",
1094 resource
.xinerama_placement
))
1095 resource
.xinerama_placement
= false;
1097 if (! config
.getValue("session.xineramaSupport.windowMaximizing",
1098 resource
.xinerama_maximize
))
1099 resource
.xinerama_maximize
= false;
1101 if (! config
.getValue("session.xineramaSupport.windowSnapping",
1102 resource
.xinerama_snap
))
1103 resource
.xinerama_snap
= false;
1106 resource
.mod_mask
= 0;
1107 if (config
.getValue("session.modifierMask", s
)) {
1108 if (s
.find("Mod1") != string::npos
)
1109 resource
.mod_mask
|= Mod1Mask
;
1110 if (s
.find("Mod2") != string::npos
)
1111 resource
.mod_mask
|= Mod2Mask
;
1112 if (s
.find("Mod3") != string::npos
)
1113 resource
.mod_mask
|= Mod3Mask
;
1114 if (s
.find("Mod4") != string::npos
)
1115 resource
.mod_mask
|= Mod4Mask
;
1116 if (s
.find("Mod5") != string::npos
)
1117 resource
.mod_mask
|= Mod5Mask
;
1118 if (s
.find("Shift") != string::npos
)
1119 resource
.mod_mask
|= ShiftMask
;
1120 if (s
.find("Control") != string::npos
)
1121 resource
.mod_mask
|= ControlMask
;
1123 if (! resource
.mod_mask
)
1124 resource
.mod_mask
= Mod1Mask
;
1128 void Blackbox::reconfigure(void) {
1129 // don't reconfigure while saving the initial rc file, it's a waste and it
1130 // breaks somethings (workspace names)
1131 if (state() == Openbox::State_Starting
) return;
1133 reconfigure_wait
= True
;
1135 if (! timer
->timing()) timer
->start();
1139 void Blackbox::real_reconfigure(void) {
1142 otk::OBDisplay::gcCache()->purge();
1144 std::for_each(screenList
.begin(), screenList
.end(),
1145 std::mem_fun(&BScreen::reconfigure
));
1149 void Blackbox::saveStyleFilename(const string
& filename
) {
1150 assert(! filename
.empty());
1151 resource
.style_file
= filename
;
1152 config
.setValue("session.styleFile", resource
.style_file
);
1156 void Blackbox::timeout(Blackbox
*t
) {
1157 if (t
->reconfigure_wait
)
1158 t
->real_reconfigure();
1160 t
->reconfigure_wait
= False
;
1164 void Blackbox::setChangingWindow(BlackboxWindow
*win
) {
1165 // make sure one of the two is null and the other isn't
1166 assert((! changing_window
&& win
) || (! win
&& changing_window
));
1167 changing_window
= win
;
1171 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1172 if (focused_window
&& focused_window
== win
) // nothing to do
1175 BScreen
*old_screen
= 0;
1177 if (focused_window
) {
1178 focused_window
->setFocusFlag(False
);
1179 old_screen
= focused_window
->getScreen();
1182 if (win
&& ! win
->isIconic()) {
1183 // the active screen is the one with the last focused window...
1184 // this will keep focus on this screen no matter where the mouse goes,
1185 // so multihead keybindings will continue to work on that screen until the
1186 // user focuses a window on a different screen.
1187 active_screen
= win
->getScreen();
1188 focused_window
= win
;
1192 if (active_screen
) {
1193 // set input focus to the toolbar of the screen with mouse
1194 XSetInputFocus(otk::OBDisplay::display
,
1195 active_screen
->getRootWindow(),
1196 RevertToPointerRoot
, CurrentTime
);
1198 // set input focus to the toolbar of the first managed screen
1199 XSetInputFocus(otk::OBDisplay::display
,
1200 screenList
.front()->getRootWindow(),
1201 RevertToPointerRoot
, CurrentTime
);
1204 // set input focus to the toolbar of the last screen
1205 XSetInputFocus(otk::OBDisplay::display
, old_screen
->getRootWindow(),
1206 RevertToPointerRoot
, CurrentTime
);
1210 if (active_screen
&& active_screen
->isScreenManaged()) {
1211 active_screen
->updateNetizenWindowFocus();
1214 if (old_screen
&& old_screen
!= active_screen
) {
1215 old_screen
->updateNetizenWindowFocus();