1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // blackbox.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #include <X11/cursorfont.h>
33 #include <X11/keysym.h>
36 #include <X11/extensions/shape.h>
41 #endif // HAVE_STDIO_H
45 #endif // HAVE_STDLIB_H
49 #endif // HAVE_STRING_H
52 # include <sys/types.h>
54 #endif // HAVE_UNISTD_H
56 #ifdef HAVE_SYS_PARAM_H
57 # include <sys/param.h>
58 #endif // HAVE_SYS_PARAM_H
60 #ifdef HAVE_SYS_SELECT_H
61 # include <sys/select.h>
62 #endif // HAVE_SYS_SELECT_H
66 #endif // HAVE_SIGNAL_H
68 #ifdef HAVE_SYS_SIGNAL_H
69 # include <sys/signal.h>
70 #endif // HAVE_SYS_SIGNAL_H
72 #ifdef HAVE_SYS_STAT_H
73 # include <sys/types.h>
74 # include <sys/stat.h>
75 #endif // HAVE_SYS_STAT_H
77 #ifdef TIME_WITH_SYS_TIME
78 # include <sys/time.h>
80 #else // !TIME_WITH_SYS_TIME
81 # ifdef HAVE_SYS_TIME_H
82 # include <sys/time.h>
83 # else // !HAVE_SYS_TIME_H
85 # endif // HAVE_SYS_TIME_H
86 #endif // TIME_WITH_SYS_TIME
90 #endif // HAVE_LIBGEN_H
100 #include "blackbox.hh"
101 #include "Basemenu.hh"
102 #include "Clientmenu.hh"
103 #include "GCCache.hh"
105 #include "Rootmenu.hh"
108 #include "Toolbar.hh"
111 #include "Workspace.hh"
112 #include "Workspacemenu.hh"
115 // X event scanner for enter/leave notifies - adapted from twm
118 bool leave
, inferior
, enter
;
121 static Bool
queueScanner(Display
*, XEvent
*e
, char *args
) {
122 scanargs
*scan
= (scanargs
*) args
;
123 if ((e
->type
== LeaveNotify
) &&
124 (e
->xcrossing
.window
== scan
->w
) &&
125 (e
->xcrossing
.mode
== NotifyNormal
)) {
127 scan
->inferior
= (e
->xcrossing
.detail
== NotifyInferior
);
128 } else if ((e
->type
== EnterNotify
) && (e
->xcrossing
.mode
== NotifyUngrab
)) {
138 Blackbox::Blackbox(char **m_argv
, char *dpy_name
, char *rc
, char *menu
)
139 : BaseDisplay(m_argv
[0], dpy_name
) {
140 if (! XSupportsLocale())
141 fprintf(stderr
, "X server does not support locale\n");
143 if (XSetLocaleModifiers("") == NULL
)
144 fprintf(stderr
, "cannot set locale modifiers\n");
149 // try to make sure the ~/.openbox directory exists
150 mkdir(expandTilde("~/.openbox").c_str(), S_IREAD
| S_IWRITE
| S_IEXEC
|
151 S_IRGRP
| S_IWGRP
| S_IXGRP
|
152 S_IROTH
| S_IWOTH
| S_IXOTH
);
154 if (! rc
) rc
= "~/.openbox/rc";
155 rc_file
= expandTilde(rc
);
156 config
.setFile(rc_file
);
157 if (! menu
) menu
= "~/.openbox/menu";
158 menu_file
= expandTilde(menu
);
162 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
= 0;
165 focused_window
= changing_window
= (BlackboxWindow
*) 0;
169 xatom
= new XAtom(getXDisplay());
171 cursor
.session
= XCreateFontCursor(getXDisplay(), XC_left_ptr
);
172 cursor
.move
= XCreateFontCursor(getXDisplay(), XC_fleur
);
173 cursor
.ll_angle
= XCreateFontCursor(getXDisplay(), XC_ll_angle
);
174 cursor
.lr_angle
= XCreateFontCursor(getXDisplay(), XC_lr_angle
);
175 cursor
.ul_angle
= XCreateFontCursor(getXDisplay(), XC_ul_angle
);
176 cursor
.ur_angle
= XCreateFontCursor(getXDisplay(), XC_ur_angle
);
178 for (unsigned int i
= 0; i
< getNumberOfScreens(); i
++) {
179 BScreen
*screen
= new BScreen(this, i
);
181 if (! screen
->isScreenManaged()) {
186 screenList
.push_back(screen
);
189 if (screenList
.empty()) {
191 i18n(blackboxSet
, blackboxNoManagableScreens
,
192 "Blackbox::Blackbox: no managable screens found, aborting.\n"));
196 // save current settings and default values
199 // set the screen with mouse to the first managed screen
200 active_screen
= screenList
.front();
203 XSynchronize(getXDisplay(), False
);
204 XSync(getXDisplay(), False
);
206 reconfigure_wait
= reread_menu_wait
= False
;
208 timer
= new BTimer(this, this);
209 timer
->setTimeout(0l);
213 Blackbox::~Blackbox(void) {
214 std::for_each(screenList
.begin(), screenList
.end(), PointerAssassin());
216 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
225 void Blackbox::process_event(XEvent
*e
) {
228 // strip the lock key modifiers
229 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
231 last_time
= e
->xbutton
.time
;
233 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
234 Basemenu
*menu
= (Basemenu
*) 0;
235 Slit
*slit
= (Slit
*) 0;
236 Toolbar
*tbar
= (Toolbar
*) 0;
237 BScreen
*scrn
= (BScreen
*) 0;
239 if ((win
= searchWindow(e
->xbutton
.window
))) {
240 win
->buttonPressEvent(&e
->xbutton
);
242 /* XXX: is this sane on low colour desktops? */
243 if (e
->xbutton
.button
== 1)
244 win
->installColormap(True
);
245 } else if ((menu
= searchMenu(e
->xbutton
.window
))) {
246 menu
->buttonPressEvent(&e
->xbutton
);
247 } else if ((slit
= searchSlit(e
->xbutton
.window
))) {
248 slit
->buttonPressEvent(&e
->xbutton
);
249 } else if ((tbar
= searchToolbar(e
->xbutton
.window
))) {
250 tbar
->buttonPressEvent(&e
->xbutton
);
251 } else if ((scrn
= searchScreen(e
->xbutton
.window
))) {
252 scrn
->buttonPressEvent(&e
->xbutton
);
253 if (active_screen
!= scrn
) {
254 active_screen
= scrn
;
255 // first, set no focus window on the old screen
257 // and move focus to this screen
264 case ButtonRelease
: {
265 // strip the lock key modifiers
266 e
->xbutton
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
268 last_time
= e
->xbutton
.time
;
270 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
271 Basemenu
*menu
= (Basemenu
*) 0;
272 Toolbar
*tbar
= (Toolbar
*) 0;
274 if ((win
= searchWindow(e
->xbutton
.window
)))
275 win
->buttonReleaseEvent(&e
->xbutton
);
276 else if ((menu
= searchMenu(e
->xbutton
.window
)))
277 menu
->buttonReleaseEvent(&e
->xbutton
);
278 else if ((tbar
= searchToolbar(e
->xbutton
.window
)))
279 tbar
->buttonReleaseEvent(&e
->xbutton
);
284 case ConfigureRequest
: {
285 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
286 Slit
*slit
= (Slit
*) 0;
288 if ((win
= searchWindow(e
->xconfigurerequest
.window
))) {
289 win
->configureRequestEvent(&e
->xconfigurerequest
);
290 } else if ((slit
= searchSlit(e
->xconfigurerequest
.window
))) {
291 slit
->configureRequestEvent(&e
->xconfigurerequest
);
293 if (validateWindow(e
->xconfigurerequest
.window
)) {
296 xwc
.x
= e
->xconfigurerequest
.x
;
297 xwc
.y
= e
->xconfigurerequest
.y
;
298 xwc
.width
= e
->xconfigurerequest
.width
;
299 xwc
.height
= e
->xconfigurerequest
.height
;
300 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
301 xwc
.sibling
= e
->xconfigurerequest
.above
;
302 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
304 XConfigureWindow(getXDisplay(), e
->xconfigurerequest
.window
,
305 e
->xconfigurerequest
.value_mask
, &xwc
);
314 fprintf(stderr
, "Blackbox::process_event(): MapRequest for 0x%lx\n",
315 e
->xmaprequest
.window
);
318 BlackboxWindow
*win
= searchWindow(e
->xmaprequest
.window
);
322 if (win
->isIconic()) {
326 if (win
->isShaded()) {
331 if (focus
&& (win
->isTransient() || win
->getScreen()->doFocusNew()) &&
333 win
->setInputFocus();
335 BScreen
*screen
= searchScreen(e
->xmaprequest
.parent
);
339 we got a map request for a window who's parent isn't root. this
340 can happen in only one circumstance:
342 a client window unmapped a managed window, and then remapped it
343 somewhere between unmapping the client window and reparenting it
346 regardless of how it happens, we need to find the screen that
349 XWindowAttributes wattrib
;
350 if (! XGetWindowAttributes(getXDisplay(), e
->xmaprequest
.window
,
352 // failed to get the window attributes, perhaps the window has
353 // now been destroyed?
357 screen
= searchScreen(wattrib
.root
);
358 assert(screen
!= 0); // this should never happen
361 screen
->manageWindow(e
->xmaprequest
.window
);
368 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
369 Slit
*slit
= (Slit
*) 0;
370 BScreen
*screen
= (BScreen
*) 0;
372 if ((win
= searchWindow(e
->xunmap
.window
))) {
373 win
->unmapNotifyEvent(&e
->xunmap
);
374 } else if ((slit
= searchSlit(e
->xunmap
.window
))) {
375 slit
->unmapNotifyEvent(&e
->xunmap
);
376 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
377 screen
->removeSystrayWindow(e
->xunmap
.window
);
383 case DestroyNotify
: {
384 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
385 Slit
*slit
= (Slit
*) 0;
386 BScreen
*screen
= (BScreen
*) 0;
387 BWindowGroup
*group
= (BWindowGroup
*) 0;
389 if ((win
= searchWindow(e
->xdestroywindow
.window
))) {
390 win
->destroyNotifyEvent(&e
->xdestroywindow
);
391 } else if ((slit
= searchSlit(e
->xdestroywindow
.window
))) {
392 slit
->removeClient(e
->xdestroywindow
.window
, False
);
393 } else if ((group
= searchGroup(e
->xdestroywindow
.window
))) {
395 } else if ((screen
= searchSystrayWindow(e
->xunmap
.window
))) {
396 screen
->removeSystrayWindow(e
->xunmap
.window
);
402 case ReparentNotify
: {
404 this event is quite rare and is usually handled in unmapNotify
405 however, if the window is unmapped when the reparent event occurs
406 the window manager never sees it because an unmap event is not sent
407 to an already unmapped window.
409 BlackboxWindow
*win
= searchWindow(e
->xreparent
.window
);
411 win
->reparentNotifyEvent(&e
->xreparent
);
413 Slit
*slit
= searchSlit(e
->xreparent
.window
);
414 if (slit
&& slit
->getWindowID() != e
->xreparent
.parent
)
415 slit
->removeClient(e
->xreparent
.window
, True
);
421 // motion notify compression...
424 while (XCheckTypedWindowEvent(getXDisplay(), e
->xmotion
.window
,
425 MotionNotify
, &realevent
)) {
429 // if we have compressed some motion events, use the last one
433 // the pointer is on the wrong screen
434 if (! e
->xmotion
.same_screen
)
437 // strip the lock key modifiers
438 e
->xmotion
.state
&= ~(NumLockMask
| ScrollLockMask
| LockMask
);
440 last_time
= e
->xmotion
.time
;
442 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
443 Basemenu
*menu
= (Basemenu
*) 0;
445 if ((win
= searchWindow(e
->xmotion
.window
)))
446 win
->motionNotifyEvent(&e
->xmotion
);
447 else if ((menu
= searchMenu(e
->xmotion
.window
)))
448 menu
->motionNotifyEvent(&e
->xmotion
);
453 case PropertyNotify
: {
454 last_time
= e
->xproperty
.time
;
456 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
457 BScreen
*screen
= (BScreen
*) 0;
459 if ((win
= searchWindow(e
->xproperty
.window
)))
460 win
->propertyNotifyEvent(&e
->xproperty
);
461 else if ((screen
= searchScreen(e
->xproperty
.window
)))
462 screen
->propertyNotifyEvent(&e
->xproperty
);
467 last_time
= e
->xcrossing
.time
;
469 BScreen
*screen
= (BScreen
*) 0;
470 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
471 Basemenu
*menu
= (Basemenu
*) 0;
472 Toolbar
*tbar
= (Toolbar
*) 0;
473 Slit
*slit
= (Slit
*) 0;
475 if (e
->xcrossing
.mode
== NotifyGrab
) break;
479 sa
.w
= e
->xcrossing
.window
;
480 sa
.enter
= sa
.leave
= False
;
481 XCheckIfEvent(getXDisplay(), &dummy
, queueScanner
, (char *) &sa
);
483 if ((e
->xcrossing
.window
== e
->xcrossing
.root
) &&
484 (screen
= searchScreen(e
->xcrossing
.window
))) {
485 screen
->getImageControl()->installRootColormap();
486 } else if ((win
= searchWindow(e
->xcrossing
.window
))) {
487 if (win
->getScreen()->isSloppyFocus() &&
488 (! win
->isFocused()) && (! no_focus
) &&
489 win
->isNormal()) { // don't focus non-normal windows with mouseover
490 if ((! sa
.leave
|| sa
.inferior
) && win
->isVisible()) {
491 if (win
->setInputFocus())
492 win
->installColormap(True
); // XXX: shouldnt we honour no install?
495 } else if ((menu
= searchMenu(e
->xcrossing
.window
))) {
496 menu
->enterNotifyEvent(&e
->xcrossing
);
497 } else if ((tbar
= searchToolbar(e
->xcrossing
.window
))) {
498 tbar
->enterNotifyEvent(&e
->xcrossing
);
499 } else if ((slit
= searchSlit(e
->xcrossing
.window
))) {
500 slit
->enterNotifyEvent(&e
->xcrossing
);
506 last_time
= e
->xcrossing
.time
;
508 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
509 Basemenu
*menu
= (Basemenu
*) 0;
510 Toolbar
*tbar
= (Toolbar
*) 0;
511 Slit
*slit
= (Slit
*) 0;
513 if ((menu
= searchMenu(e
->xcrossing
.window
)))
514 menu
->leaveNotifyEvent(&e
->xcrossing
);
515 else if ((win
= searchWindow(e
->xcrossing
.window
)))
516 win
->installColormap(False
);
517 else if ((tbar
= searchToolbar(e
->xcrossing
.window
)))
518 tbar
->leaveNotifyEvent(&e
->xcrossing
);
519 else if ((slit
= searchSlit(e
->xcrossing
.window
)))
520 slit
->leaveNotifyEvent(&e
->xcrossing
);
525 // compress expose events
528 int ex1
, ey1
, ex2
, ey2
;
531 ex2
= ex1
+ e
->xexpose
.width
- 1;
532 ey2
= ey1
+ e
->xexpose
.height
- 1;
533 while (XCheckTypedWindowEvent(getXDisplay(), e
->xexpose
.window
,
534 Expose
, &realevent
)) {
538 ex1
= std::min(realevent
.xexpose
.x
, ex1
);
539 ey1
= std::min(realevent
.xexpose
.y
, ey1
);
540 ex2
= std::max(realevent
.xexpose
.x
+ realevent
.xexpose
.width
- 1, ex2
);
541 ey2
= std::max(realevent
.xexpose
.y
+ realevent
.xexpose
.height
- 1, ey2
);
546 // use the merged area
549 e
->xexpose
.width
= ex2
- ex1
+ 1;
550 e
->xexpose
.height
= ey2
- ey1
+ 1;
552 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
553 Basemenu
*menu
= (Basemenu
*) 0;
554 Toolbar
*tbar
= (Toolbar
*) 0;
556 if ((win
= searchWindow(e
->xexpose
.window
)))
557 win
->exposeEvent(&e
->xexpose
);
558 else if ((menu
= searchMenu(e
->xexpose
.window
)))
559 menu
->exposeEvent(&e
->xexpose
);
560 else if ((tbar
= searchToolbar(e
->xexpose
.window
)))
561 tbar
->exposeEvent(&e
->xexpose
);
567 Toolbar
*tbar
= searchToolbar(e
->xkey
.window
);
569 if (tbar
&& tbar
->isEditing())
570 tbar
->keyPressEvent(&e
->xkey
);
575 case ColormapNotify
: {
576 BScreen
*screen
= searchScreen(e
->xcolormap
.window
);
579 screen
->setRootColormapInstalled((e
->xcolormap
.state
==
580 ColormapInstalled
) ? True
: False
);
586 if (e
->xfocus
.detail
!= NotifyNonlinear
&&
587 e
->xfocus
.detail
!= NotifyAncestor
) {
589 don't process FocusIns when:
590 1. the new focus window isn't an ancestor or inferior of the old
591 focus window (NotifyNonlinear)
592 make sure to allow the FocusIn when the old focus window was an
593 ancestor but didn't have a parent, such as root (NotifyAncestor)
598 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
600 if (! win
->isFocused())
601 win
->setFocusFlag(True
);
604 set the event window to None. when the FocusOut event handler calls
605 this function recursively, it uses this as an indication that focus
606 has moved to a known window.
608 e
->xfocus
.window
= None
;
615 if (e
->xfocus
.detail
!= NotifyNonlinear
) {
617 don't process FocusOuts when:
618 2. the new focus window isn't an ancestor or inferior of the old
619 focus window (NotifyNonlinear)
624 BlackboxWindow
*win
= searchWindow(e
->xfocus
.window
);
625 if (win
&& win
->isFocused()) {
627 before we mark "win" as unfocused, we need to verify that focus is
628 going to a known location, is in a known location, or set focus
633 // don't check the current focus if FocusOut was generated during a grab
634 bool check_focus
= (e
->xfocus
.mode
== NotifyNormal
);
637 First, check if there is a pending FocusIn event waiting. if there
638 is, process it and determine if focus has moved to another window
639 (the FocusIn event handler sets the window in the event
640 structure to None to indicate this).
642 if (XCheckTypedEvent(getXDisplay(), FocusIn
, &event
)) {
644 process_event(&event
);
645 if (event
.xfocus
.window
== None
) {
653 Second, we query the X server for the current input focus.
654 to make sure that we keep a consistent state.
656 BlackboxWindow
*focus
;
659 XGetInputFocus(getXDisplay(), &w
, &revert
);
660 focus
= searchWindow(w
);
663 focus got from "win" to "focus" under some very strange
664 circumstances, and we need to make sure that the focus indication
667 setFocusedWindow(focus
);
669 // we have no idea where focus went... so we set it to somewhere
678 case ClientMessage
: {
679 if (e
->xclient
.format
== 32) {
680 if (e
->xclient
.message_type
== xatom
->getAtom(XAtom::wm_change_state
)) {
681 // WM_CHANGE_STATE message
682 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
683 if (! win
|| ! win
->validateClient()) return;
685 if (e
->xclient
.data
.l
[0] == IconicState
)
687 if (e
->xclient
.data
.l
[0] == NormalState
)
689 } else if (e
->xclient
.message_type
==
690 xatom
->getAtom(XAtom::blackbox_change_workspace
) ||
691 e
->xclient
.message_type
==
692 xatom
->getAtom(XAtom::net_current_desktop
)) {
693 // NET_CURRENT_DESKTOP message
694 BScreen
*screen
= searchScreen(e
->xclient
.window
);
696 unsigned int workspace
= e
->xclient
.data
.l
[0];
697 if (screen
&& workspace
< screen
->getWorkspaceCount())
698 screen
->changeWorkspaceID(workspace
);
699 } else if (e
->xclient
.message_type
==
700 xatom
->getAtom(XAtom::blackbox_change_window_focus
)) {
701 // TEMP HACK TO KEEP BBKEYS WORKING
702 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
704 if (win
&& win
->isVisible() && win
->setInputFocus())
705 win
->installColormap(True
);
706 } else if (e
->xclient
.message_type
==
707 xatom
->getAtom(XAtom::net_active_window
)) {
709 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
712 BScreen
*screen
= win
->getScreen();
715 win
->deiconify(False
, True
);
716 if (win
->getWorkspaceNumber() != screen
->getCurrentWorkspaceID())
717 screen
->changeWorkspaceID(win
->getWorkspaceNumber());
718 if (win
->isVisible() && win
->setInputFocus()) {
719 win
->getScreen()->getWorkspace(win
->getWorkspaceNumber())->
721 win
->installColormap(True
);
724 } else if (e
->xclient
.message_type
==
725 xatom
->getAtom(XAtom::blackbox_cycle_window_focus
)) {
726 // BLACKBOX_CYCLE_WINDOW_FOCUS
727 BScreen
*screen
= searchScreen(e
->xclient
.window
);
730 if (! e
->xclient
.data
.l
[0])
735 } else if (e
->xclient
.message_type
==
736 xatom
->getAtom(XAtom::net_wm_desktop
)) {
738 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
741 BScreen
*screen
= win
->getScreen();
742 unsigned long wksp
= (unsigned) e
->xclient
.data
.l
[0];
743 if (wksp
< screen
->getWorkspaceCount()) {
744 if (win
->isIconic()) win
->deiconify(False
, True
);
745 if (win
->isStuck()) win
->stick();
746 if (wksp
!= screen
->getCurrentWorkspaceID())
750 screen
->reassociateWindow(win
, wksp
, True
);
751 } else if (wksp
== 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
752 wksp
== 0xffffffff) {
753 if (win
->isIconic()) win
->deiconify(False
, True
);
754 if (! win
->isStuck()) win
->stick();
755 if (! win
->isVisible()) win
->show();
758 } else if (e
->xclient
.message_type
==
759 xatom
->getAtom(XAtom::blackbox_change_attributes
)) {
760 // BLACKBOX_CHANGE_ATTRIBUTES
761 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
763 if (win
&& win
->validateClient()) {
765 net
.flags
= e
->xclient
.data
.l
[0];
766 net
.attrib
= e
->xclient
.data
.l
[1];
767 net
.workspace
= e
->xclient
.data
.l
[2];
768 net
.stack
= e
->xclient
.data
.l
[3];
769 net
.decoration
= e
->xclient
.data
.l
[4];
771 win
->changeBlackboxHints(&net
);
773 } else if (e
->xclient
.message_type
==
774 xatom
->getAtom(XAtom::net_number_of_desktops
)) {
775 // NET_NUMBER_OF_DESKTOPS
776 BScreen
*screen
= searchScreen(e
->xclient
.window
);
778 if (e
->xclient
.data
.l
[0] > 0)
779 screen
->changeWorkspaceCount((unsigned) e
->xclient
.data
.l
[0]);
780 } else if (e
->xclient
.message_type
==
781 xatom
->getAtom(XAtom::net_close_window
)) {
783 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
784 if (win
&& win
->validateClient())
785 win
->close(); // could this be smarter?
786 } else if (e
->xclient
.message_type
==
787 xatom
->getAtom(XAtom::net_wm_moveresize
)) {
789 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
790 if (win
&& win
->validateClient()) {
791 int x_root
= e
->xclient
.data
.l
[0],
792 y_root
= e
->xclient
.data
.l
[1];
793 if ((Atom
) e
->xclient
.data
.l
[2] ==
794 xatom
->getAtom(XAtom::net_wm_moveresize_move
)) {
795 win
->beginMove(x_root
, y_root
);
797 if ((Atom
) e
->xclient
.data
.l
[2] ==
798 xatom
->getAtom(XAtom::net_wm_moveresize_size_topleft
))
799 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopLeft
);
800 else if ((Atom
) e
->xclient
.data
.l
[2] ==
801 xatom
->getAtom(XAtom::net_wm_moveresize_size_topright
))
802 win
->beginResize(x_root
, y_root
, BlackboxWindow::TopRight
);
803 else if ((Atom
) e
->xclient
.data
.l
[2] ==
804 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomleft
))
805 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomLeft
);
806 else if ((Atom
) e
->xclient
.data
.l
[2] ==
807 xatom
->getAtom(XAtom::net_wm_moveresize_size_bottomright
))
808 win
->beginResize(x_root
, y_root
, BlackboxWindow::BottomRight
);
811 } else if (e
->xclient
.message_type
==
812 xatom
->getAtom(XAtom::net_wm_state
)) {
814 BlackboxWindow
*win
= searchWindow(e
->xclient
.window
);
815 if (win
&& win
->validateClient()) {
816 const Atom action
= (Atom
) e
->xclient
.data
.l
[0];
817 const Atom state
[] = { (Atom
) e
->xclient
.data
.l
[1],
818 (Atom
) e
->xclient
.data
.l
[2] };
820 for (int i
= 0; i
< 2; ++i
) {
824 if ((Atom
) e
->xclient
.data
.l
[0] == 1) {
826 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
828 } else if (state
[i
] ==
829 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
830 if (win
->isMaximizedHoriz()) {
831 win
->maximize(0); // unmaximize
832 win
->maximize(1); // full
833 } else if (! win
->isMaximized()) {
834 win
->maximize(2); // vert
836 } else if (state
[i
] ==
837 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
838 if (win
->isMaximizedVert()) {
839 win
->maximize(0); // unmaximize
840 win
->maximize(1); // full
841 } else if (! win
->isMaximized()) {
842 win
->maximize(3); // horiz
844 } else if (state
[i
] ==
845 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
846 if (! win
->isShaded())
848 } else if (state
[i
] ==
849 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
850 win
->setSkipTaskbar(True
);
851 } else if (state
[i
] ==
852 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
853 win
->setSkipPager(True
);
854 } else if (state
[i
] ==
855 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
856 win
->setFullscreen(True
);
858 } else if (action
== 0) {
860 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
861 win
->setModal(False
);
862 } else if (state
[i
] ==
863 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
864 if (win
->isMaximizedFull()) {
865 win
->maximize(0); // unmaximize
866 win
->maximize(3); // horiz
867 } else if (win
->isMaximizedVert()) {
868 win
->maximize(0); // unmaximize
870 } else if (state
[i
] ==
871 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
872 if (win
->isMaximizedFull()) {
873 win
->maximize(0); // unmaximize
874 win
->maximize(2); // vert
875 } else if (win
->isMaximizedHoriz()) {
876 win
->maximize(0); // unmaximize
878 } else if (state
[i
] ==
879 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
882 } else if (state
[i
] ==
883 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
884 win
->setSkipTaskbar(False
);
885 } else if (state
[i
] ==
886 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
887 win
->setSkipPager(False
);
888 } else if (state
[i
] ==
889 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
890 win
->setFullscreen(False
);
892 } else if (action
== 2) {
894 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
)) {
895 win
->setModal(! win
->isModal());
896 } else if (state
[i
] ==
897 xatom
->getAtom(XAtom::net_wm_state_maximized_vert
)) {
898 if (win
->isMaximizedFull()) {
899 win
->maximize(0); // unmaximize
900 win
->maximize(3); // horiz
901 } else if (win
->isMaximizedVert()) {
902 win
->maximize(0); // unmaximize
903 } else if (win
->isMaximizedHoriz()) {
904 win
->maximize(0); // unmaximize
905 win
->maximize(1); // full
907 win
->maximize(2); // vert
909 } else if (state
[i
] ==
910 xatom
->getAtom(XAtom::net_wm_state_maximized_horz
)) {
911 if (win
->isMaximizedFull()) {
912 win
->maximize(0); // unmaximize
913 win
->maximize(2); // vert
914 } else if (win
->isMaximizedHoriz()) {
915 win
->maximize(0); // unmaximize
916 } else if (win
->isMaximizedVert()) {
917 win
->maximize(0); // unmaximize
918 win
->maximize(1); // full
920 win
->maximize(3); // horiz
922 } else if (state
[i
] ==
923 xatom
->getAtom(XAtom::net_wm_state_shaded
)) {
925 } else if (state
[i
] ==
926 xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
)) {
927 win
->setSkipTaskbar(! win
->skipTaskbar());
928 } else if (state
[i
] ==
929 xatom
->getAtom(XAtom::net_wm_state_skip_pager
)) {
930 win
->setSkipPager(! win
->skipPager());
931 } else if (state
[i
] ==
932 xatom
->getAtom(XAtom::net_wm_state_fullscreen
)) {
933 win
->setFullscreen(! win
->isFullscreen());
945 case ConfigureNotify
:
947 break; // not handled, just ignore
951 if (e
->type
== getShapeEventBase()) {
952 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
953 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
956 win
->shapeEvent(shape_event
);
964 bool Blackbox::handleSignal(int sig
) {
993 bool Blackbox::validateWindow(Window window
) {
995 if (XCheckTypedWindowEvent(getXDisplay(), window
, DestroyNotify
, &event
)) {
996 XPutBackEvent(getXDisplay(), &event
);
1005 BScreen
*Blackbox::searchScreen(Window window
) {
1006 ScreenList::iterator it
= screenList
.begin();
1008 for (; it
!= screenList
.end(); ++it
) {
1010 if (s
->getRootWindow() == window
)
1014 return (BScreen
*) 0;
1018 BScreen
*Blackbox::searchSystrayWindow(Window window
) {
1019 WindowScreenLookup::iterator it
= systraySearchList
.find(window
);
1020 if (it
!= systraySearchList
.end())
1023 return (BScreen
*) 0;
1027 BlackboxWindow
*Blackbox::searchWindow(Window window
) {
1028 WindowLookup::iterator it
= windowSearchList
.find(window
);
1029 if (it
!= windowSearchList
.end())
1032 return (BlackboxWindow
*) 0;
1036 BWindowGroup
*Blackbox::searchGroup(Window window
) {
1037 GroupLookup::iterator it
= groupSearchList
.find(window
);
1038 if (it
!= groupSearchList
.end())
1041 return (BWindowGroup
*) 0;
1045 Basemenu
*Blackbox::searchMenu(Window window
) {
1046 MenuLookup::iterator it
= menuSearchList
.find(window
);
1047 if (it
!= menuSearchList
.end())
1050 return (Basemenu
*) 0;
1054 Toolbar
*Blackbox::searchToolbar(Window window
) {
1055 ToolbarLookup::iterator it
= toolbarSearchList
.find(window
);
1056 if (it
!= toolbarSearchList
.end())
1059 return (Toolbar
*) 0;
1063 Slit
*Blackbox::searchSlit(Window window
) {
1064 SlitLookup::iterator it
= slitSearchList
.find(window
);
1065 if (it
!= slitSearchList
.end())
1072 void Blackbox::saveSystrayWindowSearch(Window window
, BScreen
*screen
) {
1073 systraySearchList
.insert(WindowScreenLookupPair(window
, screen
));
1077 void Blackbox::saveWindowSearch(Window window
, BlackboxWindow
*data
) {
1078 windowSearchList
.insert(WindowLookupPair(window
, data
));
1082 void Blackbox::saveGroupSearch(Window window
, BWindowGroup
*data
) {
1083 groupSearchList
.insert(GroupLookupPair(window
, data
));
1087 void Blackbox::saveMenuSearch(Window window
, Basemenu
*data
) {
1088 menuSearchList
.insert(MenuLookupPair(window
, data
));
1092 void Blackbox::saveToolbarSearch(Window window
, Toolbar
*data
) {
1093 toolbarSearchList
.insert(ToolbarLookupPair(window
, data
));
1097 void Blackbox::saveSlitSearch(Window window
, Slit
*data
) {
1098 slitSearchList
.insert(SlitLookupPair(window
, data
));
1102 void Blackbox::removeSystrayWindowSearch(Window window
) {
1103 systraySearchList
.erase(window
);
1107 void Blackbox::removeWindowSearch(Window window
) {
1108 windowSearchList
.erase(window
);
1112 void Blackbox::removeGroupSearch(Window window
) {
1113 groupSearchList
.erase(window
);
1117 void Blackbox::removeMenuSearch(Window window
) {
1118 menuSearchList
.erase(window
);
1122 void Blackbox::removeToolbarSearch(Window window
) {
1123 toolbarSearchList
.erase(window
);
1127 void Blackbox::removeSlitSearch(Window window
) {
1128 slitSearchList
.erase(window
);
1132 void Blackbox::restart(const char *prog
) {
1136 putenv(const_cast<char *>(screenList
.front()->displayString().c_str()));
1137 execlp(prog
, prog
, NULL
);
1141 // fall back in case the above execlp doesn't work
1142 execvp(argv
[0], argv
);
1143 string name
= basename(argv
[0]);
1144 execvp(name
.c_str(), argv
);
1148 void Blackbox::shutdown(void) {
1149 BaseDisplay::shutdown();
1151 XSetInputFocus(getXDisplay(), PointerRoot
, None
, CurrentTime
);
1153 std::for_each(screenList
.begin(), screenList
.end(),
1154 std::mem_fun(&BScreen::shutdown
));
1156 XSync(getXDisplay(), False
);
1161 void Blackbox::saveXineramaPlacement(bool x
) {
1162 resource
.xinerama_placement
= x
;
1163 config
.setValue("session.xineramaSupport.windowPlacement",
1164 resource
.xinerama_placement
);
1165 reconfigure(); // make sure all screens get this change
1169 void Blackbox::saveXineramaMaximizing(bool x
) {
1170 resource
.xinerama_maximize
= x
;
1171 config
.setValue("session.xineramaSupport.windowMaximizing",
1172 resource
.xinerama_maximize
);
1173 reconfigure(); // make sure all screens get this change
1177 void Blackbox::saveXineramaSnapping(bool x
) {
1178 resource
.xinerama_snap
= x
;
1179 config
.setValue("session.xineramaSupport.windowSnapping",
1180 resource
.xinerama_snap
);
1181 reconfigure(); // make sure all screens get this change
1187 * Save all values as they are so that the defaults will be written to the rc
1190 void Blackbox::save_rc(void) {
1191 config
.setAutoSave(false);
1193 config
.setValue("session.colorsPerChannel", resource
.colors_per_channel
);
1194 config
.setValue("session.doubleClickInterval",
1195 resource
.double_click_interval
);
1196 config
.setValue("session.autoRaiseDelay",
1197 ((resource
.auto_raise_delay
.tv_sec
* 1000) +
1198 (resource
.auto_raise_delay
.tv_usec
/ 1000)));
1199 config
.setValue("session.cacheLife", resource
.cache_life
/ 60000);
1200 config
.setValue("session.cacheMax", resource
.cache_max
);
1201 config
.setValue("session.styleFile", resource
.style_file
);
1202 config
.setValue("session.titlebarLayout", resource
.titlebar_layout
);
1205 saveXineramaPlacement(resource
.xinerama_placement
);
1206 saveXineramaMaximizing(resource
.xinerama_maximize
);
1207 saveXineramaSnapping(resource
.xinerama_snap
);
1210 std::for_each(screenList
.begin(), screenList
.end(),
1211 std::mem_fun(&BScreen::save_rc
));
1213 config
.setAutoSave(true);
1218 void Blackbox::load_rc(void) {
1219 if (! config
.load())
1224 if (! config
.getValue("session.colorsPerChannel",
1225 resource
.colors_per_channel
))
1226 resource
.colors_per_channel
= 4;
1227 if (resource
.colors_per_channel
< 2) resource
.colors_per_channel
= 2;
1228 else if (resource
.colors_per_channel
> 6) resource
.colors_per_channel
= 6;
1230 if (config
.getValue("session.styleFile", s
))
1231 resource
.style_file
= expandTilde(s
);
1233 resource
.style_file
= DEFAULTSTYLE
;
1235 if (! config
.getValue("session.doubleClickInterval",
1236 resource
.double_click_interval
));
1237 resource
.double_click_interval
= 250;
1239 if (! config
.getValue("session.autoRaiseDelay",
1240 resource
.auto_raise_delay
.tv_usec
))
1241 resource
.auto_raise_delay
.tv_usec
= 400;
1242 resource
.auto_raise_delay
.tv_sec
= resource
.auto_raise_delay
.tv_usec
/ 1000;
1243 resource
.auto_raise_delay
.tv_usec
-=
1244 (resource
.auto_raise_delay
.tv_sec
* 1000);
1245 resource
.auto_raise_delay
.tv_usec
*= 1000;
1247 if (! config
.getValue("session.cacheLife", resource
.cache_life
))
1248 resource
.cache_life
= 5;
1249 resource
.cache_life
*= 60000;
1251 if (! config
.getValue("session.cacheMax", resource
.cache_max
))
1252 resource
.cache_max
= 200;
1254 if (! config
.getValue("session.titlebarLayout", resource
.titlebar_layout
))
1255 resource
.titlebar_layout
= "ILMC";
1258 if (! config
.getValue("session.xineramaSupport.windowPlacement",
1259 resource
.xinerama_placement
))
1260 resource
.xinerama_placement
= false;
1262 if (! config
.getValue("session.xineramaSupport.windowMaximizing",
1263 resource
.xinerama_maximize
))
1264 resource
.xinerama_maximize
= false;
1266 if (! config
.getValue("session.xineramaSupport.windowSnapping",
1267 resource
.xinerama_snap
))
1268 resource
.xinerama_snap
= false;
1273 void Blackbox::reconfigure(void) {
1274 // don't reconfigure while saving the initial rc file, it's a waste and it
1275 // breaks somethings (workspace names)
1276 if (isStartup()) return;
1278 reconfigure_wait
= True
;
1280 if (! timer
->isTiming()) timer
->start();
1284 void Blackbox::real_reconfigure(void) {
1287 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
1289 menuTimestamps
.clear();
1293 std::for_each(screenList
.begin(), screenList
.end(),
1294 std::mem_fun(&BScreen::reconfigure
));
1298 void Blackbox::checkMenu(void) {
1299 bool reread
= False
;
1300 MenuTimestampList::iterator it
= menuTimestamps
.begin();
1301 for(; it
!= menuTimestamps
.end(); ++it
) {
1302 MenuTimestamp
*tmp
= *it
;
1305 if (! stat(tmp
->filename
.c_str(), &buf
)) {
1306 if (tmp
->timestamp
!= buf
.st_ctime
)
1313 if (reread
) rereadMenu();
1317 void Blackbox::rereadMenu(void) {
1318 reread_menu_wait
= True
;
1320 if (! timer
->isTiming()) timer
->start();
1324 void Blackbox::real_rereadMenu(void) {
1325 std::for_each(menuTimestamps
.begin(), menuTimestamps
.end(),
1327 menuTimestamps
.clear();
1329 std::for_each(screenList
.begin(), screenList
.end(),
1330 std::mem_fun(&BScreen::rereadMenu
));
1334 void Blackbox::saveStyleFilename(const string
& filename
) {
1335 assert(! filename
.empty());
1336 resource
.style_file
= filename
;
1337 config
.setValue("session.styleFile", resource
.style_file
);
1341 void Blackbox::addMenuTimestamp(const string
& filename
) {
1342 assert(! filename
.empty());
1345 MenuTimestampList::iterator it
= menuTimestamps
.begin();
1346 for (; it
!= menuTimestamps
.end() && ! found
; ++it
) {
1347 if ((*it
)->filename
== filename
) found
= True
;
1352 if (! stat(filename
.c_str(), &buf
)) {
1353 MenuTimestamp
*ts
= new MenuTimestamp
;
1355 ts
->filename
= filename
;
1356 ts
->timestamp
= buf
.st_ctime
;
1358 menuTimestamps
.push_back(ts
);
1364 void Blackbox::timeout(void) {
1365 if (reconfigure_wait
)
1368 if (reread_menu_wait
)
1371 reconfigure_wait
= reread_menu_wait
= False
;
1375 void Blackbox::setChangingWindow(BlackboxWindow
*win
) {
1376 // make sure one of the two is null and the other isn't
1377 assert((! changing_window
&& win
) || (! win
&& changing_window
));
1378 changing_window
= win
;
1382 void Blackbox::setFocusedWindow(BlackboxWindow
*win
) {
1383 if (focused_window
&& focused_window
== win
) // nothing to do
1386 BScreen
*old_screen
= 0;
1388 if (focused_window
) {
1389 focused_window
->setFocusFlag(False
);
1390 old_screen
= focused_window
->getScreen();
1393 if (win
&& ! win
->isIconic()) {
1394 // the active screen is the one with the last focused window...
1395 // this will keep focus on this screen no matter where the mouse goes,
1396 // so multihead keybindings will continue to work on that screen until the
1397 // user focuses a window on a different screen.
1398 active_screen
= win
->getScreen();
1399 focused_window
= win
;
1403 if (active_screen
) {
1404 // set input focus to the toolbar of the screen with mouse
1405 XSetInputFocus(getXDisplay(),
1406 active_screen
->getRootWindow(),
1407 RevertToPointerRoot
, CurrentTime
);
1409 // set input focus to the toolbar of the first managed screen
1410 XSetInputFocus(getXDisplay(),
1411 screenList
.front()->getRootWindow(),
1412 RevertToPointerRoot
, CurrentTime
);
1415 // set input focus to the toolbar of the last screen
1416 XSetInputFocus(getXDisplay(), old_screen
->getRootWindow(),
1417 RevertToPointerRoot
, CurrentTime
);
1421 if (active_screen
&& active_screen
->isScreenManaged()) {
1422 active_screen
->getToolbar()->redrawWindowLabel(True
);
1423 active_screen
->updateNetizenWindowFocus();
1426 if (old_screen
&& old_screen
!= active_screen
) {
1427 old_screen
->getToolbar()->redrawWindowLabel(True
);
1428 old_screen
->updateNetizenWindowFocus();