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