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