]> icculus.org git repositories - dana/openbox.git/blob - src/blackbox.cc
try make the ~/.openbox dir if it doesnt exist.
[dana/openbox.git] / src / blackbox.cc
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)
5 //
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:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
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.
23
24 #ifdef    HAVE_CONFIG_H
25 #  include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #include <X11/cursorfont.h>
33 #include <X11/keysym.h>
34
35 #ifdef    SHAPE
36 #include <X11/extensions/shape.h>
37 #endif // SHAPE
38
39 #ifdef    HAVE_STDIO_H
40 #  include <stdio.h>
41 #endif // HAVE_STDIO_H
42
43 #ifdef HAVE_STDLIB_H
44 #  include <stdlib.h>
45 #endif // HAVE_STDLIB_H
46
47 #ifdef HAVE_STRING_H
48 #  include <string.h>
49 #endif // HAVE_STRING_H
50
51 #ifdef    HAVE_UNISTD_H
52 #  include <sys/types.h>
53 #  include <unistd.h>
54 #endif // HAVE_UNISTD_H
55
56 #ifdef    HAVE_SYS_PARAM_H
57 #  include <sys/param.h>
58 #endif // HAVE_SYS_PARAM_H
59
60 #ifdef    HAVE_SYS_SELECT_H
61 #  include <sys/select.h>
62 #endif // HAVE_SYS_SELECT_H
63
64 #ifdef    HAVE_SIGNAL_H
65 #  include <signal.h>
66 #endif // HAVE_SIGNAL_H
67
68 #ifdef    HAVE_SYS_SIGNAL_H
69 #  include <sys/signal.h>
70 #endif // HAVE_SYS_SIGNAL_H
71
72 #ifdef    HAVE_SYS_STAT_H
73 #  include <sys/types.h>
74 #  include <sys/stat.h>
75 #endif // HAVE_SYS_STAT_H
76
77 #ifdef    TIME_WITH_SYS_TIME
78 #  include <sys/time.h>
79 #  include <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
84 #    include <time.h>
85 #  endif // HAVE_SYS_TIME_H
86 #endif // TIME_WITH_SYS_TIME
87
88 #ifdef    HAVE_LIBGEN_H
89 #  include <libgen.h>
90 #endif // HAVE_LIBGEN_H
91 }
92
93 #include <assert.h>
94
95 #include <algorithm>
96 #include <string>
97 using std::string;
98
99 #include "i18n.hh"
100 #include "blackbox.hh"
101 #include "Basemenu.hh"
102 #include "Clientmenu.hh"
103 #include "GCCache.hh"
104 #include "Image.hh"
105 #include "Rootmenu.hh"
106 #include "Screen.hh"
107 #include "Slit.hh"
108 #include "Toolbar.hh"
109 #include "Util.hh"
110 #include "Window.hh"
111 #include "Workspace.hh"
112 #include "Workspacemenu.hh"
113 #include "XAtom.hh"
114
115 // X event scanner for enter/leave notifies - adapted from twm
116 struct scanargs {
117   Window w;
118   bool leave, inferior, enter;
119 };
120
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)) {
126     scan->leave = True;
127     scan->inferior = (e->xcrossing.detail == NotifyInferior);
128   } else if ((e->type == EnterNotify) && (e->xcrossing.mode == NotifyUngrab)) {
129     scan->enter = True;
130   }
131
132   return False;
133 }
134
135 Blackbox *blackbox;
136
137
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");
142
143   if (XSetLocaleModifiers("") == NULL)
144     fprintf(stderr, "cannot set locale modifiers\n");
145
146   ::blackbox = this;
147   argv = m_argv;
148
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);
153   
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);
159
160   no_focus = False;
161
162   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
163
164   active_screen = 0;
165   focused_window = changing_window = (BlackboxWindow *) 0;
166
167   XrmInitialize();
168   load_rc();
169
170   xatom = new XAtom(getXDisplay());
171
172   cursor.session = XCreateFontCursor(getXDisplay(), XC_left_ptr);
173   cursor.move = XCreateFontCursor(getXDisplay(), XC_fleur);
174   cursor.ll_angle = XCreateFontCursor(getXDisplay(), XC_ll_angle);
175   cursor.lr_angle = XCreateFontCursor(getXDisplay(), XC_lr_angle);
176   cursor.ul_angle = XCreateFontCursor(getXDisplay(), XC_ul_angle);
177   cursor.ur_angle = XCreateFontCursor(getXDisplay(), XC_ur_angle);
178
179   for (unsigned int i = 0; i < getNumberOfScreens(); i++) {
180     BScreen *screen = new BScreen(this, i);
181
182     if (! screen->isScreenManaged()) {
183       delete screen;
184       continue;
185     }
186
187     screenList.push_back(screen);
188   }
189
190   if (screenList.empty()) {
191     fprintf(stderr,
192             i18n(blackboxSet, blackboxNoManagableScreens,
193               "Blackbox::Blackbox: no managable screens found, aborting.\n"));
194     ::exit(3);
195   }
196
197   // save current settings and default values
198   save_rc();
199
200   // set the screen with mouse to the first managed screen
201   active_screen = screenList.front();
202   setFocusedWindow(0);
203
204   XSynchronize(getXDisplay(), False);
205   XSync(getXDisplay(), False);
206
207   reconfigure_wait = reread_menu_wait = False;
208
209   timer = new BTimer(this, this);
210   timer->setTimeout(0l);
211 }
212
213
214 Blackbox::~Blackbox(void) {
215   std::for_each(screenList.begin(), screenList.end(), PointerAssassin());
216
217   std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
218                 PointerAssassin());
219
220   delete xatom;
221
222   delete timer;
223 }
224
225
226 void Blackbox::process_event(XEvent *e) {
227   switch (e->type) {
228   case ButtonPress: {
229     // strip the lock key modifiers
230     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
231
232     last_time = e->xbutton.time;
233
234     BlackboxWindow *win = (BlackboxWindow *) 0;
235     Basemenu *menu = (Basemenu *) 0;
236     Slit *slit = (Slit *) 0;
237     Toolbar *tbar = (Toolbar *) 0;
238     BScreen *scrn = (BScreen *) 0;
239
240     if ((win = searchWindow(e->xbutton.window))) {
241       win->buttonPressEvent(&e->xbutton);
242
243       /* XXX: is this sane on low colour desktops? */
244       if (e->xbutton.button == 1)
245         win->installColormap(True);
246     } else if ((menu = searchMenu(e->xbutton.window))) {
247       menu->buttonPressEvent(&e->xbutton);
248     } else if ((slit = searchSlit(e->xbutton.window))) {
249       slit->buttonPressEvent(&e->xbutton);
250     } else if ((tbar = searchToolbar(e->xbutton.window))) {
251       tbar->buttonPressEvent(&e->xbutton);
252     } else if ((scrn = searchScreen(e->xbutton.window))) {
253       scrn->buttonPressEvent(&e->xbutton);
254       if (active_screen != scrn) {
255         active_screen = scrn;
256         // first, set no focus window on the old screen
257         setFocusedWindow(0);
258         // and move focus to this screen
259         setFocusedWindow(0);
260       }
261     }
262     break;
263   }
264
265   case ButtonRelease: {
266     // strip the lock key modifiers
267     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
268
269     last_time = e->xbutton.time;
270
271     BlackboxWindow *win = (BlackboxWindow *) 0;
272     Basemenu *menu = (Basemenu *) 0;
273     Toolbar *tbar = (Toolbar *) 0;
274
275     if ((win = searchWindow(e->xbutton.window)))
276       win->buttonReleaseEvent(&e->xbutton);
277     else if ((menu = searchMenu(e->xbutton.window)))
278       menu->buttonReleaseEvent(&e->xbutton);
279     else if ((tbar = searchToolbar(e->xbutton.window)))
280       tbar->buttonReleaseEvent(&e->xbutton);
281
282     break;
283   }
284
285   case ConfigureRequest: {
286     // compress configure requests...
287     XEvent realevent;
288     unsigned int i = 0;
289     while(XCheckTypedWindowEvent(getXDisplay(), e->xconfigurerequest.window,
290                                  ConfigureRequest, &realevent)) {
291       i++;
292     }
293     if ( i > 0 )
294       e = &realevent;
295
296     BlackboxWindow *win = (BlackboxWindow *) 0;
297     Slit *slit = (Slit *) 0;
298
299     if ((win = searchWindow(e->xconfigurerequest.window))) {
300       win->configureRequestEvent(&e->xconfigurerequest);
301     } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
302       slit->configureRequestEvent(&e->xconfigurerequest);
303     } else {
304       if (validateWindow(e->xconfigurerequest.window)) {
305         XWindowChanges xwc;
306
307         xwc.x = e->xconfigurerequest.x;
308         xwc.y = e->xconfigurerequest.y;
309         xwc.width = e->xconfigurerequest.width;
310         xwc.height = e->xconfigurerequest.height;
311         xwc.border_width = e->xconfigurerequest.border_width;
312         xwc.sibling = e->xconfigurerequest.above;
313         xwc.stack_mode = e->xconfigurerequest.detail;
314
315         XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
316                          e->xconfigurerequest.value_mask, &xwc);
317       }
318     }
319
320     break;
321   }
322
323   case MapRequest: {
324 #ifdef    DEBUG
325     fprintf(stderr, "Blackbox::process_event(): MapRequest for 0x%lx\n",
326             e->xmaprequest.window);
327 #endif // DEBUG
328
329     BlackboxWindow *win = searchWindow(e->xmaprequest.window);
330
331     if (win) {
332       if (win->isIconic()) {
333         win->deiconify();
334         win->setInputFocus();
335       }
336     } else {
337       BScreen *screen = searchScreen(e->xmaprequest.parent);
338
339       if (! screen) {
340         /*
341           we got a map request for a window who's parent isn't root. this
342           can happen in only one circumstance:
343
344             a client window unmapped a managed window, and then remapped it
345             somewhere between unmapping the client window and reparenting it
346             to root.
347
348           regardless of how it happens, we need to find the screen that
349           the window is on
350         */
351         XWindowAttributes wattrib;
352         if (! XGetWindowAttributes(getXDisplay(), e->xmaprequest.window,
353                                    &wattrib)) {
354           // failed to get the window attributes, perhaps the window has
355           // now been destroyed?
356           break;
357         }
358
359         screen = searchScreen(wattrib.root);
360         assert(screen != 0); // this should never happen
361       }
362
363       screen->manageWindow(e->xmaprequest.window);
364     }
365
366     break;
367   }
368
369   case UnmapNotify: {
370     BlackboxWindow *win = (BlackboxWindow *) 0;
371     Slit *slit = (Slit *) 0;
372     BScreen *screen = (BScreen *) 0;
373
374     if ((win = searchWindow(e->xunmap.window))) {
375       win->unmapNotifyEvent(&e->xunmap);
376     } else if ((slit = searchSlit(e->xunmap.window))) {
377       slit->unmapNotifyEvent(&e->xunmap);
378     } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
379       screen->removeSystrayWindow(e->xunmap.window);
380     } else if ((screen = searchDesktopWindow(e->xunmap.window))) {
381       screen->removeDesktopWindow(e->xunmap.window);
382     }
383
384     break;
385   }
386
387   case DestroyNotify: {
388     BlackboxWindow *win = (BlackboxWindow *) 0;
389     Slit *slit = (Slit *) 0;
390     BScreen *screen = (BScreen *) 0;
391     BWindowGroup *group = (BWindowGroup *) 0;
392
393     if ((win = searchWindow(e->xdestroywindow.window))) {
394       win->destroyNotifyEvent(&e->xdestroywindow);
395     } else if ((slit = searchSlit(e->xdestroywindow.window))) {
396       slit->removeClient(e->xdestroywindow.window, False);
397     } else if ((group = searchGroup(e->xdestroywindow.window))) {
398       delete group;
399     } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
400       screen->removeSystrayWindow(e->xunmap.window);
401     } else if ((screen = searchDesktopWindow(e->xunmap.window))) {
402       screen->removeDesktopWindow(e->xunmap.window);
403     }
404
405     break;
406   }
407
408   case ReparentNotify: {
409     /*
410       this event is quite rare and is usually handled in unmapNotify
411       however, if the window is unmapped when the reparent event occurs
412       the window manager never sees it because an unmap event is not sent
413       to an already unmapped window.
414     */
415     BlackboxWindow *win = searchWindow(e->xreparent.window);
416     if (win) {
417       win->reparentNotifyEvent(&e->xreparent);
418     } else {
419       Slit *slit = searchSlit(e->xreparent.window);
420       if (slit && slit->getWindowID() != e->xreparent.parent)
421         slit->removeClient(e->xreparent.window, True);
422     }
423     break;
424   }
425
426   case MotionNotify: {
427     // motion notify compression...
428     XEvent realevent;
429     unsigned int i = 0;
430     while (XCheckTypedWindowEvent(getXDisplay(), e->xmotion.window,
431                                   MotionNotify, &realevent)) {
432       i++;
433     }
434
435     // if we have compressed some motion events, use the last one
436     if ( i > 0 )
437       e = &realevent;
438
439     // strip the lock key modifiers
440     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
441
442     last_time = e->xmotion.time;
443
444     BlackboxWindow *win = (BlackboxWindow *) 0;
445     Basemenu *menu = (Basemenu *) 0;
446
447     if ((win = searchWindow(e->xmotion.window)))
448       win->motionNotifyEvent(&e->xmotion);
449     else if ((menu = searchMenu(e->xmotion.window)))
450       menu->motionNotifyEvent(&e->xmotion);
451
452     break;
453   }
454
455   case PropertyNotify: {
456     last_time = e->xproperty.time;
457
458     BlackboxWindow *win = searchWindow(e->xproperty.window);
459     if (win)
460       win->propertyNotifyEvent(&e->xproperty);
461     break;
462   }
463
464   case EnterNotify: {
465     last_time = e->xcrossing.time;
466
467     BScreen *screen = (BScreen *) 0;
468     BlackboxWindow *win = (BlackboxWindow *) 0;
469     Basemenu *menu = (Basemenu *) 0;
470     Toolbar *tbar = (Toolbar *) 0;
471     Slit *slit = (Slit *) 0;
472
473     if (e->xcrossing.mode == NotifyGrab) break;
474
475     XEvent dummy;
476     scanargs sa;
477     sa.w = e->xcrossing.window;
478     sa.enter = sa.leave = False;
479     XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
480
481     if ((e->xcrossing.window == e->xcrossing.root) &&
482         (screen = searchScreen(e->xcrossing.window))) {
483       screen->getImageControl()->installRootColormap();
484     } else if ((win = searchWindow(e->xcrossing.window))) {
485       if (win->getScreen()->isSloppyFocus() &&
486           (! win->isFocused()) && (! no_focus)) {
487         if (((! sa.leave) || sa.inferior) && win->isVisible()) {
488           if (win->setInputFocus())
489             win->installColormap(True); // XXX: shouldnt we honour no install?
490         }
491       }
492     } else if ((menu = searchMenu(e->xcrossing.window))) {
493       menu->enterNotifyEvent(&e->xcrossing);
494     } else if ((tbar = searchToolbar(e->xcrossing.window))) {
495       tbar->enterNotifyEvent(&e->xcrossing);
496     } else if ((slit = searchSlit(e->xcrossing.window))) {
497       slit->enterNotifyEvent(&e->xcrossing);
498     }
499     break;
500   }
501
502   case LeaveNotify: {
503     last_time = e->xcrossing.time;
504
505     BlackboxWindow *win = (BlackboxWindow *) 0;
506     Basemenu *menu = (Basemenu *) 0;
507     Toolbar *tbar = (Toolbar *) 0;
508     Slit *slit = (Slit *) 0;
509
510     if ((menu = searchMenu(e->xcrossing.window)))
511       menu->leaveNotifyEvent(&e->xcrossing);
512     else if ((win = searchWindow(e->xcrossing.window)))
513       win->installColormap(False);
514     else if ((tbar = searchToolbar(e->xcrossing.window)))
515       tbar->leaveNotifyEvent(&e->xcrossing);
516     else if ((slit = searchSlit(e->xcrossing.window)))
517       slit->leaveNotifyEvent(&e->xcrossing);
518     break;
519   }
520
521   case Expose: {
522     // compress expose events
523     XEvent realevent;
524     unsigned int i = 0;
525     int ex1, ey1, ex2, ey2;
526     ex1 = e->xexpose.x;
527     ey1 = e->xexpose.y;
528     ex2 = ex1 + e->xexpose.width - 1;
529     ey2 = ey1 + e->xexpose.height - 1;
530     while (XCheckTypedWindowEvent(getXDisplay(), e->xexpose.window,
531                                   Expose, &realevent)) {
532       i++;
533
534       // merge expose area
535       ex1 = std::min(realevent.xexpose.x, ex1);
536       ey1 = std::min(realevent.xexpose.y, ey1);
537       ex2 = std::max(realevent.xexpose.x + realevent.xexpose.width - 1, ex2);
538       ey2 = std::max(realevent.xexpose.y + realevent.xexpose.height - 1, ey2);
539     }
540     if ( i > 0 )
541       e = &realevent;
542
543     // use the merged area
544     e->xexpose.x = ex1;
545     e->xexpose.y = ey1;
546     e->xexpose.width = ex2 - ex1 + 1;
547     e->xexpose.height = ey2 - ey1 + 1;
548
549     BlackboxWindow *win = (BlackboxWindow *) 0;
550     Basemenu *menu = (Basemenu *) 0;
551     Toolbar *tbar = (Toolbar *) 0;
552
553     if ((win = searchWindow(e->xexpose.window)))
554       win->exposeEvent(&e->xexpose);
555     else if ((menu = searchMenu(e->xexpose.window)))
556       menu->exposeEvent(&e->xexpose);
557     else if ((tbar = searchToolbar(e->xexpose.window)))
558       tbar->exposeEvent(&e->xexpose);
559
560     break;
561   }
562
563   case KeyPress: {
564     Toolbar *tbar = searchToolbar(e->xkey.window);
565
566     if (tbar && tbar->isEditing())
567       tbar->keyPressEvent(&e->xkey);
568
569     break;
570   }
571
572   case ColormapNotify: {
573     BScreen *screen = searchScreen(e->xcolormap.window);
574
575     if (screen)
576       screen->setRootColormapInstalled((e->xcolormap.state ==
577                                         ColormapInstalled) ? True : False);
578
579     break;
580   }
581
582   case FocusIn: {
583     if (e->xfocus.detail != NotifyNonlinear &&
584         e->xfocus.detail != NotifyAncestor) {
585       /*
586         don't process FocusIns when:
587         1. the new focus window isn't an ancestor or inferior of the old
588         focus window (NotifyNonlinear)
589         make sure to allow the FocusIn when the old focus window was an
590         ancestor but didn't have a parent, such as root (NotifyAncestor)
591       */
592       break;
593     }
594
595     BlackboxWindow *win = searchWindow(e->xfocus.window);
596     if (win) {
597       if (! win->isFocused())
598         win->setFocusFlag(True);
599
600       /*
601         set the event window to None.  when the FocusOut event handler calls
602         this function recursively, it uses this as an indication that focus
603         has moved to a known window.
604       */
605       e->xfocus.window = None;
606     }
607
608     break;
609   }
610
611   case FocusOut: {
612     if (e->xfocus.detail != NotifyNonlinear) {
613       /*
614         don't process FocusOuts when:
615         2. the new focus window isn't an ancestor or inferior of the old
616         focus window (NotifyNonlinear)
617       */
618       break;
619     }
620
621     BlackboxWindow *win = searchWindow(e->xfocus.window);
622     if (win && win->isFocused()) {
623       /*
624         before we mark "win" as unfocused, we need to verify that focus is
625         going to a known location, is in a known location, or set focus
626         to a known location.
627       */
628
629       XEvent event;
630       // don't check the current focus if FocusOut was generated during a grab
631       bool check_focus = (e->xfocus.mode == NotifyNormal);
632
633       /*
634         First, check if there is a pending FocusIn event waiting.  if there
635         is, process it and determine if focus has moved to another window
636         (the FocusIn event handler sets the window in the event
637         structure to None to indicate this).
638       */
639       if (XCheckTypedEvent(getXDisplay(), FocusIn, &event)) {
640
641         process_event(&event);
642         if (event.xfocus.window == None) {
643           // focus has moved
644           check_focus = False;
645         }
646       }
647
648       if (check_focus) {
649         /*
650           Second, we query the X server for the current input focus.
651           to make sure that we keep a consistent state.
652         */
653         BlackboxWindow *focus;
654         Window w;
655         int revert;
656         XGetInputFocus(getXDisplay(), &w, &revert);
657         focus = searchWindow(w);
658         if (focus) {
659           /*
660             focus got from "win" to "focus" under some very strange
661             circumstances, and we need to make sure that the focus indication
662             is correct.
663           */
664           setFocusedWindow(focus);
665         } else {
666           // we have no idea where focus went... so we set it to somewhere
667           setFocusedWindow(0);
668         }
669       }
670     }
671
672     break;
673   }
674
675   case ClientMessage: {
676     if (e->xclient.format == 32) {
677       if (e->xclient.message_type == xatom->getAtom(XAtom::wm_change_state)) {
678         // WM_CHANGE_STATE message
679         BlackboxWindow *win = searchWindow(e->xclient.window);
680         if (! win || ! win->validateClient()) return;
681
682         if (e->xclient.data.l[0] == IconicState)
683           win->iconify();
684         if (e->xclient.data.l[0] == NormalState)
685           win->deiconify();
686       } else if (e->xclient.message_type == 
687                  xatom->getAtom(XAtom::blackbox_change_workspace) || 
688                  e->xclient.message_type == 
689                  xatom->getAtom(XAtom::net_current_desktop)) {
690         // NET_CURRENT_DESKTOP message
691         BScreen *screen = searchScreen(e->xclient.window);
692
693         unsigned int workspace = e->xclient.data.l[0];
694         if (screen && workspace < screen->getWorkspaceCount())
695           screen->changeWorkspaceID(workspace);
696       } else if (e->xclient.message_type == 
697                  xatom->getAtom(XAtom::blackbox_change_window_focus) ||
698                  e->xclient.message_type == 
699                  xatom->getAtom(XAtom::net_active_window)) {
700         // NET_ACTIVE_WINDOW
701         BlackboxWindow *win = searchWindow(e->xclient.window);
702
703         if (win) {
704           if (win->isIconic())
705             win->deiconify(False, True);
706           if (win->isVisible() && win->setInputFocus()) {
707             //win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
708             //  raiseWindow(win);
709             win->installColormap(True);
710           }
711         }
712       } else if (e->xclient.message_type == 
713                  xatom->getAtom(XAtom::blackbox_cycle_window_focus)) {
714         // BLACKBOX_CYCLE_WINDOW_FOCUS
715         BScreen *screen = searchScreen(e->xclient.window);
716
717         if (screen) {
718           if (! e->xclient.data.l[0])
719             screen->prevFocus();
720           else
721             screen->nextFocus();
722         }
723       } else if (e->xclient.message_type == 
724                  xatom->getAtom(XAtom::net_wm_desktop)) {
725         // NET_WM_DESKTOP
726         BlackboxWindow *win = searchWindow(e->xclient.window);
727
728         if (win) {
729           BScreen *screen = win->getScreen();
730           unsigned long wksp = (unsigned) e->xclient.data.l[0];
731           if (wksp < screen->getWorkspaceCount()) {
732             if (win->isIconic()) win->deiconify(False, True);
733             if (win->isStuck()) win->stick();
734             if (wksp != screen->getCurrentWorkspaceID())
735               win->withdraw();
736             else
737               win->show();
738             screen->reassociateWindow(win, wksp, True);
739           } else if (wksp == 0xfffffffe) { // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
740             if (win->isIconic()) win->deiconify(False, True);
741             if (! win->isStuck()) win->stick();
742             if (! win->isVisible()) win->show();
743           }
744         }
745       } else if (e->xclient.message_type == 
746                  xatom->getAtom(XAtom::blackbox_change_attributes)) {
747         // BLACKBOX_CHANGE_ATTRIBUTES
748         BlackboxWindow *win = searchWindow(e->xclient.window);
749
750         if (win && win->validateClient()) {
751           BlackboxHints net;
752           net.flags = e->xclient.data.l[0];
753           net.attrib = e->xclient.data.l[1];
754           net.workspace = e->xclient.data.l[2];
755           net.stack = e->xclient.data.l[3];
756           net.decoration = e->xclient.data.l[4];
757
758           win->changeBlackboxHints(&net);
759         }
760       } else if (e->xclient.message_type == 
761                 xatom->getAtom(XAtom::net_number_of_desktops)) {
762         // NET_NUMBER_OF_DESKTOPS
763         BScreen *screen = searchScreen(e->xclient.window);
764         
765         if (e->xclient.data.l[0] > 0) {
766           if ((unsigned) e->xclient.data.l[0] < screen->getWorkspaceCount()) {
767             // shrink
768             for (int i = screen->getWorkspaceCount();
769                  i > e->xclient.data.l[0]; --i)
770               screen->removeLastWorkspace();
771             // removeLast already sets the current workspace to the 
772             // last available one.
773           } else if ((unsigned) e->xclient.data.l[0] >
774                      screen->getWorkspaceCount()) {
775             // grow
776             for(int i = screen->getWorkspaceCount(); 
777                 i < e->xclient.data.l[0]; ++i)
778               screen->addWorkspace();
779           }
780         }
781       } else if (e->xclient.message_type ==
782                  xatom->getAtom(XAtom::net_close_window)) {
783         // NET_CLOSE_WINDOW
784         BlackboxWindow *win = searchWindow(e->xclient.window);
785         if (win && win->validateClient())
786           win->close(); // could this be smarter?
787       } else if (e->xclient.message_type ==
788                  xatom->getAtom(XAtom::net_wm_moveresize)) {
789         // NET_WM_MOVERESIZE
790         BlackboxWindow *win = searchWindow(e->xclient.window);
791         if (win && win->validateClient()) {
792           int x_root = e->xclient.data.l[0],
793               y_root = e->xclient.data.l[1];
794           if ((Atom) e->xclient.data.l[2] ==
795               xatom->getAtom(XAtom::net_wm_moveresize_move)) {
796             win->beginMove(x_root, y_root);
797           } else {
798             if ((Atom) e->xclient.data.l[2] ==
799                 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
800               win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
801             else if ((Atom) e->xclient.data.l[2] ==
802                      xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
803               win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
804             else if ((Atom) e->xclient.data.l[2] ==
805                      xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
806               win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
807             else if ((Atom) e->xclient.data.l[2] ==
808                 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
809               win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
810           }
811         }
812       } else if (e->xclient.message_type ==
813                  xatom->getAtom(XAtom::net_wm_state)) {
814         // NET_WM_STATE
815         BlackboxWindow *win = searchWindow(e->xclient.window);
816         if (win && win->validateClient()) {
817           const Atom action = (Atom) e->xclient.data.l[0];
818           const Atom state[] = { (Atom) e->xclient.data.l[1],
819                                  (Atom) e->xclient.data.l[2] };
820           
821           for (int i = 0; i < 2; ++i) {
822             if (! state[i])
823               continue;
824
825             if ((Atom) e->xclient.data.l[0] == 1) {
826               // ADD
827               if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
828                 win->setModal(True);
829               } else if (state[i] ==
830                          xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
831                 if (win->isMaximizedHoriz()) {
832                   win->maximize(0); // unmaximize
833                   win->maximize(1); // full
834                 } else if (! win->isMaximized()) {
835                   win->maximize(2); // vert
836                 }
837               } else if (state[i] ==
838                          xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
839                 if (win->isMaximizedVert()) {
840                   win->maximize(0); // unmaximize
841                   win->maximize(1); // full
842                 } else if (! win->isMaximized()) {
843                   win->maximize(3); // horiz
844                 }
845               } else if (state[i] ==
846                          xatom->getAtom(XAtom::net_wm_state_shaded)) {
847                 if (! win->isShaded())
848                   win->shade();
849               } else if (state[i] ==
850                          xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
851                 win->setSkipTaskbar(True);
852               } else if (state[i] ==
853                          xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
854                 win->setSkipPager(True);
855               } else if (state[i] ==
856                          xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
857                 win->setFullscreen(True);
858               }
859             } else if (action == 0) {
860               // REMOVE
861               if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
862                 win->setModal(False);
863               } else if (state[i] ==
864                          xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
865                 if (win->isMaximizedFull()) {
866                   win->maximize(0); // unmaximize
867                   win->maximize(3); // horiz
868                 } else if (win->isMaximizedVert()) {
869                   win->maximize(0); // unmaximize
870                 }
871               } else if (state[i] ==
872                          xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
873                 if (win->isMaximizedFull()) {
874                   win->maximize(0); // unmaximize
875                   win->maximize(2); // vert
876                 } else if (win->isMaximizedHoriz()) {
877                   win->maximize(0); // unmaximize
878                 }
879               } else if (state[i] ==
880                          xatom->getAtom(XAtom::net_wm_state_shaded)) {
881                 if (win->isShaded())
882                   win->shade();
883               } else if (state[i] ==
884                          xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
885                 win->setSkipTaskbar(False);
886               } else if (state[i] ==
887                          xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
888                 win->setSkipPager(False);
889               } else if (state[i] ==
890                          xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
891                 win->setFullscreen(False);
892               }
893             } else if (action == 2) {
894               // TOGGLE
895               if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
896                 win->setModal(! win->isModal());
897               } else if (state[i] ==
898                          xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
899                 if (win->isMaximizedFull()) {
900                   win->maximize(0); // unmaximize
901                   win->maximize(3); // horiz
902                 } else if (win->isMaximizedVert()) {
903                   win->maximize(0); // unmaximize
904                 } else if (win->isMaximizedHoriz()) {
905                   win->maximize(0); // unmaximize
906                   win->maximize(1); // full
907                 } else {
908                   win->maximize(2); // vert
909                 }
910               } else if (state[i] ==
911                          xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
912                 if (win->isMaximizedFull()) {
913                   win->maximize(0); // unmaximize
914                   win->maximize(2); // vert
915                 } else if (win->isMaximizedHoriz()) {
916                   win->maximize(0); // unmaximize
917                 } else if (win->isMaximizedVert()) {
918                   win->maximize(0); // unmaximize
919                   win->maximize(1); // full
920                 } else {
921                   win->maximize(3); // horiz
922                 }
923               } else if (state[i] ==
924                          xatom->getAtom(XAtom::net_wm_state_shaded)) {
925                 win->shade();
926               } else if (state[i] ==
927                          xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
928                 win->setSkipTaskbar(! win->skipTaskbar());
929               } else if (state[i] ==
930                          xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
931                 win->setSkipPager(! win->skipPager());
932               } else if (state[i] ==
933                          xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
934                 win->setFullscreen(! win->isFullscreen());
935               }
936             }
937           }
938         }
939       }
940     }
941
942     break;
943   }
944
945   case NoExpose:
946   case ConfigureNotify:
947   case MapNotify:
948     break; // not handled, just ignore
949
950   default: {
951 #ifdef    SHAPE
952     if (e->type == getShapeEventBase()) {
953       XShapeEvent *shape_event = (XShapeEvent *) e;
954       BlackboxWindow *win = searchWindow(e->xany.window);
955
956       if (win)
957         win->shapeEvent(shape_event);
958     }
959 #endif // SHAPE
960   }
961   } // switch
962 }
963
964
965 bool Blackbox::handleSignal(int sig) {
966   switch (sig) {
967   case SIGHUP:
968   case SIGUSR1:
969     reconfigure();
970     break;
971
972   case SIGUSR2:
973     rereadMenu();
974     break;
975
976   case SIGPIPE:
977   case SIGSEGV:
978   case SIGFPE:
979   case SIGINT:
980   case SIGTERM:
981     shutdown();
982
983   default:
984     return False;
985   }
986
987   return True;
988 }
989
990
991 bool Blackbox::validateWindow(Window window) {
992   XEvent event;
993   if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
994     XPutBackEvent(getXDisplay(), &event);
995
996     return False;
997   }
998
999   return True;
1000 }
1001
1002
1003 BScreen *Blackbox::searchScreen(Window window) {
1004   ScreenList::iterator it = screenList.begin();
1005
1006   for (; it != screenList.end(); ++it) {
1007     BScreen *s = *it;
1008     if (s->getRootWindow() == window)
1009       return s;
1010   }
1011
1012   return (BScreen *) 0;
1013 }
1014
1015
1016 BScreen *Blackbox::searchDesktopWindow(Window window) {
1017   WindowScreenLookup::iterator it = desktopSearchList.find(window);
1018   if (it != desktopSearchList.end())
1019     return it->second;
1020
1021   return (BScreen*) 0;
1022 }
1023
1024
1025 BScreen *Blackbox::searchSystrayWindow(Window window) {
1026   WindowScreenLookup::iterator it = systraySearchList.find(window);
1027   if (it != systraySearchList.end())
1028     return it->second;
1029
1030   return (BScreen*) 0;
1031 }
1032
1033
1034 BlackboxWindow *Blackbox::searchWindow(Window window) {
1035   WindowLookup::iterator it = windowSearchList.find(window);
1036   if (it != windowSearchList.end())
1037     return it->second;
1038
1039   return (BlackboxWindow*) 0;
1040 }
1041
1042
1043 BWindowGroup *Blackbox::searchGroup(Window window) {
1044   GroupLookup::iterator it = groupSearchList.find(window);
1045   if (it != groupSearchList.end())
1046     return it->second;
1047
1048   return (BWindowGroup *) 0;
1049 }
1050
1051
1052 Basemenu *Blackbox::searchMenu(Window window) {
1053   MenuLookup::iterator it = menuSearchList.find(window);
1054   if (it != menuSearchList.end())
1055     return it->second;
1056
1057   return (Basemenu*) 0;
1058 }
1059
1060
1061 Toolbar *Blackbox::searchToolbar(Window window) {
1062   ToolbarLookup::iterator it = toolbarSearchList.find(window);
1063   if (it != toolbarSearchList.end())
1064     return it->second;
1065
1066   return (Toolbar*) 0;
1067 }
1068
1069
1070 Slit *Blackbox::searchSlit(Window window) {
1071   SlitLookup::iterator it = slitSearchList.find(window);
1072   if (it != slitSearchList.end())
1073     return it->second;
1074
1075   return (Slit*) 0;
1076 }
1077
1078
1079 void Blackbox::saveDesktopWindowSearch(Window window, BScreen *screen) {
1080   desktopSearchList.insert(WindowScreenLookupPair(window, screen));
1081 }
1082
1083
1084 void Blackbox::saveSystrayWindowSearch(Window window, BScreen *screen) {
1085   systraySearchList.insert(WindowScreenLookupPair(window, screen));
1086 }
1087
1088
1089 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
1090   windowSearchList.insert(WindowLookupPair(window, data));
1091 }
1092
1093
1094 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
1095   groupSearchList.insert(GroupLookupPair(window, data));
1096 }
1097
1098
1099 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
1100   menuSearchList.insert(MenuLookupPair(window, data));
1101 }
1102
1103
1104 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
1105   toolbarSearchList.insert(ToolbarLookupPair(window, data));
1106 }
1107
1108
1109 void Blackbox::saveSlitSearch(Window window, Slit *data) {
1110   slitSearchList.insert(SlitLookupPair(window, data));
1111 }
1112
1113
1114 void Blackbox::removeDesktopWindowSearch(Window window) {
1115   desktopSearchList.erase(window);
1116 }
1117
1118
1119 void Blackbox::removeSystrayWindowSearch(Window window) {
1120   systraySearchList.erase(window);
1121 }
1122
1123
1124 void Blackbox::removeWindowSearch(Window window) {
1125   windowSearchList.erase(window);
1126 }
1127
1128
1129 void Blackbox::removeGroupSearch(Window window) {
1130   groupSearchList.erase(window);
1131 }
1132
1133
1134 void Blackbox::removeMenuSearch(Window window) {
1135   menuSearchList.erase(window);
1136 }
1137
1138
1139 void Blackbox::removeToolbarSearch(Window window) {
1140   toolbarSearchList.erase(window);
1141 }
1142
1143
1144 void Blackbox::removeSlitSearch(Window window) {
1145   slitSearchList.erase(window);
1146 }
1147
1148
1149 void Blackbox::restart(const char *prog) {
1150   shutdown();
1151
1152   if (prog) {
1153     putenv(const_cast<char *>(screenList.front()->displayString().c_str()));
1154     execlp(prog, prog, NULL);
1155     perror(prog);
1156   }
1157
1158   // fall back in case the above execlp doesn't work
1159   execvp(argv[0], argv);
1160   string name = basename(argv[0]);
1161   execvp(name.c_str(), argv);
1162 }
1163
1164
1165 void Blackbox::shutdown(void) {
1166   BaseDisplay::shutdown();
1167
1168   XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
1169
1170   std::for_each(screenList.begin(), screenList.end(),
1171                 std::mem_fun(&BScreen::shutdown));
1172
1173   XSync(getXDisplay(), False);
1174 }
1175
1176
1177 /*
1178  * Save all values as they are so that the defaults will be written to the rc
1179  * file
1180  */
1181 void Blackbox::save_rc(void) {
1182   config.setAutoSave(false);
1183
1184   config.setValue("session.colorsPerChannel", resource.colors_per_channel);
1185   config.setValue("session.doubleClickInterval",
1186                   resource.double_click_interval);
1187   config.setValue("session.autoRaiseDelay",
1188                   ((resource.auto_raise_delay.tv_sec * 1000) +
1189                    (resource.auto_raise_delay.tv_usec / 1000)));
1190   config.setValue("session.cacheLife", resource.cache_life / 60000);
1191   config.setValue("session.cacheMax", resource.cache_max);
1192   config.setValue("session.styleFile", resource.style_file);
1193   config.setValue("session.titlebarLayout", resource.titlebar_layout);
1194   
1195   std::for_each(screenList.begin(), screenList.end(),
1196                 std::mem_fun(&BScreen::save_rc));
1197  
1198   config.setAutoSave(true);
1199   config.save();
1200 }
1201
1202
1203 void Blackbox::load_rc(void) {
1204   if (! config.load())
1205         config.create();
1206   
1207   string s;
1208
1209   if (! config.getValue("session.colorsPerChannel",
1210                         resource.colors_per_channel))
1211     resource.colors_per_channel = 4;
1212   if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1213   else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1214
1215   if (config.getValue("session.styleFile", s))
1216     resource.style_file = expandTilde(s);
1217   else
1218     resource.style_file = DEFAULTSTYLE;
1219
1220   if (! config.getValue("session.doubleClickInterval",
1221                        resource.double_click_interval));
1222     resource.double_click_interval = 250;
1223
1224   if (! config.getValue("session.autoRaiseDelay",
1225                        resource.auto_raise_delay.tv_usec))
1226     resource.auto_raise_delay.tv_usec = 400;
1227   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1228   resource.auto_raise_delay.tv_usec -=
1229     (resource.auto_raise_delay.tv_sec * 1000);
1230   resource.auto_raise_delay.tv_usec *= 1000;
1231
1232   if (! config.getValue("session.cacheLife", resource.cache_life))
1233     resource.cache_life = 5;
1234   resource.cache_life *= 60000;
1235
1236   if (! config.getValue("session.cacheMax", resource.cache_max))
1237     resource.cache_max = 200;
1238   
1239   if (! config.getValue("session.titlebarLayout", resource.titlebar_layout))
1240     resource.titlebar_layout = "ILMC";
1241 }
1242
1243
1244 void Blackbox::reconfigure(void) {
1245   reconfigure_wait = True;
1246
1247   if (! timer->isTiming()) timer->start();
1248 }
1249
1250
1251 void Blackbox::real_reconfigure(void) {
1252   load_rc();
1253   
1254   std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1255                 PointerAssassin());
1256   menuTimestamps.clear();
1257
1258   gcCache()->purge();
1259
1260   std::for_each(screenList.begin(), screenList.end(),
1261                 std::mem_fun(&BScreen::reconfigure));
1262 }
1263
1264
1265 void Blackbox::checkMenu(void) {
1266   bool reread = False;
1267   MenuTimestampList::iterator it = menuTimestamps.begin();
1268   for(; it != menuTimestamps.end(); ++it) {
1269     MenuTimestamp *tmp = *it;
1270     struct stat buf;
1271
1272     if (! stat(tmp->filename.c_str(), &buf)) {
1273       if (tmp->timestamp != buf.st_ctime)
1274         reread = True;
1275     } else {
1276       reread = True;
1277     }
1278   }
1279
1280   if (reread) rereadMenu();
1281 }
1282
1283
1284 void Blackbox::rereadMenu(void) {
1285   reread_menu_wait = True;
1286
1287   if (! timer->isTiming()) timer->start();
1288 }
1289
1290
1291 void Blackbox::real_rereadMenu(void) {
1292   std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1293                 PointerAssassin());
1294   menuTimestamps.clear();
1295
1296   std::for_each(screenList.begin(), screenList.end(),
1297                 std::mem_fun(&BScreen::rereadMenu));
1298 }
1299
1300
1301 void Blackbox::saveStyleFilename(const string& filename) {
1302   assert(! filename.empty());
1303   resource.style_file = filename;
1304   config.setValue("session.styleFile", resource.style_file);
1305 }
1306
1307
1308 void Blackbox::addMenuTimestamp(const string& filename) {
1309   assert(! filename.empty());
1310   bool found = False;
1311
1312   MenuTimestampList::iterator it = menuTimestamps.begin();
1313   for (; it != menuTimestamps.end() && ! found; ++it) {
1314     if ((*it)->filename == filename) found = True;
1315   }
1316   if (! found) {
1317     struct stat buf;
1318
1319     if (! stat(filename.c_str(), &buf)) {
1320       MenuTimestamp *ts = new MenuTimestamp;
1321
1322       ts->filename = filename;
1323       ts->timestamp = buf.st_ctime;
1324
1325       menuTimestamps.push_back(ts);
1326     }
1327   }
1328 }
1329
1330
1331 void Blackbox::timeout(void) {
1332   if (reconfigure_wait)
1333     real_reconfigure();
1334
1335   if (reread_menu_wait)
1336     real_rereadMenu();
1337
1338   reconfigure_wait = reread_menu_wait = False;
1339 }
1340
1341
1342 void Blackbox::setChangingWindow(BlackboxWindow *win) {
1343   // make sure one of the two is null and the other isn't
1344   assert((! changing_window && win) || (! win && changing_window));
1345   changing_window = win;
1346 }
1347
1348
1349 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1350   if (focused_window && focused_window == win) // nothing to do
1351     return;
1352
1353   BScreen *old_screen = 0;
1354
1355   if (focused_window) {
1356     focused_window->setFocusFlag(False);
1357     old_screen = focused_window->getScreen();
1358   }
1359
1360   if (win && ! win->isIconic()) {
1361     // the active screen is the one with the last focused window...
1362     // this will keep focus on this screen no matter where the mouse goes,
1363     // so multihead keybindings will continue to work on that screen until the
1364     // user focuses a window on a different screen.
1365     active_screen = win->getScreen();
1366     focused_window = win;
1367   } else {
1368     focused_window = 0;
1369     if (! old_screen) {
1370       if (active_screen) {
1371         // set input focus to the toolbar of the screen with mouse
1372         XSetInputFocus(getXDisplay(),
1373                        active_screen->getRootWindow(),
1374                        RevertToPointerRoot, CurrentTime);
1375       } else {
1376         // set input focus to the toolbar of the first managed screen
1377         XSetInputFocus(getXDisplay(),
1378                        screenList.front()->getRootWindow(),
1379                        RevertToPointerRoot, CurrentTime);
1380       }
1381     } else {
1382       // set input focus to the toolbar of the last screen
1383       XSetInputFocus(getXDisplay(), old_screen->getRootWindow(),
1384                      RevertToPointerRoot, CurrentTime);
1385     }
1386   }
1387
1388   if (active_screen && active_screen->isScreenManaged()) {
1389     active_screen->getToolbar()->redrawWindowLabel(True);
1390     active_screen->updateNetizenWindowFocus();
1391   }
1392
1393   if (old_screen && old_screen != active_screen) {
1394     old_screen->getToolbar()->redrawWindowLabel(True);
1395     old_screen->updateNetizenWindowFocus();
1396   }
1397 }