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