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