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