]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
updated nls to use openbox.cat
[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 config.setValue("session.titlebarLayout", resource.titlebar_layout);
992
993 std::for_each(screenList.begin(), screenList.end(),
994 std::mem_fun(&BScreen::save_rc));
995
996 config.setAutoSave(true);
997 config.save();
998 }
999
1000
1001 void Blackbox::load_rc(void) {
1002 if (! config.load())
1003 config.create();
1004
1005 string s;
1006
1007 if (! config.getValue("session.colorsPerChannel",
1008 resource.colors_per_channel))
1009 resource.colors_per_channel = 4;
1010 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1011 else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1012
1013 if (config.getValue("session.styleFile", s))
1014 resource.style_file = expandTilde(s);
1015 else
1016 resource.style_file = DEFAULTSTYLE;
1017
1018 if (! config.getValue("session.doubleClickInterval",
1019 resource.double_click_interval));
1020 resource.double_click_interval = 250;
1021
1022 if (! config.getValue("session.autoRaiseDelay",
1023 resource.auto_raise_delay.tv_usec))
1024 resource.auto_raise_delay.tv_usec = 400;
1025 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1026 resource.auto_raise_delay.tv_usec -=
1027 (resource.auto_raise_delay.tv_sec * 1000);
1028 resource.auto_raise_delay.tv_usec *= 1000;
1029
1030 if (! config.getValue("session.cacheLife", resource.cache_life))
1031 resource.cache_life = 5;
1032 resource.cache_life *= 60000;
1033
1034 if (! config.getValue("session.cacheMax", resource.cache_max))
1035 resource.cache_max = 200;
1036
1037 if (! config.getValue("session.titlebarLayout", resource.titlebar_layout))
1038 resource.titlebar_layout = "ILMC";
1039 }
1040
1041
1042 void Blackbox::reconfigure(void) {
1043 reconfigure_wait = True;
1044
1045 if (! timer->isTiming()) timer->start();
1046 }
1047
1048
1049 void Blackbox::real_reconfigure(void) {
1050 load_rc();
1051
1052 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1053 PointerAssassin());
1054 menuTimestamps.clear();
1055
1056 gcCache()->purge();
1057
1058 std::for_each(screenList.begin(), screenList.end(),
1059 std::mem_fun(&BScreen::reconfigure));
1060 }
1061
1062
1063 void Blackbox::checkMenu(void) {
1064 bool reread = False;
1065 MenuTimestampList::iterator it = menuTimestamps.begin();
1066 for(; it != menuTimestamps.end(); ++it) {
1067 MenuTimestamp *tmp = *it;
1068 struct stat buf;
1069
1070 if (! stat(tmp->filename.c_str(), &buf)) {
1071 if (tmp->timestamp != buf.st_ctime)
1072 reread = True;
1073 } else {
1074 reread = True;
1075 }
1076 }
1077
1078 if (reread) rereadMenu();
1079 }
1080
1081
1082 void Blackbox::rereadMenu(void) {
1083 reread_menu_wait = True;
1084
1085 if (! timer->isTiming()) timer->start();
1086 }
1087
1088
1089 void Blackbox::real_rereadMenu(void) {
1090 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1091 PointerAssassin());
1092 menuTimestamps.clear();
1093
1094 std::for_each(screenList.begin(), screenList.end(),
1095 std::mem_fun(&BScreen::rereadMenu));
1096 }
1097
1098
1099 void Blackbox::saveStyleFilename(const string& filename) {
1100 assert(! filename.empty());
1101 resource.style_file = filename;
1102 config.setValue("session.styleFile", resource.style_file);
1103 }
1104
1105
1106 void Blackbox::addMenuTimestamp(const string& filename) {
1107 assert(! filename.empty());
1108 bool found = False;
1109
1110 MenuTimestampList::iterator it = menuTimestamps.begin();
1111 for (; it != menuTimestamps.end() && ! found; ++it) {
1112 if ((*it)->filename == filename) found = True;
1113 }
1114 if (! found) {
1115 struct stat buf;
1116
1117 if (! stat(filename.c_str(), &buf)) {
1118 MenuTimestamp *ts = new MenuTimestamp;
1119
1120 ts->filename = filename;
1121 ts->timestamp = buf.st_ctime;
1122
1123 menuTimestamps.push_back(ts);
1124 }
1125 }
1126 }
1127
1128
1129 void Blackbox::timeout(void) {
1130 if (reconfigure_wait)
1131 real_reconfigure();
1132
1133 if (reread_menu_wait)
1134 real_rereadMenu();
1135
1136 reconfigure_wait = reread_menu_wait = False;
1137 }
1138
1139
1140 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1141 if (focused_window && focused_window == win) // nothing to do
1142 return;
1143
1144 BScreen *old_screen = 0;
1145
1146 if (focused_window) {
1147 focused_window->setFocusFlag(False);
1148 old_screen = focused_window->getScreen();
1149 }
1150
1151 if (win && ! win->isIconic()) {
1152 // the active screen is the one with the last focused window...
1153 // this will keep focus on this screen no matter where the mouse goes,
1154 // so multihead keybindings will continue to work on that screen until the
1155 // user focuses a window on a different screen.
1156 active_screen = win->getScreen();
1157 focused_window = win;
1158 } else {
1159 focused_window = 0;
1160 if (! old_screen) {
1161 if (active_screen) {
1162 // set input focus to the toolbar of the screen with mouse
1163 XSetInputFocus(getXDisplay(),
1164 active_screen->getRootWindow(),
1165 RevertToPointerRoot, CurrentTime);
1166 } else {
1167 // set input focus to the toolbar of the first managed screen
1168 XSetInputFocus(getXDisplay(),
1169 screenList.front()->getRootWindow(),
1170 RevertToPointerRoot, CurrentTime);
1171 }
1172 } else {
1173 // set input focus to the toolbar of the last screen
1174 XSetInputFocus(getXDisplay(), old_screen->getRootWindow(),
1175 RevertToPointerRoot, CurrentTime);
1176 }
1177 }
1178
1179 if (active_screen && active_screen->isScreenManaged()) {
1180 active_screen->getToolbar()->redrawWindowLabel(True);
1181 active_screen->updateNetizenWindowFocus();
1182 }
1183
1184 if (old_screen && old_screen != active_screen) {
1185 old_screen->getToolbar()->redrawWindowLabel(True);
1186 old_screen->updateNetizenWindowFocus();
1187 }
1188 }
This page took 0.095153 seconds and 4 git commands to generate.