]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
63a5055b8d8b143d41aa4565bec43db9afdc7dc7
[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
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 init_icccm();
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 timer;
211 }
212
213
214 void Blackbox::process_event(XEvent *e) {
215 switch (e->type) {
216 case ButtonPress: {
217 // strip the lock key modifiers
218 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
219
220 last_time = e->xbutton.time;
221
222 BlackboxWindow *win = (BlackboxWindow *) 0;
223 Basemenu *menu = (Basemenu *) 0;
224 Slit *slit = (Slit *) 0;
225 Toolbar *tbar = (Toolbar *) 0;
226 BScreen *scrn = (BScreen *) 0;
227
228 if ((win = searchWindow(e->xbutton.window))) {
229 win->buttonPressEvent(&e->xbutton);
230
231 /* XXX: is this sane on low colour desktops? */
232 if (e->xbutton.button == 1)
233 win->installColormap(True);
234 } else if ((menu = searchMenu(e->xbutton.window))) {
235 menu->buttonPressEvent(&e->xbutton);
236 } else if ((slit = searchSlit(e->xbutton.window))) {
237 slit->buttonPressEvent(&e->xbutton);
238 } else if ((tbar = searchToolbar(e->xbutton.window))) {
239 tbar->buttonPressEvent(&e->xbutton);
240 } else if ((scrn = searchScreen(e->xbutton.window))) {
241 scrn->buttonPressEvent(&e->xbutton);
242 if (active_screen != scrn) {
243 active_screen = scrn;
244 // first, set no focus window on the old screen
245 setFocusedWindow(0);
246 // and move focus to this screen
247 setFocusedWindow(0);
248 }
249 }
250 break;
251 }
252
253 case ButtonRelease: {
254 // strip the lock key modifiers
255 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
256
257 last_time = e->xbutton.time;
258
259 BlackboxWindow *win = (BlackboxWindow *) 0;
260 Basemenu *menu = (Basemenu *) 0;
261 Toolbar *tbar = (Toolbar *) 0;
262
263 if ((win = searchWindow(e->xbutton.window)))
264 win->buttonReleaseEvent(&e->xbutton);
265 else if ((menu = searchMenu(e->xbutton.window)))
266 menu->buttonReleaseEvent(&e->xbutton);
267 else if ((tbar = searchToolbar(e->xbutton.window)))
268 tbar->buttonReleaseEvent(&e->xbutton);
269
270 break;
271 }
272
273 case ConfigureRequest: {
274 // compress configure requests...
275 XEvent realevent;
276 unsigned int i = 0;
277 while(XCheckTypedWindowEvent(getXDisplay(), e->xconfigurerequest.window,
278 ConfigureRequest, &realevent)) {
279 i++;
280 }
281 if ( i > 0 )
282 e = &realevent;
283
284 BlackboxWindow *win = (BlackboxWindow *) 0;
285 Slit *slit = (Slit *) 0;
286
287 if ((win = searchWindow(e->xconfigurerequest.window))) {
288 win->configureRequestEvent(&e->xconfigurerequest);
289 } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
290 slit->configureRequestEvent(&e->xconfigurerequest);
291 } else {
292 if (validateWindow(e->xconfigurerequest.window)) {
293 XWindowChanges xwc;
294
295 xwc.x = e->xconfigurerequest.x;
296 xwc.y = e->xconfigurerequest.y;
297 xwc.width = e->xconfigurerequest.width;
298 xwc.height = e->xconfigurerequest.height;
299 xwc.border_width = e->xconfigurerequest.border_width;
300 xwc.sibling = e->xconfigurerequest.above;
301 xwc.stack_mode = e->xconfigurerequest.detail;
302
303 XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
304 e->xconfigurerequest.value_mask, &xwc);
305 }
306 }
307
308 break;
309 }
310
311 case MapRequest: {
312 #ifdef DEBUG
313 fprintf(stderr, "Blackbox::process_event(): MapRequest for 0x%lx\n",
314 e->xmaprequest.window);
315 #endif // DEBUG
316
317 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
318
319 if (! win) {
320 BScreen *screen = searchScreen(e->xmaprequest.parent);
321
322 if (! screen) {
323 /*
324 we got a map request for a window who's parent isn't root. this
325 can happen in only one circumstance:
326
327 a client window unmapped a managed window, and then remapped it
328 somewhere between unmapping the client window and reparenting it
329 to root.
330
331 regardless of how it happens, we need to find the screen that
332 the window is on
333 */
334 XWindowAttributes wattrib;
335 if (! XGetWindowAttributes(getXDisplay(), e->xmaprequest.window,
336 &wattrib)) {
337 // failed to get the window attributes, perhaps the window has
338 // now been destroyed?
339 break;
340 }
341
342 screen = searchScreen(wattrib.root);
343 assert(screen != 0); // this should never happen
344 }
345
346 screen->manageWindow(e->xmaprequest.window);
347 }
348
349 break;
350 }
351
352 case UnmapNotify: {
353 BlackboxWindow *win = (BlackboxWindow *) 0;
354 Slit *slit = (Slit *) 0;
355
356 if ((win = searchWindow(e->xunmap.window))) {
357 win->unmapNotifyEvent(&e->xunmap);
358 } else if ((slit = searchSlit(e->xunmap.window))) {
359 slit->unmapNotifyEvent(&e->xunmap);
360 }
361
362 break;
363 }
364
365 case DestroyNotify: {
366 BlackboxWindow *win = (BlackboxWindow *) 0;
367 Slit *slit = (Slit *) 0;
368 BWindowGroup *group = (BWindowGroup *) 0;
369
370 if ((win = searchWindow(e->xdestroywindow.window))) {
371 win->destroyNotifyEvent(&e->xdestroywindow);
372 } else if ((slit = searchSlit(e->xdestroywindow.window))) {
373 slit->removeClient(e->xdestroywindow.window, False);
374 } else if ((group = searchGroup(e->xdestroywindow.window))) {
375 delete group;
376 }
377
378 break;
379 }
380
381 case ReparentNotify: {
382 /*
383 this event is quite rare and is usually handled in unmapNotify
384 however, if the window is unmapped when the reparent event occurs
385 the window manager never sees it because an unmap event is not sent
386 to an already unmapped window.
387 */
388 BlackboxWindow *win = searchWindow(e->xreparent.window);
389 if (win) {
390 win->reparentNotifyEvent(&e->xreparent);
391 } else {
392 Slit *slit = searchSlit(e->xreparent.window);
393 if (slit && slit->getWindowID() != e->xreparent.parent)
394 slit->removeClient(e->xreparent.window, True);
395 }
396 break;
397 }
398
399 case MotionNotify: {
400 // motion notify compression...
401 XEvent realevent;
402 unsigned int i = 0;
403 while (XCheckTypedWindowEvent(getXDisplay(), e->xmotion.window,
404 MotionNotify, &realevent)) {
405 i++;
406 }
407
408 // if we have compressed some motion events, use the last one
409 if ( i > 0 )
410 e = &realevent;
411
412 // strip the lock key modifiers
413 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
414
415 last_time = e->xmotion.time;
416
417 BlackboxWindow *win = (BlackboxWindow *) 0;
418 Basemenu *menu = (Basemenu *) 0;
419
420 if ((win = searchWindow(e->xmotion.window)))
421 win->motionNotifyEvent(&e->xmotion);
422 else if ((menu = searchMenu(e->xmotion.window)))
423 menu->motionNotifyEvent(&e->xmotion);
424
425 break;
426 }
427
428 case PropertyNotify: {
429 last_time = e->xproperty.time;
430
431 if (e->xproperty.state != PropertyDelete) {
432 BlackboxWindow *win = searchWindow(e->xproperty.window);
433
434 if (win)
435 win->propertyNotifyEvent(e->xproperty.atom);
436 }
437
438 break;
439 }
440
441 case EnterNotify: {
442 last_time = e->xcrossing.time;
443
444 BScreen *screen = (BScreen *) 0;
445 BlackboxWindow *win = (BlackboxWindow *) 0;
446 Basemenu *menu = (Basemenu *) 0;
447 Toolbar *tbar = (Toolbar *) 0;
448 Slit *slit = (Slit *) 0;
449
450 if (e->xcrossing.mode == NotifyGrab) break;
451
452 XEvent dummy;
453 scanargs sa;
454 sa.w = e->xcrossing.window;
455 sa.enter = sa.leave = False;
456 XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
457
458 if ((e->xcrossing.window == e->xcrossing.root) &&
459 (screen = searchScreen(e->xcrossing.window))) {
460 screen->getImageControl()->installRootColormap();
461 } else if ((win = searchWindow(e->xcrossing.window))) {
462 if (win->getScreen()->isSloppyFocus() &&
463 (! win->isFocused()) && (! no_focus)) {
464 if (((! sa.leave) || sa.inferior) && win->isVisible()) {
465 if (win->setInputFocus())
466 win->installColormap(True); // XXX: shouldnt we honour no install?
467 }
468 }
469 } else if ((menu = searchMenu(e->xcrossing.window))) {
470 menu->enterNotifyEvent(&e->xcrossing);
471 } else if ((tbar = searchToolbar(e->xcrossing.window))) {
472 tbar->enterNotifyEvent(&e->xcrossing);
473 } else if ((slit = searchSlit(e->xcrossing.window))) {
474 slit->enterNotifyEvent(&e->xcrossing);
475 }
476 break;
477 }
478
479 case LeaveNotify: {
480 last_time = e->xcrossing.time;
481
482 BlackboxWindow *win = (BlackboxWindow *) 0;
483 Basemenu *menu = (Basemenu *) 0;
484 Toolbar *tbar = (Toolbar *) 0;
485 Slit *slit = (Slit *) 0;
486
487 if ((menu = searchMenu(e->xcrossing.window)))
488 menu->leaveNotifyEvent(&e->xcrossing);
489 else if ((win = searchWindow(e->xcrossing.window)))
490 win->installColormap(False);
491 else if ((tbar = searchToolbar(e->xcrossing.window)))
492 tbar->leaveNotifyEvent(&e->xcrossing);
493 else if ((slit = searchSlit(e->xcrossing.window)))
494 slit->leaveNotifyEvent(&e->xcrossing);
495 break;
496 }
497
498 case Expose: {
499 // compress expose events
500 XEvent realevent;
501 unsigned int i = 0;
502 int ex1, ey1, ex2, ey2;
503 ex1 = e->xexpose.x;
504 ey1 = e->xexpose.y;
505 ex2 = ex1 + e->xexpose.width - 1;
506 ey2 = ey1 + e->xexpose.height - 1;
507 while (XCheckTypedWindowEvent(getXDisplay(), e->xexpose.window,
508 Expose, &realevent)) {
509 i++;
510
511 // merge expose area
512 ex1 = std::min(realevent.xexpose.x, ex1);
513 ey1 = std::min(realevent.xexpose.y, ey1);
514 ex2 = std::max(realevent.xexpose.x + realevent.xexpose.width - 1, ex2);
515 ey2 = std::max(realevent.xexpose.y + realevent.xexpose.height - 1, ey2);
516 }
517 if ( i > 0 )
518 e = &realevent;
519
520 // use the merged area
521 e->xexpose.x = ex1;
522 e->xexpose.y = ey1;
523 e->xexpose.width = ex2 - ex1 + 1;
524 e->xexpose.height = ey2 - ey1 + 1;
525
526 BlackboxWindow *win = (BlackboxWindow *) 0;
527 Basemenu *menu = (Basemenu *) 0;
528 Toolbar *tbar = (Toolbar *) 0;
529
530 if ((win = searchWindow(e->xexpose.window)))
531 win->exposeEvent(&e->xexpose);
532 else if ((menu = searchMenu(e->xexpose.window)))
533 menu->exposeEvent(&e->xexpose);
534 else if ((tbar = searchToolbar(e->xexpose.window)))
535 tbar->exposeEvent(&e->xexpose);
536
537 break;
538 }
539
540 case KeyPress: {
541 Toolbar *tbar = searchToolbar(e->xkey.window);
542
543 if (tbar && tbar->isEditing())
544 tbar->keyPressEvent(&e->xkey);
545
546 break;
547 }
548
549 case ColormapNotify: {
550 BScreen *screen = searchScreen(e->xcolormap.window);
551
552 if (screen)
553 screen->setRootColormapInstalled((e->xcolormap.state ==
554 ColormapInstalled) ? True : False);
555
556 break;
557 }
558
559 case FocusIn: {
560 if (e->xfocus.detail != NotifyNonlinear) {
561 /*
562 don't process FocusIns when:
563 1. the new focus window isn't an ancestor or inferior of the old
564 focus window (NotifyNonlinear)
565 */
566 break;
567 }
568
569 BlackboxWindow *win = searchWindow(e->xfocus.window);
570 if (win) {
571 if (! win->isFocused())
572 win->setFocusFlag(True);
573
574 /*
575 set the event window to None. when the FocusOut event handler calls
576 this function recursively, it uses this as an indication that focus
577 has moved to a known window.
578 */
579 e->xfocus.window = None;
580 }
581
582 break;
583 }
584
585 case FocusOut: {
586 if (e->xfocus.detail != NotifyNonlinear) {
587 /*
588 don't process FocusOuts when:
589 2. the new focus window isn't an ancestor or inferior of the old
590 focus window (NotifyNonlinear)
591 */
592 break;
593 }
594
595 BlackboxWindow *win = searchWindow(e->xfocus.window);
596 if (win && win->isFocused()) {
597 /*
598 before we mark "win" as unfocused, we need to verify that focus is
599 going to a known location, is in a known location, or set focus
600 to a known location.
601 */
602
603 XEvent event;
604 // don't check the current focus if FocusOut was generated during a grab
605 bool check_focus = (e->xfocus.mode == NotifyNormal);
606
607 /*
608 First, check if there is a pending FocusIn event waiting. if there
609 is, process it and determine if focus has moved to another window
610 (the FocusIn event handler sets the window in the event
611 structure to None to indicate this).
612 */
613 if (XCheckTypedEvent(getXDisplay(), FocusIn, &event)) {
614
615 process_event(&event);
616 if (event.xfocus.window == None) {
617 // focus has moved
618 check_focus = False;
619 }
620 }
621
622 if (check_focus) {
623 /*
624 Second, we query the X server for the current input focus.
625 to make sure that we keep a consistent state.
626 */
627 BlackboxWindow *focus;
628 Window w;
629 int revert;
630 XGetInputFocus(getXDisplay(), &w, &revert);
631 focus = searchWindow(w);
632 if (focus) {
633 /*
634 focus got from "win" to "focus" under some very strange
635 circumstances, and we need to make sure that the focus indication
636 is correct.
637 */
638 setFocusedWindow(focus);
639 } else {
640 // we have no idea where focus went... so we set it to somewhere
641 setFocusedWindow(0);
642 }
643 }
644 }
645
646 break;
647 }
648
649 case ClientMessage: {
650 if (e->xclient.format == 32) {
651 if (e->xclient.message_type == getWMChangeStateAtom()) {
652 BlackboxWindow *win = searchWindow(e->xclient.window);
653 if (! win || ! win->validateClient()) return;
654
655 if (e->xclient.data.l[0] == IconicState)
656 win->iconify();
657 if (e->xclient.data.l[0] == NormalState)
658 win->deiconify();
659 } else if(e->xclient.message_type == getBlackboxChangeWorkspaceAtom()) {
660 BScreen *screen = searchScreen(e->xclient.window);
661
662 if (screen && e->xclient.data.l[0] >= 0 &&
663 e->xclient.data.l[0] <
664 static_cast<signed>(screen->getWorkspaceCount()))
665 screen->changeWorkspaceID(e->xclient.data.l[0]);
666 } else if (e->xclient.message_type == getBlackboxChangeWindowFocusAtom()) {
667 BlackboxWindow *win = searchWindow(e->xclient.window);
668
669 if (win && win->isVisible() && win->setInputFocus())
670 win->installColormap(True);
671 } else if (e->xclient.message_type == getBlackboxCycleWindowFocusAtom()) {
672 BScreen *screen = searchScreen(e->xclient.window);
673
674 if (screen) {
675 if (! e->xclient.data.l[0])
676 screen->prevFocus();
677 else
678 screen->nextFocus();
679 }
680 } else if (e->xclient.message_type == getBlackboxChangeAttributesAtom()) {
681 BlackboxWindow *win = searchWindow(e->xclient.window);
682
683 if (win && win->validateClient()) {
684 BlackboxHints net;
685 net.flags = e->xclient.data.l[0];
686 net.attrib = e->xclient.data.l[1];
687 net.workspace = e->xclient.data.l[2];
688 net.stack = e->xclient.data.l[3];
689 net.decoration = e->xclient.data.l[4];
690
691 win->changeBlackboxHints(&net);
692 }
693 }
694 }
695
696 break;
697 }
698
699 case NoExpose:
700 case ConfigureNotify:
701 case MapNotify:
702 break; // not handled, just ignore
703
704 default: {
705 #ifdef SHAPE
706 if (e->type == getShapeEventBase()) {
707 XShapeEvent *shape_event = (XShapeEvent *) e;
708 BlackboxWindow *win = searchWindow(e->xany.window);
709
710 if (win)
711 win->shapeEvent(shape_event);
712 }
713 #endif // SHAPE
714 }
715 } // switch
716 }
717
718
719 bool Blackbox::handleSignal(int sig) {
720 switch (sig) {
721 case SIGHUP:
722 case SIGUSR1:
723 reconfigure();
724 break;
725
726 case SIGUSR2:
727 rereadMenu();
728 break;
729
730 case SIGPIPE:
731 case SIGSEGV:
732 case SIGFPE:
733 case SIGINT:
734 case SIGTERM:
735 shutdown();
736
737 default:
738 return False;
739 }
740
741 return True;
742 }
743
744
745 void Blackbox::init_icccm(void) {
746 xa_wm_colormap_windows =
747 XInternAtom(getXDisplay(), "WM_COLORMAP_WINDOWS", False);
748 xa_wm_protocols = XInternAtom(getXDisplay(), "WM_PROTOCOLS", False);
749 xa_wm_state = XInternAtom(getXDisplay(), "WM_STATE", False);
750 xa_wm_change_state = XInternAtom(getXDisplay(), "WM_CHANGE_STATE", False);
751 xa_wm_delete_window = XInternAtom(getXDisplay(), "WM_DELETE_WINDOW", False);
752 xa_wm_take_focus = XInternAtom(getXDisplay(), "WM_TAKE_FOCUS", False);
753 motif_wm_hints = XInternAtom(getXDisplay(), "_MOTIF_WM_HINTS", False);
754
755 blackbox_hints = XInternAtom(getXDisplay(), "_BLACKBOX_HINTS", False);
756 blackbox_attributes =
757 XInternAtom(getXDisplay(), "_BLACKBOX_ATTRIBUTES", False);
758 blackbox_change_attributes =
759 XInternAtom(getXDisplay(), "_BLACKBOX_CHANGE_ATTRIBUTES", False);
760 blackbox_structure_messages =
761 XInternAtom(getXDisplay(), "_BLACKBOX_STRUCTURE_MESSAGES", False);
762 blackbox_notify_startup =
763 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_STARTUP", False);
764 blackbox_notify_window_add =
765 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_ADD", False);
766 blackbox_notify_window_del =
767 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_DEL", False);
768 blackbox_notify_current_workspace =
769 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_CURRENT_WORKSPACE", False);
770 blackbox_notify_workspace_count =
771 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WORKSPACE_COUNT", False);
772 blackbox_notify_window_focus =
773 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_FOCUS", False);
774 blackbox_notify_window_raise =
775 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_RAISE", False);
776 blackbox_notify_window_lower =
777 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_LOWER", False);
778 blackbox_change_workspace =
779 XInternAtom(getXDisplay(), "_BLACKBOX_CHANGE_WORKSPACE", False);
780 blackbox_change_window_focus =
781 XInternAtom(getXDisplay(), "_BLACKBOX_CHANGE_WINDOW_FOCUS", False);
782 blackbox_cycle_window_focus =
783 XInternAtom(getXDisplay(), "_BLACKBOX_CYCLE_WINDOW_FOCUS", False);
784
785 #ifdef NEWWMSPEC
786 net_supported = XInternAtom(getXDisplay(), "_NET_SUPPORTED", False);
787 net_client_list = XInternAtom(getXDisplay(), "_NET_CLIENT_LIST", False);
788 net_client_list_stacking =
789 XInternAtom(getXDisplay(), "_NET_CLIENT_LIST_STACKING", False);
790 net_number_of_desktops =
791 XInternAtom(getXDisplay(), "_NET_NUMBER_OF_DESKTOPS", False);
792 net_desktop_geometry =
793 XInternAtom(getXDisplay(), "_NET_DESKTOP_GEOMETRY", False);
794 net_desktop_viewport =
795 XInternAtom(getXDisplay(), "_NET_DESKTOP_VIEWPORT", False);
796 net_current_desktop =
797 XInternAtom(getXDisplay(), "_NET_CURRENT_DESKTOP", False);
798 net_desktop_names = XInternAtom(getXDisplay(), "_NET_DESKTOP_NAMES", False);
799 net_active_window = XInternAtom(getXDisplay(), "_NET_ACTIVE_WINDOW", False);
800 net_workarea = XInternAtom(getXDisplay(), "_NET_WORKAREA", False);
801 net_supporting_wm_check =
802 XInternAtom(getXDisplay(), "_NET_SUPPORTING_WM_CHECK", False);
803 net_virtual_roots = XInternAtom(getXDisplay(), "_NET_VIRTUAL_ROOTS", False);
804 net_close_window = XInternAtom(getXDisplay(), "_NET_CLOSE_WINDOW", False);
805 net_wm_moveresize = XInternAtom(getXDisplay(), "_NET_WM_MOVERESIZE", False);
806 net_properties = XInternAtom(getXDisplay(), "_NET_PROPERTIES", False);
807 net_wm_name = XInternAtom(getXDisplay(), "_NET_WM_NAME", False);
808 net_wm_desktop = XInternAtom(getXDisplay(), "_NET_WM_DESKTOP", False);
809 net_wm_window_type =
810 XInternAtom(getXDisplay(), "_NET_WM_WINDOW_TYPE", False);
811 net_wm_state = XInternAtom(getXDisplay(), "_NET_WM_STATE", False);
812 net_wm_strut = XInternAtom(getXDisplay(), "_NET_WM_STRUT", False);
813 net_wm_icon_geometry =
814 XInternAtom(getXDisplay(), "_NET_WM_ICON_GEOMETRY", False);
815 net_wm_icon = XInternAtom(getXDisplay(), "_NET_WM_ICON", False);
816 net_wm_pid = XInternAtom(getXDisplay(), "_NET_WM_PID", False);
817 net_wm_handled_icons =
818 XInternAtom(getXDisplay(), "_NET_WM_HANDLED_ICONS", False);
819 net_wm_ping = XInternAtom(getXDisplay(), "_NET_WM_PING", False);
820 #endif // NEWWMSPEC
821
822 #ifdef HAVE_GETPID
823 blackbox_pid = XInternAtom(getXDisplay(), "_BLACKBOX_PID", False);
824 #endif // HAVE_GETPID
825 }
826
827
828 bool Blackbox::validateWindow(Window window) {
829 XEvent event;
830 if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
831 XPutBackEvent(getXDisplay(), &event);
832
833 return False;
834 }
835
836 return True;
837 }
838
839
840 BScreen *Blackbox::searchScreen(Window window) {
841 ScreenList::iterator it = screenList.begin();
842
843 for (; it != screenList.end(); ++it) {
844 BScreen *s = *it;
845 if (s->getRootWindow() == window)
846 return s;
847 }
848
849 return (BScreen *) 0;
850 }
851
852
853 BlackboxWindow *Blackbox::searchWindow(Window window) {
854 WindowLookup::iterator it = windowSearchList.find(window);
855 if (it != windowSearchList.end())
856 return it->second;
857
858 return (BlackboxWindow*) 0;
859 }
860
861
862 BWindowGroup *Blackbox::searchGroup(Window window) {
863 GroupLookup::iterator it = groupSearchList.find(window);
864 if (it != groupSearchList.end())
865 return it->second;
866
867 return (BWindowGroup *) 0;
868 }
869
870
871 Basemenu *Blackbox::searchMenu(Window window) {
872 MenuLookup::iterator it = menuSearchList.find(window);
873 if (it != menuSearchList.end())
874 return it->second;
875
876 return (Basemenu*) 0;
877 }
878
879
880 Toolbar *Blackbox::searchToolbar(Window window) {
881 ToolbarLookup::iterator it = toolbarSearchList.find(window);
882 if (it != toolbarSearchList.end())
883 return it->second;
884
885 return (Toolbar*) 0;
886 }
887
888
889 Slit *Blackbox::searchSlit(Window window) {
890 SlitLookup::iterator it = slitSearchList.find(window);
891 if (it != slitSearchList.end())
892 return it->second;
893
894 return (Slit*) 0;
895 }
896
897
898 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
899 windowSearchList.insert(WindowLookupPair(window, data));
900 }
901
902
903 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
904 groupSearchList.insert(GroupLookupPair(window, data));
905 }
906
907
908 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
909 menuSearchList.insert(MenuLookupPair(window, data));
910 }
911
912
913 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
914 toolbarSearchList.insert(ToolbarLookupPair(window, data));
915 }
916
917
918 void Blackbox::saveSlitSearch(Window window, Slit *data) {
919 slitSearchList.insert(SlitLookupPair(window, data));
920 }
921
922
923 void Blackbox::removeWindowSearch(Window window) {
924 windowSearchList.erase(window);
925 }
926
927
928 void Blackbox::removeGroupSearch(Window window) {
929 groupSearchList.erase(window);
930 }
931
932
933 void Blackbox::removeMenuSearch(Window window) {
934 menuSearchList.erase(window);
935 }
936
937
938 void Blackbox::removeToolbarSearch(Window window) {
939 toolbarSearchList.erase(window);
940 }
941
942
943 void Blackbox::removeSlitSearch(Window window) {
944 slitSearchList.erase(window);
945 }
946
947
948 void Blackbox::restart(const char *prog) {
949 shutdown();
950
951 if (prog) {
952 execlp(prog, prog, NULL);
953 perror(prog);
954 }
955
956 // fall back in case the above execlp doesn't work
957 execvp(argv[0], argv);
958 string name = basename(argv[0]);
959 execvp(name.c_str(), argv);
960 }
961
962
963 void Blackbox::shutdown(void) {
964 BaseDisplay::shutdown();
965
966 XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
967
968 std::for_each(screenList.begin(), screenList.end(),
969 std::mem_fun(&BScreen::shutdown));
970
971 XSync(getXDisplay(), False);
972 }
973
974
975 /*
976 * Save all values as they are so that the defaults will be written to the rc
977 * file
978 */
979 void Blackbox::save_rc(void) {
980 config.setAutoSave(false);
981
982 config.setValue("session.colorsPerChannel", resource.colors_per_channel);
983 config.setValue("session.doubleClickInterval",
984 resource.double_click_interval);
985 config.setValue("session.autoRaiseDelay",
986 ((resource.auto_raise_delay.tv_sec * 1000) +
987 (resource.auto_raise_delay.tv_usec / 1000)));
988 config.setValue("session.cacheLife", resource.cache_life / 60000);
989 config.setValue("session.cacheMax", resource.cache_max);
990 config.setValue("session.styleFile", resource.style_file);
991
992 std::for_each(screenList.begin(), screenList.end(),
993 std::mem_fun(&BScreen::save_rc));
994
995 config.setAutoSave(true);
996 config.save();
997 }
998
999
1000 void Blackbox::load_rc(void) {
1001 if (! config.load())
1002 config.create();
1003
1004 string s;
1005
1006 if (! config.getValue("session.colorsPerChannel",
1007 resource.colors_per_channel))
1008 resource.colors_per_channel = 4;
1009 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1010 else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1011
1012 if (config.getValue("session.styleFile", s))
1013 resource.style_file = expandTilde(s);
1014 else
1015 resource.style_file = DEFAULTSTYLE;
1016
1017 if (! config.getValue("session.doubleClickInterval",
1018 resource.double_click_interval));
1019 resource.double_click_interval = 250;
1020
1021 if (! config.getValue("session.autoRaiseDelay",
1022 resource.auto_raise_delay.tv_usec))
1023 resource.auto_raise_delay.tv_usec = 400;
1024 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1025 resource.auto_raise_delay.tv_usec -=
1026 (resource.auto_raise_delay.tv_sec * 1000);
1027 resource.auto_raise_delay.tv_usec *= 1000;
1028
1029 if (! config.getValue("session.cacheLife", resource.cache_life))
1030 resource.cache_life = 5;
1031 resource.cache_life *= 60000;
1032
1033 if (! config.getValue("session.cacheMax", resource.cache_max))
1034 resource.cache_max = 200;
1035 }
1036
1037
1038 void Blackbox::reconfigure(void) {
1039 reconfigure_wait = True;
1040
1041 if (! timer->isTiming()) timer->start();
1042 }
1043
1044
1045 void Blackbox::real_reconfigure(void) {
1046 load_rc();
1047
1048 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1049 PointerAssassin());
1050 menuTimestamps.clear();
1051
1052 gcCache()->purge();
1053
1054 std::for_each(screenList.begin(), screenList.end(),
1055 std::mem_fun(&BScreen::reconfigure));
1056 }
1057
1058
1059 void Blackbox::checkMenu(void) {
1060 bool reread = False;
1061 MenuTimestampList::iterator it = menuTimestamps.begin();
1062 for(; it != menuTimestamps.end(); ++it) {
1063 MenuTimestamp *tmp = *it;
1064 struct stat buf;
1065
1066 if (! stat(tmp->filename.c_str(), &buf)) {
1067 if (tmp->timestamp != buf.st_ctime)
1068 reread = True;
1069 } else {
1070 reread = True;
1071 }
1072 }
1073
1074 if (reread) rereadMenu();
1075 }
1076
1077
1078 void Blackbox::rereadMenu(void) {
1079 reread_menu_wait = True;
1080
1081 if (! timer->isTiming()) timer->start();
1082 }
1083
1084
1085 void Blackbox::real_rereadMenu(void) {
1086 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1087 PointerAssassin());
1088 menuTimestamps.clear();
1089
1090 std::for_each(screenList.begin(), screenList.end(),
1091 std::mem_fun(&BScreen::rereadMenu));
1092 }
1093
1094
1095 void Blackbox::saveStyleFilename(const string& filename) {
1096 assert(! filename.empty());
1097 resource.style_file = filename;
1098 config.setValue("session.styleFile", resource.style_file);
1099 }
1100
1101
1102 void Blackbox::addMenuTimestamp(const string& filename) {
1103 assert(! filename.empty());
1104 bool found = False;
1105
1106 MenuTimestampList::iterator it = menuTimestamps.begin();
1107 for (; it != menuTimestamps.end() && ! found; ++it) {
1108 if ((*it)->filename == filename) found = True;
1109 }
1110 if (! found) {
1111 struct stat buf;
1112
1113 if (! stat(filename.c_str(), &buf)) {
1114 MenuTimestamp *ts = new MenuTimestamp;
1115
1116 ts->filename = filename;
1117 ts->timestamp = buf.st_ctime;
1118
1119 menuTimestamps.push_back(ts);
1120 }
1121 }
1122 }
1123
1124
1125 void Blackbox::timeout(void) {
1126 if (reconfigure_wait)
1127 real_reconfigure();
1128
1129 if (reread_menu_wait)
1130 real_rereadMenu();
1131
1132 reconfigure_wait = reread_menu_wait = False;
1133 }
1134
1135
1136 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1137 if (focused_window && focused_window == win) // nothing to do
1138 return;
1139
1140 BScreen *old_screen = 0;
1141
1142 if (focused_window) {
1143 focused_window->setFocusFlag(False);
1144 old_screen = focused_window->getScreen();
1145 }
1146
1147 if (win && ! win->isIconic()) {
1148 // the active screen is the one with the last focused window...
1149 // this will keep focus on this screen no matter where the mouse goes,
1150 // so multihead keybindings will continue to work on that screen until the
1151 // user focuses a window on a different screen.
1152 active_screen = win->getScreen();
1153 focused_window = win;
1154 } else {
1155 focused_window = 0;
1156 if (! old_screen) {
1157 if (active_screen) {
1158 // set input focus to the toolbar of the screen with mouse
1159 XSetInputFocus(getXDisplay(),
1160 active_screen->getToolbar()->getWindowID(),
1161 RevertToPointerRoot, CurrentTime);
1162 } else {
1163 // set input focus to the toolbar of the first managed screen
1164 XSetInputFocus(getXDisplay(),
1165 screenList.front()->getToolbar()->getWindowID(),
1166 RevertToPointerRoot, CurrentTime);
1167 }
1168 } else {
1169 // set input focus to the toolbar of the last screen
1170 XSetInputFocus(getXDisplay(), old_screen->getToolbar()->getWindowID(),
1171 RevertToPointerRoot, CurrentTime);
1172 }
1173 }
1174
1175 if (active_screen && active_screen->isScreenManaged()) {
1176 active_screen->getToolbar()->redrawWindowLabel(True);
1177 active_screen->updateNetizenWindowFocus();
1178 }
1179
1180 if (old_screen && old_screen != active_screen) {
1181 old_screen->getToolbar()->redrawWindowLabel(True);
1182 old_screen->updateNetizenWindowFocus();
1183 }
1184 }
This page took 0.086566 seconds and 4 git commands to generate.