]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
dont accept motion events with same_screen set to false
[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 }
388
389 break;
390 }
391
392 case DestroyNotify: {
393 BlackboxWindow *win = (BlackboxWindow *) 0;
394 Slit *slit = (Slit *) 0;
395 BScreen *screen = (BScreen *) 0;
396 BWindowGroup *group = (BWindowGroup *) 0;
397
398 if ((win = searchWindow(e->xdestroywindow.window))) {
399 win->destroyNotifyEvent(&e->xdestroywindow);
400 } else if ((slit = searchSlit(e->xdestroywindow.window))) {
401 slit->removeClient(e->xdestroywindow.window, False);
402 } else if ((group = searchGroup(e->xdestroywindow.window))) {
403 delete group;
404 } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
405 screen->removeSystrayWindow(e->xunmap.window);
406 }
407
408 break;
409 }
410
411 case ReparentNotify: {
412 /*
413 this event is quite rare and is usually handled in unmapNotify
414 however, if the window is unmapped when the reparent event occurs
415 the window manager never sees it because an unmap event is not sent
416 to an already unmapped window.
417 */
418 BlackboxWindow *win = searchWindow(e->xreparent.window);
419 if (win) {
420 win->reparentNotifyEvent(&e->xreparent);
421 } else {
422 Slit *slit = searchSlit(e->xreparent.window);
423 if (slit && slit->getWindowID() != e->xreparent.parent)
424 slit->removeClient(e->xreparent.window, True);
425 }
426 break;
427 }
428
429 case MotionNotify: {
430 // motion notify compression...
431 XEvent realevent;
432 unsigned int i = 0;
433 while (XCheckTypedWindowEvent(getXDisplay(), e->xmotion.window,
434 MotionNotify, &realevent)) {
435 i++;
436 }
437
438 // if we have compressed some motion events, use the last one
439 if ( i > 0 )
440 e = &realevent;
441
442 if (! e->xmotion.same_screen)
443 break;
444
445 // strip the lock key modifiers
446 e->xmotion.state &= ~(NumLockMask | ScrollLockMask | LockMask);
447
448 last_time = e->xmotion.time;
449
450 BlackboxWindow *win = (BlackboxWindow *) 0;
451 Basemenu *menu = (Basemenu *) 0;
452
453 if ((win = searchWindow(e->xmotion.window)))
454 win->motionNotifyEvent(&e->xmotion);
455 else if ((menu = searchMenu(e->xmotion.window)))
456 menu->motionNotifyEvent(&e->xmotion);
457
458 break;
459 }
460
461 case PropertyNotify: {
462 last_time = e->xproperty.time;
463
464 BlackboxWindow *win = (BlackboxWindow *) 0;
465 BScreen *screen = (BScreen *) 0;
466
467 if ((win = searchWindow(e->xproperty.window)))
468 win->propertyNotifyEvent(&e->xproperty);
469 else if ((screen = searchScreen(e->xproperty.window)))
470 screen->propertyNotifyEvent(&e->xproperty);
471 break;
472 }
473
474 case EnterNotify: {
475 last_time = e->xcrossing.time;
476
477 BScreen *screen = (BScreen *) 0;
478 BlackboxWindow *win = (BlackboxWindow *) 0;
479 Basemenu *menu = (Basemenu *) 0;
480 Toolbar *tbar = (Toolbar *) 0;
481 Slit *slit = (Slit *) 0;
482
483 if (e->xcrossing.mode == NotifyGrab) break;
484
485 XEvent dummy;
486 scanargs sa;
487 sa.w = e->xcrossing.window;
488 sa.enter = sa.leave = False;
489 XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
490
491 if ((e->xcrossing.window == e->xcrossing.root) &&
492 (screen = searchScreen(e->xcrossing.window))) {
493 screen->getImageControl()->installRootColormap();
494 } else if ((win = searchWindow(e->xcrossing.window))) {
495 if (win->getScreen()->isSloppyFocus() &&
496 (! win->isFocused()) && (! no_focus) &&
497 win->isNormal()) { // don't focus non-normal windows with mouseover
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 wksp == 0xffffffff) {
763 if (win->isIconic()) win->deiconify(False, True);
764 if (! win->isStuck()) win->stick();
765 if (! win->isVisible()) win->show();
766 }
767 }
768 } else if (e->xclient.message_type ==
769 xatom->getAtom(XAtom::blackbox_change_attributes)) {
770 // BLACKBOX_CHANGE_ATTRIBUTES
771 BlackboxWindow *win = searchWindow(e->xclient.window);
772
773 if (win && win->validateClient()) {
774 BlackboxHints net;
775 net.flags = e->xclient.data.l[0];
776 net.attrib = e->xclient.data.l[1];
777 net.workspace = e->xclient.data.l[2];
778 net.stack = e->xclient.data.l[3];
779 net.decoration = e->xclient.data.l[4];
780
781 win->changeBlackboxHints(&net);
782 }
783 } else if (e->xclient.message_type ==
784 xatom->getAtom(XAtom::net_number_of_desktops)) {
785 // NET_NUMBER_OF_DESKTOPS
786 BScreen *screen = searchScreen(e->xclient.window);
787
788 if (e->xclient.data.l[0] > 0)
789 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
790 } else if (e->xclient.message_type ==
791 xatom->getAtom(XAtom::net_close_window)) {
792 // NET_CLOSE_WINDOW
793 BlackboxWindow *win = searchWindow(e->xclient.window);
794 if (win && win->validateClient())
795 win->close(); // could this be smarter?
796 } else if (e->xclient.message_type ==
797 xatom->getAtom(XAtom::net_wm_moveresize)) {
798 // NET_WM_MOVERESIZE
799 BlackboxWindow *win = searchWindow(e->xclient.window);
800 if (win && win->validateClient()) {
801 int x_root = e->xclient.data.l[0],
802 y_root = e->xclient.data.l[1];
803 if ((Atom) e->xclient.data.l[2] ==
804 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
805 win->beginMove(x_root, y_root);
806 } else {
807 if ((Atom) e->xclient.data.l[2] ==
808 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
809 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
810 else if ((Atom) e->xclient.data.l[2] ==
811 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
812 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
813 else if ((Atom) e->xclient.data.l[2] ==
814 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
815 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
816 else if ((Atom) e->xclient.data.l[2] ==
817 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
818 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
819 }
820 }
821 } else if (e->xclient.message_type ==
822 xatom->getAtom(XAtom::net_wm_state)) {
823 // NET_WM_STATE
824 BlackboxWindow *win = searchWindow(e->xclient.window);
825 if (win && win->validateClient()) {
826 const Atom action = (Atom) e->xclient.data.l[0];
827 const Atom state[] = { (Atom) e->xclient.data.l[1],
828 (Atom) e->xclient.data.l[2] };
829
830 for (int i = 0; i < 2; ++i) {
831 if (! state[i])
832 continue;
833
834 if ((Atom) e->xclient.data.l[0] == 1) {
835 // ADD
836 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
837 win->setModal(True);
838 } else if (state[i] ==
839 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
840 if (win->isMaximizedHoriz()) {
841 win->maximize(0); // unmaximize
842 win->maximize(1); // full
843 } else if (! win->isMaximized()) {
844 win->maximize(2); // vert
845 }
846 } else if (state[i] ==
847 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
848 if (win->isMaximizedVert()) {
849 win->maximize(0); // unmaximize
850 win->maximize(1); // full
851 } else if (! win->isMaximized()) {
852 win->maximize(3); // horiz
853 }
854 } else if (state[i] ==
855 xatom->getAtom(XAtom::net_wm_state_shaded)) {
856 if (! win->isShaded())
857 win->shade();
858 } else if (state[i] ==
859 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
860 win->setSkipTaskbar(True);
861 } else if (state[i] ==
862 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
863 win->setSkipPager(True);
864 } else if (state[i] ==
865 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
866 win->setFullscreen(True);
867 }
868 } else if (action == 0) {
869 // REMOVE
870 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
871 win->setModal(False);
872 } else if (state[i] ==
873 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
874 if (win->isMaximizedFull()) {
875 win->maximize(0); // unmaximize
876 win->maximize(3); // horiz
877 } else if (win->isMaximizedVert()) {
878 win->maximize(0); // unmaximize
879 }
880 } else if (state[i] ==
881 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
882 if (win->isMaximizedFull()) {
883 win->maximize(0); // unmaximize
884 win->maximize(2); // vert
885 } else if (win->isMaximizedHoriz()) {
886 win->maximize(0); // unmaximize
887 }
888 } else if (state[i] ==
889 xatom->getAtom(XAtom::net_wm_state_shaded)) {
890 if (win->isShaded())
891 win->shade();
892 } else if (state[i] ==
893 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
894 win->setSkipTaskbar(False);
895 } else if (state[i] ==
896 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
897 win->setSkipPager(False);
898 } else if (state[i] ==
899 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
900 win->setFullscreen(False);
901 }
902 } else if (action == 2) {
903 // TOGGLE
904 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
905 win->setModal(! win->isModal());
906 } else if (state[i] ==
907 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
908 if (win->isMaximizedFull()) {
909 win->maximize(0); // unmaximize
910 win->maximize(3); // horiz
911 } else if (win->isMaximizedVert()) {
912 win->maximize(0); // unmaximize
913 } else if (win->isMaximizedHoriz()) {
914 win->maximize(0); // unmaximize
915 win->maximize(1); // full
916 } else {
917 win->maximize(2); // vert
918 }
919 } else if (state[i] ==
920 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
921 if (win->isMaximizedFull()) {
922 win->maximize(0); // unmaximize
923 win->maximize(2); // vert
924 } else if (win->isMaximizedHoriz()) {
925 win->maximize(0); // unmaximize
926 } else if (win->isMaximizedVert()) {
927 win->maximize(0); // unmaximize
928 win->maximize(1); // full
929 } else {
930 win->maximize(3); // horiz
931 }
932 } else if (state[i] ==
933 xatom->getAtom(XAtom::net_wm_state_shaded)) {
934 win->shade();
935 } else if (state[i] ==
936 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
937 win->setSkipTaskbar(! win->skipTaskbar());
938 } else if (state[i] ==
939 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
940 win->setSkipPager(! win->skipPager());
941 } else if (state[i] ==
942 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
943 win->setFullscreen(! win->isFullscreen());
944 }
945 }
946 }
947 }
948 }
949 }
950
951 break;
952 }
953
954 case NoExpose:
955 case ConfigureNotify:
956 case MapNotify:
957 break; // not handled, just ignore
958
959 default: {
960 #ifdef SHAPE
961 if (e->type == getShapeEventBase()) {
962 XShapeEvent *shape_event = (XShapeEvent *) e;
963 BlackboxWindow *win = searchWindow(e->xany.window);
964
965 if (win)
966 win->shapeEvent(shape_event);
967 }
968 #endif // SHAPE
969 }
970 } // switch
971 }
972
973
974 bool Blackbox::handleSignal(int sig) {
975 switch (sig) {
976 case SIGHUP:
977 reconfigure();
978 break;
979
980 case SIGUSR1:
981 restart();
982 break;
983
984 case SIGUSR2:
985 rereadMenu();
986 break;
987
988 case SIGPIPE:
989 case SIGSEGV:
990 case SIGFPE:
991 case SIGINT:
992 case SIGTERM:
993 shutdown();
994
995 default:
996 return False;
997 }
998
999 return True;
1000 }
1001
1002
1003 bool Blackbox::validateWindow(Window window) {
1004 XEvent event;
1005 if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
1006 XPutBackEvent(getXDisplay(), &event);
1007
1008 return False;
1009 }
1010
1011 return True;
1012 }
1013
1014
1015 BScreen *Blackbox::searchScreen(Window window) {
1016 ScreenList::iterator it = screenList.begin();
1017
1018 for (; it != screenList.end(); ++it) {
1019 BScreen *s = *it;
1020 if (s->getRootWindow() == window)
1021 return s;
1022 }
1023
1024 return (BScreen *) 0;
1025 }
1026
1027
1028 BScreen *Blackbox::searchSystrayWindow(Window window) {
1029 WindowScreenLookup::iterator it = systraySearchList.find(window);
1030 if (it != systraySearchList.end())
1031 return it->second;
1032
1033 return (BScreen*) 0;
1034 }
1035
1036
1037 BlackboxWindow *Blackbox::searchWindow(Window window) {
1038 WindowLookup::iterator it = windowSearchList.find(window);
1039 if (it != windowSearchList.end())
1040 return it->second;
1041
1042 return (BlackboxWindow*) 0;
1043 }
1044
1045
1046 BWindowGroup *Blackbox::searchGroup(Window window) {
1047 GroupLookup::iterator it = groupSearchList.find(window);
1048 if (it != groupSearchList.end())
1049 return it->second;
1050
1051 return (BWindowGroup *) 0;
1052 }
1053
1054
1055 Basemenu *Blackbox::searchMenu(Window window) {
1056 MenuLookup::iterator it = menuSearchList.find(window);
1057 if (it != menuSearchList.end())
1058 return it->second;
1059
1060 return (Basemenu*) 0;
1061 }
1062
1063
1064 Toolbar *Blackbox::searchToolbar(Window window) {
1065 ToolbarLookup::iterator it = toolbarSearchList.find(window);
1066 if (it != toolbarSearchList.end())
1067 return it->second;
1068
1069 return (Toolbar*) 0;
1070 }
1071
1072
1073 Slit *Blackbox::searchSlit(Window window) {
1074 SlitLookup::iterator it = slitSearchList.find(window);
1075 if (it != slitSearchList.end())
1076 return it->second;
1077
1078 return (Slit*) 0;
1079 }
1080
1081
1082 void Blackbox::saveSystrayWindowSearch(Window window, BScreen *screen) {
1083 systraySearchList.insert(WindowScreenLookupPair(window, screen));
1084 }
1085
1086
1087 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
1088 windowSearchList.insert(WindowLookupPair(window, data));
1089 }
1090
1091
1092 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
1093 groupSearchList.insert(GroupLookupPair(window, data));
1094 }
1095
1096
1097 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
1098 menuSearchList.insert(MenuLookupPair(window, data));
1099 }
1100
1101
1102 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
1103 toolbarSearchList.insert(ToolbarLookupPair(window, data));
1104 }
1105
1106
1107 void Blackbox::saveSlitSearch(Window window, Slit *data) {
1108 slitSearchList.insert(SlitLookupPair(window, data));
1109 }
1110
1111
1112 void Blackbox::removeSystrayWindowSearch(Window window) {
1113 systraySearchList.erase(window);
1114 }
1115
1116
1117 void Blackbox::removeWindowSearch(Window window) {
1118 windowSearchList.erase(window);
1119 }
1120
1121
1122 void Blackbox::removeGroupSearch(Window window) {
1123 groupSearchList.erase(window);
1124 }
1125
1126
1127 void Blackbox::removeMenuSearch(Window window) {
1128 menuSearchList.erase(window);
1129 }
1130
1131
1132 void Blackbox::removeToolbarSearch(Window window) {
1133 toolbarSearchList.erase(window);
1134 }
1135
1136
1137 void Blackbox::removeSlitSearch(Window window) {
1138 slitSearchList.erase(window);
1139 }
1140
1141
1142 void Blackbox::restart(const char *prog) {
1143 shutdown();
1144
1145 if (prog) {
1146 putenv(const_cast<char *>(screenList.front()->displayString().c_str()));
1147 execlp(prog, prog, NULL);
1148 perror(prog);
1149 }
1150
1151 // fall back in case the above execlp doesn't work
1152 execvp(argv[0], argv);
1153 string name = basename(argv[0]);
1154 execvp(name.c_str(), argv);
1155 }
1156
1157
1158 void Blackbox::shutdown(void) {
1159 BaseDisplay::shutdown();
1160
1161 XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
1162
1163 std::for_each(screenList.begin(), screenList.end(),
1164 std::mem_fun(&BScreen::shutdown));
1165
1166 XSync(getXDisplay(), False);
1167 }
1168
1169
1170 #ifdef XINERAMA
1171 void Blackbox::saveXineramaPlacement(bool x) {
1172 resource.xinerama_placement = x;
1173 config.setValue("session.xineramaSupport.windowPlacement",
1174 resource.xinerama_placement);
1175 reconfigure(); // make sure all screens get this change
1176 }
1177
1178
1179 void Blackbox::saveXineramaMaximizing(bool x) {
1180 resource.xinerama_maximize = x;
1181 config.setValue("session.xineramaSupport.windowMaximizing",
1182 resource.xinerama_maximize);
1183 reconfigure(); // make sure all screens get this change
1184 }
1185
1186
1187 void Blackbox::saveXineramaSnapping(bool x) {
1188 resource.xinerama_snap = x;
1189 config.setValue("session.xineramaSupport.windowSnapping",
1190 resource.xinerama_snap);
1191 reconfigure(); // make sure all screens get this change
1192 }
1193 #endif // XINERAMA
1194
1195
1196 /*
1197 * Save all values as they are so that the defaults will be written to the rc
1198 * file
1199 */
1200 void Blackbox::save_rc(void) {
1201 config.setAutoSave(false);
1202
1203 config.setValue("session.colorsPerChannel", resource.colors_per_channel);
1204 config.setValue("session.doubleClickInterval",
1205 resource.double_click_interval);
1206 config.setValue("session.autoRaiseDelay",
1207 ((resource.auto_raise_delay.tv_sec * 1000) +
1208 (resource.auto_raise_delay.tv_usec / 1000)));
1209 config.setValue("session.cacheLife", resource.cache_life / 60000);
1210 config.setValue("session.cacheMax", resource.cache_max);
1211 config.setValue("session.styleFile", resource.style_file);
1212 config.setValue("session.titlebarLayout", resource.titlebar_layout);
1213
1214 #ifdef XINERAMA
1215 saveXineramaPlacement(resource.xinerama_placement);
1216 saveXineramaMaximizing(resource.xinerama_maximize);
1217 saveXineramaSnapping(resource.xinerama_snap);
1218 #endif // XINERAMA
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 #ifdef XINERAMA
1268 if (! config.getValue("session.xineramaSupport.windowPlacement",
1269 resource.xinerama_placement))
1270 resource.xinerama_placement = false;
1271
1272 if (! config.getValue("session.xineramaSupport.windowMaximizing",
1273 resource.xinerama_maximize))
1274 resource.xinerama_maximize = false;
1275
1276 if (! config.getValue("session.xineramaSupport.windowSnapping",
1277 resource.xinerama_snap))
1278 resource.xinerama_snap = false;
1279 #endif // XINERAMA
1280 }
1281
1282
1283 void Blackbox::reconfigure(void) {
1284 // don't reconfigure while saving the initial rc file, it's a waste and it
1285 // breaks somethings (workspace names)
1286 if (isStartup()) return;
1287
1288 reconfigure_wait = True;
1289
1290 if (! timer->isTiming()) timer->start();
1291 }
1292
1293
1294 void Blackbox::real_reconfigure(void) {
1295 load_rc();
1296
1297 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1298 PointerAssassin());
1299 menuTimestamps.clear();
1300
1301 gcCache()->purge();
1302
1303 std::for_each(screenList.begin(), screenList.end(),
1304 std::mem_fun(&BScreen::reconfigure));
1305 }
1306
1307
1308 void Blackbox::checkMenu(void) {
1309 bool reread = False;
1310 MenuTimestampList::iterator it = menuTimestamps.begin();
1311 for(; it != menuTimestamps.end(); ++it) {
1312 MenuTimestamp *tmp = *it;
1313 struct stat buf;
1314
1315 if (! stat(tmp->filename.c_str(), &buf)) {
1316 if (tmp->timestamp != buf.st_ctime)
1317 reread = True;
1318 } else {
1319 reread = True;
1320 }
1321 }
1322
1323 if (reread) rereadMenu();
1324 }
1325
1326
1327 void Blackbox::rereadMenu(void) {
1328 reread_menu_wait = True;
1329
1330 if (! timer->isTiming()) timer->start();
1331 }
1332
1333
1334 void Blackbox::real_rereadMenu(void) {
1335 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1336 PointerAssassin());
1337 menuTimestamps.clear();
1338
1339 std::for_each(screenList.begin(), screenList.end(),
1340 std::mem_fun(&BScreen::rereadMenu));
1341 }
1342
1343
1344 void Blackbox::saveStyleFilename(const string& filename) {
1345 assert(! filename.empty());
1346 resource.style_file = filename;
1347 config.setValue("session.styleFile", resource.style_file);
1348 }
1349
1350
1351 void Blackbox::addMenuTimestamp(const string& filename) {
1352 assert(! filename.empty());
1353 bool found = False;
1354
1355 MenuTimestampList::iterator it = menuTimestamps.begin();
1356 for (; it != menuTimestamps.end() && ! found; ++it) {
1357 if ((*it)->filename == filename) found = True;
1358 }
1359 if (! found) {
1360 struct stat buf;
1361
1362 if (! stat(filename.c_str(), &buf)) {
1363 MenuTimestamp *ts = new MenuTimestamp;
1364
1365 ts->filename = filename;
1366 ts->timestamp = buf.st_ctime;
1367
1368 menuTimestamps.push_back(ts);
1369 }
1370 }
1371 }
1372
1373
1374 void Blackbox::timeout(void) {
1375 if (reconfigure_wait)
1376 real_reconfigure();
1377
1378 if (reread_menu_wait)
1379 real_rereadMenu();
1380
1381 reconfigure_wait = reread_menu_wait = False;
1382 }
1383
1384
1385 void Blackbox::setChangingWindow(BlackboxWindow *win) {
1386 // make sure one of the two is null and the other isn't
1387 assert((! changing_window && win) || (! win && changing_window));
1388 changing_window = win;
1389 }
1390
1391
1392 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1393 if (focused_window && focused_window == win) // nothing to do
1394 return;
1395
1396 BScreen *old_screen = 0;
1397
1398 if (focused_window) {
1399 focused_window->setFocusFlag(False);
1400 old_screen = focused_window->getScreen();
1401 }
1402
1403 if (win && ! win->isIconic()) {
1404 // the active screen is the one with the last focused window...
1405 // this will keep focus on this screen no matter where the mouse goes,
1406 // so multihead keybindings will continue to work on that screen until the
1407 // user focuses a window on a different screen.
1408 active_screen = win->getScreen();
1409 focused_window = win;
1410 } else {
1411 focused_window = 0;
1412 if (! old_screen) {
1413 if (active_screen) {
1414 // set input focus to the toolbar of the screen with mouse
1415 XSetInputFocus(getXDisplay(),
1416 active_screen->getRootWindow(),
1417 RevertToPointerRoot, CurrentTime);
1418 } else {
1419 // set input focus to the toolbar of the first managed screen
1420 XSetInputFocus(getXDisplay(),
1421 screenList.front()->getRootWindow(),
1422 RevertToPointerRoot, CurrentTime);
1423 }
1424 } else {
1425 // set input focus to the toolbar of the last screen
1426 XSetInputFocus(getXDisplay(), old_screen->getRootWindow(),
1427 RevertToPointerRoot, CurrentTime);
1428 }
1429 }
1430
1431 if (active_screen && active_screen->isScreenManaged()) {
1432 active_screen->getToolbar()->redrawWindowLabel(True);
1433 active_screen->updateNetizenWindowFocus();
1434 }
1435
1436 if (old_screen && old_screen != active_screen) {
1437 old_screen->getToolbar()->redrawWindowLabel(True);
1438 old_screen->updateNetizenWindowFocus();
1439 }
1440 }
This page took 0.10763 seconds and 5 git commands to generate.