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