Configureable button mappings!
[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 #include "Input.hh"
115
116 // X event scanner for enter/leave notifies - adapted from twm
117 struct scanargs {
118   Window w;
119   bool leave, inferior, enter;
120 };
121
122 static Bool queueScanner(Display *, XEvent *e, char *args) {
123   scanargs *scan = (scanargs *) args;
124   if ((e->type == LeaveNotify) &&
125       (e->xcrossing.window == scan->w) &&
126       (e->xcrossing.mode == NotifyNormal)) {
127     scan->leave = True;
128     scan->inferior = (e->xcrossing.detail == NotifyInferior);
129   } else if ((e->type == EnterNotify) && (e->xcrossing.mode == NotifyUngrab)) {
130     scan->enter = True;
131   }
132
133   return False;
134 }
135
136 Blackbox *blackbox;
137
138
139 Blackbox::Blackbox(char **m_argv, char *dpy_name, char *rc, char *menu)
140   : BaseDisplay(m_argv[0], dpy_name) {
141   if (! XSupportsLocale())
142     fprintf(stderr, "X server does not support locale\n");
143
144   if (XSetLocaleModifiers("") == NULL)
145     fprintf(stderr, "cannot set locale modifiers\n");
146
147   ::blackbox = this;
148   argv = m_argv;
149   if (! rc) rc = "~/.openbox/rc";
150   rc_file = expandTilde(rc);
151   config.setFile(rc_file);  
152   if (! menu) menu = "~/.openbox/menu";
153   menu_file = expandTilde(menu);
154
155   no_focus = False;
156
157   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
158
159   active_screen = 0;
160   focused_window = changing_window = (BlackboxWindow *) 0;
161
162   XrmInitialize();
163   load_rc();
164
165   xatom = new XAtom(getXDisplay());
166   input = new BInput(this);
167
168   cursor.session = XCreateFontCursor(getXDisplay(), XC_left_ptr);
169   cursor.move = XCreateFontCursor(getXDisplay(), XC_fleur);
170   cursor.ll_angle = XCreateFontCursor(getXDisplay(), XC_ll_angle);
171   cursor.lr_angle = XCreateFontCursor(getXDisplay(), XC_lr_angle);
172   cursor.ul_angle = XCreateFontCursor(getXDisplay(), XC_ul_angle);
173   cursor.ur_angle = XCreateFontCursor(getXDisplay(), XC_ur_angle);
174
175   for (unsigned int i = 0; i < getNumberOfScreens(); i++) {
176     BScreen *screen = new BScreen(this, i);
177
178     if (! screen->isScreenManaged()) {
179       delete screen;
180       continue;
181     }
182
183     screenList.push_back(screen);
184   }
185
186   if (screenList.empty()) {
187     fprintf(stderr,
188             i18n(blackboxSet, blackboxNoManagableScreens,
189               "Blackbox::Blackbox: no managable screens found, aborting.\n"));
190     ::exit(3);
191   }
192
193   // save current settings and default values
194   save_rc();
195
196   // set the screen with mouse to the first managed screen
197   active_screen = screenList.front();
198   setFocusedWindow(0);
199
200   XSynchronize(getXDisplay(), False);
201   XSync(getXDisplay(), False);
202
203   reconfigure_wait = reread_menu_wait = False;
204
205   timer = new BTimer(this, this);
206   timer->setTimeout(0l);
207 }
208
209
210 Blackbox::~Blackbox(void) {
211   std::for_each(screenList.begin(), screenList.end(), PointerAssassin());
212
213   std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
214                 PointerAssassin());
215
216   delete xatom;
217
218   delete timer;
219 }
220
221
222 void Blackbox::process_event(XEvent *e) {
223   switch (e->type) {
224   case ButtonPress: {
225     // strip the lock key modifiers
226     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
227
228     last_time = e->xbutton.time;
229
230     BlackboxWindow *win = (BlackboxWindow *) 0;
231     Basemenu *menu = (Basemenu *) 0;
232     Slit *slit = (Slit *) 0;
233     Toolbar *tbar = (Toolbar *) 0;
234     BScreen *scrn = (BScreen *) 0;
235
236     if ((win = searchWindow(e->xbutton.window))) {
237       win->buttonPressEvent(&e->xbutton);
238
239       /* XXX: is this sane on low colour desktops? */
240       if (e->xbutton.button == 1)
241         win->installColormap(True);
242     } else if ((menu = searchMenu(e->xbutton.window))) {
243       menu->buttonPressEvent(&e->xbutton);
244     } else if ((slit = searchSlit(e->xbutton.window))) {
245       slit->buttonPressEvent(&e->xbutton);
246     } else if ((tbar = searchToolbar(e->xbutton.window))) {
247       tbar->buttonPressEvent(&e->xbutton);
248     } else if ((scrn = searchScreen(e->xbutton.window))) {
249       scrn->buttonPressEvent(&e->xbutton);
250       if (active_screen != scrn) {
251         active_screen = scrn;
252         // first, set no focus window on the old screen
253         setFocusedWindow(0);
254         // and move focus to this screen
255         setFocusedWindow(0);
256       }
257     }
258     break;
259   }
260
261   case ButtonRelease: {
262     // strip the lock key modifiers
263     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
264
265     last_time = e->xbutton.time;
266
267     BlackboxWindow *win = (BlackboxWindow *) 0;
268     Basemenu *menu = (Basemenu *) 0;
269     Toolbar *tbar = (Toolbar *) 0;
270
271     if ((win = searchWindow(e->xbutton.window)))
272       win->buttonReleaseEvent(&e->xbutton);
273     else if ((menu = searchMenu(e->xbutton.window)))
274       menu->buttonReleaseEvent(&e->xbutton);
275     else if ((tbar = searchToolbar(e->xbutton.window)))
276       tbar->buttonReleaseEvent(&e->xbutton);
277
278     break;
279   }
280
281   case ConfigureRequest: {
282     // compress configure requests...
283     XEvent realevent;
284     unsigned int i = 0;
285     while(XCheckTypedWindowEvent(getXDisplay(), e->xconfigurerequest.window,
286                                  ConfigureRequest, &realevent)) {
287       i++;
288     }
289     if ( i > 0 )
290       e = &realevent;
291
292     BlackboxWindow *win = (BlackboxWindow *) 0;
293     Slit *slit = (Slit *) 0;
294
295     if ((win = searchWindow(e->xconfigurerequest.window))) {
296       win->configureRequestEvent(&e->xconfigurerequest);
297     } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
298       slit->configureRequestEvent(&e->xconfigurerequest);
299     } else {
300       if (validateWindow(e->xconfigurerequest.window)) {
301         XWindowChanges xwc;
302
303         xwc.x = e->xconfigurerequest.x;
304         xwc.y = e->xconfigurerequest.y;
305         xwc.width = e->xconfigurerequest.width;
306         xwc.height = e->xconfigurerequest.height;
307         xwc.border_width = e->xconfigurerequest.border_width;
308         xwc.sibling = e->xconfigurerequest.above;
309         xwc.stack_mode = e->xconfigurerequest.detail;
310
311         XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
312                          e->xconfigurerequest.value_mask, &xwc);
313       }
314     }
315
316     break;
317   }
318
319   case MapRequest: {
320 #ifdef    DEBUG
321     fprintf(stderr, "Blackbox::process_event(): MapRequest for 0x%lx\n",
322             e->xmaprequest.window);
323 #endif // DEBUG
324
325     BlackboxWindow *win = searchWindow(e->xmaprequest.window);
326
327     if (! win) {
328       BScreen *screen = searchScreen(e->xmaprequest.parent);
329
330       if (! screen) {
331         /*
332           we got a map request for a window who's parent isn't root. this
333           can happen in only one circumstance:
334
335             a client window unmapped a managed window, and then remapped it
336             somewhere between unmapping the client window and reparenting it
337             to root.
338
339           regardless of how it happens, we need to find the screen that
340           the window is on
341         */
342         XWindowAttributes wattrib;
343         if (! XGetWindowAttributes(getXDisplay(), e->xmaprequest.window,
344                                    &wattrib)) {
345           // failed to get the window attributes, perhaps the window has
346           // now been destroyed?
347           break;
348         }
349
350         screen = searchScreen(wattrib.root);
351         assert(screen != 0); // this should never happen
352       }
353
354       screen->manageWindow(e->xmaprequest.window);
355     }
356
357     break;
358   }
359
360   case UnmapNotify: {
361     BlackboxWindow *win = (BlackboxWindow *) 0;
362     Slit *slit = (Slit *) 0;
363     BScreen *screen = (BScreen *) 0;
364
365     if ((win = searchWindow(e->xunmap.window))) {
366       win->unmapNotifyEvent(&e->xunmap);
367     } else if ((slit = searchSlit(e->xunmap.window))) {
368       slit->unmapNotifyEvent(&e->xunmap);
369     } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
370       screen->removeSystrayWindow(e->xunmap.window);
371     } else if ((screen = searchDesktopWindow(e->xunmap.window))) {
372       screen->removeDesktopWindow(e->xunmap.window);
373     }
374
375     break;
376   }
377
378   case DestroyNotify: {
379     BlackboxWindow *win = (BlackboxWindow *) 0;
380     Slit *slit = (Slit *) 0;
381     BScreen *screen = (BScreen *) 0;
382     BWindowGroup *group = (BWindowGroup *) 0;
383
384     if ((win = searchWindow(e->xdestroywindow.window))) {
385       win->destroyNotifyEvent(&e->xdestroywindow);
386     } else if ((slit = searchSlit(e->xdestroywindow.window))) {
387       slit->removeClient(e->xdestroywindow.window, False);
388     } else if ((group = searchGroup(e->xdestroywindow.window))) {
389       delete group;
390     } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
391       screen->removeSystrayWindow(e->xunmap.window);
392     } else if ((screen = searchDesktopWindow(e->xunmap.window))) {
393       screen->removeDesktopWindow(e->xunmap.window);
394     }
395
396     break;
397   }
398
399   case ReparentNotify: {
400     /*
401       this event is quite rare and is usually handled in unmapNotify
402       however, if the window is unmapped when the reparent event occurs
403       the window manager never sees it because an unmap event is not sent
404       to an already unmapped window.
405     */
406     BlackboxWindow *win = searchWindow(e->xreparent.window);
407     if (win) {
408       win->reparentNotifyEvent(&e->xreparent);
409     } else {
410       Slit *slit = searchSlit(e->xreparent.window);
411       if (slit && slit->getWindowID() != e->xreparent.parent)
412         slit->removeClient(e->xreparent.window, True);
413     }
414     break;
415   }
416
417   case MotionNotify: {
418     // motion notify compression...
419     XEvent realevent;
420     unsigned int i = 0;
421     while (XCheckTypedWindowEvent(getXDisplay(), e->xmotion.window,
422                                   MotionNotify, &realevent)) {
423       i++;
424     }
425
426     // if we have compressed some motion events, use the last one
427     if ( i > 0 )
428       e = &realevent;
429
430     // strip the lock key modifiers
431     e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
432
433     last_time = e->xmotion.time;
434
435     BlackboxWindow *win = (BlackboxWindow *) 0;
436     Basemenu *menu = (Basemenu *) 0;
437
438     if ((win = searchWindow(e->xmotion.window)))
439       win->motionNotifyEvent(&e->xmotion);
440     else if ((menu = searchMenu(e->xmotion.window)))
441       menu->motionNotifyEvent(&e->xmotion);
442
443     break;
444   }
445
446   case PropertyNotify: {
447     last_time = e->xproperty.time;
448
449     if (e->xproperty.state != PropertyDelete) {
450       BlackboxWindow *win = searchWindow(e->xproperty.window);
451
452       if (win)
453         win->propertyNotifyEvent(e->xproperty.atom);
454     }
455
456     break;
457   }
458
459   case EnterNotify: {
460     last_time = e->xcrossing.time;
461
462     BScreen *screen = (BScreen *) 0;
463     BlackboxWindow *win = (BlackboxWindow *) 0;
464     Basemenu *menu = (Basemenu *) 0;
465     Toolbar *tbar = (Toolbar *) 0;
466     Slit *slit = (Slit *) 0;
467
468     if (e->xcrossing.mode == NotifyGrab) break;
469
470     XEvent dummy;
471     scanargs sa;
472     sa.w = e->xcrossing.window;
473     sa.enter = sa.leave = False;
474     XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
475
476     if ((e->xcrossing.window == e->xcrossing.root) &&
477         (screen = searchScreen(e->xcrossing.window))) {
478       screen->getImageControl()->installRootColormap();
479     } else if ((win = searchWindow(e->xcrossing.window))) {
480       if (win->getScreen()->isSloppyFocus() &&
481           (! win->isFocused()) && (! no_focus)) {
482         if (((! sa.leave) || sa.inferior) && win->isVisible()) {
483           if (win->setInputFocus())
484             win->installColormap(True); // XXX: shouldnt we honour no install?
485         }
486       }
487     } else if ((menu = searchMenu(e->xcrossing.window))) {
488       menu->enterNotifyEvent(&e->xcrossing);
489     } else if ((tbar = searchToolbar(e->xcrossing.window))) {
490       tbar->enterNotifyEvent(&e->xcrossing);
491     } else if ((slit = searchSlit(e->xcrossing.window))) {
492       slit->enterNotifyEvent(&e->xcrossing);
493     }
494     break;
495   }
496
497   case LeaveNotify: {
498     last_time = e->xcrossing.time;
499
500     BlackboxWindow *win = (BlackboxWindow *) 0;
501     Basemenu *menu = (Basemenu *) 0;
502     Toolbar *tbar = (Toolbar *) 0;
503     Slit *slit = (Slit *) 0;
504
505     if ((menu = searchMenu(e->xcrossing.window)))
506       menu->leaveNotifyEvent(&e->xcrossing);
507     else if ((win = searchWindow(e->xcrossing.window)))
508       win->installColormap(False);
509     else if ((tbar = searchToolbar(e->xcrossing.window)))
510       tbar->leaveNotifyEvent(&e->xcrossing);
511     else if ((slit = searchSlit(e->xcrossing.window)))
512       slit->leaveNotifyEvent(&e->xcrossing);
513     break;
514   }
515
516   case Expose: {
517     // compress expose events
518     XEvent realevent;
519     unsigned int i = 0;
520     int ex1, ey1, ex2, ey2;
521     ex1 = e->xexpose.x;
522     ey1 = e->xexpose.y;
523     ex2 = ex1 + e->xexpose.width - 1;
524     ey2 = ey1 + e->xexpose.height - 1;
525     while (XCheckTypedWindowEvent(getXDisplay(), e->xexpose.window,
526                                   Expose, &realevent)) {
527       i++;
528
529       // merge expose area
530       ex1 = std::min(realevent.xexpose.x, ex1);
531       ey1 = std::min(realevent.xexpose.y, ey1);
532       ex2 = std::max(realevent.xexpose.x + realevent.xexpose.width - 1, ex2);
533       ey2 = std::max(realevent.xexpose.y + realevent.xexpose.height - 1, ey2);
534     }
535     if ( i > 0 )
536       e = &realevent;
537
538     // use the merged area
539     e->xexpose.x = ex1;
540     e->xexpose.y = ey1;
541     e->xexpose.width = ex2 - ex1 + 1;
542     e->xexpose.height = ey2 - ey1 + 1;
543
544     BlackboxWindow *win = (BlackboxWindow *) 0;
545     Basemenu *menu = (Basemenu *) 0;
546     Toolbar *tbar = (Toolbar *) 0;
547
548     if ((win = searchWindow(e->xexpose.window)))
549       win->exposeEvent(&e->xexpose);
550     else if ((menu = searchMenu(e->xexpose.window)))
551       menu->exposeEvent(&e->xexpose);
552     else if ((tbar = searchToolbar(e->xexpose.window)))
553       tbar->exposeEvent(&e->xexpose);
554
555     break;
556   }
557
558   case KeyPress: {
559     Toolbar *tbar = searchToolbar(e->xkey.window);
560
561     if (tbar && tbar->isEditing())
562       tbar->keyPressEvent(&e->xkey);
563
564     break;
565   }
566
567   case ColormapNotify: {
568     BScreen *screen = searchScreen(e->xcolormap.window);
569
570     if (screen)
571       screen->setRootColormapInstalled((e->xcolormap.state ==
572                                         ColormapInstalled) ? True : False);
573
574     break;
575   }
576
577   case FocusIn: {
578     if (e->xfocus.detail != NotifyNonlinear &&
579         e->xfocus.detail != NotifyAncestor) {
580       /*
581         don't process FocusIns when:
582         1. the new focus window isn't an ancestor or inferior of the old
583         focus window (NotifyNonlinear)
584         make sure to allow the FocusIn when the old focus window was an
585         ancestor but didn't have a parent, such as root (NotifyAncestor)
586       */
587       break;
588     }
589
590     BlackboxWindow *win = searchWindow(e->xfocus.window);
591     if (win) {
592       if (! win->isFocused())
593         win->setFocusFlag(True);
594
595       /*
596         set the event window to None.  when the FocusOut event handler calls
597         this function recursively, it uses this as an indication that focus
598         has moved to a known window.
599       */
600       e->xfocus.window = None;
601     }
602
603     break;
604   }
605
606   case FocusOut: {
607     if (e->xfocus.detail != NotifyNonlinear) {
608       /*
609         don't process FocusOuts when:
610         2. the new focus window isn't an ancestor or inferior of the old
611         focus window (NotifyNonlinear)
612       */
613       break;
614     }
615
616     BlackboxWindow *win = searchWindow(e->xfocus.window);
617     if (win && win->isFocused()) {
618       /*
619         before we mark "win" as unfocused, we need to verify that focus is
620         going to a known location, is in a known location, or set focus
621         to a known location.
622       */
623
624       XEvent event;
625       // don't check the current focus if FocusOut was generated during a grab
626       bool check_focus = (e->xfocus.mode == NotifyNormal);
627
628       /*
629         First, check if there is a pending FocusIn event waiting.  if there
630         is, process it and determine if focus has moved to another window
631         (the FocusIn event handler sets the window in the event
632         structure to None to indicate this).
633       */
634       if (XCheckTypedEvent(getXDisplay(), FocusIn, &event)) {
635
636         process_event(&event);
637         if (event.xfocus.window == None) {
638           // focus has moved
639           check_focus = False;
640         }
641       }
642
643       if (check_focus) {
644         /*
645           Second, we query the X server for the current input focus.
646           to make sure that we keep a consistent state.
647         */
648         BlackboxWindow *focus;
649         Window w;
650         int revert;
651         XGetInputFocus(getXDisplay(), &w, &revert);
652         focus = searchWindow(w);
653         if (focus) {
654           /*
655             focus got from "win" to "focus" under some very strange
656             circumstances, and we need to make sure that the focus indication
657             is correct.
658           */
659           setFocusedWindow(focus);
660         } else {
661           // we have no idea where focus went... so we set it to somewhere
662           setFocusedWindow(0);
663         }
664       }
665     }
666
667     break;
668   }
669
670   case ClientMessage: {
671     if (e->xclient.format == 32) {
672       if (e->xclient.message_type == xatom->getAtom(XAtom::wm_change_state)) {
673         // WM_CHANGE_STATE message
674         BlackboxWindow *win = searchWindow(e->xclient.window);
675         if (! win || ! win->validateClient()) return;
676
677         if (e->xclient.data.l[0] == IconicState)
678           win->iconify();
679         if (e->xclient.data.l[0] == NormalState)
680           win->deiconify();
681       } else if (e->xclient.message_type == 
682                  xatom->getAtom(XAtom::blackbox_change_workspace) || 
683                  e->xclient.message_type == 
684                  xatom->getAtom(XAtom::net_current_desktop)) {
685         // NET_CURRENT_DESKTOP message
686         BScreen *screen = searchScreen(e->xclient.window);
687
688         unsigned int workspace = e->xclient.data.l[0];
689         if (screen && workspace < screen->getWorkspaceCount())
690           screen->changeWorkspaceID(workspace);
691       } else if (e->xclient.message_type == 
692                  xatom->getAtom(XAtom::blackbox_change_window_focus) ||
693                  e->xclient.message_type == 
694                  xatom->getAtom(XAtom::net_active_window)) {
695         // NET_ACTIVE_WINDOW
696         BlackboxWindow *win = searchWindow(e->xclient.window);
697
698         if (win) {
699           if (win->isIconic())
700             win->deiconify(False, True);
701           if (win->isVisible() && win->setInputFocus()) {
702             //win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
703             //  raiseWindow(win);
704             win->installColormap(True);
705           }
706         }
707       } else if (e->xclient.message_type == 
708                  xatom->getAtom(XAtom::blackbox_cycle_window_focus)) {
709         // BLACKBOX_CYCLE_WINDOW_FOCUS
710         BScreen *screen = searchScreen(e->xclient.window);
711
712         if (screen) {
713           if (! e->xclient.data.l[0])
714             screen->prevFocus();
715           else
716             screen->nextFocus();
717         }
718       } else if (e->xclient.message_type == 
719                  xatom->getAtom(XAtom::net_wm_desktop)) {
720         // NET_WM_DESKTOP
721         BlackboxWindow *win = searchWindow(e->xclient.window);
722
723         if (win) {
724           BScreen *screen = win->getScreen();
725           unsigned long wksp = (unsigned) e->xclient.data.l[0];
726           if (wksp < screen->getWorkspaceCount()) {
727             if (win->isIconic()) win->deiconify(False, True);
728             if (win->isStuck()) win->stick();
729             if (wksp != screen->getCurrentWorkspaceID())
730               win->withdraw();
731             else
732               win->show();
733             screen->reassociateWindow(win, wksp, True);
734           } else if (wksp == 0xfffffffe) { // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
735             if (win->isIconic()) win->deiconify(False, True);
736             if (! win->isStuck()) win->stick();
737             if (! win->isVisible()) win->show();
738           }
739         }
740       } else if (e->xclient.message_type == 
741                  xatom->getAtom(XAtom::blackbox_change_attributes)) {
742         // BLACKBOX_CHANGE_ATTRIBUTES
743         BlackboxWindow *win = searchWindow(e->xclient.window);
744
745         if (win && win->validateClient()) {
746           BlackboxHints net;
747           net.flags = e->xclient.data.l[0];
748           net.attrib = e->xclient.data.l[1];
749           net.workspace = e->xclient.data.l[2];
750           net.stack = e->xclient.data.l[3];
751           net.decoration = e->xclient.data.l[4];
752
753           win->changeBlackboxHints(&net);
754         }
755       } else if (e->xclient.message_type == 
756                 xatom->getAtom(XAtom::net_number_of_desktops)) {
757         // NET_NUMBER_OF_DESKTOPS
758         BScreen *screen = searchScreen(e->xclient.window);
759         
760         if (e->xclient.data.l[0] > 0) {
761           if ((unsigned) e->xclient.data.l[0] < screen->getWorkspaceCount()) {
762             // shrink
763             for (int i = screen->getWorkspaceCount();
764                  i > e->xclient.data.l[0]; --i)
765               screen->removeLastWorkspace();
766             // removeLast already sets the current workspace to the 
767             // last available one.
768           } else if ((unsigned) e->xclient.data.l[0] >
769                      screen->getWorkspaceCount()) {
770             // grow
771             for(int i = screen->getWorkspaceCount(); 
772                 i < e->xclient.data.l[0]; ++i)
773               screen->addWorkspace();
774           }
775         }
776       } else if (e->xclient.message_type ==
777                  xatom->getAtom(XAtom::net_close_window)) {
778         // NET_CLOSE_WINDOW
779         BlackboxWindow *win = searchWindow(e->xclient.window);
780         if (win && win->validateClient())
781           win->close(); // could this be smarter?
782       } else if (e->xclient.message_type ==
783                  xatom->getAtom(XAtom::net_wm_moveresize)) {
784         // NET_WM_MOVERESIZE
785         BlackboxWindow *win = searchWindow(e->xclient.window);
786         if (win && win->validateClient()) {
787           int x_root = e->xclient.data.l[0],
788               y_root = e->xclient.data.l[1];
789           if ((Atom) e->xclient.data.l[2] ==
790               xatom->getAtom(XAtom::net_wm_moveresize_move)) {
791             win->beginMove(x_root, y_root);
792           } else {
793             if ((Atom) e->xclient.data.l[2] ==
794                 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
795               win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
796             else if ((Atom) e->xclient.data.l[2] ==
797                      xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
798               win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
799             else if ((Atom) e->xclient.data.l[2] ==
800                      xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
801               win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
802             else if ((Atom) e->xclient.data.l[2] ==
803                 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
804               win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
805           }
806         }
807       } else if (e->xclient.message_type ==
808                  xatom->getAtom(XAtom::net_wm_state)) {
809         // NET_WM_STATE
810         BlackboxWindow *win = searchWindow(e->xclient.window);
811         if (win && win->validateClient()) {
812           const Atom action = (Atom) e->xclient.data.l[0];
813           const Atom state[] = { (Atom) e->xclient.data.l[1],
814                                  (Atom) e->xclient.data.l[2] };
815           
816           for (int i = 0; i < 2; ++i) {
817             if (! state[i])
818               continue;
819
820             if ((Atom) e->xclient.data.l[0] == 1) {
821               // ADD
822               if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
823                 win->setModal(True);
824               } else if (state[i] ==
825                          xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
826                 if (win->isMaximizedHoriz()) {
827                   win->maximize(0); // unmaximize
828                   win->maximize(1); // full
829                 } else if (! win->isMaximized()) {
830                   win->maximize(2); // vert
831                 }
832               } else if (state[i] ==
833                          xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
834                 if (win->isMaximizedVert()) {
835                   win->maximize(0); // unmaximize
836                   win->maximize(1); // full
837                 } else if (! win->isMaximized()) {
838                   win->maximize(3); // horiz
839                 }
840               } else if (state[i] ==
841                          xatom->getAtom(XAtom::net_wm_state_shaded)) {
842                 if (! win->isShaded())
843                   win->shade();
844               } else if (state[i] ==
845                          xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
846                 win->setSkipTaskbar(True);
847               } else if (state[i] ==
848                          xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
849                 win->setSkipPager(True);
850               } else if (state[i] ==
851                          xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
852                 win->setFullscreen(True);
853               }
854             } else if (action == 0) {
855               // REMOVE
856               if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
857                 win->setModal(False);
858               } else if (state[i] ==
859                          xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
860                 if (win->isMaximizedFull()) {
861                   win->maximize(0); // unmaximize
862                   win->maximize(3); // horiz
863                 } else if (win->isMaximizedVert()) {
864                   win->maximize(0); // unmaximize
865                 }
866               } else if (state[i] ==
867                          xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
868                 if (win->isMaximizedFull()) {
869                   win->maximize(0); // unmaximize
870                   win->maximize(2); // vert
871                 } else if (win->isMaximizedHoriz()) {
872                   win->maximize(0); // unmaximize
873                 }
874               } else if (state[i] ==
875                          xatom->getAtom(XAtom::net_wm_state_shaded)) {
876                 if (win->isShaded())
877                   win->shade();
878               } else if (state[i] ==
879                          xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
880                 win->setSkipTaskbar(False);
881               } else if (state[i] ==
882                          xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
883                 win->setSkipPager(False);
884               } else if (state[i] ==
885                          xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
886                 win->setFullscreen(False);
887               }
888             } else if (action == 2) {
889               // TOGGLE
890               if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
891                 win->setModal(! win->isModal());
892               } else if (state[i] ==
893                          xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
894                 if (win->isMaximizedFull()) {
895                   win->maximize(0); // unmaximize
896                   win->maximize(3); // horiz
897                 } else if (win->isMaximizedVert()) {
898                   win->maximize(0); // unmaximize
899                 } else if (win->isMaximizedHoriz()) {
900                   win->maximize(0); // unmaximize
901                   win->maximize(1); // full
902                 } else {
903                   win->maximize(2); // vert
904                 }
905               } else if (state[i] ==
906                          xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
907                 if (win->isMaximizedFull()) {
908                   win->maximize(0); // unmaximize
909                   win->maximize(2); // vert
910                 } else if (win->isMaximizedHoriz()) {
911                   win->maximize(0); // unmaximize
912                 } else if (win->isMaximizedVert()) {
913                   win->maximize(0); // unmaximize
914                   win->maximize(1); // full
915                 } else {
916                   win->maximize(3); // horiz
917                 }
918               } else if (state[i] ==
919                          xatom->getAtom(XAtom::net_wm_state_shaded)) {
920                 win->shade();
921               } else if (state[i] ==
922                          xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
923                 win->setSkipTaskbar(! win->skipTaskbar());
924               } else if (state[i] ==
925                          xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
926                 win->setSkipPager(! win->skipPager());
927               } else if (state[i] ==
928                          xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
929                 win->setFullscreen(! win->isFullscreen());
930               }
931             }
932           }
933         }
934       }
935     }
936
937     break;
938   }
939
940   case NoExpose:
941   case ConfigureNotify:
942   case MapNotify:
943     break; // not handled, just ignore
944
945   default: {
946 #ifdef    SHAPE
947     if (e->type == getShapeEventBase()) {
948       XShapeEvent *shape_event = (XShapeEvent *) e;
949       BlackboxWindow *win = searchWindow(e->xany.window);
950
951       if (win)
952         win->shapeEvent(shape_event);
953     }
954 #endif // SHAPE
955   }
956   } // switch
957 }
958
959
960 bool Blackbox::handleSignal(int sig) {
961   switch (sig) {
962   case SIGHUP:
963   case SIGUSR1:
964     reconfigure();
965     break;
966
967   case SIGUSR2:
968     rereadMenu();
969     break;
970
971   case SIGPIPE:
972   case SIGSEGV:
973   case SIGFPE:
974   case SIGINT:
975   case SIGTERM:
976     shutdown();
977
978   default:
979     return False;
980   }
981
982   return True;
983 }
984
985
986 bool Blackbox::validateWindow(Window window) {
987   XEvent event;
988   if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
989     XPutBackEvent(getXDisplay(), &event);
990
991     return False;
992   }
993
994   return True;
995 }
996
997
998 BScreen *Blackbox::searchScreen(Window window) {
999   ScreenList::iterator it = screenList.begin();
1000
1001   for (; it != screenList.end(); ++it) {
1002     BScreen *s = *it;
1003     if (s->getRootWindow() == window)
1004       return s;
1005   }
1006
1007   return (BScreen *) 0;
1008 }
1009
1010
1011 BScreen *Blackbox::searchDesktopWindow(Window window) {
1012   WindowScreenLookup::iterator it = desktopSearchList.find(window);
1013   if (it != desktopSearchList.end())
1014     return it->second;
1015
1016   return (BScreen*) 0;
1017 }
1018
1019
1020 BScreen *Blackbox::searchSystrayWindow(Window window) {
1021   WindowScreenLookup::iterator it = systraySearchList.find(window);
1022   if (it != systraySearchList.end())
1023     return it->second;
1024
1025   return (BScreen*) 0;
1026 }
1027
1028
1029 BlackboxWindow *Blackbox::searchWindow(Window window) {
1030   WindowLookup::iterator it = windowSearchList.find(window);
1031   if (it != windowSearchList.end())
1032     return it->second;
1033
1034   return (BlackboxWindow*) 0;
1035 }
1036
1037
1038 BWindowGroup *Blackbox::searchGroup(Window window) {
1039   GroupLookup::iterator it = groupSearchList.find(window);
1040   if (it != groupSearchList.end())
1041     return it->second;
1042
1043   return (BWindowGroup *) 0;
1044 }
1045
1046
1047 Basemenu *Blackbox::searchMenu(Window window) {
1048   MenuLookup::iterator it = menuSearchList.find(window);
1049   if (it != menuSearchList.end())
1050     return it->second;
1051
1052   return (Basemenu*) 0;
1053 }
1054
1055
1056 Toolbar *Blackbox::searchToolbar(Window window) {
1057   ToolbarLookup::iterator it = toolbarSearchList.find(window);
1058   if (it != toolbarSearchList.end())
1059     return it->second;
1060
1061   return (Toolbar*) 0;
1062 }
1063
1064
1065 Slit *Blackbox::searchSlit(Window window) {
1066   SlitLookup::iterator it = slitSearchList.find(window);
1067   if (it != slitSearchList.end())
1068     return it->second;
1069
1070   return (Slit*) 0;
1071 }
1072
1073
1074 void Blackbox::saveDesktopWindowSearch(Window window, BScreen *screen) {
1075   desktopSearchList.insert(WindowScreenLookupPair(window, screen));
1076 }
1077
1078
1079 void Blackbox::saveSystrayWindowSearch(Window window, BScreen *screen) {
1080   systraySearchList.insert(WindowScreenLookupPair(window, screen));
1081 }
1082
1083
1084 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
1085   windowSearchList.insert(WindowLookupPair(window, data));
1086 }
1087
1088
1089 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
1090   groupSearchList.insert(GroupLookupPair(window, data));
1091 }
1092
1093
1094 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
1095   menuSearchList.insert(MenuLookupPair(window, data));
1096 }
1097
1098
1099 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
1100   toolbarSearchList.insert(ToolbarLookupPair(window, data));
1101 }
1102
1103
1104 void Blackbox::saveSlitSearch(Window window, Slit *data) {
1105   slitSearchList.insert(SlitLookupPair(window, data));
1106 }
1107
1108
1109 void Blackbox::removeDesktopWindowSearch(Window window) {
1110   desktopSearchList.erase(window);
1111 }
1112
1113
1114 void Blackbox::removeSystrayWindowSearch(Window window) {
1115   systraySearchList.erase(window);
1116 }
1117
1118
1119 void Blackbox::removeWindowSearch(Window window) {
1120   windowSearchList.erase(window);
1121 }
1122
1123
1124 void Blackbox::removeGroupSearch(Window window) {
1125   groupSearchList.erase(window);
1126 }
1127
1128
1129 void Blackbox::removeMenuSearch(Window window) {
1130   menuSearchList.erase(window);
1131 }
1132
1133
1134 void Blackbox::removeToolbarSearch(Window window) {
1135   toolbarSearchList.erase(window);
1136 }
1137
1138
1139 void Blackbox::removeSlitSearch(Window window) {
1140   slitSearchList.erase(window);
1141 }
1142
1143
1144 void Blackbox::restart(const char *prog) {
1145   shutdown();
1146
1147   if (prog) {
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 }