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