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"
82 #include "bbscreen.hh"
83 #include "otk/util.hh"
84 #include "bbwindow.hh"
85 #include "workspace.hh"
92 Blackbox::Blackbox(int argc
, char **m_argv
, char *rc
)
93 : Openbox(argc
, m_argv
) {
95 if (! XSupportsLocale())
96 fprintf(stderr
, "X server does not support locale\n");
98 if (XSetLocaleModifiers("") == NULL
)
99 fprintf(stderr
, "cannot set locale modifiers\n");
104 // try to make sure the ~/.openbox directory exists
105 mkdir(otk::expandTilde("~/.openbox").c_str(), S_IREAD
| S_IWRITE
| S_IEXEC
|
106 S_IRGRP
| S_IWGRP
| S_IXGRP
|
107 S_IROTH
| S_IWOTH
| S_IXOTH
);
109 if (! rc
) rc
= "~/.openbox/rc3";
110 rc_file
= otk::expandTilde(rc
);
111 config
.setFile(rc_file
);
115 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
= 0;
118 focused_window
= changing_window
= (BlackboxWindow
*) 0;
122 xatom
= new otk::OBProperty();
124 cursor
.session
= XCreateFontCursor(otk::OBDisplay::display
, XC_left_ptr
);
125 cursor
.move
= XCreateFontCursor(otk::OBDisplay::display
, XC_fleur
);
126 cursor
.ll_angle
= XCreateFontCursor(otk::OBDisplay::display
, XC_ll_angle
);
127 cursor
.lr_angle
= XCreateFontCursor(otk::OBDisplay::display
, XC_lr_angle
);
128 cursor
.ul_angle
= XCreateFontCursor(otk::OBDisplay::display
, XC_ul_angle
);
129 cursor
.ur_angle
= XCreateFontCursor(otk::OBDisplay::display
, XC_ur_angle
);
131 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); i
++) {
132 BScreen
*screen
= new BScreen(this, i
);
134 if (! screen
->isScreenManaged()) {
139 screenList
.push_back(screen
);
142 if (screenList
.empty()) {
144 "Blackbox::Blackbox: no managable screens found, aborting.\n");
148 // save current settings and default values
151 // set the screen with mouse to the first managed screen
152 active_screen
= screenList
.front();
155 XSynchronize(otk::OBDisplay::display
, False
);
156 XSync(otk::OBDisplay::display
, False
);
158 reconfigure_wait
= False
;
160 timer
= new otk::OBTimer(Openbox::instance
->timerManager(),
161 (otk::OBTimeoutHandler
)timeout
,
163 timer
->setTimeout(0l);
167 Blackbox::~Blackbox(void) {
168 std::for_each(screenList
.begin(), screenList
.end(), otk::PointerAssassin());
176 void Blackbox::process_event(XEvent
*e
) {
179 // strip the lock key modifiers
180 //e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
182 last_time
= e
->xbutton
.time
;
184 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
185 BScreen
*scrn
= (BScreen
*) 0;
187 if ((win
= searchWindow(e
->xbutton
.window
))) {
188 win
->buttonPressEvent(&e
->xbutton
);
190 /* XXX: is this sane on low colour desktops? */
191 if (e
->xbutton
.button
== 1)
192 win
->installColormap(True
);
193 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
194 scrn
->buttonPressEvent(&e
->xbutton
);
195 if (active_screen
!= scrn
) {
196 active_screen
= scrn
;
197 // first, set no focus window on the old screen
199 // and move focus to this screen
206 case ButtonRelease
: {
207 // strip the lock key modifiers
208 //e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
210 last_time
= e
->xbutton
.time
;
212 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
214 if ((win
= searchWindow(e
->xbutton
.window
)))
215 win
->buttonReleaseEvent(&e
->xbutton
);
220 case ConfigureRequest
: {
221 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
223 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
224 win
->configureRequestEvent(&e
->xconfigurerequest
);
226 if (validateWindow(e
->xconfigurerequest
.window
)) {
229 xwc
.x
= e
->xconfigurerequest
.x
;
230 xwc
.y
= e
->xconfigurerequest
.y
;
231 xwc
.width
= e
->xconfigurerequest
.width
;
232 xwc
.height
= e
->xconfigurerequest
.height
;
233 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
234 xwc
.sibling
= e
->xconfigurerequest
.above
;
235 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
237 XConfigureWindow(otk::OBDisplay::display
, e
->xconfigurerequest
.window
,
238 e
->xconfigurerequest
.value_mask
, &xwc
);
247 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
248 e
->xmaprequest
.window
);
251 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
255 if (win
->isIconic()) {
259 if (win
->isShaded()) {
264 if (focus
&& (win
->isTransient() || win
->getScreen()->doFocusNew()) &&
266 win
->setInputFocus();
268 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
272 we got a map request for a window who's parent isn't root. this
273 can happen in only one circumstance:
275 a client window unmapped a managed window, and then remapped it
276 somewhere between unmapping the client window and reparenting it
279 regardless of how it happens, we need to find the screen that
282 XWindowAttributes wattrib
;
283 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
->xmaprequest
.window
,
285 // failed to get the window attributes, perhaps the window has
286 // now been destroyed?
290 screen
= searchScreen(wattrib
.root
);
291 assert(screen
!= 0); // this should never happen
294 screen
->manageWindow(e
->xmaprequest
.window
);
301 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
302 BScreen
*screen
= (BScreen
*) 0;
304 if ((win
= searchWindow(e
->xunmap
.window
))) {
305 win
->unmapNotifyEvent(&e
->xunmap
);
306 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
307 screen
->removeSystrayWindow(e
->xunmap
.window
);
313 case DestroyNotify
: {
314 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
315 BScreen
*screen
= (BScreen
*) 0;
316 BWindowGroup
*group
= (BWindowGroup
*) 0;
318 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
319 win
->destroyNotifyEvent(&e
->xdestroywindow
);
320 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
322 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
323 screen
->removeSystrayWindow(e
->xunmap
.window
);
329 case ReparentNotify
: {
331 this event is quite rare and is usually handled in unmapNotify
332 however, if the window is unmapped when the reparent event occurs
333 the window manager never sees it because an unmap event is not sent
334 to an already unmapped window.
336 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
338 win
->reparentNotifyEvent(&e
->xreparent
);
343 // motion notify compression...
346 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, e
->xmotion
.window
,
347 MotionNotify
, &realevent
)) {
351 // if we have compressed some motion events, use the last one
355 // the pointer is on the wrong screen
356 if (! e
->xmotion
.same_screen
)
359 // strip the lock key modifiers
360 //e->xmotion.state &= ~(NumLockMask | ScrollLockMask | LockMask);
362 last_time
= e
->xmotion
.time
;
364 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
366 if ((win
= searchWindow(e
->xmotion
.window
)))
367 win
->motionNotifyEvent(&e
->xmotion
);
372 case PropertyNotify
: {
373 last_time
= e
->xproperty
.time
;
375 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
376 BScreen
*screen
= (BScreen
*) 0;
378 if ((win
= searchWindow(e
->xproperty
.window
)))
379 win
->propertyNotifyEvent(&e
->xproperty
);
380 else if ((screen
= searchScreen(e
->xproperty
.window
)))
381 screen
->propertyNotifyEvent(&e
->xproperty
);
386 last_time
= e
->xcrossing
.time
;
388 BScreen
*screen
= (BScreen
*) 0;
389 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
391 if (e
->xcrossing
.mode
== NotifyGrab
) break;
393 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
394 (screen
= searchScreen(e
->xcrossing
.window
))) {
395 screen
->getImageControl()->installRootColormap();
396 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
398 win
->enterNotifyEvent(&e
->xcrossing
);
404 last_time
= e
->xcrossing
.time
;
406 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
408 if ((win
= searchWindow(e
->xcrossing
.window
)))
409 win
->leaveNotifyEvent(&e
->xcrossing
);
414 // compress expose events
417 int ex1
, ey1
, ex2
, ey2
;
420 ex2
= ex1
+ e
->xexpose
.width
- 1;
421 ey2
= ey1
+ e
->xexpose
.height
- 1;
422 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, e
->xexpose
.window
,
423 Expose
, &realevent
)) {
427 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
428 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
429 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
430 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
435 // use the merged area
438 e
->xexpose
.width
= ex2
- ex1
+ 1;
439 e
->xexpose
.height
= ey2
- ey1
+ 1;
441 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
443 if ((win
= searchWindow(e
->xexpose
.window
)))
444 win
->exposeEvent(&e
->xexpose
);
453 case ColormapNotify
: {
454 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
457 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
458 ColormapInstalled
) ? True
: False
);
464 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
465 e
->xfocus
.detail
!= NotifyAncestor
) {
467 don't process FocusIns when:
468 1. the new focus window isn't an ancestor or inferior of the old
469 focus window (NotifyNonlinear)
470 make sure to allow the FocusIn when the old focus window was an
471 ancestor but didn't have a parent, such as root (NotifyAncestor)
476 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
478 if (! win
->isFocused())
479 win
->setFocusFlag(True
);
482 set the event window to None. when the FocusOut event handler calls
483 this function recursively, it uses this as an indication that focus
484 has moved to a known window.
486 e
->xfocus
.window
= None
;
488 no_focus
= False
; // focusing is back on
495 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
497 don't process FocusOuts when:
498 2. the new focus window isn't an ancestor or inferior of the old
499 focus window (NotifyNonlinear)
504 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
505 if (win
&& win
->isFocused()) {
507 before we mark "win" as unfocused, we need to verify that focus is
508 going to a known location, is in a known location, or set focus
513 // don't check the current focus if FocusOut was generated during a grab
514 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
517 First, check if there is a pending FocusIn event waiting. if there
518 is, process it and determine if focus has moved to another window
519 (the FocusIn event handler sets the window in the event
520 structure to None to indicate this).
522 if (XCheckTypedEvent(otk::OBDisplay::display
, FocusIn
, &event
)) {
524 process_event(&event
);
525 if (event
.xfocus
.window
== None
) {
533 Second, we query the X server for the current input focus.
534 to make sure that we keep a consistent state.
536 BlackboxWindow
*focus
;
539 XGetInputFocus(otk::OBDisplay::display
, &w
, &revert
);
540 focus
= searchWindow(w
);
543 focus got from "win" to "focus" under some very strange
544 circumstances, and we need to make sure that the focus indication
547 setFocusedWindow(focus
);
549 // we have no idea where focus went... so we set it to somewhere
558 case ClientMessage
: {
559 if (e
->xclient
.format
== 32) {
560 if (e
->xclient
.message_type
== xatom
->atom(otk::OBProperty::wm_change_state
)) {
561 // WM_CHANGE_STATE message
562 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
563 if (! win
|| ! win
->validateClient()) return;
565 if (e
->xclient
.data
.l
[0] == IconicState
)
567 if (e
->xclient
.data
.l
[0] == NormalState
)
569 } else if (e
->xclient
.message_type
==
570 xatom
->atom(otk::OBProperty::blackbox_change_workspace
) ||
571 e
->xclient
.message_type
==
572 xatom
->atom(otk::OBProperty::net_current_desktop
)) {
573 // NET_CURRENT_DESKTOP message
574 BScreen
*screen
= searchScreen(e
->xclient
.window
);
576 unsigned int workspace
= e
->xclient
.data
.l
[0];
577 if (screen
&& workspace
< screen
->getWorkspaceCount())
578 screen
->changeWorkspaceID(workspace
);
579 } else if (e
->xclient
.message_type
==
580 xatom
->atom(otk::OBProperty::blackbox_change_window_focus
)) {
581 // TEMP HACK TO KEEP BBKEYS WORKING
582 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
584 if (win
&& win
->isVisible() && win
->setInputFocus())
585 win
->installColormap(True
);
586 } else if (e
->xclient
.message_type
==
587 xatom
->atom(otk::OBProperty::net_active_window
)) {
589 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
592 BScreen
*screen
= win
->getScreen();
595 win
->deiconify(False
, False
);
596 if (! win
->isStuck() &&
597 (win
->getWorkspaceNumber() != screen
->getCurrentWorkspaceID())) {
599 screen
->changeWorkspaceID(win
->getWorkspaceNumber());
601 if (win
->isVisible() && win
->setInputFocus()) {
602 win
->getScreen()->getWorkspace(win
->getWorkspaceNumber())->
604 win
->installColormap(True
);
607 } else if (e
->xclient
.message_type
==
608 xatom
->atom(otk::OBProperty::blackbox_cycle_window_focus
)) {
609 // BLACKBOX_CYCLE_WINDOW_FOCUS
610 BScreen
*screen
= searchScreen(e
->xclient
.window
);
613 if (! e
->xclient
.data
.l
[0])
618 } else if (e
->xclient
.message_type
==
619 xatom
->atom(otk::OBProperty::net_wm_desktop
)) {
621 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
624 BScreen
*screen
= win
->getScreen();
625 unsigned long wksp
= (unsigned) e
->xclient
.data
.l
[0];
626 if (wksp
< screen
->getWorkspaceCount()) {
627 if (win
->isIconic()) win
->deiconify(False
, True
);
628 if (win
->isStuck()) win
->stick();
629 if (wksp
!= screen
->getCurrentWorkspaceID())
633 screen
->reassociateWindow(win
, wksp
, True
);
634 } else if (wksp
== 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
635 wksp
== 0xffffffff) {
636 if (win
->isIconic()) win
->deiconify(False
, True
);
637 if (! win
->isStuck()) win
->stick();
638 if (! win
->isVisible()) win
->show();
641 } else if (e
->xclient
.message_type
==
642 xatom
->atom(otk::OBProperty::blackbox_change_attributes
)) {
643 // BLACKBOX_CHANGE_ATTRIBUTES
644 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
646 if (win
&& win
->validateClient()) {
648 net
.flags
= e
->xclient
.data
.l
[0];
649 net
.attrib
= e
->xclient
.data
.l
[1];
650 net
.workspace
= e
->xclient
.data
.l
[2];
651 net
.stack
= e
->xclient
.data
.l
[3];
652 net
.decoration
= e
->xclient
.data
.l
[4];
654 win
->changeBlackboxHints(&net
);
656 } else if (e
->xclient
.message_type
==
657 xatom
->atom(otk::OBProperty::net_number_of_desktops
)) {
658 // NET_NUMBER_OF_DESKTOPS
659 BScreen
*screen
= searchScreen(e
->xclient
.window
);
661 if (e
->xclient
.data
.l
[0] > 0)
662 screen
->changeWorkspaceCount((unsigned) e
->xclient
.data
.l
[0]);
663 } else if (e
->xclient
.message_type
==
664 xatom
->atom(otk::OBProperty::net_close_window
)) {
666 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
667 if (win
&& win
->validateClient())
668 win
->close(); // could this be smarter?
669 } else if (e
->xclient
.message_type
==
670 xatom
->atom(otk::OBProperty::net_wm_moveresize
)) {
672 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
673 if (win
&& win
->validateClient()) {
674 int x_root
= e
->xclient
.data
.l
[0],
675 y_root
= e
->xclient
.data
.l
[1];
676 if ((Atom
) e
->xclient
.data
.l
[2] ==
677 xatom
->atom(otk::OBProperty::net_wm_moveresize_move
)) {
678 win
->beginMove(x_root
, y_root
);
680 if ((Atom
) e
->xclient
.data
.l
[2] ==
681 xatom
->atom(otk::OBProperty::net_wm_moveresize_size_topleft
))
682 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopLeft
);
683 else if ((Atom
) e
->xclient
.data
.l
[2] ==
684 xatom
->atom(otk::OBProperty::net_wm_moveresize_size_topright
))
685 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopRight
);
686 else if ((Atom
) e
->xclient
.data
.l
[2] ==
687 xatom
->atom(otk::OBProperty::net_wm_moveresize_size_bottomleft
))
688 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomLeft
);
689 else if ((Atom
) e
->xclient
.data
.l
[2] ==
690 xatom
->atom(otk::OBProperty::net_wm_moveresize_size_bottomright
))
691 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomRight
);
694 } else if (e
->xclient
.message_type
==
695 xatom
->atom(otk::OBProperty::net_wm_state
)) {
697 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
698 if (win
&& win
->validateClient()) {
699 const Atom action
= (Atom
) e
->xclient
.data
.l
[0];
700 const Atom state
[] = { (Atom
) e
->xclient
.data
.l
[1],
701 (Atom
) e
->xclient
.data
.l
[2] };
703 for (int i
= 0; i
< 2; ++i
) {
707 if ((Atom
) e
->xclient
.data
.l
[0] == 1) {
709 if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_modal
)) {
711 } else if (state
[i
] ==
712 xatom
->atom(otk::OBProperty::net_wm_state_maximized_vert
)) {
713 if (win
->isMaximizedHoriz()) {
714 win
->maximize(0); // unmaximize
715 win
->maximize(1); // full
716 } else if (! win
->isMaximized()) {
717 win
->maximize(2); // vert
719 } else if (state
[i
] ==
720 xatom
->atom(otk::OBProperty::net_wm_state_maximized_horz
)) {
721 if (win
->isMaximizedVert()) {
722 win
->maximize(0); // unmaximize
723 win
->maximize(1); // full
724 } else if (! win
->isMaximized()) {
725 win
->maximize(3); // horiz
727 } else if (state
[i
] ==
728 xatom
->atom(otk::OBProperty::net_wm_state_shaded
)) {
729 if (! win
->isShaded())
731 } else if (state
[i
] ==
732 xatom
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
733 win
->setSkipTaskbar(True
);
734 } else if (state
[i
] ==
735 xatom
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
736 win
->setSkipPager(True
);
737 } else if (state
[i
] ==
738 xatom
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
739 win
->setFullscreen(True
);
741 } else if (action
== 0) {
743 if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_modal
)) {
744 win
->setModal(False
);
745 } else if (state
[i
] ==
746 xatom
->atom(otk::OBProperty::net_wm_state_maximized_vert
)) {
747 if (win
->isMaximizedFull()) {
748 win
->maximize(0); // unmaximize
749 win
->maximize(3); // horiz
750 } else if (win
->isMaximizedVert()) {
751 win
->maximize(0); // unmaximize
753 } else if (state
[i
] ==
754 xatom
->atom(otk::OBProperty::net_wm_state_maximized_horz
)) {
755 if (win
->isMaximizedFull()) {
756 win
->maximize(0); // unmaximize
757 win
->maximize(2); // vert
758 } else if (win
->isMaximizedHoriz()) {
759 win
->maximize(0); // unmaximize
761 } else if (state
[i
] ==
762 xatom
->atom(otk::OBProperty::net_wm_state_shaded
)) {
765 } else if (state
[i
] ==
766 xatom
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
767 win
->setSkipTaskbar(False
);
768 } else if (state
[i
] ==
769 xatom
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
770 win
->setSkipPager(False
);
771 } else if (state
[i
] ==
772 xatom
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
773 win
->setFullscreen(False
);
775 } else if (action
== 2) {
777 if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_modal
)) {
778 win
->setModal(! win
->isModal());
779 } else if (state
[i
] ==
780 xatom
->atom(otk::OBProperty::net_wm_state_maximized_vert
)) {
781 if (win
->isMaximizedFull()) {
782 win
->maximize(0); // unmaximize
783 win
->maximize(3); // horiz
784 } else if (win
->isMaximizedVert()) {
785 win
->maximize(0); // unmaximize
786 } else if (win
->isMaximizedHoriz()) {
787 win
->maximize(0); // unmaximize
788 win
->maximize(1); // full
790 win
->maximize(2); // vert
792 } else if (state
[i
] ==
793 xatom
->atom(otk::OBProperty::net_wm_state_maximized_horz
)) {
794 if (win
->isMaximizedFull()) {
795 win
->maximize(0); // unmaximize
796 win
->maximize(2); // vert
797 } else if (win
->isMaximizedHoriz()) {
798 win
->maximize(0); // unmaximize
799 } else if (win
->isMaximizedVert()) {
800 win
->maximize(0); // unmaximize
801 win
->maximize(1); // full
803 win
->maximize(3); // horiz
805 } else if (state
[i
] ==
806 xatom
->atom(otk::OBProperty::net_wm_state_shaded
)) {
808 } else if (state
[i
] ==
809 xatom
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
810 win
->setSkipTaskbar(! win
->skipTaskbar());
811 } else if (state
[i
] ==
812 xatom
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
813 win
->setSkipPager(! win
->skipPager());
814 } else if (state
[i
] ==
815 xatom
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
816 win
->setFullscreen(! win
->isFullscreen());
828 case ConfigureNotify
:
830 break; // not handled, just ignore
834 if (e
->type
== otk::OBDisplay::shapeEventBase()) {
835 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
836 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
838 if (win
&& shape_event
->kind
== ShapeBounding
)
839 win
->shapeEvent(shape_event
);
847 bool Blackbox::handleSignal(int sig
) {
875 bool Blackbox::validateWindow(Window window
) {
877 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, window
, DestroyNotify
, &event
)) {
878 XPutBackEvent(otk::OBDisplay::display
, &event
);
887 BScreen
*Blackbox::searchScreen(Window window
) {
888 ScreenList::iterator it
= screenList
.begin();
890 for (; it
!= screenList
.end(); ++it
) {
892 if (s
->getRootWindow() == window
)
896 return (BScreen
*) 0;
900 BScreen
*Blackbox::searchSystrayWindow(Window window
) {
901 WindowScreenLookup::iterator it
= systraySearchList
.find(window
);
902 if (it
!= systraySearchList
.end())
909 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
910 WindowLookup::iterator it
= windowSearchList
.find(window
);
911 if (it
!= windowSearchList
.end())
914 return (BlackboxWindow
*) 0;
918 BWindowGroup
*Blackbox::searchGroup(Window window
) {
919 GroupLookup::iterator it
= groupSearchList
.find(window
);
920 if (it
!= groupSearchList
.end())
923 return (BWindowGroup
*) 0;
927 void Blackbox::saveSystrayWindowSearch(Window window
, BScreen
*screen
) {
928 systraySearchList
.insert(WindowScreenLookupPair(window
, screen
));
932 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
933 windowSearchList
.insert(WindowLookupPair(window
, data
));
937 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
938 groupSearchList
.insert(GroupLookupPair(window
, data
));
942 void Blackbox::removeSystrayWindowSearch(Window window
) {
943 systraySearchList
.erase(window
);
947 void Blackbox::removeWindowSearch(Window window
) {
948 windowSearchList
.erase(window
);
952 void Blackbox::removeGroupSearch(Window window
) {
953 groupSearchList
.erase(window
);
957 void Blackbox::restart(const char *prog
) {
961 putenv(const_cast<char *>(screenList
.front()->displayString().c_str()));
962 execlp(prog
, prog
, NULL
);
966 // fall back in case the above execlp doesn't work
967 execvp(argv
[0], argv
);
968 string name
= ::basename(argv
[0]);
969 execvp(name
.c_str(), argv
);
973 void Blackbox::shutdown(void) {
976 XSetInputFocus(otk::OBDisplay::display
, PointerRoot
, None
, CurrentTime
);
978 std::for_each(screenList
.begin(), screenList
.end(),
979 std::mem_fun(&BScreen::shutdown
));
981 XSync(otk::OBDisplay::display
, False
);
986 void Blackbox::saveXineramaPlacement(bool x
) {
987 resource
.xinerama_placement
= x
;
988 config
.setValue("session.xineramaSupport.windowPlacement",
989 resource
.xinerama_placement
);
990 reconfigure(); // make sure all screens get this
992 void Blackbox::saveXineramaMaximizing(bool x
) {
993 resource
.xinerama_maximize
= x
;
994 config
.setValue("session.xineramaSupport.windowMaximizing",
995 resource
.xinerama_maximize
);
996 reconfigure(); // make sure all screens get this change
1000 void Blackbox::saveXineramaSnapping(bool x
) {
1001 resource
.xinerama_snap
= x
;
1002 config
.setValue("session.xineramaSupport.windowSnapping",
1003 resource
.xinerama_snap
);
1004 reconfigure(); // make sure all screens get this change
1010 * Save all values as they are so that the defaults will be written to the rc
1013 void Blackbox::save_rc(void) {
1014 config
.setAutoSave(false);
1016 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
1017 config
.setValue("session.doubleClickInterval",
1018 resource
.double_click_interval
);
1019 config
.setValue("session.autoRaiseDelay",
1020 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
1021 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
1022 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
1023 config
.setValue("session.cacheMax", resource
.cache_max
);
1024 config
.setValue("session.styleFile", resource
.style_file
);
1025 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
1028 if (resource
.mod_mask
& Mod1Mask
) s
+= "Mod1-";
1029 if (resource
.mod_mask
& Mod2Mask
) s
+= "Mod2-";
1030 if (resource
.mod_mask
& Mod3Mask
) s
+= "Mod3-";
1031 if (resource
.mod_mask
& Mod4Mask
) s
+= "Mod4-";
1032 if (resource
.mod_mask
& Mod5Mask
) s
+= "Mod5-";
1033 if (resource
.mod_mask
& ShiftMask
) s
+= "Shift-";
1034 if (resource
.mod_mask
& ControlMask
) s
+= "Control-";
1035 s
.resize(s
.size() - 1); // drop the last '-'
1036 config
.setValue("session.modifierMask", s
);
1039 saveXineramaPlacement(resource
.xinerama_placement
);
1040 saveXineramaMaximizing(resource
.xinerama_maximize
);
1041 saveXineramaSnapping(resource
.xinerama_snap
);
1044 std::for_each(screenList
.begin(), screenList
.end(),
1045 std::mem_fun(&BScreen::save_rc
));
1047 config
.setAutoSave(true);
1052 void Blackbox::load_rc(void) {
1053 if (! config
.load())
1058 if (! config
.getValue("session.colorsPerChannel",
1059 resource
.colors_per_channel
))
1060 resource
.colors_per_channel
= 4;
1061 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
1062 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
1064 if (config
.getValue("session.styleFile", s
))
1065 resource
.style_file
= otk::expandTilde(s
);
1067 resource
.style_file
= DEFAULTSTYLE
;
1069 if (! config
.getValue("session.doubleClickInterval",
1070 resource
.double_click_interval
));
1071 resource
.double_click_interval
= 250;
1073 if (! config
.getValue("session.autoRaiseDelay",
1074 resource
.auto_raise_delay
.tv_usec
))
1075 resource
.auto_raise_delay
.tv_usec
= 400;
1076 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
1077 resource
.auto_raise_delay
.tv_usec
-=
1078 (resource
.auto_raise_delay
.tv_sec
* 1000);
1079 resource
.auto_raise_delay
.tv_usec
*= 1000;
1081 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
1082 resource
.cache_life
= 5;
1083 resource
.cache_life
*= 60000;
1085 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
1086 resource
.cache_max
= 200;
1088 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
1089 resource
.titlebar_layout
= "ILMC";
1092 if (! config
.getValue("session.xineramaSupport.windowPlacement",
1093 resource
.xinerama_placement
))
1094 resource
.xinerama_placement
= false;
1096 if (! config
.getValue("session.xineramaSupport.windowMaximizing",
1097 resource
.xinerama_maximize
))
1098 resource
.xinerama_maximize
= false;
1100 if (! config
.getValue("session.xineramaSupport.windowSnapping",
1101 resource
.xinerama_snap
))
1102 resource
.xinerama_snap
= false;
1105 resource
.mod_mask
= 0;
1106 if (config
.getValue("session.modifierMask", s
)) {
1107 if (s
.find("Mod1") != string::npos
)
1108 resource
.mod_mask
|= Mod1Mask
;
1109 if (s
.find("Mod2") != string::npos
)
1110 resource
.mod_mask
|= Mod2Mask
;
1111 if (s
.find("Mod3") != string::npos
)
1112 resource
.mod_mask
|= Mod3Mask
;
1113 if (s
.find("Mod4") != string::npos
)
1114 resource
.mod_mask
|= Mod4Mask
;
1115 if (s
.find("Mod5") != string::npos
)
1116 resource
.mod_mask
|= Mod5Mask
;
1117 if (s
.find("Shift") != string::npos
)
1118 resource
.mod_mask
|= ShiftMask
;
1119 if (s
.find("Control") != string::npos
)
1120 resource
.mod_mask
|= ControlMask
;
1122 if (! resource
.mod_mask
)
1123 resource
.mod_mask
= Mod1Mask
;
1127 void Blackbox::reconfigure(void) {
1128 // don't reconfigure while saving the initial rc file, it's a waste and it
1129 // breaks somethings (workspace names)
1130 if (state() == Openbox::State_Starting
) return;
1132 reconfigure_wait
= True
;
1134 if (! timer
->timing()) timer
->start();
1138 void Blackbox::real_reconfigure(void) {
1141 otk::OBDisplay::gcCache()->purge();
1143 std::for_each(screenList
.begin(), screenList
.end(),
1144 std::mem_fun(&BScreen::reconfigure
));
1148 void Blackbox::saveStyleFilename(const string
& filename
) {
1149 assert(! filename
.empty());
1150 resource
.style_file
= filename
;
1151 config
.setValue("session.styleFile", resource
.style_file
);
1155 void Blackbox::timeout(Blackbox
*t
) {
1156 if (t
->reconfigure_wait
)
1157 t
->real_reconfigure();
1159 t
->reconfigure_wait
= False
;
1163 void Blackbox::setChangingWindow(BlackboxWindow
*win
) {
1164 // make sure one of the two is null and the other isn't
1165 assert((! changing_window
&& win
) || (! win
&& changing_window
));
1166 changing_window
= win
;
1170 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1171 if (focused_window
&& focused_window
== win
) // nothing to do
1174 BScreen
*old_screen
= 0;
1176 if (focused_window
) {
1177 focused_window
->setFocusFlag(False
);
1178 old_screen
= focused_window
->getScreen();
1181 if (win
&& ! win
->isIconic()) {
1182 // the active screen is the one with the last focused window...
1183 // this will keep focus on this screen no matter where the mouse goes,
1184 // so multihead keybindings will continue to work on that screen until the
1185 // user focuses a window on a different screen.
1186 active_screen
= win
->getScreen();
1187 focused_window
= win
;
1191 if (active_screen
) {
1192 // set input focus to the toolbar of the screen with mouse
1193 XSetInputFocus(otk::OBDisplay::display
,
1194 active_screen
->getRootWindow(),
1195 RevertToPointerRoot
, CurrentTime
);
1197 // set input focus to the toolbar of the first managed screen
1198 XSetInputFocus(otk::OBDisplay::display
,
1199 screenList
.front()->getRootWindow(),
1200 RevertToPointerRoot
, CurrentTime
);
1203 // set input focus to the toolbar of the last screen
1204 XSetInputFocus(otk::OBDisplay::display
, old_screen
->getRootWindow(),
1205 RevertToPointerRoot
, CurrentTime
);
1209 if (active_screen
&& active_screen
->isScreenManaged()) {
1210 active_screen
->updateNetizenWindowFocus();
1213 if (old_screen
&& old_screen
!= active_screen
) {
1214 old_screen
->updateNetizenWindowFocus();