]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
c93b28a6331683a727333f07ac746234483e31a1
[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 /*
564 don't process FocusIns when:
565 1. the new focus window isn't an ancestor or inferior of the old
566 focus window (NotifyNonlinear)
567 */
568 break;
569 }
570
571 BlackboxWindow *win = searchWindow(e->xfocus.window);
572 if (win) {
573 if (! win->isFocused())
574 win->setFocusFlag(True);
575
576 /*
577 set the event window to None. when the FocusOut event handler calls
578 this function recursively, it uses this as an indication that focus
579 has moved to a known window.
580 */
581 e->xfocus.window = None;
582 }
583
584 break;
585 }
586
587 case FocusOut: {
588 if (e->xfocus.detail != NotifyNonlinear) {
589 /*
590 don't process FocusOuts when:
591 2. the new focus window isn't an ancestor or inferior of the old
592 focus window (NotifyNonlinear)
593 */
594 break;
595 }
596
597 BlackboxWindow *win = searchWindow(e->xfocus.window);
598 if (win && win->isFocused()) {
599 /*
600 before we mark "win" as unfocused, we need to verify that focus is
601 going to a known location, is in a known location, or set focus
602 to a known location.
603 */
604
605 XEvent event;
606 // don't check the current focus if FocusOut was generated during a grab
607 bool check_focus = (e->xfocus.mode == NotifyNormal);
608
609 /*
610 First, check if there is a pending FocusIn event waiting. if there
611 is, process it and determine if focus has moved to another window
612 (the FocusIn event handler sets the window in the event
613 structure to None to indicate this).
614 */
615 if (XCheckTypedEvent(getXDisplay(), FocusIn, &event)) {
616
617 process_event(&event);
618 if (event.xfocus.window == None) {
619 // focus has moved
620 check_focus = False;
621 }
622 }
623
624 if (check_focus) {
625 /*
626 Second, we query the X server for the current input focus.
627 to make sure that we keep a consistent state.
628 */
629 BlackboxWindow *focus;
630 Window w;
631 int revert;
632 XGetInputFocus(getXDisplay(), &w, &revert);
633 focus = searchWindow(w);
634 if (focus) {
635 /*
636 focus got from "win" to "focus" under some very strange
637 circumstances, and we need to make sure that the focus indication
638 is correct.
639 */
640 setFocusedWindow(focus);
641 } else {
642 // we have no idea where focus went... so we set it to somewhere
643 setFocusedWindow(0);
644 }
645 }
646 }
647
648 break;
649 }
650
651 case ClientMessage: {
652 if (e->xclient.format == 32) {
653 if (e->xclient.message_type == getWMChangeStateAtom()) {
654 BlackboxWindow *win = searchWindow(e->xclient.window);
655 if (! win || ! win->validateClient()) return;
656
657 if (e->xclient.data.l[0] == IconicState)
658 win->iconify();
659 if (e->xclient.data.l[0] == NormalState)
660 win->deiconify();
661 } else if(e->xclient.message_type == getBlackboxChangeWorkspaceAtom()) {
662 BScreen *screen = searchScreen(e->xclient.window);
663
664 if (screen && e->xclient.data.l[0] >= 0 &&
665 e->xclient.data.l[0] <
666 static_cast<signed>(screen->getWorkspaceCount()))
667 screen->changeWorkspaceID(e->xclient.data.l[0]);
668 } else if (e->xclient.message_type == getBlackboxChangeWindowFocusAtom()) {
669 BlackboxWindow *win = searchWindow(e->xclient.window);
670
671 if (win && win->isVisible() && win->setInputFocus())
672 win->installColormap(True);
673 } else if (e->xclient.message_type == getBlackboxCycleWindowFocusAtom()) {
674 BScreen *screen = searchScreen(e->xclient.window);
675
676 if (screen) {
677 if (! e->xclient.data.l[0])
678 screen->prevFocus();
679 else
680 screen->nextFocus();
681 }
682 } else if (e->xclient.message_type == getBlackboxChangeAttributesAtom()) {
683 BlackboxWindow *win = searchWindow(e->xclient.window);
684
685 if (win && win->validateClient()) {
686 BlackboxHints net;
687 net.flags = e->xclient.data.l[0];
688 net.attrib = e->xclient.data.l[1];
689 net.workspace = e->xclient.data.l[2];
690 net.stack = e->xclient.data.l[3];
691 net.decoration = e->xclient.data.l[4];
692
693 win->changeBlackboxHints(&net);
694 }
695 }
696 }
697
698 break;
699 }
700
701 case NoExpose:
702 case ConfigureNotify:
703 case MapNotify:
704 break; // not handled, just ignore
705
706 default: {
707 #ifdef SHAPE
708 if (e->type == getShapeEventBase()) {
709 XShapeEvent *shape_event = (XShapeEvent *) e;
710 BlackboxWindow *win = searchWindow(e->xany.window);
711
712 if (win)
713 win->shapeEvent(shape_event);
714 }
715 #endif // SHAPE
716 }
717 } // switch
718 }
719
720
721 bool Blackbox::handleSignal(int sig) {
722 switch (sig) {
723 case SIGHUP:
724 case SIGUSR1:
725 reconfigure();
726 break;
727
728 case SIGUSR2:
729 rereadMenu();
730 break;
731
732 case SIGPIPE:
733 case SIGSEGV:
734 case SIGFPE:
735 case SIGINT:
736 case SIGTERM:
737 shutdown();
738
739 default:
740 return False;
741 }
742
743 return True;
744 }
745
746
747 bool Blackbox::validateWindow(Window window) {
748 XEvent event;
749 if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
750 XPutBackEvent(getXDisplay(), &event);
751
752 return False;
753 }
754
755 return True;
756 }
757
758
759 BScreen *Blackbox::searchScreen(Window window) {
760 ScreenList::iterator it = screenList.begin();
761
762 for (; it != screenList.end(); ++it) {
763 BScreen *s = *it;
764 if (s->getRootWindow() == window)
765 return s;
766 }
767
768 return (BScreen *) 0;
769 }
770
771
772 BlackboxWindow *Blackbox::searchWindow(Window window) {
773 WindowLookup::iterator it = windowSearchList.find(window);
774 if (it != windowSearchList.end())
775 return it->second;
776
777 return (BlackboxWindow*) 0;
778 }
779
780
781 BWindowGroup *Blackbox::searchGroup(Window window) {
782 GroupLookup::iterator it = groupSearchList.find(window);
783 if (it != groupSearchList.end())
784 return it->second;
785
786 return (BWindowGroup *) 0;
787 }
788
789
790 Basemenu *Blackbox::searchMenu(Window window) {
791 MenuLookup::iterator it = menuSearchList.find(window);
792 if (it != menuSearchList.end())
793 return it->second;
794
795 return (Basemenu*) 0;
796 }
797
798
799 Toolbar *Blackbox::searchToolbar(Window window) {
800 ToolbarLookup::iterator it = toolbarSearchList.find(window);
801 if (it != toolbarSearchList.end())
802 return it->second;
803
804 return (Toolbar*) 0;
805 }
806
807
808 Slit *Blackbox::searchSlit(Window window) {
809 SlitLookup::iterator it = slitSearchList.find(window);
810 if (it != slitSearchList.end())
811 return it->second;
812
813 return (Slit*) 0;
814 }
815
816
817 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
818 windowSearchList.insert(WindowLookupPair(window, data));
819 }
820
821
822 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
823 groupSearchList.insert(GroupLookupPair(window, data));
824 }
825
826
827 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
828 menuSearchList.insert(MenuLookupPair(window, data));
829 }
830
831
832 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
833 toolbarSearchList.insert(ToolbarLookupPair(window, data));
834 }
835
836
837 void Blackbox::saveSlitSearch(Window window, Slit *data) {
838 slitSearchList.insert(SlitLookupPair(window, data));
839 }
840
841
842 void Blackbox::removeWindowSearch(Window window) {
843 windowSearchList.erase(window);
844 }
845
846
847 void Blackbox::removeGroupSearch(Window window) {
848 groupSearchList.erase(window);
849 }
850
851
852 void Blackbox::removeMenuSearch(Window window) {
853 menuSearchList.erase(window);
854 }
855
856
857 void Blackbox::removeToolbarSearch(Window window) {
858 toolbarSearchList.erase(window);
859 }
860
861
862 void Blackbox::removeSlitSearch(Window window) {
863 slitSearchList.erase(window);
864 }
865
866
867 void Blackbox::restart(const char *prog) {
868 shutdown();
869
870 if (prog) {
871 execlp(prog, prog, NULL);
872 perror(prog);
873 }
874
875 // fall back in case the above execlp doesn't work
876 execvp(argv[0], argv);
877 string name = basename(argv[0]);
878 execvp(name.c_str(), argv);
879 }
880
881
882 void Blackbox::shutdown(void) {
883 BaseDisplay::shutdown();
884
885 XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
886
887 std::for_each(screenList.begin(), screenList.end(),
888 std::mem_fun(&BScreen::shutdown));
889
890 XSync(getXDisplay(), False);
891 }
892
893
894 /*
895 * Save all values as they are so that the defaults will be written to the rc
896 * file
897 */
898 void Blackbox::save_rc(void) {
899 config.setAutoSave(false);
900
901 config.setValue("session.colorsPerChannel", resource.colors_per_channel);
902 config.setValue("session.doubleClickInterval",
903 resource.double_click_interval);
904 config.setValue("session.autoRaiseDelay",
905 ((resource.auto_raise_delay.tv_sec * 1000) +
906 (resource.auto_raise_delay.tv_usec / 1000)));
907 config.setValue("session.cacheLife", resource.cache_life / 60000);
908 config.setValue("session.cacheMax", resource.cache_max);
909 config.setValue("session.styleFile", resource.style_file);
910 config.setValue("session.titlebarLayout", resource.titlebar_layout);
911
912 std::for_each(screenList.begin(), screenList.end(),
913 std::mem_fun(&BScreen::save_rc));
914
915 config.setAutoSave(true);
916 config.save();
917 }
918
919
920 void Blackbox::load_rc(void) {
921 if (! config.load())
922 config.create();
923
924 string s;
925
926 if (! config.getValue("session.colorsPerChannel",
927 resource.colors_per_channel))
928 resource.colors_per_channel = 4;
929 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
930 else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
931
932 if (config.getValue("session.styleFile", s))
933 resource.style_file = expandTilde(s);
934 else
935 resource.style_file = DEFAULTSTYLE;
936
937 if (! config.getValue("session.doubleClickInterval",
938 resource.double_click_interval));
939 resource.double_click_interval = 250;
940
941 if (! config.getValue("session.autoRaiseDelay",
942 resource.auto_raise_delay.tv_usec))
943 resource.auto_raise_delay.tv_usec = 400;
944 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
945 resource.auto_raise_delay.tv_usec -=
946 (resource.auto_raise_delay.tv_sec * 1000);
947 resource.auto_raise_delay.tv_usec *= 1000;
948
949 if (! config.getValue("session.cacheLife", resource.cache_life))
950 resource.cache_life = 5;
951 resource.cache_life *= 60000;
952
953 if (! config.getValue("session.cacheMax", resource.cache_max))
954 resource.cache_max = 200;
955
956 if (! config.getValue("session.titlebarLayout", resource.titlebar_layout))
957 resource.titlebar_layout = "ILMC";
958 }
959
960
961 void Blackbox::reconfigure(void) {
962 reconfigure_wait = True;
963
964 if (! timer->isTiming()) timer->start();
965 }
966
967
968 void Blackbox::real_reconfigure(void) {
969 load_rc();
970
971 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
972 PointerAssassin());
973 menuTimestamps.clear();
974
975 gcCache()->purge();
976
977 std::for_each(screenList.begin(), screenList.end(),
978 std::mem_fun(&BScreen::reconfigure));
979 }
980
981
982 void Blackbox::checkMenu(void) {
983 bool reread = False;
984 MenuTimestampList::iterator it = menuTimestamps.begin();
985 for(; it != menuTimestamps.end(); ++it) {
986 MenuTimestamp *tmp = *it;
987 struct stat buf;
988
989 if (! stat(tmp->filename.c_str(), &buf)) {
990 if (tmp->timestamp != buf.st_ctime)
991 reread = True;
992 } else {
993 reread = True;
994 }
995 }
996
997 if (reread) rereadMenu();
998 }
999
1000
1001 void Blackbox::rereadMenu(void) {
1002 reread_menu_wait = True;
1003
1004 if (! timer->isTiming()) timer->start();
1005 }
1006
1007
1008 void Blackbox::real_rereadMenu(void) {
1009 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1010 PointerAssassin());
1011 menuTimestamps.clear();
1012
1013 std::for_each(screenList.begin(), screenList.end(),
1014 std::mem_fun(&BScreen::rereadMenu));
1015 }
1016
1017
1018 void Blackbox::saveStyleFilename(const string& filename) {
1019 assert(! filename.empty());
1020 resource.style_file = filename;
1021 config.setValue("session.styleFile", resource.style_file);
1022 }
1023
1024
1025 void Blackbox::addMenuTimestamp(const string& filename) {
1026 assert(! filename.empty());
1027 bool found = False;
1028
1029 MenuTimestampList::iterator it = menuTimestamps.begin();
1030 for (; it != menuTimestamps.end() && ! found; ++it) {
1031 if ((*it)->filename == filename) found = True;
1032 }
1033 if (! found) {
1034 struct stat buf;
1035
1036 if (! stat(filename.c_str(), &buf)) {
1037 MenuTimestamp *ts = new MenuTimestamp;
1038
1039 ts->filename = filename;
1040 ts->timestamp = buf.st_ctime;
1041
1042 menuTimestamps.push_back(ts);
1043 }
1044 }
1045 }
1046
1047
1048 void Blackbox::timeout(void) {
1049 if (reconfigure_wait)
1050 real_reconfigure();
1051
1052 if (reread_menu_wait)
1053 real_rereadMenu();
1054
1055 reconfigure_wait = reread_menu_wait = False;
1056 }
1057
1058
1059 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1060 if (focused_window && focused_window == win) // nothing to do
1061 return;
1062
1063 BScreen *old_screen = 0;
1064
1065 if (focused_window) {
1066 focused_window->setFocusFlag(False);
1067 old_screen = focused_window->getScreen();
1068 }
1069
1070 if (win && ! win->isIconic()) {
1071 // the active screen is the one with the last focused window...
1072 // this will keep focus on this screen no matter where the mouse goes,
1073 // so multihead keybindings will continue to work on that screen until the
1074 // user focuses a window on a different screen.
1075 active_screen = win->getScreen();
1076 focused_window = win;
1077 } else {
1078 focused_window = 0;
1079 if (! old_screen) {
1080 if (active_screen) {
1081 // set input focus to the toolbar of the screen with mouse
1082 XSetInputFocus(getXDisplay(),
1083 active_screen->getRootWindow(),
1084 RevertToPointerRoot, CurrentTime);
1085 } else {
1086 // set input focus to the toolbar of the first managed screen
1087 XSetInputFocus(getXDisplay(),
1088 screenList.front()->getRootWindow(),
1089 RevertToPointerRoot, CurrentTime);
1090 }
1091 } else {
1092 // set input focus to the toolbar of the last screen
1093 XSetInputFocus(getXDisplay(), old_screen->getRootWindow(),
1094 RevertToPointerRoot, CurrentTime);
1095 }
1096 }
1097
1098 if (active_screen && active_screen->isScreenManaged()) {
1099 active_screen->getToolbar()->redrawWindowLabel(True);
1100 active_screen->updateNetizenWindowFocus();
1101 }
1102
1103 if (old_screen && old_screen != active_screen) {
1104 old_screen->getToolbar()->redrawWindowLabel(True);
1105 old_screen->updateNetizenWindowFocus();
1106 }
1107 }
This page took 0.091876 seconds and 4 git commands to generate.