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