]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
add comment
[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 // the pointer is on the wrong screen
443 if (! e->xmotion.same_screen)
444 break;
445
446 // strip the lock key modifiers
447 e->xmotion.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 win->isNormal()) { // don't focus non-normal windows with mouseover
499 if (((! sa.leave) || sa.inferior) && win->isVisible()) {
500 if (win->setInputFocus())
501 win->installColormap(True); // XXX: shouldnt we honour no install?
502 }
503 }
504 } else if ((menu = searchMenu(e->xcrossing.window))) {
505 menu->enterNotifyEvent(&e->xcrossing);
506 } else if ((tbar = searchToolbar(e->xcrossing.window))) {
507 tbar->enterNotifyEvent(&e->xcrossing);
508 } else if ((slit = searchSlit(e->xcrossing.window))) {
509 slit->enterNotifyEvent(&e->xcrossing);
510 }
511 break;
512 }
513
514 case LeaveNotify: {
515 last_time = e->xcrossing.time;
516
517 BlackboxWindow *win = (BlackboxWindow *) 0;
518 Basemenu *menu = (Basemenu *) 0;
519 Toolbar *tbar = (Toolbar *) 0;
520 Slit *slit = (Slit *) 0;
521
522 if ((menu = searchMenu(e->xcrossing.window)))
523 menu->leaveNotifyEvent(&e->xcrossing);
524 else if ((win = searchWindow(e->xcrossing.window)))
525 win->installColormap(False);
526 else if ((tbar = searchToolbar(e->xcrossing.window)))
527 tbar->leaveNotifyEvent(&e->xcrossing);
528 else if ((slit = searchSlit(e->xcrossing.window)))
529 slit->leaveNotifyEvent(&e->xcrossing);
530 break;
531 }
532
533 case Expose: {
534 // compress expose events
535 XEvent realevent;
536 unsigned int i = 0;
537 int ex1, ey1, ex2, ey2;
538 ex1 = e->xexpose.x;
539 ey1 = e->xexpose.y;
540 ex2 = ex1 + e->xexpose.width - 1;
541 ey2 = ey1 + e->xexpose.height - 1;
542 while (XCheckTypedWindowEvent(getXDisplay(), e->xexpose.window,
543 Expose, &realevent)) {
544 i++;
545
546 // merge expose area
547 ex1 = std::min(realevent.xexpose.x, ex1);
548 ey1 = std::min(realevent.xexpose.y, ey1);
549 ex2 = std::max(realevent.xexpose.x + realevent.xexpose.width - 1, ex2);
550 ey2 = std::max(realevent.xexpose.y + realevent.xexpose.height - 1, ey2);
551 }
552 if ( i > 0 )
553 e = &realevent;
554
555 // use the merged area
556 e->xexpose.x = ex1;
557 e->xexpose.y = ey1;
558 e->xexpose.width = ex2 - ex1 + 1;
559 e->xexpose.height = ey2 - ey1 + 1;
560
561 BlackboxWindow *win = (BlackboxWindow *) 0;
562 Basemenu *menu = (Basemenu *) 0;
563 Toolbar *tbar = (Toolbar *) 0;
564
565 if ((win = searchWindow(e->xexpose.window)))
566 win->exposeEvent(&e->xexpose);
567 else if ((menu = searchMenu(e->xexpose.window)))
568 menu->exposeEvent(&e->xexpose);
569 else if ((tbar = searchToolbar(e->xexpose.window)))
570 tbar->exposeEvent(&e->xexpose);
571
572 break;
573 }
574
575 case KeyPress: {
576 Toolbar *tbar = searchToolbar(e->xkey.window);
577
578 if (tbar && tbar->isEditing())
579 tbar->keyPressEvent(&e->xkey);
580
581 break;
582 }
583
584 case ColormapNotify: {
585 BScreen *screen = searchScreen(e->xcolormap.window);
586
587 if (screen)
588 screen->setRootColormapInstalled((e->xcolormap.state ==
589 ColormapInstalled) ? True : False);
590
591 break;
592 }
593
594 case FocusIn: {
595 if (e->xfocus.detail != NotifyNonlinear &&
596 e->xfocus.detail != NotifyAncestor) {
597 /*
598 don't process FocusIns when:
599 1. the new focus window isn't an ancestor or inferior of the old
600 focus window (NotifyNonlinear)
601 make sure to allow the FocusIn when the old focus window was an
602 ancestor but didn't have a parent, such as root (NotifyAncestor)
603 */
604 break;
605 }
606
607 BlackboxWindow *win = searchWindow(e->xfocus.window);
608 if (win) {
609 if (! win->isFocused())
610 win->setFocusFlag(True);
611
612 /*
613 set the event window to None. when the FocusOut event handler calls
614 this function recursively, it uses this as an indication that focus
615 has moved to a known window.
616 */
617 e->xfocus.window = None;
618 }
619
620 break;
621 }
622
623 case FocusOut: {
624 if (e->xfocus.detail != NotifyNonlinear) {
625 /*
626 don't process FocusOuts when:
627 2. the new focus window isn't an ancestor or inferior of the old
628 focus window (NotifyNonlinear)
629 */
630 break;
631 }
632
633 BlackboxWindow *win = searchWindow(e->xfocus.window);
634 if (win && win->isFocused()) {
635 /*
636 before we mark "win" as unfocused, we need to verify that focus is
637 going to a known location, is in a known location, or set focus
638 to a known location.
639 */
640
641 XEvent event;
642 // don't check the current focus if FocusOut was generated during a grab
643 bool check_focus = (e->xfocus.mode == NotifyNormal);
644
645 /*
646 First, check if there is a pending FocusIn event waiting. if there
647 is, process it and determine if focus has moved to another window
648 (the FocusIn event handler sets the window in the event
649 structure to None to indicate this).
650 */
651 if (XCheckTypedEvent(getXDisplay(), FocusIn, &event)) {
652
653 process_event(&event);
654 if (event.xfocus.window == None) {
655 // focus has moved
656 check_focus = False;
657 }
658 }
659
660 if (check_focus) {
661 /*
662 Second, we query the X server for the current input focus.
663 to make sure that we keep a consistent state.
664 */
665 BlackboxWindow *focus;
666 Window w;
667 int revert;
668 XGetInputFocus(getXDisplay(), &w, &revert);
669 focus = searchWindow(w);
670 if (focus) {
671 /*
672 focus got from "win" to "focus" under some very strange
673 circumstances, and we need to make sure that the focus indication
674 is correct.
675 */
676 setFocusedWindow(focus);
677 } else {
678 // we have no idea where focus went... so we set it to somewhere
679 setFocusedWindow(0);
680 }
681 }
682 }
683
684 break;
685 }
686
687 case ClientMessage: {
688 if (e->xclient.format == 32) {
689 if (e->xclient.message_type == xatom->getAtom(XAtom::wm_change_state)) {
690 // WM_CHANGE_STATE message
691 BlackboxWindow *win = searchWindow(e->xclient.window);
692 if (! win || ! win->validateClient()) return;
693
694 if (e->xclient.data.l[0] == IconicState)
695 win->iconify();
696 if (e->xclient.data.l[0] == NormalState)
697 win->deiconify();
698 } else if (e->xclient.message_type ==
699 xatom->getAtom(XAtom::blackbox_change_workspace) ||
700 e->xclient.message_type ==
701 xatom->getAtom(XAtom::net_current_desktop)) {
702 // NET_CURRENT_DESKTOP message
703 BScreen *screen = searchScreen(e->xclient.window);
704
705 unsigned int workspace = e->xclient.data.l[0];
706 if (screen && workspace < screen->getWorkspaceCount())
707 screen->changeWorkspaceID(workspace);
708 } else if (e->xclient.message_type ==
709 xatom->getAtom(XAtom::blackbox_change_window_focus)) {
710 // TEMP HACK TO KEEP BBKEYS WORKING
711 BlackboxWindow *win = searchWindow(e->xclient.window);
712
713 if (win && win->isVisible() && win->setInputFocus())
714 win->installColormap(True);
715 } else if (e->xclient.message_type ==
716 xatom->getAtom(XAtom::net_active_window)) {
717 // NET_ACTIVE_WINDOW
718 BlackboxWindow *win = searchWindow(e->xclient.window);
719
720 if (win) {
721 BScreen *screen = win->getScreen();
722
723 if (win->isIconic())
724 win->deiconify(False, True);
725 if (win->isShaded())
726 win->shade();
727 if (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())
728 screen->changeWorkspaceID(win->getWorkspaceNumber());
729 if (win->isVisible() && win->setInputFocus()) {
730 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
731 raiseWindow(win);
732 win->installColormap(True);
733 }
734 }
735 } else if (e->xclient.message_type ==
736 xatom->getAtom(XAtom::blackbox_cycle_window_focus)) {
737 // BLACKBOX_CYCLE_WINDOW_FOCUS
738 BScreen *screen = searchScreen(e->xclient.window);
739
740 if (screen) {
741 if (! e->xclient.data.l[0])
742 screen->prevFocus();
743 else
744 screen->nextFocus();
745 }
746 } else if (e->xclient.message_type ==
747 xatom->getAtom(XAtom::net_wm_desktop)) {
748 // NET_WM_DESKTOP
749 BlackboxWindow *win = searchWindow(e->xclient.window);
750
751 if (win) {
752 BScreen *screen = win->getScreen();
753 unsigned long wksp = (unsigned) e->xclient.data.l[0];
754 if (wksp < screen->getWorkspaceCount()) {
755 if (win->isIconic()) win->deiconify(False, True);
756 if (win->isStuck()) win->stick();
757 if (wksp != screen->getCurrentWorkspaceID())
758 win->withdraw();
759 else
760 win->show();
761 screen->reassociateWindow(win, wksp, True);
762 } else if (wksp == 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
763 wksp == 0xffffffff) {
764 if (win->isIconic()) win->deiconify(False, True);
765 if (! win->isStuck()) win->stick();
766 if (! win->isVisible()) win->show();
767 }
768 }
769 } else if (e->xclient.message_type ==
770 xatom->getAtom(XAtom::blackbox_change_attributes)) {
771 // BLACKBOX_CHANGE_ATTRIBUTES
772 BlackboxWindow *win = searchWindow(e->xclient.window);
773
774 if (win && win->validateClient()) {
775 BlackboxHints net;
776 net.flags = e->xclient.data.l[0];
777 net.attrib = e->xclient.data.l[1];
778 net.workspace = e->xclient.data.l[2];
779 net.stack = e->xclient.data.l[3];
780 net.decoration = e->xclient.data.l[4];
781
782 win->changeBlackboxHints(&net);
783 }
784 } else if (e->xclient.message_type ==
785 xatom->getAtom(XAtom::net_number_of_desktops)) {
786 // NET_NUMBER_OF_DESKTOPS
787 BScreen *screen = searchScreen(e->xclient.window);
788
789 if (e->xclient.data.l[0] > 0)
790 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
791 } else if (e->xclient.message_type ==
792 xatom->getAtom(XAtom::net_close_window)) {
793 // NET_CLOSE_WINDOW
794 BlackboxWindow *win = searchWindow(e->xclient.window);
795 if (win && win->validateClient())
796 win->close(); // could this be smarter?
797 } else if (e->xclient.message_type ==
798 xatom->getAtom(XAtom::net_wm_moveresize)) {
799 // NET_WM_MOVERESIZE
800 BlackboxWindow *win = searchWindow(e->xclient.window);
801 if (win && win->validateClient()) {
802 int x_root = e->xclient.data.l[0],
803 y_root = e->xclient.data.l[1];
804 if ((Atom) e->xclient.data.l[2] ==
805 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
806 win->beginMove(x_root, y_root);
807 } else {
808 if ((Atom) e->xclient.data.l[2] ==
809 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
810 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
811 else if ((Atom) e->xclient.data.l[2] ==
812 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
813 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
814 else if ((Atom) e->xclient.data.l[2] ==
815 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
816 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
817 else if ((Atom) e->xclient.data.l[2] ==
818 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
819 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
820 }
821 }
822 } else if (e->xclient.message_type ==
823 xatom->getAtom(XAtom::net_wm_state)) {
824 // NET_WM_STATE
825 BlackboxWindow *win = searchWindow(e->xclient.window);
826 if (win && win->validateClient()) {
827 const Atom action = (Atom) e->xclient.data.l[0];
828 const Atom state[] = { (Atom) e->xclient.data.l[1],
829 (Atom) e->xclient.data.l[2] };
830
831 for (int i = 0; i < 2; ++i) {
832 if (! state[i])
833 continue;
834
835 if ((Atom) e->xclient.data.l[0] == 1) {
836 // ADD
837 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
838 win->setModal(True);
839 } else if (state[i] ==
840 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
841 if (win->isMaximizedHoriz()) {
842 win->maximize(0); // unmaximize
843 win->maximize(1); // full
844 } else if (! win->isMaximized()) {
845 win->maximize(2); // vert
846 }
847 } else if (state[i] ==
848 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
849 if (win->isMaximizedVert()) {
850 win->maximize(0); // unmaximize
851 win->maximize(1); // full
852 } else if (! win->isMaximized()) {
853 win->maximize(3); // horiz
854 }
855 } else if (state[i] ==
856 xatom->getAtom(XAtom::net_wm_state_shaded)) {
857 if (! win->isShaded())
858 win->shade();
859 } else if (state[i] ==
860 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
861 win->setSkipTaskbar(True);
862 } else if (state[i] ==
863 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
864 win->setSkipPager(True);
865 } else if (state[i] ==
866 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
867 win->setFullscreen(True);
868 }
869 } else if (action == 0) {
870 // REMOVE
871 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
872 win->setModal(False);
873 } else if (state[i] ==
874 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
875 if (win->isMaximizedFull()) {
876 win->maximize(0); // unmaximize
877 win->maximize(3); // horiz
878 } else if (win->isMaximizedVert()) {
879 win->maximize(0); // unmaximize
880 }
881 } else if (state[i] ==
882 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
883 if (win->isMaximizedFull()) {
884 win->maximize(0); // unmaximize
885 win->maximize(2); // vert
886 } else if (win->isMaximizedHoriz()) {
887 win->maximize(0); // unmaximize
888 }
889 } else if (state[i] ==
890 xatom->getAtom(XAtom::net_wm_state_shaded)) {
891 if (win->isShaded())
892 win->shade();
893 } else if (state[i] ==
894 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
895 win->setSkipTaskbar(False);
896 } else if (state[i] ==
897 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
898 win->setSkipPager(False);
899 } else if (state[i] ==
900 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
901 win->setFullscreen(False);
902 }
903 } else if (action == 2) {
904 // TOGGLE
905 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
906 win->setModal(! win->isModal());
907 } else if (state[i] ==
908 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
909 if (win->isMaximizedFull()) {
910 win->maximize(0); // unmaximize
911 win->maximize(3); // horiz
912 } else if (win->isMaximizedVert()) {
913 win->maximize(0); // unmaximize
914 } else if (win->isMaximizedHoriz()) {
915 win->maximize(0); // unmaximize
916 win->maximize(1); // full
917 } else {
918 win->maximize(2); // vert
919 }
920 } else if (state[i] ==
921 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
922 if (win->isMaximizedFull()) {
923 win->maximize(0); // unmaximize
924 win->maximize(2); // vert
925 } else if (win->isMaximizedHoriz()) {
926 win->maximize(0); // unmaximize
927 } else if (win->isMaximizedVert()) {
928 win->maximize(0); // unmaximize
929 win->maximize(1); // full
930 } else {
931 win->maximize(3); // horiz
932 }
933 } else if (state[i] ==
934 xatom->getAtom(XAtom::net_wm_state_shaded)) {
935 win->shade();
936 } else if (state[i] ==
937 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
938 win->setSkipTaskbar(! win->skipTaskbar());
939 } else if (state[i] ==
940 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
941 win->setSkipPager(! win->skipPager());
942 } else if (state[i] ==
943 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
944 win->setFullscreen(! win->isFullscreen());
945 }
946 }
947 }
948 }
949 }
950 }
951
952 break;
953 }
954
955 case NoExpose:
956 case ConfigureNotify:
957 case MapNotify:
958 break; // not handled, just ignore
959
960 default: {
961 #ifdef SHAPE
962 if (e->type == getShapeEventBase()) {
963 XShapeEvent *shape_event = (XShapeEvent *) e;
964 BlackboxWindow *win = searchWindow(e->xany.window);
965
966 if (win)
967 win->shapeEvent(shape_event);
968 }
969 #endif // SHAPE
970 }
971 } // switch
972 }
973
974
975 bool Blackbox::handleSignal(int sig) {
976 switch (sig) {
977 case SIGHUP:
978 reconfigure();
979 break;
980
981 case SIGUSR1:
982 restart();
983 break;
984
985 case SIGUSR2:
986 rereadMenu();
987 break;
988
989 case SIGPIPE:
990 case SIGSEGV:
991 case SIGFPE:
992 case SIGINT:
993 case SIGTERM:
994 shutdown();
995
996 default:
997 return False;
998 }
999
1000 return True;
1001 }
1002
1003
1004 bool Blackbox::validateWindow(Window window) {
1005 XEvent event;
1006 if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
1007 XPutBackEvent(getXDisplay(), &event);
1008
1009 return False;
1010 }
1011
1012 return True;
1013 }
1014
1015
1016 BScreen *Blackbox::searchScreen(Window window) {
1017 ScreenList::iterator it = screenList.begin();
1018
1019 for (; it != screenList.end(); ++it) {
1020 BScreen *s = *it;
1021 if (s->getRootWindow() == window)
1022 return s;
1023 }
1024
1025 return (BScreen *) 0;
1026 }
1027
1028
1029 BScreen *Blackbox::searchSystrayWindow(Window window) {
1030 WindowScreenLookup::iterator it = systraySearchList.find(window);
1031 if (it != systraySearchList.end())
1032 return it->second;
1033
1034 return (BScreen*) 0;
1035 }
1036
1037
1038 BlackboxWindow *Blackbox::searchWindow(Window window) {
1039 WindowLookup::iterator it = windowSearchList.find(window);
1040 if (it != windowSearchList.end())
1041 return it->second;
1042
1043 return (BlackboxWindow*) 0;
1044 }
1045
1046
1047 BWindowGroup *Blackbox::searchGroup(Window window) {
1048 GroupLookup::iterator it = groupSearchList.find(window);
1049 if (it != groupSearchList.end())
1050 return it->second;
1051
1052 return (BWindowGroup *) 0;
1053 }
1054
1055
1056 Basemenu *Blackbox::searchMenu(Window window) {
1057 MenuLookup::iterator it = menuSearchList.find(window);
1058 if (it != menuSearchList.end())
1059 return it->second;
1060
1061 return (Basemenu*) 0;
1062 }
1063
1064
1065 Toolbar *Blackbox::searchToolbar(Window window) {
1066 ToolbarLookup::iterator it = toolbarSearchList.find(window);
1067 if (it != toolbarSearchList.end())
1068 return it->second;
1069
1070 return (Toolbar*) 0;
1071 }
1072
1073
1074 Slit *Blackbox::searchSlit(Window window) {
1075 SlitLookup::iterator it = slitSearchList.find(window);
1076 if (it != slitSearchList.end())
1077 return it->second;
1078
1079 return (Slit*) 0;
1080 }
1081
1082
1083 void Blackbox::saveSystrayWindowSearch(Window window, BScreen *screen) {
1084 systraySearchList.insert(WindowScreenLookupPair(window, screen));
1085 }
1086
1087
1088 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
1089 windowSearchList.insert(WindowLookupPair(window, data));
1090 }
1091
1092
1093 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
1094 groupSearchList.insert(GroupLookupPair(window, data));
1095 }
1096
1097
1098 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
1099 menuSearchList.insert(MenuLookupPair(window, data));
1100 }
1101
1102
1103 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
1104 toolbarSearchList.insert(ToolbarLookupPair(window, data));
1105 }
1106
1107
1108 void Blackbox::saveSlitSearch(Window window, Slit *data) {
1109 slitSearchList.insert(SlitLookupPair(window, data));
1110 }
1111
1112
1113 void Blackbox::removeSystrayWindowSearch(Window window) {
1114 systraySearchList.erase(window);
1115 }
1116
1117
1118 void Blackbox::removeWindowSearch(Window window) {
1119 windowSearchList.erase(window);
1120 }
1121
1122
1123 void Blackbox::removeGroupSearch(Window window) {
1124 groupSearchList.erase(window);
1125 }
1126
1127
1128 void Blackbox::removeMenuSearch(Window window) {
1129 menuSearchList.erase(window);
1130 }
1131
1132
1133 void Blackbox::removeToolbarSearch(Window window) {
1134 toolbarSearchList.erase(window);
1135 }
1136
1137
1138 void Blackbox::removeSlitSearch(Window window) {
1139 slitSearchList.erase(window);
1140 }
1141
1142
1143 void Blackbox::restart(const char *prog) {
1144 shutdown();
1145
1146 if (prog) {
1147 putenv(const_cast<char *>(screenList.front()->displayString().c_str()));
1148 execlp(prog, prog, NULL);
1149 perror(prog);
1150 }
1151
1152 // fall back in case the above execlp doesn't work
1153 execvp(argv[0], argv);
1154 string name = basename(argv[0]);
1155 execvp(name.c_str(), argv);
1156 }
1157
1158
1159 void Blackbox::shutdown(void) {
1160 BaseDisplay::shutdown();
1161
1162 XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
1163
1164 std::for_each(screenList.begin(), screenList.end(),
1165 std::mem_fun(&BScreen::shutdown));
1166
1167 XSync(getXDisplay(), False);
1168 }
1169
1170
1171 #ifdef XINERAMA
1172 void Blackbox::saveXineramaPlacement(bool x) {
1173 resource.xinerama_placement = x;
1174 config.setValue("session.xineramaSupport.windowPlacement",
1175 resource.xinerama_placement);
1176 reconfigure(); // make sure all screens get this change
1177 }
1178
1179
1180 void Blackbox::saveXineramaMaximizing(bool x) {
1181 resource.xinerama_maximize = x;
1182 config.setValue("session.xineramaSupport.windowMaximizing",
1183 resource.xinerama_maximize);
1184 reconfigure(); // make sure all screens get this change
1185 }
1186
1187
1188 void Blackbox::saveXineramaSnapping(bool x) {
1189 resource.xinerama_snap = x;
1190 config.setValue("session.xineramaSupport.windowSnapping",
1191 resource.xinerama_snap);
1192 reconfigure(); // make sure all screens get this change
1193 }
1194 #endif // XINERAMA
1195
1196
1197 /*
1198 * Save all values as they are so that the defaults will be written to the rc
1199 * file
1200 */
1201 void Blackbox::save_rc(void) {
1202 config.setAutoSave(false);
1203
1204 config.setValue("session.colorsPerChannel", resource.colors_per_channel);
1205 config.setValue("session.doubleClickInterval",
1206 resource.double_click_interval);
1207 config.setValue("session.autoRaiseDelay",
1208 ((resource.auto_raise_delay.tv_sec * 1000) +
1209 (resource.auto_raise_delay.tv_usec / 1000)));
1210 config.setValue("session.cacheLife", resource.cache_life / 60000);
1211 config.setValue("session.cacheMax", resource.cache_max);
1212 config.setValue("session.styleFile", resource.style_file);
1213 config.setValue("session.titlebarLayout", resource.titlebar_layout);
1214
1215 #ifdef XINERAMA
1216 saveXineramaPlacement(resource.xinerama_placement);
1217 saveXineramaMaximizing(resource.xinerama_maximize);
1218 saveXineramaSnapping(resource.xinerama_snap);
1219 #endif // XINERAMA
1220
1221 std::for_each(screenList.begin(), screenList.end(),
1222 std::mem_fun(&BScreen::save_rc));
1223
1224 config.setAutoSave(true);
1225 config.save();
1226 }
1227
1228
1229 void Blackbox::load_rc(void) {
1230 if (! config.load())
1231 config.create();
1232
1233 string s;
1234
1235 if (! config.getValue("session.colorsPerChannel",
1236 resource.colors_per_channel))
1237 resource.colors_per_channel = 4;
1238 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1239 else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1240
1241 if (config.getValue("session.styleFile", s))
1242 resource.style_file = expandTilde(s);
1243 else
1244 resource.style_file = DEFAULTSTYLE;
1245
1246 if (! config.getValue("session.doubleClickInterval",
1247 resource.double_click_interval));
1248 resource.double_click_interval = 250;
1249
1250 if (! config.getValue("session.autoRaiseDelay",
1251 resource.auto_raise_delay.tv_usec))
1252 resource.auto_raise_delay.tv_usec = 400;
1253 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1254 resource.auto_raise_delay.tv_usec -=
1255 (resource.auto_raise_delay.tv_sec * 1000);
1256 resource.auto_raise_delay.tv_usec *= 1000;
1257
1258 if (! config.getValue("session.cacheLife", resource.cache_life))
1259 resource.cache_life = 5;
1260 resource.cache_life *= 60000;
1261
1262 if (! config.getValue("session.cacheMax", resource.cache_max))
1263 resource.cache_max = 200;
1264
1265 if (! config.getValue("session.titlebarLayout", resource.titlebar_layout))
1266 resource.titlebar_layout = "ILMC";
1267
1268 #ifdef XINERAMA
1269 if (! config.getValue("session.xineramaSupport.windowPlacement",
1270 resource.xinerama_placement))
1271 resource.xinerama_placement = false;
1272
1273 if (! config.getValue("session.xineramaSupport.windowMaximizing",
1274 resource.xinerama_maximize))
1275 resource.xinerama_maximize = false;
1276
1277 if (! config.getValue("session.xineramaSupport.windowSnapping",
1278 resource.xinerama_snap))
1279 resource.xinerama_snap = false;
1280 #endif // XINERAMA
1281 }
1282
1283
1284 void Blackbox::reconfigure(void) {
1285 // don't reconfigure while saving the initial rc file, it's a waste and it
1286 // breaks somethings (workspace names)
1287 if (isStartup()) return;
1288
1289 reconfigure_wait = True;
1290
1291 if (! timer->isTiming()) timer->start();
1292 }
1293
1294
1295 void Blackbox::real_reconfigure(void) {
1296 load_rc();
1297
1298 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1299 PointerAssassin());
1300 menuTimestamps.clear();
1301
1302 gcCache()->purge();
1303
1304 std::for_each(screenList.begin(), screenList.end(),
1305 std::mem_fun(&BScreen::reconfigure));
1306 }
1307
1308
1309 void Blackbox::checkMenu(void) {
1310 bool reread = False;
1311 MenuTimestampList::iterator it = menuTimestamps.begin();
1312 for(; it != menuTimestamps.end(); ++it) {
1313 MenuTimestamp *tmp = *it;
1314 struct stat buf;
1315
1316 if (! stat(tmp->filename.c_str(), &buf)) {
1317 if (tmp->timestamp != buf.st_ctime)
1318 reread = True;
1319 } else {
1320 reread = True;
1321 }
1322 }
1323
1324 if (reread) rereadMenu();
1325 }
1326
1327
1328 void Blackbox::rereadMenu(void) {
1329 reread_menu_wait = True;
1330
1331 if (! timer->isTiming()) timer->start();
1332 }
1333
1334
1335 void Blackbox::real_rereadMenu(void) {
1336 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1337 PointerAssassin());
1338 menuTimestamps.clear();
1339
1340 std::for_each(screenList.begin(), screenList.end(),
1341 std::mem_fun(&BScreen::rereadMenu));
1342 }
1343
1344
1345 void Blackbox::saveStyleFilename(const string& filename) {
1346 assert(! filename.empty());
1347 resource.style_file = filename;
1348 config.setValue("session.styleFile", resource.style_file);
1349 }
1350
1351
1352 void Blackbox::addMenuTimestamp(const string& filename) {
1353 assert(! filename.empty());
1354 bool found = False;
1355
1356 MenuTimestampList::iterator it = menuTimestamps.begin();
1357 for (; it != menuTimestamps.end() && ! found; ++it) {
1358 if ((*it)->filename == filename) found = True;
1359 }
1360 if (! found) {
1361 struct stat buf;
1362
1363 if (! stat(filename.c_str(), &buf)) {
1364 MenuTimestamp *ts = new MenuTimestamp;
1365
1366 ts->filename = filename;
1367 ts->timestamp = buf.st_ctime;
1368
1369 menuTimestamps.push_back(ts);
1370 }
1371 }
1372 }
1373
1374
1375 void Blackbox::timeout(void) {
1376 if (reconfigure_wait)
1377 real_reconfigure();
1378
1379 if (reread_menu_wait)
1380 real_rereadMenu();
1381
1382 reconfigure_wait = reread_menu_wait = False;
1383 }
1384
1385
1386 void Blackbox::setChangingWindow(BlackboxWindow *win) {
1387 // make sure one of the two is null and the other isn't
1388 assert((! changing_window && win) || (! win && changing_window));
1389 changing_window = win;
1390 }
1391
1392
1393 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1394 if (focused_window && focused_window == win) // nothing to do
1395 return;
1396
1397 BScreen *old_screen = 0;
1398
1399 if (focused_window) {
1400 focused_window->setFocusFlag(False);
1401 old_screen = focused_window->getScreen();
1402 }
1403
1404 if (win && ! win->isIconic()) {
1405 // the active screen is the one with the last focused window...
1406 // this will keep focus on this screen no matter where the mouse goes,
1407 // so multihead keybindings will continue to work on that screen until the
1408 // user focuses a window on a different screen.
1409 active_screen = win->getScreen();
1410 focused_window = win;
1411 } else {
1412 focused_window = 0;
1413 if (! old_screen) {
1414 if (active_screen) {
1415 // set input focus to the toolbar of the screen with mouse
1416 XSetInputFocus(getXDisplay(),
1417 active_screen->getRootWindow(),
1418 RevertToPointerRoot, CurrentTime);
1419 } else {
1420 // set input focus to the toolbar of the first managed screen
1421 XSetInputFocus(getXDisplay(),
1422 screenList.front()->getRootWindow(),
1423 RevertToPointerRoot, CurrentTime);
1424 }
1425 } else {
1426 // set input focus to the toolbar of the last screen
1427 XSetInputFocus(getXDisplay(), old_screen->getRootWindow(),
1428 RevertToPointerRoot, CurrentTime);
1429 }
1430 }
1431
1432 if (active_screen && active_screen->isScreenManaged()) {
1433 active_screen->getToolbar()->redrawWindowLabel(True);
1434 active_screen->updateNetizenWindowFocus();
1435 }
1436
1437 if (old_screen && old_screen != active_screen) {
1438 old_screen->getToolbar()->redrawWindowLabel(True);
1439 old_screen->updateNetizenWindowFocus();
1440 }
1441 }
This page took 0.096024 seconds and 5 git commands to generate.