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/rc";
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 OBTimer(this);
162 timer
->setTimeout(0l);
166 Blackbox::~Blackbox(void) {
167 std::for_each(screenList
.begin(), screenList
.end(), otk::PointerAssassin());
175 void Blackbox::process_event(XEvent
*e
) {
178 // strip the lock key modifiers
179 //e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
181 last_time
= e
->xbutton
.time
;
183 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
184 BScreen
*scrn
= (BScreen
*) 0;
186 if ((win
= searchWindow(e
->xbutton
.window
))) {
187 win
->buttonPressEvent(&e
->xbutton
);
189 /* XXX: is this sane on low colour desktops? */
190 if (e
->xbutton
.button
== 1)
191 win
->installColormap(True
);
192 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
193 scrn
->buttonPressEvent(&e
->xbutton
);
194 if (active_screen
!= scrn
) {
195 active_screen
= scrn
;
196 // first, set no focus window on the old screen
198 // and move focus to this screen
205 case ButtonRelease
: {
206 // strip the lock key modifiers
207 //e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
209 last_time
= e
->xbutton
.time
;
211 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
213 if ((win
= searchWindow(e
->xbutton
.window
)))
214 win
->buttonReleaseEvent(&e
->xbutton
);
219 case ConfigureRequest
: {
220 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
222 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
223 win
->configureRequestEvent(&e
->xconfigurerequest
);
225 if (validateWindow(e
->xconfigurerequest
.window
)) {
228 xwc
.x
= e
->xconfigurerequest
.x
;
229 xwc
.y
= e
->xconfigurerequest
.y
;
230 xwc
.width
= e
->xconfigurerequest
.width
;
231 xwc
.height
= e
->xconfigurerequest
.height
;
232 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
233 xwc
.sibling
= e
->xconfigurerequest
.above
;
234 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
236 XConfigureWindow(otk::OBDisplay::display
, e
->xconfigurerequest
.window
,
237 e
->xconfigurerequest
.value_mask
, &xwc
);
246 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
247 e
->xmaprequest
.window
);
250 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
254 if (win
->isIconic()) {
258 if (win
->isShaded()) {
263 if (focus
&& (win
->isTransient() || win
->getScreen()->doFocusNew()) &&
265 win
->setInputFocus();
267 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
271 we got a map request for a window who's parent isn't root. this
272 can happen in only one circumstance:
274 a client window unmapped a managed window, and then remapped it
275 somewhere between unmapping the client window and reparenting it
278 regardless of how it happens, we need to find the screen that
281 XWindowAttributes wattrib
;
282 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
->xmaprequest
.window
,
284 // failed to get the window attributes, perhaps the window has
285 // now been destroyed?
289 screen
= searchScreen(wattrib
.root
);
290 assert(screen
!= 0); // this should never happen
293 screen
->manageWindow(e
->xmaprequest
.window
);
300 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
301 BScreen
*screen
= (BScreen
*) 0;
303 if ((win
= searchWindow(e
->xunmap
.window
))) {
304 win
->unmapNotifyEvent(&e
->xunmap
);
305 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
306 screen
->removeSystrayWindow(e
->xunmap
.window
);
312 case DestroyNotify
: {
313 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
314 BScreen
*screen
= (BScreen
*) 0;
315 BWindowGroup
*group
= (BWindowGroup
*) 0;
317 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
318 win
->destroyNotifyEvent(&e
->xdestroywindow
);
319 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
321 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
322 screen
->removeSystrayWindow(e
->xunmap
.window
);
328 case ReparentNotify
: {
330 this event is quite rare and is usually handled in unmapNotify
331 however, if the window is unmapped when the reparent event occurs
332 the window manager never sees it because an unmap event is not sent
333 to an already unmapped window.
335 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
337 win
->reparentNotifyEvent(&e
->xreparent
);
342 // motion notify compression...
345 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, e
->xmotion
.window
,
346 MotionNotify
, &realevent
)) {
350 // if we have compressed some motion events, use the last one
354 // the pointer is on the wrong screen
355 if (! e
->xmotion
.same_screen
)
358 // strip the lock key modifiers
359 //e->xmotion.state &= ~(NumLockMask | ScrollLockMask | LockMask);
361 last_time
= e
->xmotion
.time
;
363 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
365 if ((win
= searchWindow(e
->xmotion
.window
)))
366 win
->motionNotifyEvent(&e
->xmotion
);
371 case PropertyNotify
: {
372 last_time
= e
->xproperty
.time
;
374 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
375 BScreen
*screen
= (BScreen
*) 0;
377 if ((win
= searchWindow(e
->xproperty
.window
)))
378 win
->propertyNotifyEvent(&e
->xproperty
);
379 else if ((screen
= searchScreen(e
->xproperty
.window
)))
380 screen
->propertyNotifyEvent(&e
->xproperty
);
385 last_time
= e
->xcrossing
.time
;
387 BScreen
*screen
= (BScreen
*) 0;
388 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
390 if (e
->xcrossing
.mode
== NotifyGrab
) break;
392 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
393 (screen
= searchScreen(e
->xcrossing
.window
))) {
394 screen
->getImageControl()->installRootColormap();
395 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
397 win
->enterNotifyEvent(&e
->xcrossing
);
403 last_time
= e
->xcrossing
.time
;
405 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
407 if ((win
= searchWindow(e
->xcrossing
.window
)))
408 win
->leaveNotifyEvent(&e
->xcrossing
);
413 // compress expose events
416 int ex1
, ey1
, ex2
, ey2
;
419 ex2
= ex1
+ e
->xexpose
.width
- 1;
420 ey2
= ey1
+ e
->xexpose
.height
- 1;
421 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, e
->xexpose
.window
,
422 Expose
, &realevent
)) {
426 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
427 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
428 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
429 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
434 // use the merged area
437 e
->xexpose
.width
= ex2
- ex1
+ 1;
438 e
->xexpose
.height
= ey2
- ey1
+ 1;
440 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
442 if ((win
= searchWindow(e
->xexpose
.window
)))
443 win
->exposeEvent(&e
->xexpose
);
452 case ColormapNotify
: {
453 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
456 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
457 ColormapInstalled
) ? True
: False
);
463 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
464 e
->xfocus
.detail
!= NotifyAncestor
) {
466 don't process FocusIns when:
467 1. the new focus window isn't an ancestor or inferior of the old
468 focus window (NotifyNonlinear)
469 make sure to allow the FocusIn when the old focus window was an
470 ancestor but didn't have a parent, such as root (NotifyAncestor)
475 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
477 if (! win
->isFocused())
478 win
->setFocusFlag(True
);
481 set the event window to None. when the FocusOut event handler calls
482 this function recursively, it uses this as an indication that focus
483 has moved to a known window.
485 e
->xfocus
.window
= None
;
487 no_focus
= False
; // focusing is back on
494 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
496 don't process FocusOuts when:
497 2. the new focus window isn't an ancestor or inferior of the old
498 focus window (NotifyNonlinear)
503 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
504 if (win
&& win
->isFocused()) {
506 before we mark "win" as unfocused, we need to verify that focus is
507 going to a known location, is in a known location, or set focus
512 // don't check the current focus if FocusOut was generated during a grab
513 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
516 First, check if there is a pending FocusIn event waiting. if there
517 is, process it and determine if focus has moved to another window
518 (the FocusIn event handler sets the window in the event
519 structure to None to indicate this).
521 if (XCheckTypedEvent(otk::OBDisplay::display
, FocusIn
, &event
)) {
523 process_event(&event
);
524 if (event
.xfocus
.window
== None
) {
532 Second, we query the X server for the current input focus.
533 to make sure that we keep a consistent state.
535 BlackboxWindow
*focus
;
538 XGetInputFocus(otk::OBDisplay::display
, &w
, &revert
);
539 focus
= searchWindow(w
);
542 focus got from "win" to "focus" under some very strange
543 circumstances, and we need to make sure that the focus indication
546 setFocusedWindow(focus
);
548 // we have no idea where focus went... so we set it to somewhere
557 case ClientMessage
: {
558 if (e
->xclient
.format
== 32) {
559 if (e
->xclient
.message_type
== xatom
->getAtom(XAtom::wm_change_state
)) {
560 // WM_CHANGE_STATE message
561 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
562 if (! win
|| ! win
->validateClient()) return;
564 if (e
->xclient
.data
.l
[0] == IconicState
)
566 if (e
->xclient
.data
.l
[0] == NormalState
)
568 } else if (e
->xclient
.message_type
==
569 xatom
->getAtom(XAtom::blackbox_change_workspace
) ||
570 e
->xclient
.message_type
==
571 xatom
->getAtom(XAtom::net_current_desktop
)) {
572 // NET_CURRENT_DESKTOP message
573 BScreen
*screen
= searchScreen(e
->xclient
.window
);
575 unsigned int workspace
= e
->xclient
.data
.l
[0];
576 if (screen
&& workspace
< screen
->getWorkspaceCount())
577 screen
->changeWorkspaceID(workspace
);
578 } else if (e
->xclient
.message_type
==
579 xatom
->getAtom(XAtom::blackbox_change_window_focus
)) {
580 // TEMP HACK TO KEEP BBKEYS WORKING
581 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
583 if (win
&& win
->isVisible() && win
->setInputFocus())
584 win
->installColormap(True
);
585 } else if (e
->xclient
.message_type
==
586 xatom
->getAtom(XAtom::net_active_window
)) {
588 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
591 BScreen
*screen
= win
->getScreen();
594 win
->deiconify(False
, False
);
595 if (! win
->isStuck() &&
596 (win
->getWorkspaceNumber() != screen
->getCurrentWorkspaceID())) {
598 screen
->changeWorkspaceID(win
->getWorkspaceNumber());
600 if (win
->isVisible() && win
->setInputFocus()) {
601 win
->getScreen()->getWorkspace(win
->getWorkspaceNumber())->
603 win
->installColormap(True
);
606 } else if (e
->xclient
.message_type
==
607 xatom
->getAtom(XAtom::blackbox_cycle_window_focus
)) {
608 // BLACKBOX_CYCLE_WINDOW_FOCUS
609 BScreen
*screen
= searchScreen(e
->xclient
.window
);
612 if (! e
->xclient
.data
.l
[0])
617 } else if (e
->xclient
.message_type
==
618 xatom
->getAtom(XAtom::net_wm_desktop
)) {
620 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
623 BScreen
*screen
= win
->getScreen();
624 unsigned long wksp
= (unsigned) e
->xclient
.data
.l
[0];
625 if (wksp
< screen
->getWorkspaceCount()) {
626 if (win
->isIconic()) win
->deiconify(False
, True
);
627 if (win
->isStuck()) win
->stick();
628 if (wksp
!= screen
->getCurrentWorkspaceID())
632 screen
->reassociateWindow(win
, wksp
, True
);
633 } else if (wksp
== 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
634 wksp
== 0xffffffff) {
635 if (win
->isIconic()) win
->deiconify(False
, True
);
636 if (! win
->isStuck()) win
->stick();
637 if (! win
->isVisible()) win
->show();
640 } else if (e
->xclient
.message_type
==
641 xatom
->getAtom(XAtom::blackbox_change_attributes
)) {
642 // BLACKBOX_CHANGE_ATTRIBUTES
643 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
645 if (win
&& win
->validateClient()) {
647 net
.flags
= e
->xclient
.data
.l
[0];
648 net
.attrib
= e
->xclient
.data
.l
[1];
649 net
.workspace
= e
->xclient
.data
.l
[2];
650 net
.stack
= e
->xclient
.data
.l
[3];
651 net
.decoration
= e
->xclient
.data
.l
[4];
653 win
->changeBlackboxHints(&net
);
655 } else if (e
->xclient
.message_type
==
656 xatom
->getAtom(XAtom::net_number_of_desktops
)) {
657 // NET_NUMBER_OF_DESKTOPS
658 BScreen
*screen
= searchScreen(e
->xclient
.window
);
660 if (e
->xclient
.data
.l
[0] > 0)
661 screen
->changeWorkspaceCount((unsigned) e
->xclient
.data
.l
[0]);
662 } else if (e
->xclient
.message_type
==
663 xatom
->getAtom(XAtom::net_close_window
)) {
665 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
666 if (win
&& win
->validateClient())
667 win
->close(); // could this be smarter?
668 } else if (e
->xclient
.message_type
==
669 xatom
->getAtom(XAtom::net_wm_moveresize
)) {
671 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
672 if (win
&& win
->validateClient()) {
673 int x_root
= e
->xclient
.data
.l
[0],
674 y_root
= e
->xclient
.data
.l
[1];
675 if ((Atom
) e
->xclient
.data
.l
[2] ==
676 xatom
->getAtom(XAtom::net_wm_moveresize_move
)) {
677 win
->beginMove(x_root
, y_root
);
679 if ((Atom
) e
->xclient
.data
.l
[2] ==
680 xatom
->getAtom(XAtom::net_wm_moveresize_size_topleft
))
681 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopLeft
);
682 else if ((Atom
) e
->xclient
.data
.l
[2] ==
683 xatom
->getAtom(XAtom::net_wm_moveresize_size_topright
))
684 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopRight
);
685 else if ((Atom
) e
->xclient
.data
.l
[2] ==
686 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomleft
))
687 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomLeft
);
688 else if ((Atom
) e
->xclient
.data
.l
[2] ==
689 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomright
))
690 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomRight
);
693 } else if (e
->xclient
.message_type
==
694 xatom
->getAtom(XAtom::net_wm_state
)) {
696 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
697 if (win
&& win
->validateClient()) {
698 const Atom action
= (Atom
) e
->xclient
.data
.l
[0];
699 const Atom state
[] = { (Atom
) e
->xclient
.data
.l
[1],
700 (Atom
) e
->xclient
.data
.l
[2] };
702 for (int i
= 0; i
< 2; ++i
) {
706 if ((Atom
) e
->xclient
.data
.l
[0] == 1) {
708 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
710 } else if (state
[i
] ==
711 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
712 if (win
->isMaximizedHoriz()) {
713 win
->maximize(0); // unmaximize
714 win
->maximize(1); // full
715 } else if (! win
->isMaximized()) {
716 win
->maximize(2); // vert
718 } else if (state
[i
] ==
719 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
720 if (win
->isMaximizedVert()) {
721 win
->maximize(0); // unmaximize
722 win
->maximize(1); // full
723 } else if (! win
->isMaximized()) {
724 win
->maximize(3); // horiz
726 } else if (state
[i
] ==
727 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
728 if (! win
->isShaded())
730 } else if (state
[i
] ==
731 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
732 win
->setSkipTaskbar(True
);
733 } else if (state
[i
] ==
734 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
735 win
->setSkipPager(True
);
736 } else if (state
[i
] ==
737 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
738 win
->setFullscreen(True
);
740 } else if (action
== 0) {
742 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
743 win
->setModal(False
);
744 } else if (state
[i
] ==
745 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
746 if (win
->isMaximizedFull()) {
747 win
->maximize(0); // unmaximize
748 win
->maximize(3); // horiz
749 } else if (win
->isMaximizedVert()) {
750 win
->maximize(0); // unmaximize
752 } else if (state
[i
] ==
753 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
754 if (win
->isMaximizedFull()) {
755 win
->maximize(0); // unmaximize
756 win
->maximize(2); // vert
757 } else if (win
->isMaximizedHoriz()) {
758 win
->maximize(0); // unmaximize
760 } else if (state
[i
] ==
761 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
764 } else if (state
[i
] ==
765 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
766 win
->setSkipTaskbar(False
);
767 } else if (state
[i
] ==
768 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
769 win
->setSkipPager(False
);
770 } else if (state
[i
] ==
771 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
772 win
->setFullscreen(False
);
774 } else if (action
== 2) {
776 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
777 win
->setModal(! win
->isModal());
778 } else if (state
[i
] ==
779 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
780 if (win
->isMaximizedFull()) {
781 win
->maximize(0); // unmaximize
782 win
->maximize(3); // horiz
783 } else if (win
->isMaximizedVert()) {
784 win
->maximize(0); // unmaximize
785 } else if (win
->isMaximizedHoriz()) {
786 win
->maximize(0); // unmaximize
787 win
->maximize(1); // full
789 win
->maximize(2); // vert
791 } else if (state
[i
] ==
792 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
793 if (win
->isMaximizedFull()) {
794 win
->maximize(0); // unmaximize
795 win
->maximize(2); // vert
796 } else if (win
->isMaximizedHoriz()) {
797 win
->maximize(0); // unmaximize
798 } else if (win
->isMaximizedVert()) {
799 win
->maximize(0); // unmaximize
800 win
->maximize(1); // full
802 win
->maximize(3); // horiz
804 } else if (state
[i
] ==
805 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
807 } else if (state
[i
] ==
808 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
809 win
->setSkipTaskbar(! win
->skipTaskbar());
810 } else if (state
[i
] ==
811 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
812 win
->setSkipPager(! win
->skipPager());
813 } else if (state
[i
] ==
814 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
815 win
->setFullscreen(! win
->isFullscreen());
827 case ConfigureNotify
:
829 break; // not handled, just ignore
833 if (e
->type
== getShapeEventBase()) {
834 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
835 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
837 if (win
&& shape_event
->kind
== ShapeBounding
)
838 win
->shapeEvent(shape_event
);
846 bool Blackbox::handleSignal(int sig
) {
874 bool Blackbox::validateWindow(Window window
) {
876 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, window
, DestroyNotify
, &event
)) {
877 XPutBackEvent(otk::OBDisplay::display
, &event
);
886 BScreen
*Blackbox::searchScreen(Window window
) {
887 ScreenList::iterator it
= screenList
.begin();
889 for (; it
!= screenList
.end(); ++it
) {
891 if (s
->getRootWindow() == window
)
895 return (BScreen
*) 0;
899 BScreen
*Blackbox::searchSystrayWindow(Window window
) {
900 WindowScreenLookup::iterator it
= systraySearchList
.find(window
);
901 if (it
!= systraySearchList
.end())
908 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
909 WindowLookup::iterator it
= windowSearchList
.find(window
);
910 if (it
!= windowSearchList
.end())
913 return (BlackboxWindow
*) 0;
917 BWindowGroup
*Blackbox::searchGroup(Window window
) {
918 GroupLookup::iterator it
= groupSearchList
.find(window
);
919 if (it
!= groupSearchList
.end())
922 return (BWindowGroup
*) 0;
926 void Blackbox::saveSystrayWindowSearch(Window window
, BScreen
*screen
) {
927 systraySearchList
.insert(WindowScreenLookupPair(window
, screen
));
931 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
932 windowSearchList
.insert(WindowLookupPair(window
, data
));
936 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
937 groupSearchList
.insert(GroupLookupPair(window
, data
));
941 void Blackbox::removeSystrayWindowSearch(Window window
) {
942 systraySearchList
.erase(window
);
946 void Blackbox::removeWindowSearch(Window window
) {
947 windowSearchList
.erase(window
);
951 void Blackbox::removeGroupSearch(Window window
) {
952 groupSearchList
.erase(window
);
956 void Blackbox::restart(const char *prog
) {
960 putenv(const_cast<char *>(screenList
.front()->displayString().c_str()));
961 execlp(prog
, prog
, NULL
);
965 // fall back in case the above execlp doesn't work
966 execvp(argv
[0], argv
);
967 string name
= ::basename(argv
[0]);
968 execvp(name
.c_str(), argv
);
972 void Blackbox::shutdown(void) {
975 XSetInputFocus(otk::OBDisplay::display
, PointerRoot
, None
, CurrentTime
);
977 std::for_each(screenList
.begin(), screenList
.end(),
978 std::mem_fun(&BScreen::shutdown
));
980 XSync(otk::OBDisplay::display
, False
);
985 void Blackbox::saveXineramaPlacement(bool x
) {
986 resource
.xinerama_placement
= x
;
987 config
.setValue("session.xineramaSupport.windowPlacement",
988 resource
.xinerama_placement
);
989 reconfigure(); // make sure all screens get this
991 void Blackbox::saveXineramaMaximizing(bool x
) {
992 resource
.xinerama_maximize
= x
;
993 config
.setValue("session.xineramaSupport.windowMaximizing",
994 resource
.xinerama_maximize
);
995 reconfigure(); // make sure all screens get this change
999 void Blackbox::saveXineramaSnapping(bool x
) {
1000 resource
.xinerama_snap
= x
;
1001 config
.setValue("session.xineramaSupport.windowSnapping",
1002 resource
.xinerama_snap
);
1003 reconfigure(); // make sure all screens get this change
1009 * Save all values as they are so that the defaults will be written to the rc
1012 void Blackbox::save_rc(void) {
1013 config
.setAutoSave(false);
1015 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
1016 config
.setValue("session.doubleClickInterval",
1017 resource
.double_click_interval
);
1018 config
.setValue("session.autoRaiseDelay",
1019 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
1020 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
1021 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
1022 config
.setValue("session.cacheMax", resource
.cache_max
);
1023 config
.setValue("session.styleFile", resource
.style_file
);
1024 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
1027 if (resource
.mod_mask
& Mod1Mask
) s
+= "Mod1-";
1028 if (resource
.mod_mask
& Mod2Mask
) s
+= "Mod2-";
1029 if (resource
.mod_mask
& Mod3Mask
) s
+= "Mod3-";
1030 if (resource
.mod_mask
& Mod4Mask
) s
+= "Mod4-";
1031 if (resource
.mod_mask
& Mod5Mask
) s
+= "Mod5-";
1032 if (resource
.mod_mask
& ShiftMask
) s
+= "Shift-";
1033 if (resource
.mod_mask
& ControlMask
) s
+= "Control-";
1034 s
.resize(s
.size() - 1); // drop the last '-'
1035 config
.setValue("session.modifierMask", s
);
1038 saveXineramaPlacement(resource
.xinerama_placement
);
1039 saveXineramaMaximizing(resource
.xinerama_maximize
);
1040 saveXineramaSnapping(resource
.xinerama_snap
);
1043 std::for_each(screenList
.begin(), screenList
.end(),
1044 std::mem_fun(&BScreen::save_rc
));
1046 config
.setAutoSave(true);
1051 void Blackbox::load_rc(void) {
1052 if (! config
.load())
1057 if (! config
.getValue("session.colorsPerChannel",
1058 resource
.colors_per_channel
))
1059 resource
.colors_per_channel
= 4;
1060 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
1061 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
1063 if (config
.getValue("session.styleFile", s
))
1064 resource
.style_file
= expandTilde(s
);
1066 resource
.style_file
= DEFAULTSTYLE
;
1068 if (! config
.getValue("session.doubleClickInterval",
1069 resource
.double_click_interval
));
1070 resource
.double_click_interval
= 250;
1072 if (! config
.getValue("session.autoRaiseDelay",
1073 resource
.auto_raise_delay
.tv_usec
))
1074 resource
.auto_raise_delay
.tv_usec
= 400;
1075 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
1076 resource
.auto_raise_delay
.tv_usec
-=
1077 (resource
.auto_raise_delay
.tv_sec
* 1000);
1078 resource
.auto_raise_delay
.tv_usec
*= 1000;
1080 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
1081 resource
.cache_life
= 5;
1082 resource
.cache_life
*= 60000;
1084 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
1085 resource
.cache_max
= 200;
1087 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
1088 resource
.titlebar_layout
= "ILMC";
1091 if (! config
.getValue("session.xineramaSupport.windowPlacement",
1092 resource
.xinerama_placement
))
1093 resource
.xinerama_placement
= false;
1095 if (! config
.getValue("session.xineramaSupport.windowMaximizing",
1096 resource
.xinerama_maximize
))
1097 resource
.xinerama_maximize
= false;
1099 if (! config
.getValue("session.xineramaSupport.windowSnapping",
1100 resource
.xinerama_snap
))
1101 resource
.xinerama_snap
= false;
1104 resource
.mod_mask
= 0;
1105 if (config
.getValue("session.modifierMask", s
)) {
1106 if (s
.find("Mod1") != string::npos
)
1107 resource
.mod_mask
|= Mod1Mask
;
1108 if (s
.find("Mod2") != string::npos
)
1109 resource
.mod_mask
|= Mod2Mask
;
1110 if (s
.find("Mod3") != string::npos
)
1111 resource
.mod_mask
|= Mod3Mask
;
1112 if (s
.find("Mod4") != string::npos
)
1113 resource
.mod_mask
|= Mod4Mask
;
1114 if (s
.find("Mod5") != string::npos
)
1115 resource
.mod_mask
|= Mod5Mask
;
1116 if (s
.find("Shift") != string::npos
)
1117 resource
.mod_mask
|= ShiftMask
;
1118 if (s
.find("Control") != string::npos
)
1119 resource
.mod_mask
|= ControlMask
;
1121 if (! resource
.mod_mask
)
1122 resource
.mod_mask
= Mod1Mask
;
1126 void Blackbox::reconfigure(void) {
1127 // don't reconfigure while saving the initial rc file, it's a waste and it
1128 // breaks somethings (workspace names)
1129 if (state() == Openbox::State_Starting
) return;
1131 reconfigure_wait
= True
;
1133 if (! timer
->isTiming()) timer
->start();
1137 void Blackbox::real_reconfigure(void) {
1140 otk::OBDisplay::gcCache()->purge();
1142 std::for_each(screenList
.begin(), screenList
.end(),
1143 std::mem_fun(&BScreen::reconfigure
));
1147 void Blackbox::saveStyleFilename(const string
& filename
) {
1148 assert(! filename
.empty());
1149 resource
.style_file
= filename
;
1150 config
.setValue("session.styleFile", resource
.style_file
);
1154 void Blackbox::timeout(void) {
1155 if (reconfigure_wait
)
1158 reconfigure_wait
= False
;
1162 void Blackbox::setChangingWindow(BlackboxWindow
*win
) {
1163 // make sure one of the two is null and the other isn't
1164 assert((! changing_window
&& win
) || (! win
&& changing_window
));
1165 changing_window
= win
;
1169 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1170 if (focused_window
&& focused_window
== win
) // nothing to do
1173 BScreen
*old_screen
= 0;
1175 if (focused_window
) {
1176 focused_window
->setFocusFlag(False
);
1177 old_screen
= focused_window
->getScreen();
1180 if (win
&& ! win
->isIconic()) {
1181 // the active screen is the one with the last focused window...
1182 // this will keep focus on this screen no matter where the mouse goes,
1183 // so multihead keybindings will continue to work on that screen until the
1184 // user focuses a window on a different screen.
1185 active_screen
= win
->getScreen();
1186 focused_window
= win
;
1190 if (active_screen
) {
1191 // set input focus to the toolbar of the screen with mouse
1192 XSetInputFocus(otk::OBDisplay::display
,
1193 active_screen
->getRootWindow(),
1194 RevertToPointerRoot
, CurrentTime
);
1196 // set input focus to the toolbar of the first managed screen
1197 XSetInputFocus(otk::OBDisplay::display
,
1198 screenList
.front()->getRootWindow(),
1199 RevertToPointerRoot
, CurrentTime
);
1202 // set input focus to the toolbar of the last screen
1203 XSetInputFocus(otk::OBDisplay::display
, old_screen
->getRootWindow(),
1204 RevertToPointerRoot
, CurrentTime
);
1208 if (active_screen
&& active_screen
->isScreenManaged()) {
1209 active_screen
->updateNetizenWindowFocus();
1212 if (old_screen
&& old_screen
!= active_screen
) {
1213 old_screen
->updateNetizenWindowFocus();