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