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