]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
redecorating fixups. sync with bb cvs.
[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 <algorithm>
94 #include <string>
95 using std::string;
96
97 #include "i18n.hh"
98 #include "blackbox.hh"
99 #include "Basemenu.hh"
100 #include "Clientmenu.hh"
101 #include "GCCache.hh"
102 #include "Image.hh"
103 #include "Rootmenu.hh"
104 #include "Screen.hh"
105 #include "Slit.hh"
106 #include "Toolbar.hh"
107 #include "Util.hh"
108 #include "Window.hh"
109 #include "Workspace.hh"
110 #include "Workspacemenu.hh"
111 #include "XAtom.hh"
112
113 // X event scanner for enter/leave notifies - adapted from twm
114 struct scanargs {
115 Window w;
116 bool leave, inferior, enter;
117 };
118
119 static Bool queueScanner(Display *, XEvent *e, char *args) {
120 scanargs *scan = (scanargs *) args;
121 if ((e->type == LeaveNotify) &&
122 (e->xcrossing.window == scan->w) &&
123 (e->xcrossing.mode == NotifyNormal)) {
124 scan->leave = True;
125 scan->inferior = (e->xcrossing.detail == NotifyInferior);
126 } else if ((e->type == EnterNotify) && (e->xcrossing.mode == NotifyUngrab)) {
127 scan->enter = True;
128 }
129
130 return False;
131 }
132
133 Blackbox *blackbox;
134
135
136 Blackbox::Blackbox(char **m_argv, char *dpy_name, char *rc, char *menu)
137 : BaseDisplay(m_argv[0], dpy_name) {
138 if (! XSupportsLocale())
139 fprintf(stderr, "X server does not support locale\n");
140
141 if (XSetLocaleModifiers("") == NULL)
142 fprintf(stderr, "cannot set locale modifiers\n");
143
144 ::blackbox = this;
145 argv = m_argv;
146 if (! rc) rc = "~/.openbox/rc";
147 rc_file = expandTilde(rc);
148 config.setFile(rc_file);
149 if (! menu) menu = "~/.openbox/menu";
150 menu_file = expandTilde(menu);
151
152 no_focus = False;
153
154 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
155
156 active_screen = 0;
157 focused_window = (BlackboxWindow *) 0;
158
159 XrmInitialize();
160 load_rc();
161
162 xatom = new XAtom(this);
163
164 cursor.session = XCreateFontCursor(getXDisplay(), XC_left_ptr);
165 cursor.move = XCreateFontCursor(getXDisplay(), XC_fleur);
166 cursor.ll_angle = XCreateFontCursor(getXDisplay(), XC_ll_angle);
167 cursor.lr_angle = XCreateFontCursor(getXDisplay(), XC_lr_angle);
168
169 for (unsigned int i = 0; i < getNumberOfScreens(); i++) {
170 BScreen *screen = new BScreen(this, i);
171
172 if (! screen->isScreenManaged()) {
173 delete screen;
174 continue;
175 }
176
177 screenList.push_back(screen);
178 }
179
180 if (screenList.empty()) {
181 fprintf(stderr,
182 i18n(blackboxSet, blackboxNoManagableScreens,
183 "Blackbox::Blackbox: no managable screens found, aborting.\n"));
184 ::exit(3);
185 }
186
187 // save current settings and default values
188 save_rc();
189
190 // set the screen with mouse to the first managed screen
191 active_screen = screenList.front();
192 setFocusedWindow(0);
193
194 XSynchronize(getXDisplay(), False);
195 XSync(getXDisplay(), False);
196
197 reconfigure_wait = reread_menu_wait = False;
198
199 timer = new BTimer(this, this);
200 timer->setTimeout(0l);
201 }
202
203
204 Blackbox::~Blackbox(void) {
205 std::for_each(screenList.begin(), screenList.end(), PointerAssassin());
206
207 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
208 PointerAssassin());
209
210 delete xatom;
211
212 delete timer;
213 }
214
215
216 void Blackbox::process_event(XEvent *e) {
217 switch (e->type) {
218 case ButtonPress: {
219 // strip the lock key modifiers
220 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
221
222 last_time = e->xbutton.time;
223
224 BlackboxWindow *win = (BlackboxWindow *) 0;
225 Basemenu *menu = (Basemenu *) 0;
226 Slit *slit = (Slit *) 0;
227 Toolbar *tbar = (Toolbar *) 0;
228 BScreen *scrn = (BScreen *) 0;
229
230 if ((win = searchWindow(e->xbutton.window))) {
231 win->buttonPressEvent(&e->xbutton);
232
233 /* XXX: is this sane on low colour desktops? */
234 if (e->xbutton.button == 1)
235 win->installColormap(True);
236 } else if ((menu = searchMenu(e->xbutton.window))) {
237 menu->buttonPressEvent(&e->xbutton);
238 } else if ((slit = searchSlit(e->xbutton.window))) {
239 slit->buttonPressEvent(&e->xbutton);
240 } else if ((tbar = searchToolbar(e->xbutton.window))) {
241 tbar->buttonPressEvent(&e->xbutton);
242 } else if ((scrn = searchScreen(e->xbutton.window))) {
243 scrn->buttonPressEvent(&e->xbutton);
244 if (active_screen != scrn) {
245 active_screen = scrn;
246 // first, set no focus window on the old screen
247 setFocusedWindow(0);
248 // and move focus to this screen
249 setFocusedWindow(0);
250 }
251 }
252 break;
253 }
254
255 case ButtonRelease: {
256 // strip the lock key modifiers
257 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
258
259 last_time = e->xbutton.time;
260
261 BlackboxWindow *win = (BlackboxWindow *) 0;
262 Basemenu *menu = (Basemenu *) 0;
263 Toolbar *tbar = (Toolbar *) 0;
264
265 if ((win = searchWindow(e->xbutton.window)))
266 win->buttonReleaseEvent(&e->xbutton);
267 else if ((menu = searchMenu(e->xbutton.window)))
268 menu->buttonReleaseEvent(&e->xbutton);
269 else if ((tbar = searchToolbar(e->xbutton.window)))
270 tbar->buttonReleaseEvent(&e->xbutton);
271
272 break;
273 }
274
275 case ConfigureRequest: {
276 // compress configure requests...
277 XEvent realevent;
278 unsigned int i = 0;
279 while(XCheckTypedWindowEvent(getXDisplay(), e->xconfigurerequest.window,
280 ConfigureRequest, &realevent)) {
281 i++;
282 }
283 if ( i > 0 )
284 e = &realevent;
285
286 BlackboxWindow *win = (BlackboxWindow *) 0;
287 Slit *slit = (Slit *) 0;
288
289 if ((win = searchWindow(e->xconfigurerequest.window))) {
290 win->configureRequestEvent(&e->xconfigurerequest);
291 } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
292 slit->configureRequestEvent(&e->xconfigurerequest);
293 } else {
294 if (validateWindow(e->xconfigurerequest.window)) {
295 XWindowChanges xwc;
296
297 xwc.x = e->xconfigurerequest.x;
298 xwc.y = e->xconfigurerequest.y;
299 xwc.width = e->xconfigurerequest.width;
300 xwc.height = e->xconfigurerequest.height;
301 xwc.border_width = e->xconfigurerequest.border_width;
302 xwc.sibling = e->xconfigurerequest.above;
303 xwc.stack_mode = e->xconfigurerequest.detail;
304
305 XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
306 e->xconfigurerequest.value_mask, &xwc);
307 }
308 }
309
310 break;
311 }
312
313 case MapRequest: {
314 #ifdef DEBUG
315 fprintf(stderr, "Blackbox::process_event(): MapRequest for 0x%lx\n",
316 e->xmaprequest.window);
317 #endif // DEBUG
318
319 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
320
321 if (! win) {
322 BScreen *screen = searchScreen(e->xmaprequest.parent);
323
324 if (! screen) {
325 /*
326 we got a map request for a window who's parent isn't root. this
327 can happen in only one circumstance:
328
329 a client window unmapped a managed window, and then remapped it
330 somewhere between unmapping the client window and reparenting it
331 to root.
332
333 regardless of how it happens, we need to find the screen that
334 the window is on
335 */
336 XWindowAttributes wattrib;
337 if (! XGetWindowAttributes(getXDisplay(), e->xmaprequest.window,
338 &wattrib)) {
339 // failed to get the window attributes, perhaps the window has
340 // now been destroyed?
341 break;
342 }
343
344 screen = searchScreen(wattrib.root);
345 assert(screen != 0); // this should never happen
346 }
347
348 screen->manageWindow(e->xmaprequest.window);
349 }
350
351 break;
352 }
353
354 case UnmapNotify: {
355 BlackboxWindow *win = (BlackboxWindow *) 0;
356 Slit *slit = (Slit *) 0;
357
358 if ((win = searchWindow(e->xunmap.window))) {
359 win->unmapNotifyEvent(&e->xunmap);
360 } else if ((slit = searchSlit(e->xunmap.window))) {
361 slit->unmapNotifyEvent(&e->xunmap);
362 }
363
364 break;
365 }
366
367 case DestroyNotify: {
368 BlackboxWindow *win = (BlackboxWindow *) 0;
369 Slit *slit = (Slit *) 0;
370 BWindowGroup *group = (BWindowGroup *) 0;
371
372 if ((win = searchWindow(e->xdestroywindow.window))) {
373 win->destroyNotifyEvent(&e->xdestroywindow);
374 } else if ((slit = searchSlit(e->xdestroywindow.window))) {
375 slit->removeClient(e->xdestroywindow.window, False);
376 } else if ((group = searchGroup(e->xdestroywindow.window))) {
377 delete group;
378 }
379
380 break;
381 }
382
383 case ReparentNotify: {
384 /*
385 this event is quite rare and is usually handled in unmapNotify
386 however, if the window is unmapped when the reparent event occurs
387 the window manager never sees it because an unmap event is not sent
388 to an already unmapped window.
389 */
390 BlackboxWindow *win = searchWindow(e->xreparent.window);
391 if (win) {
392 win->reparentNotifyEvent(&e->xreparent);
393 } else {
394 Slit *slit = searchSlit(e->xreparent.window);
395 if (slit && slit->getWindowID() != e->xreparent.parent)
396 slit->removeClient(e->xreparent.window, True);
397 }
398 break;
399 }
400
401 case MotionNotify: {
402 // motion notify compression...
403 XEvent realevent;
404 unsigned int i = 0;
405 while (XCheckTypedWindowEvent(getXDisplay(), e->xmotion.window,
406 MotionNotify, &realevent)) {
407 i++;
408 }
409
410 // if we have compressed some motion events, use the last one
411 if ( i > 0 )
412 e = &realevent;
413
414 // strip the lock key modifiers
415 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
416
417 last_time = e->xmotion.time;
418
419 BlackboxWindow *win = (BlackboxWindow *) 0;
420 Basemenu *menu = (Basemenu *) 0;
421
422 if ((win = searchWindow(e->xmotion.window)))
423 win->motionNotifyEvent(&e->xmotion);
424 else if ((menu = searchMenu(e->xmotion.window)))
425 menu->motionNotifyEvent(&e->xmotion);
426
427 break;
428 }
429
430 case PropertyNotify: {
431 last_time = e->xproperty.time;
432
433 if (e->xproperty.state != PropertyDelete) {
434 BlackboxWindow *win = searchWindow(e->xproperty.window);
435
436 if (win)
437 win->propertyNotifyEvent(e->xproperty.atom);
438 }
439
440 break;
441 }
442
443 case EnterNotify: {
444 last_time = e->xcrossing.time;
445
446 BScreen *screen = (BScreen *) 0;
447 BlackboxWindow *win = (BlackboxWindow *) 0;
448 Basemenu *menu = (Basemenu *) 0;
449 Toolbar *tbar = (Toolbar *) 0;
450 Slit *slit = (Slit *) 0;
451
452 if (e->xcrossing.mode == NotifyGrab) break;
453
454 XEvent dummy;
455 scanargs sa;
456 sa.w = e->xcrossing.window;
457 sa.enter = sa.leave = False;
458 XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
459
460 if ((e->xcrossing.window == e->xcrossing.root) &&
461 (screen = searchScreen(e->xcrossing.window))) {
462 screen->getImageControl()->installRootColormap();
463 } else if ((win = searchWindow(e->xcrossing.window))) {
464 if (win->getScreen()->isSloppyFocus() &&
465 (! win->isFocused()) && (! no_focus)) {
466 if (((! sa.leave) || sa.inferior) && win->isVisible()) {
467 if (win->setInputFocus())
468 win->installColormap(True); // XXX: shouldnt we honour no install?
469 }
470 }
471 } else if ((menu = searchMenu(e->xcrossing.window))) {
472 menu->enterNotifyEvent(&e->xcrossing);
473 } else if ((tbar = searchToolbar(e->xcrossing.window))) {
474 tbar->enterNotifyEvent(&e->xcrossing);
475 } else if ((slit = searchSlit(e->xcrossing.window))) {
476 slit->enterNotifyEvent(&e->xcrossing);
477 }
478 break;
479 }
480
481 case LeaveNotify: {
482 last_time = e->xcrossing.time;
483
484 BlackboxWindow *win = (BlackboxWindow *) 0;
485 Basemenu *menu = (Basemenu *) 0;
486 Toolbar *tbar = (Toolbar *) 0;
487 Slit *slit = (Slit *) 0;
488
489 if ((menu = searchMenu(e->xcrossing.window)))
490 menu->leaveNotifyEvent(&e->xcrossing);
491 else if ((win = searchWindow(e->xcrossing.window)))
492 win->installColormap(False);
493 else if ((tbar = searchToolbar(e->xcrossing.window)))
494 tbar->leaveNotifyEvent(&e->xcrossing);
495 else if ((slit = searchSlit(e->xcrossing.window)))
496 slit->leaveNotifyEvent(&e->xcrossing);
497 break;
498 }
499
500 case Expose: {
501 // compress expose events
502 XEvent realevent;
503 unsigned int i = 0;
504 int ex1, ey1, ex2, ey2;
505 ex1 = e->xexpose.x;
506 ey1 = e->xexpose.y;
507 ex2 = ex1 + e->xexpose.width - 1;
508 ey2 = ey1 + e->xexpose.height - 1;
509 while (XCheckTypedWindowEvent(getXDisplay(), e->xexpose.window,
510 Expose, &realevent)) {
511 i++;
512
513 // merge expose area
514 ex1 = std::min(realevent.xexpose.x, ex1);
515 ey1 = std::min(realevent.xexpose.y, ey1);
516 ex2 = std::max(realevent.xexpose.x + realevent.xexpose.width - 1, ex2);
517 ey2 = std::max(realevent.xexpose.y + realevent.xexpose.height - 1, ey2);
518 }
519 if ( i > 0 )
520 e = &realevent;
521
522 // use the merged area
523 e->xexpose.x = ex1;
524 e->xexpose.y = ey1;
525 e->xexpose.width = ex2 - ex1 + 1;
526 e->xexpose.height = ey2 - ey1 + 1;
527
528 BlackboxWindow *win = (BlackboxWindow *) 0;
529 Basemenu *menu = (Basemenu *) 0;
530 Toolbar *tbar = (Toolbar *) 0;
531
532 if ((win = searchWindow(e->xexpose.window)))
533 win->exposeEvent(&e->xexpose);
534 else if ((menu = searchMenu(e->xexpose.window)))
535 menu->exposeEvent(&e->xexpose);
536 else if ((tbar = searchToolbar(e->xexpose.window)))
537 tbar->exposeEvent(&e->xexpose);
538
539 break;
540 }
541
542 case KeyPress: {
543 Toolbar *tbar = searchToolbar(e->xkey.window);
544
545 if (tbar && tbar->isEditing())
546 tbar->keyPressEvent(&e->xkey);
547
548 break;
549 }
550
551 case ColormapNotify: {
552 BScreen *screen = searchScreen(e->xcolormap.window);
553
554 if (screen)
555 screen->setRootColormapInstalled((e->xcolormap.state ==
556 ColormapInstalled) ? True : False);
557
558 break;
559 }
560
561 case FocusIn: {
562 if (e->xfocus.detail != NotifyNonlinear &&
563 e->xfocus.detail != NotifyAncestor) {
564 /*
565 don't process FocusIns when:
566 1. the new focus window isn't an ancestor or inferior of the old
567 focus window (NotifyNonlinear)
568 make sure to allow the FocusIn when the old focus window was an
569 ancestor but didn't have a parent, such as root (NotifyAncestor)
570 */
571 break;
572 }
573
574 BlackboxWindow *win = searchWindow(e->xfocus.window);
575 if (win) {
576 if (! win->isFocused())
577 win->setFocusFlag(True);
578
579 /*
580 set the event window to None. when the FocusOut event handler calls
581 this function recursively, it uses this as an indication that focus
582 has moved to a known window.
583 */
584 e->xfocus.window = None;
585 }
586
587 break;
588 }
589
590 case FocusOut: {
591 if (e->xfocus.detail != NotifyNonlinear) {
592 /*
593 don't process FocusOuts when:
594 2. the new focus window isn't an ancestor or inferior of the old
595 focus window (NotifyNonlinear)
596 */
597 break;
598 }
599
600 BlackboxWindow *win = searchWindow(e->xfocus.window);
601 if (win && win->isFocused()) {
602 /*
603 before we mark "win" as unfocused, we need to verify that focus is
604 going to a known location, is in a known location, or set focus
605 to a known location.
606 */
607
608 XEvent event;
609 // don't check the current focus if FocusOut was generated during a grab
610 bool check_focus = (e->xfocus.mode == NotifyNormal);
611
612 /*
613 First, check if there is a pending FocusIn event waiting. if there
614 is, process it and determine if focus has moved to another window
615 (the FocusIn event handler sets the window in the event
616 structure to None to indicate this).
617 */
618 if (XCheckTypedEvent(getXDisplay(), FocusIn, &event)) {
619
620 process_event(&event);
621 if (event.xfocus.window == None) {
622 // focus has moved
623 check_focus = False;
624 }
625 }
626
627 if (check_focus) {
628 /*
629 Second, we query the X server for the current input focus.
630 to make sure that we keep a consistent state.
631 */
632 BlackboxWindow *focus;
633 Window w;
634 int revert;
635 XGetInputFocus(getXDisplay(), &w, &revert);
636 focus = searchWindow(w);
637 if (focus) {
638 /*
639 focus got from "win" to "focus" under some very strange
640 circumstances, and we need to make sure that the focus indication
641 is correct.
642 */
643 setFocusedWindow(focus);
644 } else {
645 // we have no idea where focus went... so we set it to somewhere
646 setFocusedWindow(0);
647 }
648 }
649 }
650
651 break;
652 }
653
654 case ClientMessage: {
655 if (e->xclient.format == 32) {
656 if (e->xclient.message_type == xatom->getAtom(XAtom::wm_change_state)) {
657 BlackboxWindow *win = searchWindow(e->xclient.window);
658 if (! win || ! win->validateClient()) return;
659
660 if (e->xclient.data.l[0] == IconicState)
661 win->iconify();
662 if (e->xclient.data.l[0] == NormalState)
663 win->deiconify();
664 } else if(e->xclient.message_type == getBlackboxChangeWorkspaceAtom()) {
665 BScreen *screen = searchScreen(e->xclient.window);
666
667 if (screen && e->xclient.data.l[0] >= 0 &&
668 e->xclient.data.l[0] <
669 static_cast<signed>(screen->getWorkspaceCount()))
670 screen->changeWorkspaceID(e->xclient.data.l[0]);
671 } else if (e->xclient.message_type == getBlackboxChangeWindowFocusAtom()) {
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 == getBlackboxCycleWindowFocusAtom()) {
677 BScreen *screen = searchScreen(e->xclient.window);
678
679 if (screen) {
680 if (! e->xclient.data.l[0])
681 screen->prevFocus();
682 else
683 screen->nextFocus();
684 }
685 } else if (e->xclient.message_type == getBlackboxChangeAttributesAtom()) {
686 BlackboxWindow *win = searchWindow(e->xclient.window);
687
688 if (win && win->validateClient()) {
689 BlackboxHints net;
690 net.flags = e->xclient.data.l[0];
691 net.attrib = e->xclient.data.l[1];
692 net.workspace = e->xclient.data.l[2];
693 net.stack = e->xclient.data.l[3];
694 net.decoration = e->xclient.data.l[4];
695
696 win->changeBlackboxHints(&net);
697 }
698 }
699 }
700
701 break;
702 }
703
704 case NoExpose:
705 case ConfigureNotify:
706 case MapNotify:
707 break; // not handled, just ignore
708
709 default: {
710 #ifdef SHAPE
711 if (e->type == getShapeEventBase()) {
712 XShapeEvent *shape_event = (XShapeEvent *) e;
713 BlackboxWindow *win = searchWindow(e->xany.window);
714
715 if (win)
716 win->shapeEvent(shape_event);
717 }
718 #endif // SHAPE
719 }
720 } // switch
721 }
722
723
724 bool Blackbox::handleSignal(int sig) {
725 switch (sig) {
726 case SIGHUP:
727 case SIGUSR1:
728 reconfigure();
729 break;
730
731 case SIGUSR2:
732 rereadMenu();
733 break;
734
735 case SIGPIPE:
736 case SIGSEGV:
737 case SIGFPE:
738 case SIGINT:
739 case SIGTERM:
740 shutdown();
741
742 default:
743 return False;
744 }
745
746 return True;
747 }
748
749
750 bool Blackbox::validateWindow(Window window) {
751 XEvent event;
752 if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
753 XPutBackEvent(getXDisplay(), &event);
754
755 return False;
756 }
757
758 return True;
759 }
760
761
762 BScreen *Blackbox::searchScreen(Window window) {
763 ScreenList::iterator it = screenList.begin();
764
765 for (; it != screenList.end(); ++it) {
766 BScreen *s = *it;
767 if (s->getRootWindow() == window)
768 return s;
769 }
770
771 return (BScreen *) 0;
772 }
773
774
775 BlackboxWindow *Blackbox::searchWindow(Window window) {
776 WindowLookup::iterator it = windowSearchList.find(window);
777 if (it != windowSearchList.end())
778 return it->second;
779
780 return (BlackboxWindow*) 0;
781 }
782
783
784 BWindowGroup *Blackbox::searchGroup(Window window) {
785 GroupLookup::iterator it = groupSearchList.find(window);
786 if (it != groupSearchList.end())
787 return it->second;
788
789 return (BWindowGroup *) 0;
790 }
791
792
793 Basemenu *Blackbox::searchMenu(Window window) {
794 MenuLookup::iterator it = menuSearchList.find(window);
795 if (it != menuSearchList.end())
796 return it->second;
797
798 return (Basemenu*) 0;
799 }
800
801
802 Toolbar *Blackbox::searchToolbar(Window window) {
803 ToolbarLookup::iterator it = toolbarSearchList.find(window);
804 if (it != toolbarSearchList.end())
805 return it->second;
806
807 return (Toolbar*) 0;
808 }
809
810
811 Slit *Blackbox::searchSlit(Window window) {
812 SlitLookup::iterator it = slitSearchList.find(window);
813 if (it != slitSearchList.end())
814 return it->second;
815
816 return (Slit*) 0;
817 }
818
819
820 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
821 windowSearchList.insert(WindowLookupPair(window, data));
822 }
823
824
825 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
826 groupSearchList.insert(GroupLookupPair(window, data));
827 }
828
829
830 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
831 menuSearchList.insert(MenuLookupPair(window, data));
832 }
833
834
835 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
836 toolbarSearchList.insert(ToolbarLookupPair(window, data));
837 }
838
839
840 void Blackbox::saveSlitSearch(Window window, Slit *data) {
841 slitSearchList.insert(SlitLookupPair(window, data));
842 }
843
844
845 void Blackbox::removeWindowSearch(Window window) {
846 windowSearchList.erase(window);
847 }
848
849
850 void Blackbox::removeGroupSearch(Window window) {
851 groupSearchList.erase(window);
852 }
853
854
855 void Blackbox::removeMenuSearch(Window window) {
856 menuSearchList.erase(window);
857 }
858
859
860 void Blackbox::removeToolbarSearch(Window window) {
861 toolbarSearchList.erase(window);
862 }
863
864
865 void Blackbox::removeSlitSearch(Window window) {
866 slitSearchList.erase(window);
867 }
868
869
870 void Blackbox::restart(const char *prog) {
871 shutdown();
872
873 if (prog) {
874 execlp(prog, prog, NULL);
875 perror(prog);
876 }
877
878 // fall back in case the above execlp doesn't work
879 execvp(argv[0], argv);
880 string name = basename(argv[0]);
881 execvp(name.c_str(), argv);
882 }
883
884
885 void Blackbox::shutdown(void) {
886 BaseDisplay::shutdown();
887
888 XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
889
890 std::for_each(screenList.begin(), screenList.end(),
891 std::mem_fun(&BScreen::shutdown));
892
893 XSync(getXDisplay(), False);
894 }
895
896
897 /*
898 * Save all values as they are so that the defaults will be written to the rc
899 * file
900 */
901 void Blackbox::save_rc(void) {
902 config.setAutoSave(false);
903
904 config.setValue("session.colorsPerChannel", resource.colors_per_channel);
905 config.setValue("session.doubleClickInterval",
906 resource.double_click_interval);
907 config.setValue("session.autoRaiseDelay",
908 ((resource.auto_raise_delay.tv_sec * 1000) +
909 (resource.auto_raise_delay.tv_usec / 1000)));
910 config.setValue("session.cacheLife", resource.cache_life / 60000);
911 config.setValue("session.cacheMax", resource.cache_max);
912 config.setValue("session.styleFile", resource.style_file);
913 config.setValue("session.titlebarLayout", resource.titlebar_layout);
914
915 std::for_each(screenList.begin(), screenList.end(),
916 std::mem_fun(&BScreen::save_rc));
917
918 config.setAutoSave(true);
919 config.save();
920 }
921
922
923 void Blackbox::load_rc(void) {
924 if (! config.load())
925 config.create();
926
927 string s;
928
929 if (! config.getValue("session.colorsPerChannel",
930 resource.colors_per_channel))
931 resource.colors_per_channel = 4;
932 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
933 else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
934
935 if (config.getValue("session.styleFile", s))
936 resource.style_file = expandTilde(s);
937 else
938 resource.style_file = DEFAULTSTYLE;
939
940 if (! config.getValue("session.doubleClickInterval",
941 resource.double_click_interval));
942 resource.double_click_interval = 250;
943
944 if (! config.getValue("session.autoRaiseDelay",
945 resource.auto_raise_delay.tv_usec))
946 resource.auto_raise_delay.tv_usec = 400;
947 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
948 resource.auto_raise_delay.tv_usec -=
949 (resource.auto_raise_delay.tv_sec * 1000);
950 resource.auto_raise_delay.tv_usec *= 1000;
951
952 if (! config.getValue("session.cacheLife", resource.cache_life))
953 resource.cache_life = 5;
954 resource.cache_life *= 60000;
955
956 if (! config.getValue("session.cacheMax", resource.cache_max))
957 resource.cache_max = 200;
958
959 if (! config.getValue("session.titlebarLayout", resource.titlebar_layout))
960 resource.titlebar_layout = "ILMC";
961 }
962
963
964 void Blackbox::reconfigure(void) {
965 reconfigure_wait = True;
966
967 if (! timer->isTiming()) timer->start();
968 }
969
970
971 void Blackbox::real_reconfigure(void) {
972 load_rc();
973
974 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
975 PointerAssassin());
976 menuTimestamps.clear();
977
978 gcCache()->purge();
979
980 std::for_each(screenList.begin(), screenList.end(),
981 std::mem_fun(&BScreen::reconfigure));
982 }
983
984
985 void Blackbox::checkMenu(void) {
986 bool reread = False;
987 MenuTimestampList::iterator it = menuTimestamps.begin();
988 for(; it != menuTimestamps.end(); ++it) {
989 MenuTimestamp *tmp = *it;
990 struct stat buf;
991
992 if (! stat(tmp->filename.c_str(), &buf)) {
993 if (tmp->timestamp != buf.st_ctime)
994 reread = True;
995 } else {
996 reread = True;
997 }
998 }
999
1000 if (reread) rereadMenu();
1001 }
1002
1003
1004 void Blackbox::rereadMenu(void) {
1005 reread_menu_wait = True;
1006
1007 if (! timer->isTiming()) timer->start();
1008 }
1009
1010
1011 void Blackbox::real_rereadMenu(void) {
1012 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1013 PointerAssassin());
1014 menuTimestamps.clear();
1015
1016 std::for_each(screenList.begin(), screenList.end(),
1017 std::mem_fun(&BScreen::rereadMenu));
1018 }
1019
1020
1021 void Blackbox::saveStyleFilename(const string& filename) {
1022 assert(! filename.empty());
1023 resource.style_file = filename;
1024 config.setValue("session.styleFile", resource.style_file);
1025 }
1026
1027
1028 void Blackbox::addMenuTimestamp(const string& filename) {
1029 assert(! filename.empty());
1030 bool found = False;
1031
1032 MenuTimestampList::iterator it = menuTimestamps.begin();
1033 for (; it != menuTimestamps.end() && ! found; ++it) {
1034 if ((*it)->filename == filename) found = True;
1035 }
1036 if (! found) {
1037 struct stat buf;
1038
1039 if (! stat(filename.c_str(), &buf)) {
1040 MenuTimestamp *ts = new MenuTimestamp;
1041
1042 ts->filename = filename;
1043 ts->timestamp = buf.st_ctime;
1044
1045 menuTimestamps.push_back(ts);
1046 }
1047 }
1048 }
1049
1050
1051 void Blackbox::timeout(void) {
1052 if (reconfigure_wait)
1053 real_reconfigure();
1054
1055 if (reread_menu_wait)
1056 real_rereadMenu();
1057
1058 reconfigure_wait = reread_menu_wait = False;
1059 }
1060
1061
1062 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1063 if (focused_window && focused_window == win) // nothing to do
1064 return;
1065
1066 BScreen *old_screen = 0;
1067
1068 if (focused_window) {
1069 focused_window->setFocusFlag(False);
1070 old_screen = focused_window->getScreen();
1071 }
1072
1073 if (win && ! win->isIconic()) {
1074 // the active screen is the one with the last focused window...
1075 // this will keep focus on this screen no matter where the mouse goes,
1076 // so multihead keybindings will continue to work on that screen until the
1077 // user focuses a window on a different screen.
1078 active_screen = win->getScreen();
1079 focused_window = win;
1080 } else {
1081 focused_window = 0;
1082 if (! old_screen) {
1083 if (active_screen) {
1084 // set input focus to the toolbar of the screen with mouse
1085 XSetInputFocus(getXDisplay(),
1086 active_screen->getRootWindow(),
1087 RevertToPointerRoot, CurrentTime);
1088 } else {
1089 // set input focus to the toolbar of the first managed screen
1090 XSetInputFocus(getXDisplay(),
1091 screenList.front()->getRootWindow(),
1092 RevertToPointerRoot, CurrentTime);
1093 }
1094 } else {
1095 // set input focus to the toolbar of the last screen
1096 XSetInputFocus(getXDisplay(), old_screen->getRootWindow(),
1097 RevertToPointerRoot, CurrentTime);
1098 }
1099 }
1100
1101 if (active_screen && active_screen->isScreenManaged()) {
1102 active_screen->getToolbar()->redrawWindowLabel(True);
1103 active_screen->updateNetizenWindowFocus();
1104 }
1105
1106 if (old_screen && old_screen != active_screen) {
1107 old_screen->getToolbar()->redrawWindowLabel(True);
1108 old_screen->updateNetizenWindowFocus();
1109 }
1110 }
This page took 0.08717 seconds and 4 git commands to generate.