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