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