]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
cdc7137a0b07291674e1c6aa37af67e723fb0ddb
[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->getWorkspaceNumber() != screen->getCurrentWorkspaceID())
726 screen->changeWorkspaceID(win->getWorkspaceNumber());
727 if (win->isVisible() && win->setInputFocus()) {
728 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
729 raiseWindow(win);
730 win->installColormap(True);
731 }
732 }
733 } else if (e->xclient.message_type ==
734 xatom->getAtom(XAtom::blackbox_cycle_window_focus)) {
735 // BLACKBOX_CYCLE_WINDOW_FOCUS
736 BScreen *screen = searchScreen(e->xclient.window);
737
738 if (screen) {
739 if (! e->xclient.data.l[0])
740 screen->prevFocus();
741 else
742 screen->nextFocus();
743 }
744 } else if (e->xclient.message_type ==
745 xatom->getAtom(XAtom::net_wm_desktop)) {
746 // NET_WM_DESKTOP
747 BlackboxWindow *win = searchWindow(e->xclient.window);
748
749 if (win) {
750 BScreen *screen = win->getScreen();
751 unsigned long wksp = (unsigned) e->xclient.data.l[0];
752 if (wksp < screen->getWorkspaceCount()) {
753 if (win->isIconic()) win->deiconify(False, True);
754 if (win->isStuck()) win->stick();
755 if (wksp != screen->getCurrentWorkspaceID())
756 win->withdraw();
757 else
758 win->show();
759 screen->reassociateWindow(win, wksp, True);
760 } else if (wksp == 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
761 wksp == 0xffffffff) {
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 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
789 } else if (e->xclient.message_type ==
790 xatom->getAtom(XAtom::net_close_window)) {
791 // NET_CLOSE_WINDOW
792 BlackboxWindow *win = searchWindow(e->xclient.window);
793 if (win && win->validateClient())
794 win->close(); // could this be smarter?
795 } else if (e->xclient.message_type ==
796 xatom->getAtom(XAtom::net_wm_moveresize)) {
797 // NET_WM_MOVERESIZE
798 BlackboxWindow *win = searchWindow(e->xclient.window);
799 if (win && win->validateClient()) {
800 int x_root = e->xclient.data.l[0],
801 y_root = e->xclient.data.l[1];
802 if ((Atom) e->xclient.data.l[2] ==
803 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
804 win->beginMove(x_root, y_root);
805 } else {
806 if ((Atom) e->xclient.data.l[2] ==
807 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
808 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
809 else if ((Atom) e->xclient.data.l[2] ==
810 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
811 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
812 else if ((Atom) e->xclient.data.l[2] ==
813 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
814 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
815 else if ((Atom) e->xclient.data.l[2] ==
816 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
817 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
818 }
819 }
820 } else if (e->xclient.message_type ==
821 xatom->getAtom(XAtom::net_wm_state)) {
822 // NET_WM_STATE
823 BlackboxWindow *win = searchWindow(e->xclient.window);
824 if (win && win->validateClient()) {
825 const Atom action = (Atom) e->xclient.data.l[0];
826 const Atom state[] = { (Atom) e->xclient.data.l[1],
827 (Atom) e->xclient.data.l[2] };
828
829 for (int i = 0; i < 2; ++i) {
830 if (! state[i])
831 continue;
832
833 if ((Atom) e->xclient.data.l[0] == 1) {
834 // ADD
835 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
836 win->setModal(True);
837 } else if (state[i] ==
838 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
839 if (win->isMaximizedHoriz()) {
840 win->maximize(0); // unmaximize
841 win->maximize(1); // full
842 } else if (! win->isMaximized()) {
843 win->maximize(2); // vert
844 }
845 } else if (state[i] ==
846 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
847 if (win->isMaximizedVert()) {
848 win->maximize(0); // unmaximize
849 win->maximize(1); // full
850 } else if (! win->isMaximized()) {
851 win->maximize(3); // horiz
852 }
853 } else if (state[i] ==
854 xatom->getAtom(XAtom::net_wm_state_shaded)) {
855 if (! win->isShaded())
856 win->shade();
857 } else if (state[i] ==
858 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
859 win->setSkipTaskbar(True);
860 } else if (state[i] ==
861 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
862 win->setSkipPager(True);
863 } else if (state[i] ==
864 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
865 win->setFullscreen(True);
866 }
867 } else if (action == 0) {
868 // REMOVE
869 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
870 win->setModal(False);
871 } else if (state[i] ==
872 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
873 if (win->isMaximizedFull()) {
874 win->maximize(0); // unmaximize
875 win->maximize(3); // horiz
876 } else if (win->isMaximizedVert()) {
877 win->maximize(0); // unmaximize
878 }
879 } else if (state[i] ==
880 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
881 if (win->isMaximizedFull()) {
882 win->maximize(0); // unmaximize
883 win->maximize(2); // vert
884 } else if (win->isMaximizedHoriz()) {
885 win->maximize(0); // unmaximize
886 }
887 } else if (state[i] ==
888 xatom->getAtom(XAtom::net_wm_state_shaded)) {
889 if (win->isShaded())
890 win->shade();
891 } else if (state[i] ==
892 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
893 win->setSkipTaskbar(False);
894 } else if (state[i] ==
895 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
896 win->setSkipPager(False);
897 } else if (state[i] ==
898 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
899 win->setFullscreen(False);
900 }
901 } else if (action == 2) {
902 // TOGGLE
903 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
904 win->setModal(! win->isModal());
905 } else if (state[i] ==
906 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
907 if (win->isMaximizedFull()) {
908 win->maximize(0); // unmaximize
909 win->maximize(3); // horiz
910 } else if (win->isMaximizedVert()) {
911 win->maximize(0); // unmaximize
912 } else if (win->isMaximizedHoriz()) {
913 win->maximize(0); // unmaximize
914 win->maximize(1); // full
915 } else {
916 win->maximize(2); // vert
917 }
918 } else if (state[i] ==
919 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
920 if (win->isMaximizedFull()) {
921 win->maximize(0); // unmaximize
922 win->maximize(2); // vert
923 } else if (win->isMaximizedHoriz()) {
924 win->maximize(0); // unmaximize
925 } else if (win->isMaximizedVert()) {
926 win->maximize(0); // unmaximize
927 win->maximize(1); // full
928 } else {
929 win->maximize(3); // horiz
930 }
931 } else if (state[i] ==
932 xatom->getAtom(XAtom::net_wm_state_shaded)) {
933 win->shade();
934 } else if (state[i] ==
935 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
936 win->setSkipTaskbar(! win->skipTaskbar());
937 } else if (state[i] ==
938 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
939 win->setSkipPager(! win->skipPager());
940 } else if (state[i] ==
941 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
942 win->setFullscreen(! win->isFullscreen());
943 }
944 }
945 }
946 }
947 }
948 }
949
950 break;
951 }
952
953 case NoExpose:
954 case ConfigureNotify:
955 case MapNotify:
956 break; // not handled, just ignore
957
958 default: {
959 #ifdef SHAPE
960 if (e->type == getShapeEventBase()) {
961 XShapeEvent *shape_event = (XShapeEvent *) e;
962 BlackboxWindow *win = searchWindow(e->xany.window);
963
964 if (win)
965 win->shapeEvent(shape_event);
966 }
967 #endif // SHAPE
968 }
969 } // switch
970 }
971
972
973 bool Blackbox::handleSignal(int sig) {
974 switch (sig) {
975 case SIGHUP:
976 reconfigure();
977 break;
978
979 case SIGUSR1:
980 restart();
981 break;
982
983 case SIGUSR2:
984 rereadMenu();
985 break;
986
987 case SIGPIPE:
988 case SIGSEGV:
989 case SIGFPE:
990 case SIGINT:
991 case SIGTERM:
992 shutdown();
993
994 default:
995 return False;
996 }
997
998 return True;
999 }
1000
1001
1002 bool Blackbox::validateWindow(Window window) {
1003 XEvent event;
1004 if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
1005 XPutBackEvent(getXDisplay(), &event);
1006
1007 return False;
1008 }
1009
1010 return True;
1011 }
1012
1013
1014 BScreen *Blackbox::searchScreen(Window window) {
1015 ScreenList::iterator it = screenList.begin();
1016
1017 for (; it != screenList.end(); ++it) {
1018 BScreen *s = *it;
1019 if (s->getRootWindow() == window)
1020 return s;
1021 }
1022
1023 return (BScreen *) 0;
1024 }
1025
1026
1027 BScreen *Blackbox::searchSystrayWindow(Window window) {
1028 WindowScreenLookup::iterator it = systraySearchList.find(window);
1029 if (it != systraySearchList.end())
1030 return it->second;
1031
1032 return (BScreen*) 0;
1033 }
1034
1035
1036 BlackboxWindow *Blackbox::searchWindow(Window window) {
1037 WindowLookup::iterator it = windowSearchList.find(window);
1038 if (it != windowSearchList.end())
1039 return it->second;
1040
1041 return (BlackboxWindow*) 0;
1042 }
1043
1044
1045 BWindowGroup *Blackbox::searchGroup(Window window) {
1046 GroupLookup::iterator it = groupSearchList.find(window);
1047 if (it != groupSearchList.end())
1048 return it->second;
1049
1050 return (BWindowGroup *) 0;
1051 }
1052
1053
1054 Basemenu *Blackbox::searchMenu(Window window) {
1055 MenuLookup::iterator it = menuSearchList.find(window);
1056 if (it != menuSearchList.end())
1057 return it->second;
1058
1059 return (Basemenu*) 0;
1060 }
1061
1062
1063 Toolbar *Blackbox::searchToolbar(Window window) {
1064 ToolbarLookup::iterator it = toolbarSearchList.find(window);
1065 if (it != toolbarSearchList.end())
1066 return it->second;
1067
1068 return (Toolbar*) 0;
1069 }
1070
1071
1072 Slit *Blackbox::searchSlit(Window window) {
1073 SlitLookup::iterator it = slitSearchList.find(window);
1074 if (it != slitSearchList.end())
1075 return it->second;
1076
1077 return (Slit*) 0;
1078 }
1079
1080
1081 void Blackbox::saveSystrayWindowSearch(Window window, BScreen *screen) {
1082 systraySearchList.insert(WindowScreenLookupPair(window, screen));
1083 }
1084
1085
1086 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
1087 windowSearchList.insert(WindowLookupPair(window, data));
1088 }
1089
1090
1091 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
1092 groupSearchList.insert(GroupLookupPair(window, data));
1093 }
1094
1095
1096 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
1097 menuSearchList.insert(MenuLookupPair(window, data));
1098 }
1099
1100
1101 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
1102 toolbarSearchList.insert(ToolbarLookupPair(window, data));
1103 }
1104
1105
1106 void Blackbox::saveSlitSearch(Window window, Slit *data) {
1107 slitSearchList.insert(SlitLookupPair(window, data));
1108 }
1109
1110
1111 void Blackbox::removeSystrayWindowSearch(Window window) {
1112 systraySearchList.erase(window);
1113 }
1114
1115
1116 void Blackbox::removeWindowSearch(Window window) {
1117 windowSearchList.erase(window);
1118 }
1119
1120
1121 void Blackbox::removeGroupSearch(Window window) {
1122 groupSearchList.erase(window);
1123 }
1124
1125
1126 void Blackbox::removeMenuSearch(Window window) {
1127 menuSearchList.erase(window);
1128 }
1129
1130
1131 void Blackbox::removeToolbarSearch(Window window) {
1132 toolbarSearchList.erase(window);
1133 }
1134
1135
1136 void Blackbox::removeSlitSearch(Window window) {
1137 slitSearchList.erase(window);
1138 }
1139
1140
1141 void Blackbox::restart(const char *prog) {
1142 shutdown();
1143
1144 if (prog) {
1145 putenv(const_cast<char *>(screenList.front()->displayString().c_str()));
1146 execlp(prog, prog, NULL);
1147 perror(prog);
1148 }
1149
1150 // fall back in case the above execlp doesn't work
1151 execvp(argv[0], argv);
1152 string name = basename(argv[0]);
1153 execvp(name.c_str(), argv);
1154 }
1155
1156
1157 void Blackbox::shutdown(void) {
1158 BaseDisplay::shutdown();
1159
1160 XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
1161
1162 std::for_each(screenList.begin(), screenList.end(),
1163 std::mem_fun(&BScreen::shutdown));
1164
1165 XSync(getXDisplay(), False);
1166 }
1167
1168
1169 #ifdef XINERAMA
1170 void Blackbox::saveXineramaPlacement(bool x) {
1171 resource.xinerama_placement = x;
1172 config.setValue("session.xineramaSupport.windowPlacement",
1173 resource.xinerama_placement);
1174 reconfigure(); // make sure all screens get this change
1175 }
1176
1177
1178 void Blackbox::saveXineramaMaximizing(bool x) {
1179 resource.xinerama_maximize = x;
1180 config.setValue("session.xineramaSupport.windowMaximizing",
1181 resource.xinerama_maximize);
1182 reconfigure(); // make sure all screens get this change
1183 }
1184
1185
1186 void Blackbox::saveXineramaSnapping(bool x) {
1187 resource.xinerama_snap = x;
1188 config.setValue("session.xineramaSupport.windowSnapping",
1189 resource.xinerama_snap);
1190 reconfigure(); // make sure all screens get this change
1191 }
1192 #endif // XINERAMA
1193
1194
1195 /*
1196 * Save all values as they are so that the defaults will be written to the rc
1197 * file
1198 */
1199 void Blackbox::save_rc(void) {
1200 config.setAutoSave(false);
1201
1202 config.setValue("session.colorsPerChannel", resource.colors_per_channel);
1203 config.setValue("session.doubleClickInterval",
1204 resource.double_click_interval);
1205 config.setValue("session.autoRaiseDelay",
1206 ((resource.auto_raise_delay.tv_sec * 1000) +
1207 (resource.auto_raise_delay.tv_usec / 1000)));
1208 config.setValue("session.cacheLife", resource.cache_life / 60000);
1209 config.setValue("session.cacheMax", resource.cache_max);
1210 config.setValue("session.styleFile", resource.style_file);
1211 config.setValue("session.titlebarLayout", resource.titlebar_layout);
1212
1213 #ifdef XINERAMA
1214 saveXineramaPlacement(resource.xinerama_placement);
1215 saveXineramaMaximizing(resource.xinerama_maximize);
1216 saveXineramaSnapping(resource.xinerama_snap);
1217 #endif // XINERAMA
1218
1219 std::for_each(screenList.begin(), screenList.end(),
1220 std::mem_fun(&BScreen::save_rc));
1221
1222 config.setAutoSave(true);
1223 config.save();
1224 }
1225
1226
1227 void Blackbox::load_rc(void) {
1228 if (! config.load())
1229 config.create();
1230
1231 string s;
1232
1233 if (! config.getValue("session.colorsPerChannel",
1234 resource.colors_per_channel))
1235 resource.colors_per_channel = 4;
1236 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1237 else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1238
1239 if (config.getValue("session.styleFile", s))
1240 resource.style_file = expandTilde(s);
1241 else
1242 resource.style_file = DEFAULTSTYLE;
1243
1244 if (! config.getValue("session.doubleClickInterval",
1245 resource.double_click_interval));
1246 resource.double_click_interval = 250;
1247
1248 if (! config.getValue("session.autoRaiseDelay",
1249 resource.auto_raise_delay.tv_usec))
1250 resource.auto_raise_delay.tv_usec = 400;
1251 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1252 resource.auto_raise_delay.tv_usec -=
1253 (resource.auto_raise_delay.tv_sec * 1000);
1254 resource.auto_raise_delay.tv_usec *= 1000;
1255
1256 if (! config.getValue("session.cacheLife", resource.cache_life))
1257 resource.cache_life = 5;
1258 resource.cache_life *= 60000;
1259
1260 if (! config.getValue("session.cacheMax", resource.cache_max))
1261 resource.cache_max = 200;
1262
1263 if (! config.getValue("session.titlebarLayout", resource.titlebar_layout))
1264 resource.titlebar_layout = "ILMC";
1265
1266 #ifdef XINERAMA
1267 if (! config.getValue("session.xineramaSupport.windowPlacement",
1268 resource.xinerama_placement))
1269 resource.xinerama_placement = false;
1270
1271 if (! config.getValue("session.xineramaSupport.windowMaximizing",
1272 resource.xinerama_maximize))
1273 resource.xinerama_maximize = false;
1274
1275 if (! config.getValue("session.xineramaSupport.windowSnapping",
1276 resource.xinerama_snap))
1277 resource.xinerama_snap = false;
1278 #endif // XINERAMA
1279 }
1280
1281
1282 void Blackbox::reconfigure(void) {
1283 // don't reconfigure while saving the initial rc file, it's a waste and it
1284 // breaks somethings (workspace names)
1285 if (isStartup()) return;
1286
1287 reconfigure_wait = True;
1288
1289 if (! timer->isTiming()) timer->start();
1290 }
1291
1292
1293 void Blackbox::real_reconfigure(void) {
1294 load_rc();
1295
1296 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1297 PointerAssassin());
1298 menuTimestamps.clear();
1299
1300 gcCache()->purge();
1301
1302 std::for_each(screenList.begin(), screenList.end(),
1303 std::mem_fun(&BScreen::reconfigure));
1304 }
1305
1306
1307 void Blackbox::checkMenu(void) {
1308 bool reread = False;
1309 MenuTimestampList::iterator it = menuTimestamps.begin();
1310 for(; it != menuTimestamps.end(); ++it) {
1311 MenuTimestamp *tmp = *it;
1312 struct stat buf;
1313
1314 if (! stat(tmp->filename.c_str(), &buf)) {
1315 if (tmp->timestamp != buf.st_ctime)
1316 reread = True;
1317 } else {
1318 reread = True;
1319 }
1320 }
1321
1322 if (reread) rereadMenu();
1323 }
1324
1325
1326 void Blackbox::rereadMenu(void) {
1327 reread_menu_wait = True;
1328
1329 if (! timer->isTiming()) timer->start();
1330 }
1331
1332
1333 void Blackbox::real_rereadMenu(void) {
1334 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1335 PointerAssassin());
1336 menuTimestamps.clear();
1337
1338 std::for_each(screenList.begin(), screenList.end(),
1339 std::mem_fun(&BScreen::rereadMenu));
1340 }
1341
1342
1343 void Blackbox::saveStyleFilename(const string& filename) {
1344 assert(! filename.empty());
1345 resource.style_file = filename;
1346 config.setValue("session.styleFile", resource.style_file);
1347 }
1348
1349
1350 void Blackbox::addMenuTimestamp(const string& filename) {
1351 assert(! filename.empty());
1352 bool found = False;
1353
1354 MenuTimestampList::iterator it = menuTimestamps.begin();
1355 for (; it != menuTimestamps.end() && ! found; ++it) {
1356 if ((*it)->filename == filename) found = True;
1357 }
1358 if (! found) {
1359 struct stat buf;
1360
1361 if (! stat(filename.c_str(), &buf)) {
1362 MenuTimestamp *ts = new MenuTimestamp;
1363
1364 ts->filename = filename;
1365 ts->timestamp = buf.st_ctime;
1366
1367 menuTimestamps.push_back(ts);
1368 }
1369 }
1370 }
1371
1372
1373 void Blackbox::timeout(void) {
1374 if (reconfigure_wait)
1375 real_reconfigure();
1376
1377 if (reread_menu_wait)
1378 real_rereadMenu();
1379
1380 reconfigure_wait = reread_menu_wait = False;
1381 }
1382
1383
1384 void Blackbox::setChangingWindow(BlackboxWindow *win) {
1385 // make sure one of the two is null and the other isn't
1386 assert((! changing_window && win) || (! win && changing_window));
1387 changing_window = win;
1388 }
1389
1390
1391 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1392 if (focused_window && focused_window == win) // nothing to do
1393 return;
1394
1395 BScreen *old_screen = 0;
1396
1397 if (focused_window) {
1398 focused_window->setFocusFlag(False);
1399 old_screen = focused_window->getScreen();
1400 }
1401
1402 if (win && ! win->isIconic()) {
1403 // the active screen is the one with the last focused window...
1404 // this will keep focus on this screen no matter where the mouse goes,
1405 // so multihead keybindings will continue to work on that screen until the
1406 // user focuses a window on a different screen.
1407 active_screen = win->getScreen();
1408 focused_window = win;
1409 } else {
1410 focused_window = 0;
1411 if (! old_screen) {
1412 if (active_screen) {
1413 // set input focus to the toolbar of the screen with mouse
1414 XSetInputFocus(getXDisplay(),
1415 active_screen->getRootWindow(),
1416 RevertToPointerRoot, CurrentTime);
1417 } else {
1418 // set input focus to the toolbar of the first managed screen
1419 XSetInputFocus(getXDisplay(),
1420 screenList.front()->getRootWindow(),
1421 RevertToPointerRoot, CurrentTime);
1422 }
1423 } else {
1424 // set input focus to the toolbar of the last screen
1425 XSetInputFocus(getXDisplay(), old_screen->getRootWindow(),
1426 RevertToPointerRoot, CurrentTime);
1427 }
1428 }
1429
1430 if (active_screen && active_screen->isScreenManaged()) {
1431 active_screen->getToolbar()->redrawWindowLabel(True);
1432 active_screen->updateNetizenWindowFocus();
1433 }
1434
1435 if (old_screen && old_screen != active_screen) {
1436 old_screen->getToolbar()->redrawWindowLabel(True);
1437 old_screen->updateNetizenWindowFocus();
1438 }
1439 }
This page took 0.098769 seconds and 3 git commands to generate.