]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
import from bb-cvs
[chaz/openbox] / src / blackbox.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // blackbox.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef HAVE_CONFIG_H
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xatom.h>
33 #include <X11/cursorfont.h>
34 #include <X11/keysym.h>
35
36 #ifdef SHAPE
37 #include <X11/extensions/shape.h>
38 #endif // SHAPE
39
40 #ifdef HAVE_STDIO_H
41 # include <stdio.h>
42 #endif // HAVE_STDIO_H
43
44 #ifdef HAVE_STDLIB_H
45 # include <stdlib.h>
46 #endif // HAVE_STDLIB_H
47
48 #ifdef HAVE_STRING_H
49 # include <string.h>
50 #endif // HAVE_STRING_H
51
52 #ifdef HAVE_UNISTD_H
53 # include <sys/types.h>
54 # include <unistd.h>
55 #endif // HAVE_UNISTD_H
56
57 #ifdef HAVE_SYS_PARAM_H
58 # include <sys/param.h>
59 #endif // HAVE_SYS_PARAM_H
60
61 #ifdef HAVE_SYS_SELECT_H
62 # include <sys/select.h>
63 #endif // HAVE_SYS_SELECT_H
64
65 #ifdef HAVE_SIGNAL_H
66 # include <signal.h>
67 #endif // HAVE_SIGNAL_H
68
69 #ifdef HAVE_SYS_SIGNAL_H
70 # include <sys/signal.h>
71 #endif // HAVE_SYS_SIGNAL_H
72
73 #ifdef HAVE_SYS_STAT_H
74 # include <sys/types.h>
75 # include <sys/stat.h>
76 #endif // HAVE_SYS_STAT_H
77
78 #ifdef TIME_WITH_SYS_TIME
79 # include <sys/time.h>
80 # include <time.h>
81 #else // !TIME_WITH_SYS_TIME
82 # ifdef HAVE_SYS_TIME_H
83 # include <sys/time.h>
84 # else // !HAVE_SYS_TIME_H
85 # include <time.h>
86 # endif // HAVE_SYS_TIME_H
87 #endif // TIME_WITH_SYS_TIME
88
89 #ifdef HAVE_LIBGEN_H
90 # include <libgen.h>
91 #endif // HAVE_LIBGEN_H
92 }
93
94 #include <algorithm>
95 #include <string>
96 using std::string;
97
98 #include "i18n.hh"
99 #include "blackbox.hh"
100 #include "Basemenu.hh"
101 #include "Clientmenu.hh"
102 #include "GCCache.hh"
103 #include "Image.hh"
104 #include "Rootmenu.hh"
105 #include "Screen.hh"
106 #include "Slit.hh"
107 #include "Toolbar.hh"
108 #include "Util.hh"
109 #include "Window.hh"
110 #include "Workspace.hh"
111 #include "Workspacemenu.hh"
112
113
114 // X event scanner for enter/leave notifies - adapted from twm
115 struct scanargs {
116 Window w;
117 bool leave, inferior, enter;
118 };
119
120 static Bool queueScanner(Display *, XEvent *e, char *args) {
121 scanargs *scan = (scanargs *) args;
122 if ((e->type == LeaveNotify) &&
123 (e->xcrossing.window == scan->w) &&
124 (e->xcrossing.mode == NotifyNormal)) {
125 scan->leave = True;
126 scan->inferior = (e->xcrossing.detail == NotifyInferior);
127 } else if ((e->type == EnterNotify) && (e->xcrossing.mode == NotifyUngrab)) {
128 scan->enter = True;
129 }
130
131 return False;
132 }
133
134 Blackbox *blackbox;
135
136
137 Blackbox::Blackbox(char **m_argv, char *dpy_name, char *rc)
138 : BaseDisplay(m_argv[0], dpy_name) {
139 if (! XSupportsLocale())
140 fprintf(stderr, "X server does not support locale\n");
141
142 if (XSetLocaleModifiers("") == NULL)
143 fprintf(stderr, "cannot set locale modifiers\n");
144
145 ::blackbox = this;
146 argv = m_argv;
147 if (! rc) rc = "~/.blackboxrc";
148 rc_file = expandTilde(rc);
149
150 no_focus = False;
151
152 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
153
154 active_screen = 0;
155 focused_window = (BlackboxWindow *) 0;
156
157 XrmInitialize();
158 load_rc();
159
160 init_icccm();
161
162 cursor.session = XCreateFontCursor(getXDisplay(), XC_left_ptr);
163 cursor.move = XCreateFontCursor(getXDisplay(), XC_fleur);
164 cursor.ll_angle = XCreateFontCursor(getXDisplay(), XC_ll_angle);
165 cursor.lr_angle = XCreateFontCursor(getXDisplay(), XC_lr_angle);
166
167 for (unsigned int i = 0; i < getNumberOfScreens(); i++) {
168 BScreen *screen = new BScreen(this, i);
169
170 if (! screen->isScreenManaged()) {
171 delete screen;
172 continue;
173 }
174
175 screenList.push_back(screen);
176 }
177
178 if (screenList.empty()) {
179 fprintf(stderr,
180 i18n(blackboxSet, blackboxNoManagableScreens,
181 "Blackbox::Blackbox: no managable screens found, aborting.\n"));
182 ::exit(3);
183 }
184
185 // set the screen with mouse to the first managed screen
186 active_screen = screenList.front();
187 setFocusedWindow(0);
188
189 XSynchronize(getXDisplay(), False);
190 XSync(getXDisplay(), False);
191
192 reconfigure_wait = reread_menu_wait = False;
193
194 timer = new BTimer(this, this);
195 timer->setTimeout(0l);
196 }
197
198
199 Blackbox::~Blackbox(void) {
200 std::for_each(screenList.begin(), screenList.end(), PointerAssassin());
201
202 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
203 PointerAssassin());
204
205 delete timer;
206 }
207
208
209 void Blackbox::process_event(XEvent *e) {
210 switch (e->type) {
211 case ButtonPress: {
212 // strip the lock key modifiers
213 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
214
215 last_time = e->xbutton.time;
216
217 BlackboxWindow *win = (BlackboxWindow *) 0;
218 Basemenu *menu = (Basemenu *) 0;
219 Slit *slit = (Slit *) 0;
220 Toolbar *tbar = (Toolbar *) 0;
221 BScreen *scrn = (BScreen *) 0;
222
223 if ((win = searchWindow(e->xbutton.window))) {
224 win->buttonPressEvent(&e->xbutton);
225
226 /* XXX: is this sane on low colour desktops? */
227 if (e->xbutton.button == 1)
228 win->installColormap(True);
229 } else if ((menu = searchMenu(e->xbutton.window))) {
230 menu->buttonPressEvent(&e->xbutton);
231 } else if ((slit = searchSlit(e->xbutton.window))) {
232 slit->buttonPressEvent(&e->xbutton);
233 } else if ((tbar = searchToolbar(e->xbutton.window))) {
234 tbar->buttonPressEvent(&e->xbutton);
235 } else if ((scrn = searchScreen(e->xbutton.window))) {
236 scrn->buttonPressEvent(&e->xbutton);
237 if (active_screen != scrn) {
238 active_screen = scrn;
239 // first, set no focus window on the old screen
240 setFocusedWindow(0);
241 // and move focus to this screen
242 setFocusedWindow(0);
243 }
244 }
245 break;
246 }
247
248 case ButtonRelease: {
249 // strip the lock key modifiers
250 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
251
252 last_time = e->xbutton.time;
253
254 BlackboxWindow *win = (BlackboxWindow *) 0;
255 Basemenu *menu = (Basemenu *) 0;
256 Toolbar *tbar = (Toolbar *) 0;
257
258 if ((win = searchWindow(e->xbutton.window)))
259 win->buttonReleaseEvent(&e->xbutton);
260 else if ((menu = searchMenu(e->xbutton.window)))
261 menu->buttonReleaseEvent(&e->xbutton);
262 else if ((tbar = searchToolbar(e->xbutton.window)))
263 tbar->buttonReleaseEvent(&e->xbutton);
264
265 break;
266 }
267
268 case ConfigureRequest: {
269 // compress configure requests...
270 XEvent realevent;
271 unsigned int i = 0;
272 while(XCheckTypedWindowEvent(getXDisplay(), e->xconfigurerequest.window,
273 ConfigureRequest, &realevent)) {
274 i++;
275 }
276 if ( i > 0 )
277 e = &realevent;
278
279 BlackboxWindow *win = (BlackboxWindow *) 0;
280 Slit *slit = (Slit *) 0;
281
282 if ((win = searchWindow(e->xconfigurerequest.window))) {
283 win->configureRequestEvent(&e->xconfigurerequest);
284 } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
285 slit->configureRequestEvent(&e->xconfigurerequest);
286 } else {
287 if (validateWindow(e->xconfigurerequest.window)) {
288 XWindowChanges xwc;
289
290 xwc.x = e->xconfigurerequest.x;
291 xwc.y = e->xconfigurerequest.y;
292 xwc.width = e->xconfigurerequest.width;
293 xwc.height = e->xconfigurerequest.height;
294 xwc.border_width = e->xconfigurerequest.border_width;
295 xwc.sibling = e->xconfigurerequest.above;
296 xwc.stack_mode = e->xconfigurerequest.detail;
297
298 XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
299 e->xconfigurerequest.value_mask, &xwc);
300 }
301 }
302
303 break;
304 }
305
306 case MapRequest: {
307 #ifdef DEBUG
308 fprintf(stderr, "Blackbox::process_event(): MapRequest for 0x%lx\n",
309 e->xmaprequest.window);
310 #endif // DEBUG
311
312 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
313
314 if (! win) {
315 BScreen *screen = searchScreen(e->xmaprequest.parent);
316
317 if (! screen) {
318 /*
319 we got a map request for a window who's parent isn't root. this
320 can happen in only one circumstance:
321
322 a client window unmapped a managed window, and then remapped it
323 somewhere between unmapping the client window and reparenting it
324 to root.
325
326 regardless of how it happens, we need to find the screen that
327 the window is on
328 */
329 XWindowAttributes wattrib;
330 if (! XGetWindowAttributes(getXDisplay(), e->xmaprequest.window,
331 &wattrib)) {
332 // failed to get the window attributes, perhaps the window has
333 // now been destroyed?
334 break;
335 }
336
337 screen = searchScreen(wattrib.root);
338 assert(screen != 0); // this should never happen
339 }
340
341 screen->manageWindow(e->xmaprequest.window);
342 }
343
344 break;
345 }
346
347 case UnmapNotify: {
348 BlackboxWindow *win = (BlackboxWindow *) 0;
349 Slit *slit = (Slit *) 0;
350
351 if ((win = searchWindow(e->xunmap.window))) {
352 win->unmapNotifyEvent(&e->xunmap);
353 } else if ((slit = searchSlit(e->xunmap.window))) {
354 slit->unmapNotifyEvent(&e->xunmap);
355 }
356
357 break;
358 }
359
360 case DestroyNotify: {
361 BlackboxWindow *win = (BlackboxWindow *) 0;
362 Slit *slit = (Slit *) 0;
363 BWindowGroup *group = (BWindowGroup *) 0;
364
365 if ((win = searchWindow(e->xdestroywindow.window))) {
366 win->destroyNotifyEvent(&e->xdestroywindow);
367 } else if ((slit = searchSlit(e->xdestroywindow.window))) {
368 slit->removeClient(e->xdestroywindow.window, False);
369 } else if ((group = searchGroup(e->xdestroywindow.window))) {
370 delete group;
371 }
372
373 break;
374 }
375
376 case ReparentNotify: {
377 /*
378 this event is quite rare and is usually handled in unmapNotify
379 however, if the window is unmapped when the reparent event occurs
380 the window manager never sees it because an unmap event is not sent
381 to an already unmapped window.
382 */
383 BlackboxWindow *win = searchWindow(e->xreparent.window);
384 if (win) {
385 win->reparentNotifyEvent(&e->xreparent);
386 } else {
387 Slit *slit = searchSlit(e->xreparent.window);
388 if (slit && slit->getWindowID() != e->xreparent.parent)
389 slit->removeClient(e->xreparent.window, True);
390 }
391 break;
392 }
393
394 case MotionNotify: {
395 // motion notify compression...
396 XEvent realevent;
397 unsigned int i = 0;
398 while (XCheckTypedWindowEvent(getXDisplay(), e->xmotion.window,
399 MotionNotify, &realevent)) {
400 i++;
401 }
402
403 // if we have compressed some motion events, use the last one
404 if ( i > 0 )
405 e = &realevent;
406
407 // strip the lock key modifiers
408 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
409
410 last_time = e->xmotion.time;
411
412 BlackboxWindow *win = (BlackboxWindow *) 0;
413 Basemenu *menu = (Basemenu *) 0;
414
415 if ((win = searchWindow(e->xmotion.window)))
416 win->motionNotifyEvent(&e->xmotion);
417 else if ((menu = searchMenu(e->xmotion.window)))
418 menu->motionNotifyEvent(&e->xmotion);
419
420 break;
421 }
422
423 case PropertyNotify: {
424 last_time = e->xproperty.time;
425
426 if (e->xproperty.state != PropertyDelete) {
427 BlackboxWindow *win = searchWindow(e->xproperty.window);
428
429 if (win)
430 win->propertyNotifyEvent(e->xproperty.atom);
431 }
432
433 break;
434 }
435
436 case EnterNotify: {
437 last_time = e->xcrossing.time;
438
439 BScreen *screen = (BScreen *) 0;
440 BlackboxWindow *win = (BlackboxWindow *) 0;
441 Basemenu *menu = (Basemenu *) 0;
442 Toolbar *tbar = (Toolbar *) 0;
443 Slit *slit = (Slit *) 0;
444
445 if (e->xcrossing.mode == NotifyGrab) break;
446
447 XEvent dummy;
448 scanargs sa;
449 sa.w = e->xcrossing.window;
450 sa.enter = sa.leave = False;
451 XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
452
453 if ((e->xcrossing.window == e->xcrossing.root) &&
454 (screen = searchScreen(e->xcrossing.window))) {
455 screen->getImageControl()->installRootColormap();
456 } else if ((win = searchWindow(e->xcrossing.window))) {
457 if (win->getScreen()->isSloppyFocus() &&
458 (! win->isFocused()) && (! no_focus)) {
459 if (((! sa.leave) || sa.inferior) && win->isVisible()) {
460 if (win->setInputFocus())
461 win->installColormap(True); // XXX: shouldnt we honour no install?
462 }
463 }
464 } else if ((menu = searchMenu(e->xcrossing.window))) {
465 menu->enterNotifyEvent(&e->xcrossing);
466 } else if ((tbar = searchToolbar(e->xcrossing.window))) {
467 tbar->enterNotifyEvent(&e->xcrossing);
468 } else if ((slit = searchSlit(e->xcrossing.window))) {
469 slit->enterNotifyEvent(&e->xcrossing);
470 }
471 break;
472 }
473
474 case LeaveNotify: {
475 last_time = e->xcrossing.time;
476
477 BlackboxWindow *win = (BlackboxWindow *) 0;
478 Basemenu *menu = (Basemenu *) 0;
479 Toolbar *tbar = (Toolbar *) 0;
480 Slit *slit = (Slit *) 0;
481
482 if ((menu = searchMenu(e->xcrossing.window)))
483 menu->leaveNotifyEvent(&e->xcrossing);
484 else if ((win = searchWindow(e->xcrossing.window)))
485 win->installColormap(False);
486 else if ((tbar = searchToolbar(e->xcrossing.window)))
487 tbar->leaveNotifyEvent(&e->xcrossing);
488 else if ((slit = searchSlit(e->xcrossing.window)))
489 slit->leaveNotifyEvent(&e->xcrossing);
490 break;
491 }
492
493 case Expose: {
494 // compress expose events
495 XEvent realevent;
496 unsigned int i = 0;
497 int ex1, ey1, ex2, ey2;
498 ex1 = e->xexpose.x;
499 ey1 = e->xexpose.y;
500 ex2 = ex1 + e->xexpose.width - 1;
501 ey2 = ey1 + e->xexpose.height - 1;
502 while (XCheckTypedWindowEvent(getXDisplay(), e->xexpose.window,
503 Expose, &realevent)) {
504 i++;
505
506 // merge expose area
507 ex1 = std::min(realevent.xexpose.x, ex1);
508 ey1 = std::min(realevent.xexpose.y, ey1);
509 ex2 = std::max(realevent.xexpose.x + realevent.xexpose.width - 1, ex2);
510 ey2 = std::max(realevent.xexpose.y + realevent.xexpose.height - 1, ey2);
511 }
512 if ( i > 0 )
513 e = &realevent;
514
515 // use the merged area
516 e->xexpose.x = ex1;
517 e->xexpose.y = ey1;
518 e->xexpose.width = ex2 - ex1 + 1;
519 e->xexpose.height = ey2 - ey1 + 1;
520
521 BlackboxWindow *win = (BlackboxWindow *) 0;
522 Basemenu *menu = (Basemenu *) 0;
523 Toolbar *tbar = (Toolbar *) 0;
524
525 if ((win = searchWindow(e->xexpose.window)))
526 win->exposeEvent(&e->xexpose);
527 else if ((menu = searchMenu(e->xexpose.window)))
528 menu->exposeEvent(&e->xexpose);
529 else if ((tbar = searchToolbar(e->xexpose.window)))
530 tbar->exposeEvent(&e->xexpose);
531
532 break;
533 }
534
535 case KeyPress: {
536 Toolbar *tbar = searchToolbar(e->xkey.window);
537
538 if (tbar && tbar->isEditing())
539 tbar->keyPressEvent(&e->xkey);
540
541 break;
542 }
543
544 case ColormapNotify: {
545 BScreen *screen = searchScreen(e->xcolormap.window);
546
547 if (screen)
548 screen->setRootColormapInstalled((e->xcolormap.state ==
549 ColormapInstalled) ? True : False);
550
551 break;
552 }
553
554 case FocusIn: {
555 if (e->xfocus.detail != NotifyNonlinear) {
556 /*
557 don't process FocusIns when:
558 1. the new focus window isn't an ancestor or inferior of the old
559 focus window (NotifyNonlinear)
560 */
561 break;
562 }
563
564 BlackboxWindow *win = searchWindow(e->xfocus.window);
565 if (win) {
566 if (! win->isFocused())
567 win->setFocusFlag(True);
568
569 /*
570 set the event window to None. when the FocusOut event handler calls
571 this function recursively, it uses this as an indication that focus
572 has moved to a known window.
573 */
574 e->xfocus.window = None;
575 }
576
577 break;
578 }
579
580 case FocusOut: {
581 if (e->xfocus.detail != NotifyNonlinear) {
582 /*
583 don't process FocusOuts when:
584 2. the new focus window isn't an ancestor or inferior of the old
585 focus window (NotifyNonlinear)
586 */
587 break;
588 }
589
590 BlackboxWindow *win = searchWindow(e->xfocus.window);
591 if (win && win->isFocused()) {
592 /*
593 before we mark "win" as unfocused, we need to verify that focus is
594 going to a known location, is in a known location, or set focus
595 to a known location.
596 */
597
598 XEvent event;
599 // don't check the current focus if FocusOut was generated during a grab
600 bool check_focus = (e->xfocus.mode == NotifyNormal);
601
602 /*
603 First, check if there is a pending FocusIn event waiting. if there
604 is, process it and determine if focus has moved to another window
605 (the FocusIn event handler sets the window in the event
606 structure to None to indicate this).
607 */
608 if (XCheckTypedEvent(getXDisplay(), FocusIn, &event)) {
609
610 process_event(&event);
611 if (event.xfocus.window == None) {
612 // focus has moved
613 check_focus = False;
614 }
615 }
616
617 if (check_focus) {
618 /*
619 Second, we query the X server for the current input focus.
620 to make sure that we keep a consistent state.
621 */
622 BlackboxWindow *focus;
623 Window w;
624 int revert;
625 XGetInputFocus(getXDisplay(), &w, &revert);
626 focus = searchWindow(w);
627 if (focus) {
628 /*
629 focus got from "win" to "focus" under some very strange
630 circumstances, and we need to make sure that the focus indication
631 is correct.
632 */
633 setFocusedWindow(focus);
634 } else {
635 // we have no idea where focus went... so we set it to somewhere
636 setFocusedWindow(0);
637 }
638 }
639 }
640
641 break;
642 }
643
644 case ClientMessage: {
645 if (e->xclient.format == 32) {
646 if (e->xclient.message_type == getWMChangeStateAtom()) {
647 BlackboxWindow *win = searchWindow(e->xclient.window);
648 if (! win || ! win->validateClient()) return;
649
650 if (e->xclient.data.l[0] == IconicState)
651 win->iconify();
652 if (e->xclient.data.l[0] == NormalState)
653 win->deiconify();
654 } else if(e->xclient.message_type == getBlackboxChangeWorkspaceAtom()) {
655 BScreen *screen = searchScreen(e->xclient.window);
656
657 if (screen && e->xclient.data.l[0] >= 0 &&
658 e->xclient.data.l[0] <
659 static_cast<signed>(screen->getWorkspaceCount()))
660 screen->changeWorkspaceID(e->xclient.data.l[0]);
661 } else if (e->xclient.message_type == getBlackboxChangeWindowFocusAtom()) {
662 BlackboxWindow *win = searchWindow(e->xclient.window);
663
664 if (win && win->isVisible() && win->setInputFocus())
665 win->installColormap(True);
666 } else if (e->xclient.message_type == getBlackboxCycleWindowFocusAtom()) {
667 BScreen *screen = searchScreen(e->xclient.window);
668
669 if (screen) {
670 if (! e->xclient.data.l[0])
671 screen->prevFocus();
672 else
673 screen->nextFocus();
674 }
675 } else if (e->xclient.message_type == getBlackboxChangeAttributesAtom()) {
676 BlackboxWindow *win = searchWindow(e->xclient.window);
677
678 if (win && win->validateClient()) {
679 BlackboxHints net;
680 net.flags = e->xclient.data.l[0];
681 net.attrib = e->xclient.data.l[1];
682 net.workspace = e->xclient.data.l[2];
683 net.stack = e->xclient.data.l[3];
684 net.decoration = e->xclient.data.l[4];
685
686 win->changeBlackboxHints(&net);
687 }
688 }
689 }
690
691 break;
692 }
693
694 case NoExpose:
695 case ConfigureNotify:
696 case MapNotify:
697 break; // not handled, just ignore
698
699 default: {
700 #ifdef SHAPE
701 if (e->type == getShapeEventBase()) {
702 XShapeEvent *shape_event = (XShapeEvent *) e;
703 BlackboxWindow *win = searchWindow(e->xany.window);
704
705 if (win)
706 win->shapeEvent(shape_event);
707 }
708 #endif // SHAPE
709 }
710 } // switch
711 }
712
713
714 bool Blackbox::handleSignal(int sig) {
715 switch (sig) {
716 case SIGHUP:
717 reconfigure();
718 break;
719
720 case SIGUSR1:
721 reload_rc();
722 break;
723
724 case SIGUSR2:
725 rereadMenu();
726 break;
727
728 case SIGPIPE:
729 case SIGSEGV:
730 case SIGFPE:
731 case SIGINT:
732 case SIGTERM:
733 shutdown();
734
735 default:
736 return False;
737 }
738
739 return True;
740 }
741
742
743 void Blackbox::init_icccm(void) {
744 xa_wm_colormap_windows =
745 XInternAtom(getXDisplay(), "WM_COLORMAP_WINDOWS", False);
746 xa_wm_protocols = XInternAtom(getXDisplay(), "WM_PROTOCOLS", False);
747 xa_wm_state = XInternAtom(getXDisplay(), "WM_STATE", False);
748 xa_wm_change_state = XInternAtom(getXDisplay(), "WM_CHANGE_STATE", False);
749 xa_wm_delete_window = XInternAtom(getXDisplay(), "WM_DELETE_WINDOW", False);
750 xa_wm_take_focus = XInternAtom(getXDisplay(), "WM_TAKE_FOCUS", False);
751 motif_wm_hints = XInternAtom(getXDisplay(), "_MOTIF_WM_HINTS", False);
752
753 blackbox_hints = XInternAtom(getXDisplay(), "_BLACKBOX_HINTS", False);
754 blackbox_attributes =
755 XInternAtom(getXDisplay(), "_BLACKBOX_ATTRIBUTES", False);
756 blackbox_change_attributes =
757 XInternAtom(getXDisplay(), "_BLACKBOX_CHANGE_ATTRIBUTES", False);
758 blackbox_structure_messages =
759 XInternAtom(getXDisplay(), "_BLACKBOX_STRUCTURE_MESSAGES", False);
760 blackbox_notify_startup =
761 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_STARTUP", False);
762 blackbox_notify_window_add =
763 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_ADD", False);
764 blackbox_notify_window_del =
765 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_DEL", False);
766 blackbox_notify_current_workspace =
767 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_CURRENT_WORKSPACE", False);
768 blackbox_notify_workspace_count =
769 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WORKSPACE_COUNT", False);
770 blackbox_notify_window_focus =
771 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_FOCUS", False);
772 blackbox_notify_window_raise =
773 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_RAISE", False);
774 blackbox_notify_window_lower =
775 XInternAtom(getXDisplay(), "_BLACKBOX_NOTIFY_WINDOW_LOWER", False);
776 blackbox_change_workspace =
777 XInternAtom(getXDisplay(), "_BLACKBOX_CHANGE_WORKSPACE", False);
778 blackbox_change_window_focus =
779 XInternAtom(getXDisplay(), "_BLACKBOX_CHANGE_WINDOW_FOCUS", False);
780 blackbox_cycle_window_focus =
781 XInternAtom(getXDisplay(), "_BLACKBOX_CYCLE_WINDOW_FOCUS", False);
782
783 #ifdef NEWWMSPEC
784 net_supported = XInternAtom(getXDisplay(), "_NET_SUPPORTED", False);
785 net_client_list = XInternAtom(getXDisplay(), "_NET_CLIENT_LIST", False);
786 net_client_list_stacking =
787 XInternAtom(getXDisplay(), "_NET_CLIENT_LIST_STACKING", False);
788 net_number_of_desktops =
789 XInternAtom(getXDisplay(), "_NET_NUMBER_OF_DESKTOPS", False);
790 net_desktop_geometry =
791 XInternAtom(getXDisplay(), "_NET_DESKTOP_GEOMETRY", False);
792 net_desktop_viewport =
793 XInternAtom(getXDisplay(), "_NET_DESKTOP_VIEWPORT", False);
794 net_current_desktop =
795 XInternAtom(getXDisplay(), "_NET_CURRENT_DESKTOP", False);
796 net_desktop_names = XInternAtom(getXDisplay(), "_NET_DESKTOP_NAMES", False);
797 net_active_window = XInternAtom(getXDisplay(), "_NET_ACTIVE_WINDOW", False);
798 net_workarea = XInternAtom(getXDisplay(), "_NET_WORKAREA", False);
799 net_supporting_wm_check =
800 XInternAtom(getXDisplay(), "_NET_SUPPORTING_WM_CHECK", False);
801 net_virtual_roots = XInternAtom(getXDisplay(), "_NET_VIRTUAL_ROOTS", False);
802 net_close_window = XInternAtom(getXDisplay(), "_NET_CLOSE_WINDOW", False);
803 net_wm_moveresize = XInternAtom(getXDisplay(), "_NET_WM_MOVERESIZE", False);
804 net_properties = XInternAtom(getXDisplay(), "_NET_PROPERTIES", False);
805 net_wm_name = XInternAtom(getXDisplay(), "_NET_WM_NAME", False);
806 net_wm_desktop = XInternAtom(getXDisplay(), "_NET_WM_DESKTOP", False);
807 net_wm_window_type =
808 XInternAtom(getXDisplay(), "_NET_WM_WINDOW_TYPE", False);
809 net_wm_state = XInternAtom(getXDisplay(), "_NET_WM_STATE", False);
810 net_wm_strut = XInternAtom(getXDisplay(), "_NET_WM_STRUT", False);
811 net_wm_icon_geometry =
812 XInternAtom(getXDisplay(), "_NET_WM_ICON_GEOMETRY", False);
813 net_wm_icon = XInternAtom(getXDisplay(), "_NET_WM_ICON", False);
814 net_wm_pid = XInternAtom(getXDisplay(), "_NET_WM_PID", False);
815 net_wm_handled_icons =
816 XInternAtom(getXDisplay(), "_NET_WM_HANDLED_ICONS", False);
817 net_wm_ping = XInternAtom(getXDisplay(), "_NET_WM_PING", False);
818 #endif // NEWWMSPEC
819
820 #ifdef HAVE_GETPID
821 blackbox_pid = XInternAtom(getXDisplay(), "_BLACKBOX_PID", False);
822 #endif // HAVE_GETPID
823 }
824
825
826 bool Blackbox::validateWindow(Window window) {
827 XEvent event;
828 if (XCheckTypedWindowEvent(getXDisplay(), window, DestroyNotify, &event)) {
829 XPutBackEvent(getXDisplay(), &event);
830
831 return False;
832 }
833
834 return True;
835 }
836
837
838 BScreen *Blackbox::searchScreen(Window window) {
839 ScreenList::iterator it = screenList.begin();
840
841 for (; it != screenList.end(); ++it) {
842 BScreen *s = *it;
843 if (s->getRootWindow() == window)
844 return s;
845 }
846
847 return (BScreen *) 0;
848 }
849
850
851 BlackboxWindow *Blackbox::searchWindow(Window window) {
852 WindowLookup::iterator it = windowSearchList.find(window);
853 if (it != windowSearchList.end())
854 return it->second;
855
856 return (BlackboxWindow*) 0;
857 }
858
859
860 BWindowGroup *Blackbox::searchGroup(Window window) {
861 GroupLookup::iterator it = groupSearchList.find(window);
862 if (it != groupSearchList.end())
863 return it->second;
864
865 return (BWindowGroup *) 0;
866 }
867
868
869 Basemenu *Blackbox::searchMenu(Window window) {
870 MenuLookup::iterator it = menuSearchList.find(window);
871 if (it != menuSearchList.end())
872 return it->second;
873
874 return (Basemenu*) 0;
875 }
876
877
878 Toolbar *Blackbox::searchToolbar(Window window) {
879 ToolbarLookup::iterator it = toolbarSearchList.find(window);
880 if (it != toolbarSearchList.end())
881 return it->second;
882
883 return (Toolbar*) 0;
884 }
885
886
887 Slit *Blackbox::searchSlit(Window window) {
888 SlitLookup::iterator it = slitSearchList.find(window);
889 if (it != slitSearchList.end())
890 return it->second;
891
892 return (Slit*) 0;
893 }
894
895
896 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
897 windowSearchList.insert(WindowLookupPair(window, data));
898 }
899
900
901 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
902 groupSearchList.insert(GroupLookupPair(window, data));
903 }
904
905
906 void Blackbox::saveMenuSearch(Window window, Basemenu *data) {
907 menuSearchList.insert(MenuLookupPair(window, data));
908 }
909
910
911 void Blackbox::saveToolbarSearch(Window window, Toolbar *data) {
912 toolbarSearchList.insert(ToolbarLookupPair(window, data));
913 }
914
915
916 void Blackbox::saveSlitSearch(Window window, Slit *data) {
917 slitSearchList.insert(SlitLookupPair(window, data));
918 }
919
920
921 void Blackbox::removeWindowSearch(Window window) {
922 windowSearchList.erase(window);
923 }
924
925
926 void Blackbox::removeGroupSearch(Window window) {
927 groupSearchList.erase(window);
928 }
929
930
931 void Blackbox::removeMenuSearch(Window window) {
932 menuSearchList.erase(window);
933 }
934
935
936 void Blackbox::removeToolbarSearch(Window window) {
937 toolbarSearchList.erase(window);
938 }
939
940
941 void Blackbox::removeSlitSearch(Window window) {
942 slitSearchList.erase(window);
943 }
944
945
946 void Blackbox::restart(const char *prog) {
947 shutdown();
948
949 if (prog) {
950 execlp(prog, prog, NULL);
951 perror(prog);
952 }
953
954 // fall back in case the above execlp doesn't work
955 execvp(argv[0], argv);
956 string name = basename(argv[0]);
957 execvp(name.c_str(), argv);
958 }
959
960
961 void Blackbox::shutdown(void) {
962 BaseDisplay::shutdown();
963
964 XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);
965
966 std::for_each(screenList.begin(), screenList.end(),
967 std::mem_fun(&BScreen::shutdown));
968
969 XSync(getXDisplay(), False);
970
971 save_rc();
972 }
973
974
975 void Blackbox::save_rc(void) {
976 XrmDatabase new_blackboxrc = (XrmDatabase) 0;
977 char rc_string[1024];
978
979 load_rc();
980
981 sprintf(rc_string, "session.menuFile: %s", getMenuFilename());
982 XrmPutLineResource(&new_blackboxrc, rc_string);
983
984 sprintf(rc_string, "session.colorsPerChannel: %d",
985 resource.colors_per_channel);
986 XrmPutLineResource(&new_blackboxrc, rc_string);
987
988 sprintf(rc_string, "session.doubleClickInterval: %lu",
989 resource.double_click_interval);
990 XrmPutLineResource(&new_blackboxrc, rc_string);
991
992 sprintf(rc_string, "session.autoRaiseDelay: %lu",
993 ((resource.auto_raise_delay.tv_sec * 1000) +
994 (resource.auto_raise_delay.tv_usec / 1000)));
995 XrmPutLineResource(&new_blackboxrc, rc_string);
996
997 sprintf(rc_string, "session.cacheLife: %lu", resource.cache_life / 60000);
998 XrmPutLineResource(&new_blackboxrc, rc_string);
999
1000 sprintf(rc_string, "session.cacheMax: %lu", resource.cache_max);
1001 XrmPutLineResource(&new_blackboxrc, rc_string);
1002
1003 ScreenList::iterator it = screenList.begin();
1004 for (; it != screenList.end(); ++it) {
1005 BScreen *screen = *it;
1006 int screen_number = screen->getScreenNumber();
1007
1008 char *placement = (char *) 0;
1009
1010 switch (screen->getSlitPlacement()) {
1011 case Slit::TopLeft: placement = "TopLeft"; break;
1012 case Slit::CenterLeft: placement = "CenterLeft"; break;
1013 case Slit::BottomLeft: placement = "BottomLeft"; break;
1014 case Slit::TopCenter: placement = "TopCenter"; break;
1015 case Slit::BottomCenter: placement = "BottomCenter"; break;
1016 case Slit::TopRight: placement = "TopRight"; break;
1017 case Slit::BottomRight: placement = "BottomRight"; break;
1018 case Slit::CenterRight: default: placement = "CenterRight"; break;
1019 }
1020
1021 sprintf(rc_string, "session.screen%d.slit.placement: %s", screen_number,
1022 placement);
1023 XrmPutLineResource(&new_blackboxrc, rc_string);
1024
1025 sprintf(rc_string, "session.screen%d.slit.direction: %s", screen_number,
1026 ((screen->getSlitDirection() == Slit::Horizontal) ? "Horizontal" :
1027 "Vertical"));
1028 XrmPutLineResource(&new_blackboxrc, rc_string);
1029
1030 sprintf(rc_string, "session.screen%d.slit.onTop: %s", screen_number,
1031 ((screen->getSlit()->isOnTop()) ? "True" : "False"));
1032 XrmPutLineResource(&new_blackboxrc, rc_string);
1033
1034 sprintf(rc_string, "session.screen%d.slit.autoHide: %s", screen_number,
1035 ((screen->getSlit()->doAutoHide()) ? "True" : "False"));
1036 XrmPutLineResource(&new_blackboxrc, rc_string);
1037
1038 sprintf(rc_string, "session.opaqueMove: %s",
1039 ((screen->doOpaqueMove()) ? "True" : "False"));
1040 XrmPutLineResource(&new_blackboxrc, rc_string);
1041
1042 sprintf(rc_string, "session.imageDither: %s",
1043 ((screen->getImageControl()->doDither()) ? "True" : "False"));
1044 XrmPutLineResource(&new_blackboxrc, rc_string);
1045
1046 sprintf(rc_string, "session.screen%d.fullMaximization: %s", screen_number,
1047 ((screen->doFullMax()) ? "True" : "False"));
1048 XrmPutLineResource(&new_blackboxrc, rc_string);
1049
1050 sprintf(rc_string, "session.screen%d.focusNewWindows: %s", screen_number,
1051 ((screen->doFocusNew()) ? "True" : "False"));
1052 XrmPutLineResource(&new_blackboxrc, rc_string);
1053
1054 sprintf(rc_string, "session.screen%d.focusLastWindow: %s", screen_number,
1055 ((screen->doFocusLast()) ? "True" : "False"));
1056 XrmPutLineResource(&new_blackboxrc, rc_string);
1057
1058 sprintf(rc_string, "session.screen%d.rowPlacementDirection: %s",
1059 screen_number,
1060 ((screen->getRowPlacementDirection() == BScreen::LeftRight) ?
1061 "LeftToRight" : "RightToLeft"));
1062 XrmPutLineResource(&new_blackboxrc, rc_string);
1063
1064 sprintf(rc_string, "session.screen%d.colPlacementDirection: %s",
1065 screen_number,
1066 ((screen->getColPlacementDirection() == BScreen::TopBottom) ?
1067 "TopToBottom" : "BottomToTop"));
1068 XrmPutLineResource(&new_blackboxrc, rc_string);
1069
1070 switch (screen->getPlacementPolicy()) {
1071 case BScreen::CascadePlacement:
1072 placement = "CascadePlacement";
1073 break;
1074 case BScreen::ColSmartPlacement:
1075 placement = "ColSmartPlacement";
1076 break;
1077
1078 case BScreen::RowSmartPlacement:
1079 default:
1080 placement = "RowSmartPlacement";
1081 break;
1082 }
1083 sprintf(rc_string, "session.screen%d.windowPlacement: %s", screen_number,
1084 placement);
1085 XrmPutLineResource(&new_blackboxrc, rc_string);
1086
1087 string fmodel;
1088 if (screen->isSloppyFocus()) {
1089 fmodel = "SloppyFocus";
1090 if (screen->doAutoRaise()) fmodel += " AutoRaise";
1091 if (screen->doClickRaise()) fmodel += " ClickRaise";
1092 } else {
1093 fmodel = "ClickToFocus";
1094 }
1095 sprintf(rc_string, "session.screen%d.focusModel: %s", screen_number,
1096 fmodel.c_str());
1097 XrmPutLineResource(&new_blackboxrc, rc_string);
1098
1099 sprintf(rc_string, "session.screen%d.workspaces: %d", screen_number,
1100 screen->getWorkspaceCount());
1101 XrmPutLineResource(&new_blackboxrc, rc_string);
1102
1103 sprintf(rc_string, "session.screen%d.toolbar.onTop: %s", screen_number,
1104 ((screen->getToolbar()->isOnTop()) ? "True" : "False"));
1105 XrmPutLineResource(&new_blackboxrc, rc_string);
1106
1107 sprintf(rc_string, "session.screen%d.toolbar.autoHide: %s",
1108 screen_number,
1109 ((screen->getToolbar()->doAutoHide()) ? "True" : "False"));
1110 XrmPutLineResource(&new_blackboxrc, rc_string);
1111
1112 switch (screen->getToolbarPlacement()) {
1113 case Toolbar::TopLeft: placement = "TopLeft"; break;
1114 case Toolbar::BottomLeft: placement = "BottomLeft"; break;
1115 case Toolbar::TopCenter: placement = "TopCenter"; break;
1116 case Toolbar::TopRight: placement = "TopRight"; break;
1117 case Toolbar::BottomRight: placement = "BottomRight"; break;
1118 case Toolbar::BottomCenter: default: placement = "BottomCenter"; break;
1119 }
1120
1121 sprintf(rc_string, "session.screen%d.toolbar.placement: %s",
1122 screen_number, placement);
1123 XrmPutLineResource(&new_blackboxrc, rc_string);
1124
1125 load_rc(screen);
1126
1127 // these are static, but may not be saved in the users .blackboxrc,
1128 // writing these resources will allow the user to edit them at a later
1129 // time... but loading the defaults before saving allows us to rewrite the
1130 // users changes...
1131
1132 #ifdef HAVE_STRFTIME
1133 sprintf(rc_string, "session.screen%d.strftimeFormat: %s", screen_number,
1134 screen->getStrftimeFormat());
1135 XrmPutLineResource(&new_blackboxrc, rc_string);
1136 #else // !HAVE_STRFTIME
1137 sprintf(rc_string, "session.screen%d.dateFormat: %s", screen_number,
1138 ((screen->getDateFormat() == B_EuropeanDate) ?
1139 "European" : "American"));
1140 XrmPutLineResource(&new_blackboxrc, rc_string);
1141
1142 sprintf(rc_string, "session.screen%d.clockFormat: %d", screen_number,
1143 ((screen->isClock24Hour()) ? 24 : 12));
1144 XrmPutLineResource(&new_blackboxrc, rc_string);
1145 #endif // HAVE_STRFTIME
1146
1147 sprintf(rc_string, "session.screen%d.edgeSnapThreshold: %d",
1148 screen_number, screen->getEdgeSnapThreshold());
1149 XrmPutLineResource(&new_blackboxrc, rc_string);
1150
1151 sprintf(rc_string, "session.screen%d.toolbar.widthPercent: %d",
1152 screen_number, screen->getToolbarWidthPercent());
1153 XrmPutLineResource(&new_blackboxrc, rc_string);
1154
1155 // write out the user's workspace names
1156
1157 string save_string = screen->getWorkspace(0)->getName();
1158 for (unsigned int i = 1; i < screen->getWorkspaceCount(); ++i) {
1159 save_string += ',';
1160 save_string += screen->getWorkspace(i)->getName();
1161 }
1162
1163 char *resource_string = new char[save_string.length() + 48];
1164 sprintf(resource_string, "session.screen%d.workspaceNames: %s",
1165 screen_number, save_string.c_str());
1166 XrmPutLineResource(&new_blackboxrc, resource_string);
1167
1168 delete [] resource_string;
1169 }
1170
1171 XrmDatabase old_blackboxrc = XrmGetFileDatabase(rc_file.c_str());
1172
1173 XrmMergeDatabases(new_blackboxrc, &old_blackboxrc);
1174 XrmPutFileDatabase(old_blackboxrc, rc_file.c_str());
1175 XrmDestroyDatabase(old_blackboxrc);
1176 }
1177
1178
1179 void Blackbox::load_rc(void) {
1180 XrmDatabase database = (XrmDatabase) 0;
1181
1182 database = XrmGetFileDatabase(rc_file.c_str());
1183
1184 XrmValue value;
1185 char *value_type;
1186 int int_value;
1187 unsigned long long_value;
1188
1189 if (XrmGetResource(database, "session.menuFile", "Session.MenuFile",
1190 &value_type, &value)) {
1191 resource.menu_file = expandTilde(value.addr);
1192 } else {
1193 resource.menu_file = DEFAULTMENU;
1194 }
1195
1196 resource.colors_per_channel = 4;
1197 if (XrmGetResource(database, "session.colorsPerChannel",
1198 "Session.ColorsPerChannel", &value_type, &value) &&
1199 sscanf(value.addr, "%d", &int_value) == 1) {
1200 resource.colors_per_channel = int_value;
1201 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1202 if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1203 }
1204
1205 if (XrmGetResource(database, "session.styleFile", "Session.StyleFile",
1206 &value_type, &value))
1207 resource.style_file = expandTilde(value.addr);
1208 else
1209 resource.style_file = DEFAULTSTYLE;
1210
1211 resource.double_click_interval = 250;
1212 if (XrmGetResource(database, "session.doubleClickInterval",
1213 "Session.DoubleClickInterval", &value_type, &value) &&
1214 sscanf(value.addr, "%lu", &long_value) == 1) {
1215 resource.double_click_interval = long_value;
1216 }
1217
1218 resource.auto_raise_delay.tv_usec = 400;
1219 if (XrmGetResource(database, "session.autoRaiseDelay",
1220 "Session.AutoRaiseDelay", &value_type, &value) &&
1221 sscanf(value.addr, "%lu", &long_value) == 1) {
1222 resource.auto_raise_delay.tv_usec = long_value;
1223 }
1224
1225 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1226 resource.auto_raise_delay.tv_usec -=
1227 (resource.auto_raise_delay.tv_sec * 1000);
1228 resource.auto_raise_delay.tv_usec *= 1000;
1229
1230 resource.cache_life = 5l;
1231 if (XrmGetResource(database, "session.cacheLife", "Session.CacheLife",
1232 &value_type, &value) &&
1233 sscanf(value.addr, "%lu", &long_value) == 1) {
1234 resource.cache_life = long_value;
1235 }
1236 resource.cache_life *= 60000;
1237
1238 resource.cache_max = 200;
1239 if (XrmGetResource(database, "session.cacheMax", "Session.CacheMax",
1240 &value_type, &value) &&
1241 sscanf(value.addr, "%lu", &long_value) == 1) {
1242 resource.cache_max = long_value;
1243 }
1244 }
1245
1246
1247 void Blackbox::load_rc(BScreen *screen) {
1248 XrmDatabase database = (XrmDatabase) 0;
1249
1250 database = XrmGetFileDatabase(rc_file.c_str());
1251
1252 XrmValue value;
1253 char *value_type, name_lookup[1024], class_lookup[1024];
1254 int screen_number = screen->getScreenNumber();
1255 int int_value;
1256
1257 sprintf(name_lookup, "session.screen%d.fullMaximization", screen_number);
1258 sprintf(class_lookup, "Session.Screen%d.FullMaximization", screen_number);
1259 screen->saveFullMax(False);
1260 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1261 &value) &&
1262 ! strncasecmp(value.addr, "true", value.size)) {
1263 screen->saveFullMax(True);
1264 }
1265
1266 sprintf(name_lookup, "session.screen%d.focusNewWindows", screen_number);
1267 sprintf(class_lookup, "Session.Screen%d.FocusNewWindows", screen_number);
1268 screen->saveFocusNew(False);
1269 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1270 &value) &&
1271 ! strncasecmp(value.addr, "true", value.size)) {
1272 screen->saveFocusNew(True);
1273 }
1274
1275 sprintf(name_lookup, "session.screen%d.focusLastWindow", screen_number);
1276 sprintf(class_lookup, "Session.Screen%d.focusLastWindow", screen_number);
1277 screen->saveFocusLast(False);
1278 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1279 &value) &&
1280 ! strncasecmp(value.addr, "true", value.size)) {
1281 screen->saveFocusLast(True);
1282 }
1283
1284 sprintf(name_lookup, "session.screen%d.rowPlacementDirection",
1285 screen_number);
1286 sprintf(class_lookup, "Session.Screen%d.RowPlacementDirection",
1287 screen_number);
1288 screen->saveRowPlacementDirection(BScreen::LeftRight);
1289 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1290 &value) &&
1291 ! strncasecmp(value.addr, "righttoleft", value.size)) {
1292 screen->saveRowPlacementDirection(BScreen::RightLeft);
1293 }
1294
1295 sprintf(name_lookup, "session.screen%d.colPlacementDirection",
1296 screen_number);
1297 sprintf(class_lookup, "Session.Screen%d.ColPlacementDirection",
1298 screen_number);
1299 screen->saveColPlacementDirection(BScreen::TopBottom);
1300 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1301 &value) &&
1302 ! strncasecmp(value.addr, "bottomtotop", value.size)) {
1303 screen->saveColPlacementDirection(BScreen::BottomTop);
1304 }
1305
1306 sprintf(name_lookup, "session.screen%d.workspaces", screen_number);
1307 sprintf(class_lookup, "Session.Screen%d.Workspaces", screen_number);
1308 screen->saveWorkspaces(1);
1309 if (XrmGetResource(database, name_lookup, class_lookup,
1310 &value_type, &value) &&
1311 sscanf(value.addr, "%d", &int_value) == 1 &&
1312 int_value > 0 && int_value < 128) {
1313 screen->saveWorkspaces(int_value);
1314 }
1315
1316 sprintf(name_lookup, "session.screen%d.toolbar.widthPercent",
1317 screen_number);
1318 sprintf(class_lookup, "Session.Screen%d.Toolbar.WidthPercent",
1319 screen_number);
1320 screen->saveToolbarWidthPercent(66);
1321 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1322 &value) &&
1323 sscanf(value.addr, "%d", &int_value) == 1 &&
1324 int_value > 0 && int_value <= 100) {
1325 screen->saveToolbarWidthPercent(int_value);
1326 }
1327
1328 sprintf(name_lookup, "session.screen%d.toolbar.placement", screen_number);
1329 sprintf(class_lookup, "Session.Screen%d.Toolbar.Placement", screen_number);
1330 screen->saveToolbarPlacement(Toolbar::BottomCenter);
1331 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1332 &value)) {
1333 if (! strncasecmp(value.addr, "TopLeft", value.size))
1334 screen->saveToolbarPlacement(Toolbar::TopLeft);
1335 else if (! strncasecmp(value.addr, "BottomLeft", value.size))
1336 screen->saveToolbarPlacement(Toolbar::BottomLeft);
1337 else if (! strncasecmp(value.addr, "TopCenter", value.size))
1338 screen->saveToolbarPlacement(Toolbar::TopCenter);
1339 else if (! strncasecmp(value.addr, "TopRight", value.size))
1340 screen->saveToolbarPlacement(Toolbar::TopRight);
1341 else if (! strncasecmp(value.addr, "BottomRight", value.size))
1342 screen->saveToolbarPlacement(Toolbar::BottomRight);
1343 }
1344 screen->removeWorkspaceNames();
1345
1346 sprintf(name_lookup, "session.screen%d.workspaceNames", screen_number);
1347 sprintf(class_lookup, "Session.Screen%d.WorkspaceNames", screen_number);
1348 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1349 &value)) {
1350 string search = value.addr;
1351 string::const_iterator it = search.begin(),
1352 end = search.end();
1353 while (1) {
1354 string::const_iterator tmp = it; // current string.begin()
1355 it = std::find(tmp, end, ','); // look for comma between tmp and end
1356 screen->addWorkspaceName(string(tmp, it)); // string = search[tmp:it]
1357 if (it == end) break;
1358 ++it;
1359 }
1360 }
1361
1362 sprintf(name_lookup, "session.screen%d.toolbar.onTop", screen_number);
1363 sprintf(class_lookup, "Session.Screen%d.Toolbar.OnTop", screen_number);
1364 screen->saveToolbarOnTop(False);
1365 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1366 &value) &&
1367 ! strncasecmp(value.addr, "true", value.size)) {
1368 screen->saveToolbarOnTop(True);
1369 }
1370
1371 sprintf(name_lookup, "session.screen%d.toolbar.autoHide", screen_number);
1372 sprintf(class_lookup, "Session.Screen%d.Toolbar.autoHide", screen_number);
1373 screen->saveToolbarAutoHide(False);
1374 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1375 &value) &&
1376 ! strncasecmp(value.addr, "true", value.size)) {
1377 screen->saveToolbarAutoHide(True);
1378 }
1379
1380 sprintf(name_lookup, "session.screen%d.focusModel", screen_number);
1381 sprintf(class_lookup, "Session.Screen%d.FocusModel", screen_number);
1382 screen->saveSloppyFocus(True);
1383 screen->saveAutoRaise(False);
1384 screen->saveClickRaise(False);
1385 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1386 &value)) {
1387 string fmodel = value.addr;
1388
1389 if (fmodel.find("ClickToFocus") != string::npos) {
1390 screen->saveSloppyFocus(False);
1391 } else {
1392 // must be sloppy
1393
1394 if (fmodel.find("AutoRaise") != string::npos)
1395 screen->saveAutoRaise(True);
1396 if (fmodel.find("ClickRaise") != string::npos)
1397 screen->saveClickRaise(True);
1398 }
1399 }
1400
1401 sprintf(name_lookup, "session.screen%d.windowPlacement", screen_number);
1402 sprintf(class_lookup, "Session.Screen%d.WindowPlacement", screen_number);
1403 screen->savePlacementPolicy(BScreen::RowSmartPlacement);
1404 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1405 &value)) {
1406 if (! strncasecmp(value.addr, "RowSmartPlacement", value.size))
1407 /* pass */;
1408 else if (! strncasecmp(value.addr, "ColSmartPlacement", value.size))
1409 screen->savePlacementPolicy(BScreen::ColSmartPlacement);
1410 else if (! strncasecmp(value.addr, "CascadePlacement", value.size))
1411 screen->savePlacementPolicy(BScreen::CascadePlacement);
1412 }
1413
1414 sprintf(name_lookup, "session.screen%d.slit.placement", screen_number);
1415 sprintf(class_lookup, "Session.Screen%d.Slit.Placement", screen_number);
1416 screen->saveSlitPlacement(Slit::CenterRight);
1417 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1418 &value)) {
1419 if (! strncasecmp(value.addr, "TopLeft", value.size))
1420 screen->saveSlitPlacement(Slit::TopLeft);
1421 else if (! strncasecmp(value.addr, "CenterLeft", value.size))
1422 screen->saveSlitPlacement(Slit::CenterLeft);
1423 else if (! strncasecmp(value.addr, "BottomLeft", value.size))
1424 screen->saveSlitPlacement(Slit::BottomLeft);
1425 else if (! strncasecmp(value.addr, "TopCenter", value.size))
1426 screen->saveSlitPlacement(Slit::TopCenter);
1427 else if (! strncasecmp(value.addr, "BottomCenter", value.size))
1428 screen->saveSlitPlacement(Slit::BottomCenter);
1429 else if (! strncasecmp(value.addr, "TopRight", value.size))
1430 screen->saveSlitPlacement(Slit::TopRight);
1431 else if (! strncasecmp(value.addr, "BottomRight", value.size))
1432 screen->saveSlitPlacement(Slit::BottomRight);
1433 }
1434
1435 sprintf(name_lookup, "session.screen%d.slit.direction", screen_number);
1436 sprintf(class_lookup, "Session.Screen%d.Slit.Direction", screen_number);
1437 screen->saveSlitDirection(Slit::Vertical);
1438 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1439 &value) &&
1440 ! strncasecmp(value.addr, "Horizontal", value.size)) {
1441 screen->saveSlitDirection(Slit::Horizontal);
1442 }
1443
1444 sprintf(name_lookup, "session.screen%d.slit.onTop", screen_number);
1445 sprintf(class_lookup, "Session.Screen%d.Slit.OnTop", screen_number);
1446 screen->saveSlitOnTop(False);
1447 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1448 &value) &&
1449 ! strncasecmp(value.addr, "True", value.size)) {
1450 screen->saveSlitOnTop(True);
1451 }
1452
1453 sprintf(name_lookup, "session.screen%d.slit.autoHide", screen_number);
1454 sprintf(class_lookup, "Session.Screen%d.Slit.AutoHide", screen_number);
1455 screen->saveSlitAutoHide(False);
1456 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1457 &value) &&
1458 ! strncasecmp(value.addr, "true", value.size)) {
1459 screen->saveSlitAutoHide(True);
1460 }
1461
1462 #ifdef HAVE_STRFTIME
1463 sprintf(name_lookup, "session.screen%d.strftimeFormat", screen_number);
1464 sprintf(class_lookup, "Session.Screen%d.StrftimeFormat", screen_number);
1465 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1466 &value)) {
1467 screen->saveStrftimeFormat(value.addr);
1468 } else {
1469 screen->saveStrftimeFormat("%I:%M %p");
1470 }
1471 #else // HAVE_STRFTIME
1472 sprintf(name_lookup, "session.screen%d.dateFormat", screen_number);
1473 sprintf(class_lookup, "Session.Screen%d.DateFormat", screen_number);
1474 screen->saveDateFormat(B_AmericanDate);
1475 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1476 &value)) {
1477 if (! strncasecmp(value.addr, "european", value.size))
1478 screen->saveDateFormat(B_EuropeanDate);
1479 }
1480
1481 sprintf(name_lookup, "session.screen%d.clockFormat", screen_number);
1482 sprintf(class_lookup, "Session.Screen%d.ClockFormat", screen_number);
1483 screen->saveClock24Hour(False);
1484 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1485 &value) &&
1486 sscanf(value.addr, "%d", &int_value) == 1 && int_value == 24) {
1487 screen->saveClock24Hour(True);
1488 }
1489 #endif // HAVE_STRFTIME
1490
1491 sprintf(name_lookup, "session.screen%d.edgeSnapThreshold", screen_number);
1492 sprintf(class_lookup, "Session.Screen%d.EdgeSnapThreshold", screen_number);
1493 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1494 &value) &&
1495 sscanf(value.addr, "%d", &int_value) == 1) {
1496 screen->saveEdgeSnapThreshold(int_value);
1497 }
1498
1499 screen->saveImageDither(True);
1500 if (XrmGetResource(database, "session.imageDither", "Session.ImageDither",
1501 &value_type, &value) &&
1502 ! strncasecmp("false", value.addr, value.size)) {
1503 screen->saveImageDither(False);
1504 }
1505
1506 screen->saveOpaqueMove(False);
1507 if (XrmGetResource(database, "session.opaqueMove", "Session.OpaqueMove",
1508 &value_type, &value) &&
1509 ! strncasecmp("true", value.addr, value.size)) {
1510 screen->saveOpaqueMove(True);
1511 }
1512
1513 XrmDestroyDatabase(database);
1514 }
1515
1516
1517 void Blackbox::reload_rc(void) {
1518 load_rc();
1519 reconfigure();
1520 }
1521
1522
1523 void Blackbox::reconfigure(void) {
1524 reconfigure_wait = True;
1525
1526 if (! timer->isTiming()) timer->start();
1527 }
1528
1529
1530 void Blackbox::real_reconfigure(void) {
1531 XrmDatabase new_blackboxrc = (XrmDatabase) 0;
1532 char *style = new char[resource.style_file.length() + 20];
1533
1534 sprintf(style, "session.styleFile: %s", getStyleFilename());
1535 XrmPutLineResource(&new_blackboxrc, style);
1536
1537 delete [] style;
1538
1539 XrmDatabase old_blackboxrc = XrmGetFileDatabase(rc_file.c_str());
1540
1541 XrmMergeDatabases(new_blackboxrc, &old_blackboxrc);
1542 XrmPutFileDatabase(old_blackboxrc, rc_file.c_str());
1543 if (old_blackboxrc) XrmDestroyDatabase(old_blackboxrc);
1544
1545 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1546 PointerAssassin());
1547 menuTimestamps.clear();
1548
1549 gcCache()->purge();
1550
1551 std::for_each(screenList.begin(), screenList.end(),
1552 std::mem_fun(&BScreen::reconfigure));
1553 }
1554
1555
1556 void Blackbox::checkMenu(void) {
1557 bool reread = False;
1558 MenuTimestampList::iterator it = menuTimestamps.begin();
1559 for(; it != menuTimestamps.end(); ++it) {
1560 MenuTimestamp *tmp = *it;
1561 struct stat buf;
1562
1563 if (! stat(tmp->filename.c_str(), &buf)) {
1564 if (tmp->timestamp != buf.st_ctime)
1565 reread = True;
1566 } else {
1567 reread = True;
1568 }
1569 }
1570
1571 if (reread) rereadMenu();
1572 }
1573
1574
1575 void Blackbox::rereadMenu(void) {
1576 reread_menu_wait = True;
1577
1578 if (! timer->isTiming()) timer->start();
1579 }
1580
1581
1582 void Blackbox::real_rereadMenu(void) {
1583 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1584 PointerAssassin());
1585 menuTimestamps.clear();
1586
1587 std::for_each(screenList.begin(), screenList.end(),
1588 std::mem_fun(&BScreen::rereadMenu));
1589 }
1590
1591
1592 void Blackbox::saveStyleFilename(const string& filename) {
1593 assert(! filename.empty());
1594 resource.style_file = filename;
1595 }
1596
1597
1598 void Blackbox::saveMenuFilename(const string& filename) {
1599 assert(! filename.empty());
1600 bool found = False;
1601
1602 MenuTimestampList::iterator it = menuTimestamps.begin();
1603 for (; it != menuTimestamps.end() && !found; ++it) {
1604 if ((*it)->filename == filename) found = True;
1605 }
1606 if (! found) {
1607 struct stat buf;
1608
1609 if (! stat(filename.c_str(), &buf)) {
1610 MenuTimestamp *ts = new MenuTimestamp;
1611
1612 ts->filename = filename;
1613 ts->timestamp = buf.st_ctime;
1614
1615 menuTimestamps.push_back(ts);
1616 }
1617 }
1618 }
1619
1620
1621 void Blackbox::timeout(void) {
1622 if (reconfigure_wait)
1623 real_reconfigure();
1624
1625 if (reread_menu_wait)
1626 real_rereadMenu();
1627
1628 reconfigure_wait = reread_menu_wait = False;
1629 }
1630
1631
1632 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1633 if (focused_window && focused_window == win) // nothing to do
1634 return;
1635
1636 BScreen *old_screen = 0;
1637
1638 if (focused_window) {
1639 focused_window->setFocusFlag(False);
1640 old_screen = focused_window->getScreen();
1641 }
1642
1643 if (win && ! win->isIconic()) {
1644 // the active screen is the one with the last focused window...
1645 // this will keep focus on this screen no matter where the mouse goes,
1646 // so multihead keybindings will continue to work on that screen until the
1647 // user focuses a window on a different screen.
1648 active_screen = win->getScreen();
1649 focused_window = win;
1650 } else {
1651 focused_window = 0;
1652 if (! old_screen) {
1653 if (active_screen) {
1654 // set input focus to the toolbar of the screen with mouse
1655 XSetInputFocus(getXDisplay(),
1656 active_screen->getToolbar()->getWindowID(),
1657 RevertToPointerRoot, CurrentTime);
1658 } else {
1659 // set input focus to the toolbar of the first managed screen
1660 XSetInputFocus(getXDisplay(),
1661 screenList.front()->getToolbar()->getWindowID(),
1662 RevertToPointerRoot, CurrentTime);
1663 }
1664 } else {
1665 // set input focus to the toolbar of the last screen
1666 XSetInputFocus(getXDisplay(), old_screen->getToolbar()->getWindowID(),
1667 RevertToPointerRoot, CurrentTime);
1668 }
1669 }
1670
1671 if (active_screen && active_screen->isScreenManaged()) {
1672 active_screen->getToolbar()->redrawWindowLabel(True);
1673 active_screen->updateNetizenWindowFocus();
1674 }
1675
1676 if (old_screen && old_screen != active_screen) {
1677 old_screen->getToolbar()->redrawWindowLabel(True);
1678 old_screen->updateNetizenWindowFocus();
1679 }
1680 }
This page took 0.108222 seconds and 5 git commands to generate.