]> icculus.org git repositories - dana/openbox.git/blob - src/blackbox.cc
sync with bb. mostly cleanups in Window.cc
[dana/openbox.git] / src / blackbox.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // blackbox.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef    HAVE_CONFIG_H
25 #  include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #include <X11/cursorfont.h>
33 #include <X11/keysym.h>
34
35 #ifdef    SHAPE
36 #include <X11/extensions/shape.h>
37 #endif // SHAPE
38
39 #ifdef    HAVE_STDIO_H
40 #  include <stdio.h>
41 #endif // HAVE_STDIO_H
42
43 #ifdef HAVE_STDLIB_H
44 #  include <stdlib.h>
45 #endif // HAVE_STDLIB_H
46
47 #ifdef HAVE_STRING_H
48 #  include <string.h>
49 #endif // HAVE_STRING_H
50
51 #ifdef    HAVE_UNISTD_H
52 #  include <sys/types.h>
53 #  include <unistd.h>
54 #endif // HAVE_UNISTD_H
55
56 #ifdef    HAVE_SYS_PARAM_H
57 #  include <sys/param.h>
58 #endif // HAVE_SYS_PARAM_H
59
60 #ifdef    HAVE_SYS_SELECT_H
61 #  include <sys/select.h>
62 #endif // HAVE_SYS_SELECT_H
63
64 #ifdef    HAVE_SIGNAL_H
65 #  include <signal.h>
66 #endif // HAVE_SIGNAL_H
67
68 #ifdef    HAVE_SYS_SIGNAL_H
69 #  include <sys/signal.h>
70 #endif // HAVE_SYS_SIGNAL_H
71
72 #ifdef    HAVE_SYS_STAT_H
73 #  include <sys/types.h>
74 #  include <sys/stat.h>
75 #endif // HAVE_SYS_STAT_H
76
77 #ifdef    TIME_WITH_SYS_TIME
78 #  include <sys/time.h>
79 #  include <time.h>
80 #else // !TIME_WITH_SYS_TIME
81 #  ifdef    HAVE_SYS_TIME_H
82 #    include <sys/time.h>
83 #  else // !HAVE_SYS_TIME_H
84 #    include <time.h>
85 #  endif // HAVE_SYS_TIME_H
86 #endif // TIME_WITH_SYS_TIME
87
88 #ifdef    HAVE_LIBGEN_H
89 #  include <libgen.h>
90 #endif // HAVE_LIBGEN_H
91 }
92
93 #include <assert.h>
94
95 #include <algorithm>
96 #include <string>
97 using std::string;
98
99 #include "i18n.hh"
100 #include "blackbox.hh"
101 #include "Basemenu.hh"
102 #include "Clientmenu.hh"
103 #include "GCCache.hh"
104 #include "Image.hh"
105 #include "Rootmenu.hh"
106 #include "Screen.hh"
107 #include "Slit.hh"
108 #include "Toolbar.hh"
109 #include "Util.hh"
110 #include "Window.hh"
111 #include "Workspace.hh"
112 #include "Workspacemenu.hh"
113 #include "XAtom.hh"
114 #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     putenv(const_cast<char *>(screenList.front()->displayString().c_str()));
1149     execlp(prog, prog, NULL);
1150     perror(prog);
1151   }
1152
1153   // fall back in case the above execlp doesn't work
1154   execvp(argv[0], argv);
1155   string name = basename(argv[0]);
1156   execvp(name.c_str(), argv);
1157 }
1158
1159
1160 void Blackbox::shutdown(void) {
1161   BaseDisplay::shutdown();
1162
1163   XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
1164
1165   std::for_each(screenList.begin(), screenList.end(),
1166                 std::mem_fun(&BScreen::shutdown));
1167
1168   XSync(getXDisplay(), False);
1169 }
1170
1171
1172 /*
1173  * Save all values as they are so that the defaults will be written to the rc
1174  * file
1175  */
1176 void Blackbox::save_rc(void) {
1177   config.setAutoSave(false);
1178
1179   config.setValue("session.colorsPerChannel", resource.colors_per_channel);
1180   config.setValue("session.doubleClickInterval",
1181                   resource.double_click_interval);
1182   config.setValue("session.autoRaiseDelay",
1183                   ((resource.auto_raise_delay.tv_sec * 1000) +
1184                    (resource.auto_raise_delay.tv_usec / 1000)));
1185   config.setValue("session.cacheLife", resource.cache_life / 60000);
1186   config.setValue("session.cacheMax", resource.cache_max);
1187   config.setValue("session.styleFile", resource.style_file);
1188   config.setValue("session.titlebarLayout", resource.titlebar_layout);
1189   
1190   std::for_each(screenList.begin(), screenList.end(),
1191                 std::mem_fun(&BScreen::save_rc));
1192  
1193   config.setAutoSave(true);
1194   config.save();
1195 }
1196
1197
1198 void Blackbox::load_rc(void) {
1199   if (! config.load())
1200         config.create();
1201   
1202   string s;
1203
1204   if (! config.getValue("session.colorsPerChannel",
1205                         resource.colors_per_channel))
1206     resource.colors_per_channel = 4;
1207   if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1208   else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1209
1210   if (config.getValue("session.styleFile", s))
1211     resource.style_file = expandTilde(s);
1212   else
1213     resource.style_file = DEFAULTSTYLE;
1214
1215   if (! config.getValue("session.doubleClickInterval",
1216                        resource.double_click_interval));
1217     resource.double_click_interval = 250;
1218
1219   if (! config.getValue("session.autoRaiseDelay",
1220                        resource.auto_raise_delay.tv_usec))
1221     resource.auto_raise_delay.tv_usec = 400;
1222   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1223   resource.auto_raise_delay.tv_usec -=
1224     (resource.auto_raise_delay.tv_sec * 1000);
1225   resource.auto_raise_delay.tv_usec *= 1000;
1226
1227   if (! config.getValue("session.cacheLife", resource.cache_life))
1228     resource.cache_life = 5;
1229   resource.cache_life *= 60000;
1230
1231   if (! config.getValue("session.cacheMax", resource.cache_max))
1232     resource.cache_max = 200;
1233   
1234   if (! config.getValue("session.titlebarLayout", resource.titlebar_layout))
1235     resource.titlebar_layout = "ILMC";
1236 }
1237
1238
1239 void Blackbox::reconfigure(void) {
1240   reconfigure_wait = True;
1241
1242   if (! timer->isTiming()) timer->start();
1243 }
1244
1245
1246 void Blackbox::real_reconfigure(void) {
1247   load_rc();
1248   
1249   std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1250                 PointerAssassin());
1251   menuTimestamps.clear();
1252
1253   gcCache()->purge();
1254
1255   std::for_each(screenList.begin(), screenList.end(),
1256                 std::mem_fun(&BScreen::reconfigure));
1257 }
1258
1259
1260 void Blackbox::checkMenu(void) {
1261   bool reread = False;
1262   MenuTimestampList::iterator it = menuTimestamps.begin();
1263   for(; it != menuTimestamps.end(); ++it) {
1264     MenuTimestamp *tmp = *it;
1265     struct stat buf;
1266
1267     if (! stat(tmp->filename.c_str(), &buf)) {
1268       if (tmp->timestamp != buf.st_ctime)
1269         reread = True;
1270     } else {
1271       reread = True;
1272     }
1273   }
1274
1275   if (reread) rereadMenu();
1276 }
1277
1278
1279 void Blackbox::rereadMenu(void) {
1280   reread_menu_wait = True;
1281
1282   if (! timer->isTiming()) timer->start();
1283 }
1284
1285
1286 void Blackbox::real_rereadMenu(void) {
1287   std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1288                 PointerAssassin());
1289   menuTimestamps.clear();
1290
1291   std::for_each(screenList.begin(), screenList.end(),
1292                 std::mem_fun(&BScreen::rereadMenu));
1293 }
1294
1295
1296 void Blackbox::saveStyleFilename(const string& filename) {
1297   assert(! filename.empty());
1298   resource.style_file = filename;
1299   config.setValue("session.styleFile", resource.style_file);
1300 }
1301
1302
1303 void Blackbox::addMenuTimestamp(const string& filename) {
1304   assert(! filename.empty());
1305   bool found = False;
1306
1307   MenuTimestampList::iterator it = menuTimestamps.begin();
1308   for (; it != menuTimestamps.end() && ! found; ++it) {
1309     if ((*it)->filename == filename) found = True;
1310   }
1311   if (! found) {
1312     struct stat buf;
1313
1314     if (! stat(filename.c_str(), &buf)) {
1315       MenuTimestamp *ts = new MenuTimestamp;
1316
1317       ts->filename = filename;
1318       ts->timestamp = buf.st_ctime;
1319
1320       menuTimestamps.push_back(ts);
1321     }
1322   }
1323 }
1324
1325
1326 void Blackbox::timeout(void) {
1327   if (reconfigure_wait)
1328     real_reconfigure();
1329
1330   if (reread_menu_wait)
1331     real_rereadMenu();
1332
1333   reconfigure_wait = reread_menu_wait = False;
1334 }
1335
1336
1337 void Blackbox::setChangingWindow(BlackboxWindow *win) {
1338   // make sure one of the two is null and the other isn't
1339   assert((! changing_window && win) || (! win && changing_window));
1340   changing_window = win;
1341 }
1342
1343
1344 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1345   if (focused_window && focused_window == win) // nothing to do
1346     return;
1347
1348   BScreen *old_screen = 0;
1349
1350   if (focused_window) {
1351     focused_window->setFocusFlag(False);
1352     old_screen = focused_window->getScreen();
1353   }
1354
1355   if (win && ! win->isIconic()) {
1356     // the active screen is the one with the last focused window...
1357     // this will keep focus on this screen no matter where the mouse goes,
1358     // so multihead keybindings will continue to work on that screen until the
1359     // user focuses a window on a different screen.
1360     active_screen = win->getScreen();
1361     focused_window = win;
1362   } else {
1363     focused_window = 0;
1364     if (! old_screen) {
1365       if (active_screen) {
1366         // set input focus to the toolbar of the screen with mouse
1367         XSetInputFocus(getXDisplay(),
1368                        active_screen->getRootWindow(),
1369                        RevertToPointerRoot, CurrentTime);
1370       } else {
1371         // set input focus to the toolbar of the first managed screen
1372         XSetInputFocus(getXDisplay(),
1373                        screenList.front()->getRootWindow(),
1374                        RevertToPointerRoot, CurrentTime);
1375       }
1376     } else {
1377       // set input focus to the toolbar of the last screen
1378       XSetInputFocus(getXDisplay(), old_screen->getRootWindow(),
1379                      RevertToPointerRoot, CurrentTime);
1380     }
1381   }
1382
1383   if (active_screen && active_screen->isScreenManaged()) {
1384     active_screen->getToolbar()->redrawWindowLabel(True);
1385     active_screen->updateNetizenWindowFocus();
1386   }
1387
1388   if (old_screen && old_screen != active_screen) {
1389     old_screen->getToolbar()->redrawWindowLabel(True);
1390     old_screen->updateNetizenWindowFocus();
1391   }
1392 }