]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
bca48e5d405027a3dbdaa173f73d2e23e9318f73
[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, char *menu)
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 = "~/.openbox/rc";
148 rc_file = expandTilde(rc);
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 // set the screen with mouse to the first managed screen
188 active_screen = screenList.front();
189 setFocusedWindow(0);
190
191 XSynchronize(getXDisplay(), False);
192 XSync(getXDisplay(), False);
193
194 reconfigure_wait = reread_menu_wait = False;
195
196 timer = new BTimer(this, this);
197 timer->setTimeout(0l);
198 }
199
200
201 Blackbox::~Blackbox(void) {
202 std::for_each(screenList.begin(), screenList.end(), PointerAssassin());
203
204 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
205 PointerAssassin());
206
207 delete timer;
208 }
209
210
211 void Blackbox::process_event(XEvent *e) {
212 switch (e->type) {
213 case ButtonPress: {
214 // strip the lock key modifiers
215 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
216
217 last_time = e->xbutton.time;
218
219 BlackboxWindow *win = (BlackboxWindow *) 0;
220 Basemenu *menu = (Basemenu *) 0;
221 Slit *slit = (Slit *) 0;
222 Toolbar *tbar = (Toolbar *) 0;
223 BScreen *scrn = (BScreen *) 0;
224
225 if ((win = searchWindow(e->xbutton.window))) {
226 win->buttonPressEvent(&e->xbutton);
227
228 /* XXX: is this sane on low colour desktops? */
229 if (e->xbutton.button == 1)
230 win->installColormap(True);
231 } else if ((menu = searchMenu(e->xbutton.window))) {
232 menu->buttonPressEvent(&e->xbutton);
233 } else if ((slit = searchSlit(e->xbutton.window))) {
234 slit->buttonPressEvent(&e->xbutton);
235 } else if ((tbar = searchToolbar(e->xbutton.window))) {
236 tbar->buttonPressEvent(&e->xbutton);
237 } else if ((scrn = searchScreen(e->xbutton.window))) {
238 scrn->buttonPressEvent(&e->xbutton);
239 if (active_screen != scrn) {
240 active_screen = scrn;
241 // first, set no focus window on the old screen
242 setFocusedWindow(0);
243 // and move focus to this screen
244 setFocusedWindow(0);
245 }
246 }
247 break;
248 }
249
250 case ButtonRelease: {
251 // strip the lock key modifiers
252 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
253
254 last_time = e->xbutton.time;
255
256 BlackboxWindow *win = (BlackboxWindow *) 0;
257 Basemenu *menu = (Basemenu *) 0;
258 Toolbar *tbar = (Toolbar *) 0;
259
260 if ((win = searchWindow(e->xbutton.window)))
261 win->buttonReleaseEvent(&e->xbutton);
262 else if ((menu = searchMenu(e->xbutton.window)))
263 menu->buttonReleaseEvent(&e->xbutton);
264 else if ((tbar = searchToolbar(e->xbutton.window)))
265 tbar->buttonReleaseEvent(&e->xbutton);
266
267 break;
268 }
269
270 case ConfigureRequest: {
271 // compress configure requests...
272 XEvent realevent;
273 unsigned int i = 0;
274 while(XCheckTypedWindowEvent(getXDisplay(), e->xconfigurerequest.window,
275 ConfigureRequest, &realevent)) {
276 i++;
277 }
278 if ( i > 0 )
279 e = &realevent;
280
281 BlackboxWindow *win = (BlackboxWindow *) 0;
282 Slit *slit = (Slit *) 0;
283
284 if ((win = searchWindow(e->xconfigurerequest.window))) {
285 win->configureRequestEvent(&e->xconfigurerequest);
286 } else if ((slit = searchSlit(e->xconfigurerequest.window))) {
287 slit->configureRequestEvent(&e->xconfigurerequest);
288 } else {
289 if (validateWindow(e->xconfigurerequest.window)) {
290 XWindowChanges xwc;
291
292 xwc.x = e->xconfigurerequest.x;
293 xwc.y = e->xconfigurerequest.y;
294 xwc.width = e->xconfigurerequest.width;
295 xwc.height = e->xconfigurerequest.height;
296 xwc.border_width = e->xconfigurerequest.border_width;
297 xwc.sibling = e->xconfigurerequest.above;
298 xwc.stack_mode = e->xconfigurerequest.detail;
299
300 XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
301 e->xconfigurerequest.value_mask, &xwc);
302 }
303 }
304
305 break;
306 }
307
308 case MapRequest: {
309 #ifdef DEBUG
310 fprintf(stderr, "Blackbox::process_event(): MapRequest for 0x%lx\n",
311 e->xmaprequest.window);
312 #endif // DEBUG
313
314 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
315
316 if (! win) {
317 BScreen *screen = searchScreen(e->xmaprequest.parent);
318
319 if (! screen) {
320 /*
321 we got a map request for a window who's parent isn't root. this
322 can happen in only one circumstance:
323
324 a client window unmapped a managed window, and then remapped it
325 somewhere between unmapping the client window and reparenting it
326 to root.
327
328 regardless of how it happens, we need to find the screen that
329 the window is on
330 */
331 XWindowAttributes wattrib;
332 if (! XGetWindowAttributes(getXDisplay(), e->xmaprequest.window,
333 &wattrib)) {
334 // failed to get the window attributes, perhaps the window has
335 // now been destroyed?
336 break;
337 }
338
339 screen = searchScreen(wattrib.root);
340 assert(screen != 0); // this should never happen
341 }
342
343 screen->manageWindow(e->xmaprequest.window);
344 }
345
346 break;
347 }
348
349 case UnmapNotify: {
350 BlackboxWindow *win = (BlackboxWindow *) 0;
351 Slit *slit = (Slit *) 0;
352
353 if ((win = searchWindow(e->xunmap.window))) {
354 win->unmapNotifyEvent(&e->xunmap);
355 } else if ((slit = searchSlit(e->xunmap.window))) {
356 slit->unmapNotifyEvent(&e->xunmap);
357 }
358
359 break;
360 }
361
362 case DestroyNotify: {
363 BlackboxWindow *win = (BlackboxWindow *) 0;
364 Slit *slit = (Slit *) 0;
365 BWindowGroup *group = (BWindowGroup *) 0;
366
367 if ((win = searchWindow(e->xdestroywindow.window))) {
368 win->destroyNotifyEvent(&e->xdestroywindow);
369 } else if ((slit = searchSlit(e->xdestroywindow.window))) {
370 slit->removeClient(e->xdestroywindow.window, False);
371 } else if ((group = searchGroup(e->xdestroywindow.window))) {
372 delete group;
373 }
374
375 break;
376 }
377
378 case ReparentNotify: {
379 /*
380 this event is quite rare and is usually handled in unmapNotify
381 however, if the window is unmapped when the reparent event occurs
382 the window manager never sees it because an unmap event is not sent
383 to an already unmapped window.
384 */
385 BlackboxWindow *win = searchWindow(e->xreparent.window);
386 if (win) {
387 win->reparentNotifyEvent(&e->xreparent);
388 } else {
389 Slit *slit = searchSlit(e->xreparent.window);
390 if (slit && slit->getWindowID() != e->xreparent.parent)
391 slit->removeClient(e->xreparent.window, True);
392 }
393 break;
394 }
395
396 case MotionNotify: {
397 // motion notify compression...
398 XEvent realevent;
399 unsigned int i = 0;
400 while (XCheckTypedWindowEvent(getXDisplay(), e->xmotion.window,
401 MotionNotify, &realevent)) {
402 i++;
403 }
404
405 // if we have compressed some motion events, use the last one
406 if ( i > 0 )
407 e = &realevent;
408
409 // strip the lock key modifiers
410 e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
411
412 last_time = e->xmotion.time;
413
414 BlackboxWindow *win = (BlackboxWindow *) 0;
415 Basemenu *menu = (Basemenu *) 0;
416
417 if ((win = searchWindow(e->xmotion.window)))
418 win->motionNotifyEvent(&e->xmotion);
419 else if ((menu = searchMenu(e->xmotion.window)))
420 menu->motionNotifyEvent(&e->xmotion);
421
422 break;
423 }
424
425 case PropertyNotify: {
426 last_time = e->xproperty.time;
427
428 if (e->xproperty.state != PropertyDelete) {
429 BlackboxWindow *win = searchWindow(e->xproperty.window);
430
431 if (win)
432 win->propertyNotifyEvent(e->xproperty.atom);
433 }
434
435 break;
436 }
437
438 case EnterNotify: {
439 last_time = e->xcrossing.time;
440
441 BScreen *screen = (BScreen *) 0;
442 BlackboxWindow *win = (BlackboxWindow *) 0;
443 Basemenu *menu = (Basemenu *) 0;
444 Toolbar *tbar = (Toolbar *) 0;
445 Slit *slit = (Slit *) 0;
446
447 if (e->xcrossing.mode == NotifyGrab) break;
448
449 XEvent dummy;
450 scanargs sa;
451 sa.w = e->xcrossing.window;
452 sa.enter = sa.leave = False;
453 XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);
454
455 if ((e->xcrossing.window == e->xcrossing.root) &&
456 (screen = searchScreen(e->xcrossing.window))) {
457 screen->getImageControl()->installRootColormap();
458 } else if ((win = searchWindow(e->xcrossing.window))) {
459 if (win->getScreen()->isSloppyFocus() &&
460 (! win->isFocused()) && (! no_focus)) {
461 if (((! sa.leave) || sa.inferior) && win->isVisible()) {
462 if (win->setInputFocus())
463 win->installColormap(True); // XXX: shouldnt we honour no install?
464 }
465 }
466 } else if ((menu = searchMenu(e->xcrossing.window))) {
467 menu->enterNotifyEvent(&e->xcrossing);
468 } else if ((tbar = searchToolbar(e->xcrossing.window))) {
469 tbar->enterNotifyEvent(&e->xcrossing);
470 } else if ((slit = searchSlit(e->xcrossing.window))) {
471 slit->enterNotifyEvent(&e->xcrossing);
472 }
473 break;
474 }
475
476 case LeaveNotify: {
477 last_time = e->xcrossing.time;
478
479 BlackboxWindow *win = (BlackboxWindow *) 0;
480 Basemenu *menu = (Basemenu *) 0;
481 Toolbar *tbar = (Toolbar *) 0;
482 Slit *slit = (Slit *) 0;
483
484 if ((menu = searchMenu(e->xcrossing.window)))
485 menu->leaveNotifyEvent(&e->xcrossing);
486 else if ((win = searchWindow(e->xcrossing.window)))
487 win->installColormap(False);
488 else if ((tbar = searchToolbar(e->xcrossing.window)))
489 tbar->leaveNotifyEvent(&e->xcrossing);
490 else if ((slit = searchSlit(e->xcrossing.window)))
491 slit->leaveNotifyEvent(&e->xcrossing);
492 break;
493 }
494
495 case Expose: {
496 // compress expose events
497 XEvent realevent;
498 unsigned int i = 0;
499 int ex1, ey1, ex2, ey2;
500 ex1 = e->xexpose.x;
501 ey1 = e->xexpose.y;
502 ex2 = ex1 + e->xexpose.width - 1;
503 ey2 = ey1 + e->xexpose.height - 1;
504 while (XCheckTypedWindowEvent(getXDisplay(), e->xexpose.window,
505 Expose, &realevent)) {
506 i++;
507
508 // merge expose area
509 ex1 = std::min(realevent.xexpose.x, ex1);
510 ey1 = std::min(realevent.xexpose.y, ey1);
511 ex2 = std::max(realevent.xexpose.x + realevent.xexpose.width - 1, ex2);
512 ey2 = std::max(realevent.xexpose.y + realevent.xexpose.height - 1, ey2);
513 }
514 if ( i > 0 )
515 e = &realevent;
516
517 // use the merged area
518 e->xexpose.x = ex1;
519 e->xexpose.y = ey1;
520 e->xexpose.width = ex2 - ex1 + 1;
521 e->xexpose.height = ey2 - ey1 + 1;
522
523 BlackboxWindow *win = (BlackboxWindow *) 0;
524 Basemenu *menu = (Basemenu *) 0;
525 Toolbar *tbar = (Toolbar *) 0;
526
527 if ((win = searchWindow(e->xexpose.window)))
528 win->exposeEvent(&e->xexpose);
529 else if ((menu = searchMenu(e->xexpose.window)))
530 menu->exposeEvent(&e->xexpose);
531 else if ((tbar = searchToolbar(e->xexpose.window)))
532 tbar->exposeEvent(&e->xexpose);
533
534 break;
535 }
536
537 case KeyPress: {
538 Toolbar *tbar = searchToolbar(e->xkey.window);
539
540 if (tbar && tbar->isEditing())
541 tbar->keyPressEvent(&e->xkey);
542
543 break;
544 }
545
546 case ColormapNotify: {
547 BScreen *screen = searchScreen(e->xcolormap.window);
548
549 if (screen)
550 screen->setRootColormapInstalled((e->xcolormap.state ==
551 ColormapInstalled) ? True : False);
552
553 break;
554 }
555
556 case FocusIn: {
557 if (e->xfocus.detail != NotifyNonlinear) {
558 /*
559 don't process FocusIns when:
560 1. the new focus window isn't an ancestor or inferior of the old
561 focus window (NotifyNonlinear)
562 */
563 break;
564 }
565
566 BlackboxWindow *win = searchWindow(e->xfocus.window);
567 if (win) {
568 if (! win->isFocused())
569 win->setFocusFlag(True);
570
571 /*
572 set the event window to None. when the FocusOut event handler calls
573 this function recursively, it uses this as an indication that focus
574 has moved to a known window.
575 */
576 e->xfocus.window = None;
577 }
578
579 break;
580 }
581
582 case FocusOut: {
583 if (e->xfocus.detail != NotifyNonlinear) {
584 /*
585 don't process FocusOuts when:
586 2. the new focus window isn't an ancestor or inferior of the old
587 focus window (NotifyNonlinear)
588 */
589 break;
590 }
591
592 BlackboxWindow *win = searchWindow(e->xfocus.window);
593 if (win && win->isFocused()) {
594 /*
595 before we mark "win" as unfocused, we need to verify that focus is
596 going to a known location, is in a known location, or set focus
597 to a known location.
598 */
599
600 XEvent event;
601 // don't check the current focus if FocusOut was generated during a grab
602 bool check_focus = (e->xfocus.mode == NotifyNormal);
603
604 /*
605 First, check if there is a pending FocusIn event waiting. if there
606 is, process it and determine if focus has moved to another window
607 (the FocusIn event handler sets the window in the event
608 structure to None to indicate this).
609 */
610 if (XCheckTypedEvent(getXDisplay(), FocusIn, &event)) {
611
612 process_event(&event);
613 if (event.xfocus.window == None) {
614 // focus has moved
615 check_focus = False;
616 }
617 }
618
619 if (check_focus) {
620 /*
621 Second, we query the X server for the current input focus.
622 to make sure that we keep a consistent state.
623 */
624 BlackboxWindow *focus;
625 Window w;
626 int revert;
627 XGetInputFocus(getXDisplay(), &w, &revert);
628 focus = searchWindow(w);
629 if (focus) {
630 /*
631 focus got from "win" to "focus" under some very strange
632 circumstances, and we need to make sure that the focus indication
633 is correct.
634 */
635 setFocusedWindow(focus);
636 } else {
637 // we have no idea where focus went... so we set it to somewhere
638 setFocusedWindow(0);
639 }
640 }
641 }
642
643 break;
644 }
645
646 case ClientMessage: {
647 if (e->xclient.format == 32) {
648 if (e->xclient.message_type == getWMChangeStateAtom()) {
649 BlackboxWindow *win = searchWindow(e->xclient.window);
650 if (! win || ! win->validateClient()) return;
651
652 if (e->xclient.data.l[0] == IconicState)
653 win->iconify();
654 if (e->xclient.data.l[0] == NormalState)
655 win->deiconify();
656 } else if(e->xclient.message_type == getBlackboxChangeWorkspaceAtom()) {
657 BScreen *screen = searchScreen(e->xclient.window);
658
659 if (screen && e->xclient.data.l[0] >= 0 &&
660 e->xclient.data.l[0] <
661 static_cast<signed>(screen->getWorkspaceCount()))
662 screen->changeWorkspaceID(e->xclient.data.l[0]);
663 } else if (e->xclient.message_type == getBlackboxChangeWindowFocusAtom()) {
664 BlackboxWindow *win = searchWindow(e->xclient.window);
665
666 if (win && win->isVisible() && win->setInputFocus())
667 win->installColormap(True);
668 } else if (e->xclient.message_type == getBlackboxCycleWindowFocusAtom()) {
669 BScreen *screen = searchScreen(e->xclient.window);
670
671 if (screen) {
672 if (! e->xclient.data.l[0])
673 screen->prevFocus();
674 else
675 screen->nextFocus();
676 }
677 } else if (e->xclient.message_type == getBlackboxChangeAttributesAtom()) {
678 BlackboxWindow *win = searchWindow(e->xclient.window);
679
680 if (win && win->validateClient()) {
681 BlackboxHints net;
682 net.flags = e->xclient.data.l[0];
683 net.attrib = e->xclient.data.l[1];
684 net.workspace = e->xclient.data.l[2];
685 net.stack = e->xclient.data.l[3];
686 net.decoration = e->xclient.data.l[4];
687
688 win->changeBlackboxHints(&net);
689 }
690 }
691 }
692
693 break;
694 }
695
696 case NoExpose:
697 case ConfigureNotify:
698 case MapNotify:
699 break; // not handled, just ignore
700
701 default: {
702 #ifdef SHAPE
703 if (e->type == getShapeEventBase()) {
704 XShapeEvent *shape_event = (XShapeEvent *) e;
705 BlackboxWindow *win = searchWindow(e->xany.window);
706
707 if (win)
708 win->shapeEvent(shape_event);
709 }
710 #endif // SHAPE
711 }
712 } // switch
713 }
714
715
716 bool Blackbox::handleSignal(int sig) {
717 switch (sig) {
718 case SIGHUP:
719 reconfigure();
720 break;
721
722 case SIGUSR1:
723 reload_rc();
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 save_rc();
974 }
975
976
977 void Blackbox::save_rc(void) {
978 XrmDatabase new_blackboxrc = (XrmDatabase) 0;
979 char rc_string[1024];
980
981 load_rc();
982
983 sprintf(rc_string, "session.colorsPerChannel: %d",
984 resource.colors_per_channel);
985 XrmPutLineResource(&new_blackboxrc, rc_string);
986
987 sprintf(rc_string, "session.doubleClickInterval: %lu",
988 resource.double_click_interval);
989 XrmPutLineResource(&new_blackboxrc, rc_string);
990
991 sprintf(rc_string, "session.autoRaiseDelay: %lu",
992 ((resource.auto_raise_delay.tv_sec * 1000) +
993 (resource.auto_raise_delay.tv_usec / 1000)));
994 XrmPutLineResource(&new_blackboxrc, rc_string);
995
996 sprintf(rc_string, "session.cacheLife: %lu", resource.cache_life / 60000);
997 XrmPutLineResource(&new_blackboxrc, rc_string);
998
999 sprintf(rc_string, "session.cacheMax: %lu", resource.cache_max);
1000 XrmPutLineResource(&new_blackboxrc, rc_string);
1001
1002 ScreenList::iterator it = screenList.begin();
1003 for (; it != screenList.end(); ++it) {
1004 BScreen *screen = *it;
1005 int screen_number = screen->getScreenNumber();
1006
1007 char *placement = (char *) 0;
1008
1009 switch (screen->getSlitPlacement()) {
1010 case Slit::TopLeft: placement = "TopLeft"; break;
1011 case Slit::CenterLeft: placement = "CenterLeft"; break;
1012 case Slit::BottomLeft: placement = "BottomLeft"; break;
1013 case Slit::TopCenter: placement = "TopCenter"; break;
1014 case Slit::BottomCenter: placement = "BottomCenter"; break;
1015 case Slit::TopRight: placement = "TopRight"; break;
1016 case Slit::BottomRight: placement = "BottomRight"; break;
1017 case Slit::CenterRight: default: placement = "CenterRight"; break;
1018 }
1019
1020 sprintf(rc_string, "session.screen%d.slit.placement: %s", screen_number,
1021 placement);
1022 XrmPutLineResource(&new_blackboxrc, rc_string);
1023
1024 sprintf(rc_string, "session.screen%d.slit.direction: %s", screen_number,
1025 ((screen->getSlitDirection() == Slit::Horizontal) ? "Horizontal" :
1026 "Vertical"));
1027 XrmPutLineResource(&new_blackboxrc, rc_string);
1028
1029 sprintf(rc_string, "session.screen%d.slit.onTop: %s", screen_number,
1030 ((screen->getSlit()->isOnTop()) ? "True" : "False"));
1031 XrmPutLineResource(&new_blackboxrc, rc_string);
1032
1033 sprintf(rc_string, "session.screen%d.slit.autoHide: %s", screen_number,
1034 ((screen->getSlit()->doAutoHide()) ? "True" : "False"));
1035 XrmPutLineResource(&new_blackboxrc, rc_string);
1036
1037 sprintf(rc_string, "session.opaqueMove: %s",
1038 ((screen->doOpaqueMove()) ? "True" : "False"));
1039 XrmPutLineResource(&new_blackboxrc, rc_string);
1040
1041 sprintf(rc_string, "session.imageDither: %s",
1042 ((screen->getImageControl()->doDither()) ? "True" : "False"));
1043 XrmPutLineResource(&new_blackboxrc, rc_string);
1044
1045 sprintf(rc_string, "session.screen%d.fullMaximization: %s", screen_number,
1046 ((screen->doFullMax()) ? "True" : "False"));
1047 XrmPutLineResource(&new_blackboxrc, rc_string);
1048
1049 sprintf(rc_string, "session.screen%d.focusNewWindows: %s", screen_number,
1050 ((screen->doFocusNew()) ? "True" : "False"));
1051 XrmPutLineResource(&new_blackboxrc, rc_string);
1052
1053 sprintf(rc_string, "session.screen%d.focusLastWindow: %s", screen_number,
1054 ((screen->doFocusLast()) ? "True" : "False"));
1055 XrmPutLineResource(&new_blackboxrc, rc_string);
1056
1057 sprintf(rc_string, "session.screen%d.rowPlacementDirection: %s",
1058 screen_number,
1059 ((screen->getRowPlacementDirection() == BScreen::LeftRight) ?
1060 "LeftToRight" : "RightToLeft"));
1061 XrmPutLineResource(&new_blackboxrc, rc_string);
1062
1063 sprintf(rc_string, "session.screen%d.colPlacementDirection: %s",
1064 screen_number,
1065 ((screen->getColPlacementDirection() == BScreen::TopBottom) ?
1066 "TopToBottom" : "BottomToTop"));
1067 XrmPutLineResource(&new_blackboxrc, rc_string);
1068
1069 switch (screen->getPlacementPolicy()) {
1070 case BScreen::CascadePlacement:
1071 placement = "CascadePlacement";
1072 break;
1073 case BScreen::ColSmartPlacement:
1074 placement = "ColSmartPlacement";
1075 break;
1076
1077 case BScreen::RowSmartPlacement:
1078 default:
1079 placement = "RowSmartPlacement";
1080 break;
1081 }
1082 sprintf(rc_string, "session.screen%d.windowPlacement: %s", screen_number,
1083 placement);
1084 XrmPutLineResource(&new_blackboxrc, rc_string);
1085
1086 string fmodel;
1087 if (screen->isSloppyFocus()) {
1088 fmodel = "SloppyFocus";
1089 if (screen->doAutoRaise()) fmodel += " AutoRaise";
1090 if (screen->doClickRaise()) fmodel += " ClickRaise";
1091 } else {
1092 fmodel = "ClickToFocus";
1093 }
1094 sprintf(rc_string, "session.screen%d.focusModel: %s", screen_number,
1095 fmodel.c_str());
1096 XrmPutLineResource(&new_blackboxrc, rc_string);
1097
1098 sprintf(rc_string, "session.screen%d.workspaces: %d", screen_number,
1099 screen->getWorkspaceCount());
1100 XrmPutLineResource(&new_blackboxrc, rc_string);
1101
1102 sprintf(rc_string, "session.screen%d.toolbar.onTop: %s", screen_number,
1103 ((screen->getToolbar()->isOnTop()) ? "True" : "False"));
1104 XrmPutLineResource(&new_blackboxrc, rc_string);
1105
1106 sprintf(rc_string, "session.screen%d.toolbar.autoHide: %s",
1107 screen_number,
1108 ((screen->getToolbar()->doAutoHide()) ? "True" : "False"));
1109 XrmPutLineResource(&new_blackboxrc, rc_string);
1110
1111 switch (screen->getToolbarPlacement()) {
1112 case Toolbar::TopLeft: placement = "TopLeft"; break;
1113 case Toolbar::BottomLeft: placement = "BottomLeft"; break;
1114 case Toolbar::TopCenter: placement = "TopCenter"; break;
1115 case Toolbar::TopRight: placement = "TopRight"; break;
1116 case Toolbar::BottomRight: placement = "BottomRight"; break;
1117 case Toolbar::BottomCenter: default: placement = "BottomCenter"; break;
1118 }
1119
1120 sprintf(rc_string, "session.screen%d.toolbar.placement: %s",
1121 screen_number, placement);
1122 XrmPutLineResource(&new_blackboxrc, rc_string);
1123
1124 load_rc(screen);
1125
1126 // these are static, but may not be saved in the users .blackboxrc,
1127 // writing these resources will allow the user to edit them at a later
1128 // time... but loading the defaults before saving allows us to rewrite the
1129 // users changes...
1130
1131 #ifdef HAVE_STRFTIME
1132 sprintf(rc_string, "session.screen%d.strftimeFormat: %s", screen_number,
1133 screen->getStrftimeFormat());
1134 XrmPutLineResource(&new_blackboxrc, rc_string);
1135 #else // !HAVE_STRFTIME
1136 sprintf(rc_string, "session.screen%d.dateFormat: %s", screen_number,
1137 ((screen->getDateFormat() == B_EuropeanDate) ?
1138 "European" : "American"));
1139 XrmPutLineResource(&new_blackboxrc, rc_string);
1140
1141 sprintf(rc_string, "session.screen%d.clockFormat: %d", screen_number,
1142 ((screen->isClock24Hour()) ? 24 : 12));
1143 XrmPutLineResource(&new_blackboxrc, rc_string);
1144 #endif // HAVE_STRFTIME
1145
1146 sprintf(rc_string, "session.screen%d.edgeSnapThreshold: %d",
1147 screen_number, screen->getEdgeSnapThreshold());
1148 XrmPutLineResource(&new_blackboxrc, rc_string);
1149
1150 sprintf(rc_string, "session.screen%d.toolbar.widthPercent: %d",
1151 screen_number, screen->getToolbarWidthPercent());
1152 XrmPutLineResource(&new_blackboxrc, rc_string);
1153
1154 // write out the user's workspace names
1155
1156 string save_string = screen->getWorkspace(0)->getName();
1157 for (unsigned int i = 1; i < screen->getWorkspaceCount(); ++i) {
1158 save_string += ',';
1159 save_string += screen->getWorkspace(i)->getName();
1160 }
1161
1162 char *resource_string = new char[save_string.length() + 48];
1163 sprintf(resource_string, "session.screen%d.workspaceNames: %s",
1164 screen_number, save_string.c_str());
1165 XrmPutLineResource(&new_blackboxrc, resource_string);
1166
1167 delete [] resource_string;
1168 }
1169
1170 XrmDatabase old_blackboxrc = XrmGetFileDatabase(rc_file.c_str());
1171
1172 XrmMergeDatabases(new_blackboxrc, &old_blackboxrc);
1173 XrmPutFileDatabase(old_blackboxrc, rc_file.c_str());
1174 XrmDestroyDatabase(old_blackboxrc);
1175 }
1176
1177
1178 void Blackbox::load_rc(void) {
1179 XrmDatabase database = (XrmDatabase) 0;
1180
1181 database = XrmGetFileDatabase(rc_file.c_str());
1182
1183 XrmValue value;
1184 char *value_type;
1185 int int_value;
1186 unsigned long long_value;
1187
1188 resource.colors_per_channel = 4;
1189 if (XrmGetResource(database, "session.colorsPerChannel",
1190 "Session.ColorsPerChannel", &value_type, &value) &&
1191 sscanf(value.addr, "%d", &int_value) == 1) {
1192 resource.colors_per_channel = int_value;
1193 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1194 if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1195 }
1196
1197 if (XrmGetResource(database, "session.styleFile", "Session.StyleFile",
1198 &value_type, &value))
1199 resource.style_file = expandTilde(value.addr);
1200 else
1201 resource.style_file = DEFAULTSTYLE;
1202
1203 resource.double_click_interval = 250;
1204 if (XrmGetResource(database, "session.doubleClickInterval",
1205 "Session.DoubleClickInterval", &value_type, &value) &&
1206 sscanf(value.addr, "%lu", &long_value) == 1) {
1207 resource.double_click_interval = long_value;
1208 }
1209
1210 resource.auto_raise_delay.tv_usec = 400;
1211 if (XrmGetResource(database, "session.autoRaiseDelay",
1212 "Session.AutoRaiseDelay", &value_type, &value) &&
1213 sscanf(value.addr, "%lu", &long_value) == 1) {
1214 resource.auto_raise_delay.tv_usec = long_value;
1215 }
1216
1217 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1218 resource.auto_raise_delay.tv_usec -=
1219 (resource.auto_raise_delay.tv_sec * 1000);
1220 resource.auto_raise_delay.tv_usec *= 1000;
1221
1222 resource.cache_life = 5l;
1223 if (XrmGetResource(database, "session.cacheLife", "Session.CacheLife",
1224 &value_type, &value) &&
1225 sscanf(value.addr, "%lu", &long_value) == 1) {
1226 resource.cache_life = long_value;
1227 }
1228 resource.cache_life *= 60000;
1229
1230 resource.cache_max = 200;
1231 if (XrmGetResource(database, "session.cacheMax", "Session.CacheMax",
1232 &value_type, &value) &&
1233 sscanf(value.addr, "%lu", &long_value) == 1) {
1234 resource.cache_max = long_value;
1235 }
1236 }
1237
1238
1239 void Blackbox::load_rc(BScreen *screen) {
1240 XrmDatabase database = (XrmDatabase) 0;
1241
1242 database = XrmGetFileDatabase(rc_file.c_str());
1243
1244 XrmValue value;
1245 char *value_type, name_lookup[1024], class_lookup[1024];
1246 int screen_number = screen->getScreenNumber();
1247 int int_value;
1248
1249 sprintf(name_lookup, "session.screen%d.fullMaximization", screen_number);
1250 sprintf(class_lookup, "Session.Screen%d.FullMaximization", screen_number);
1251 screen->saveFullMax(False);
1252 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1253 &value) &&
1254 ! strncasecmp(value.addr, "true", value.size)) {
1255 screen->saveFullMax(True);
1256 }
1257
1258 sprintf(name_lookup, "session.screen%d.focusNewWindows", screen_number);
1259 sprintf(class_lookup, "Session.Screen%d.FocusNewWindows", screen_number);
1260 screen->saveFocusNew(False);
1261 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1262 &value) &&
1263 ! strncasecmp(value.addr, "true", value.size)) {
1264 screen->saveFocusNew(True);
1265 }
1266
1267 sprintf(name_lookup, "session.screen%d.focusLastWindow", screen_number);
1268 sprintf(class_lookup, "Session.Screen%d.focusLastWindow", screen_number);
1269 screen->saveFocusLast(False);
1270 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1271 &value) &&
1272 ! strncasecmp(value.addr, "true", value.size)) {
1273 screen->saveFocusLast(True);
1274 }
1275
1276 sprintf(name_lookup, "session.screen%d.rowPlacementDirection",
1277 screen_number);
1278 sprintf(class_lookup, "Session.Screen%d.RowPlacementDirection",
1279 screen_number);
1280 screen->saveRowPlacementDirection(BScreen::LeftRight);
1281 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1282 &value) &&
1283 ! strncasecmp(value.addr, "righttoleft", value.size)) {
1284 screen->saveRowPlacementDirection(BScreen::RightLeft);
1285 }
1286
1287 sprintf(name_lookup, "session.screen%d.colPlacementDirection",
1288 screen_number);
1289 sprintf(class_lookup, "Session.Screen%d.ColPlacementDirection",
1290 screen_number);
1291 screen->saveColPlacementDirection(BScreen::TopBottom);
1292 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1293 &value) &&
1294 ! strncasecmp(value.addr, "bottomtotop", value.size)) {
1295 screen->saveColPlacementDirection(BScreen::BottomTop);
1296 }
1297
1298 sprintf(name_lookup, "session.screen%d.workspaces", screen_number);
1299 sprintf(class_lookup, "Session.Screen%d.Workspaces", screen_number);
1300 screen->saveWorkspaces(1);
1301 if (XrmGetResource(database, name_lookup, class_lookup,
1302 &value_type, &value) &&
1303 sscanf(value.addr, "%d", &int_value) == 1 &&
1304 int_value > 0 && int_value < 128) {
1305 screen->saveWorkspaces(int_value);
1306 }
1307
1308 sprintf(name_lookup, "session.screen%d.toolbar.widthPercent",
1309 screen_number);
1310 sprintf(class_lookup, "Session.Screen%d.Toolbar.WidthPercent",
1311 screen_number);
1312 screen->saveToolbarWidthPercent(66);
1313 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1314 &value) &&
1315 sscanf(value.addr, "%d", &int_value) == 1 &&
1316 int_value > 0 && int_value <= 100) {
1317 screen->saveToolbarWidthPercent(int_value);
1318 }
1319
1320 sprintf(name_lookup, "session.screen%d.toolbar.placement", screen_number);
1321 sprintf(class_lookup, "Session.Screen%d.Toolbar.Placement", screen_number);
1322 screen->saveToolbarPlacement(Toolbar::BottomCenter);
1323 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1324 &value)) {
1325 if (! strncasecmp(value.addr, "TopLeft", value.size))
1326 screen->saveToolbarPlacement(Toolbar::TopLeft);
1327 else if (! strncasecmp(value.addr, "BottomLeft", value.size))
1328 screen->saveToolbarPlacement(Toolbar::BottomLeft);
1329 else if (! strncasecmp(value.addr, "TopCenter", value.size))
1330 screen->saveToolbarPlacement(Toolbar::TopCenter);
1331 else if (! strncasecmp(value.addr, "TopRight", value.size))
1332 screen->saveToolbarPlacement(Toolbar::TopRight);
1333 else if (! strncasecmp(value.addr, "BottomRight", value.size))
1334 screen->saveToolbarPlacement(Toolbar::BottomRight);
1335 }
1336 screen->removeWorkspaceNames();
1337
1338 sprintf(name_lookup, "session.screen%d.workspaceNames", screen_number);
1339 sprintf(class_lookup, "Session.Screen%d.WorkspaceNames", screen_number);
1340 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1341 &value)) {
1342 string search = value.addr;
1343 string::const_iterator it = search.begin(),
1344 end = search.end();
1345 while (1) {
1346 string::const_iterator tmp = it; // current string.begin()
1347 it = std::find(tmp, end, ','); // look for comma between tmp and end
1348 screen->addWorkspaceName(string(tmp, it)); // string = search[tmp:it]
1349 if (it == end) break;
1350 ++it;
1351 }
1352 }
1353
1354 sprintf(name_lookup, "session.screen%d.toolbar.onTop", screen_number);
1355 sprintf(class_lookup, "Session.Screen%d.Toolbar.OnTop", screen_number);
1356 screen->saveToolbarOnTop(False);
1357 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1358 &value) &&
1359 ! strncasecmp(value.addr, "true", value.size)) {
1360 screen->saveToolbarOnTop(True);
1361 }
1362
1363 sprintf(name_lookup, "session.screen%d.toolbar.autoHide", screen_number);
1364 sprintf(class_lookup, "Session.Screen%d.Toolbar.autoHide", screen_number);
1365 screen->saveToolbarAutoHide(False);
1366 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1367 &value) &&
1368 ! strncasecmp(value.addr, "true", value.size)) {
1369 screen->saveToolbarAutoHide(True);
1370 }
1371
1372 sprintf(name_lookup, "session.screen%d.focusModel", screen_number);
1373 sprintf(class_lookup, "Session.Screen%d.FocusModel", screen_number);
1374 screen->saveSloppyFocus(True);
1375 screen->saveAutoRaise(False);
1376 screen->saveClickRaise(False);
1377 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1378 &value)) {
1379 string fmodel = value.addr;
1380
1381 if (fmodel.find("ClickToFocus") != string::npos) {
1382 screen->saveSloppyFocus(False);
1383 } else {
1384 // must be sloppy
1385
1386 if (fmodel.find("AutoRaise") != string::npos)
1387 screen->saveAutoRaise(True);
1388 if (fmodel.find("ClickRaise") != string::npos)
1389 screen->saveClickRaise(True);
1390 }
1391 }
1392
1393 sprintf(name_lookup, "session.screen%d.windowPlacement", screen_number);
1394 sprintf(class_lookup, "Session.Screen%d.WindowPlacement", screen_number);
1395 screen->savePlacementPolicy(BScreen::RowSmartPlacement);
1396 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1397 &value)) {
1398 if (! strncasecmp(value.addr, "RowSmartPlacement", value.size))
1399 /* pass */;
1400 else if (! strncasecmp(value.addr, "ColSmartPlacement", value.size))
1401 screen->savePlacementPolicy(BScreen::ColSmartPlacement);
1402 else if (! strncasecmp(value.addr, "CascadePlacement", value.size))
1403 screen->savePlacementPolicy(BScreen::CascadePlacement);
1404 }
1405
1406 sprintf(name_lookup, "session.screen%d.slit.placement", screen_number);
1407 sprintf(class_lookup, "Session.Screen%d.Slit.Placement", screen_number);
1408 screen->saveSlitPlacement(Slit::CenterRight);
1409 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1410 &value)) {
1411 if (! strncasecmp(value.addr, "TopLeft", value.size))
1412 screen->saveSlitPlacement(Slit::TopLeft);
1413 else if (! strncasecmp(value.addr, "CenterLeft", value.size))
1414 screen->saveSlitPlacement(Slit::CenterLeft);
1415 else if (! strncasecmp(value.addr, "BottomLeft", value.size))
1416 screen->saveSlitPlacement(Slit::BottomLeft);
1417 else if (! strncasecmp(value.addr, "TopCenter", value.size))
1418 screen->saveSlitPlacement(Slit::TopCenter);
1419 else if (! strncasecmp(value.addr, "BottomCenter", value.size))
1420 screen->saveSlitPlacement(Slit::BottomCenter);
1421 else if (! strncasecmp(value.addr, "TopRight", value.size))
1422 screen->saveSlitPlacement(Slit::TopRight);
1423 else if (! strncasecmp(value.addr, "BottomRight", value.size))
1424 screen->saveSlitPlacement(Slit::BottomRight);
1425 }
1426
1427 sprintf(name_lookup, "session.screen%d.slit.direction", screen_number);
1428 sprintf(class_lookup, "Session.Screen%d.Slit.Direction", screen_number);
1429 screen->saveSlitDirection(Slit::Vertical);
1430 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1431 &value) &&
1432 ! strncasecmp(value.addr, "Horizontal", value.size)) {
1433 screen->saveSlitDirection(Slit::Horizontal);
1434 }
1435
1436 sprintf(name_lookup, "session.screen%d.slit.onTop", screen_number);
1437 sprintf(class_lookup, "Session.Screen%d.Slit.OnTop", screen_number);
1438 screen->saveSlitOnTop(False);
1439 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1440 &value) &&
1441 ! strncasecmp(value.addr, "True", value.size)) {
1442 screen->saveSlitOnTop(True);
1443 }
1444
1445 sprintf(name_lookup, "session.screen%d.slit.autoHide", screen_number);
1446 sprintf(class_lookup, "Session.Screen%d.Slit.AutoHide", screen_number);
1447 screen->saveSlitAutoHide(False);
1448 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1449 &value) &&
1450 ! strncasecmp(value.addr, "true", value.size)) {
1451 screen->saveSlitAutoHide(True);
1452 }
1453
1454 #ifdef HAVE_STRFTIME
1455 sprintf(name_lookup, "session.screen%d.strftimeFormat", screen_number);
1456 sprintf(class_lookup, "Session.Screen%d.StrftimeFormat", screen_number);
1457 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1458 &value)) {
1459 screen->saveStrftimeFormat(value.addr);
1460 } else {
1461 screen->saveStrftimeFormat("%I:%M %p");
1462 }
1463 #else // HAVE_STRFTIME
1464 sprintf(name_lookup, "session.screen%d.dateFormat", screen_number);
1465 sprintf(class_lookup, "Session.Screen%d.DateFormat", screen_number);
1466 screen->saveDateFormat(B_AmericanDate);
1467 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1468 &value)) {
1469 if (! strncasecmp(value.addr, "european", value.size))
1470 screen->saveDateFormat(B_EuropeanDate);
1471 }
1472
1473 sprintf(name_lookup, "session.screen%d.clockFormat", screen_number);
1474 sprintf(class_lookup, "Session.Screen%d.ClockFormat", screen_number);
1475 screen->saveClock24Hour(False);
1476 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1477 &value) &&
1478 sscanf(value.addr, "%d", &int_value) == 1 && int_value == 24) {
1479 screen->saveClock24Hour(True);
1480 }
1481 #endif // HAVE_STRFTIME
1482
1483 sprintf(name_lookup, "session.screen%d.edgeSnapThreshold", screen_number);
1484 sprintf(class_lookup, "Session.Screen%d.EdgeSnapThreshold", screen_number);
1485 if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
1486 &value) &&
1487 sscanf(value.addr, "%d", &int_value) == 1) {
1488 screen->saveEdgeSnapThreshold(int_value);
1489 }
1490
1491 screen->saveImageDither(True);
1492 if (XrmGetResource(database, "session.imageDither", "Session.ImageDither",
1493 &value_type, &value) &&
1494 ! strncasecmp("false", value.addr, value.size)) {
1495 screen->saveImageDither(False);
1496 }
1497
1498 screen->saveOpaqueMove(False);
1499 if (XrmGetResource(database, "session.opaqueMove", "Session.OpaqueMove",
1500 &value_type, &value) &&
1501 ! strncasecmp("true", value.addr, value.size)) {
1502 screen->saveOpaqueMove(True);
1503 }
1504
1505 XrmDestroyDatabase(database);
1506 }
1507
1508
1509 void Blackbox::reload_rc(void) {
1510 load_rc();
1511 reconfigure();
1512 }
1513
1514
1515 void Blackbox::reconfigure(void) {
1516 reconfigure_wait = True;
1517
1518 if (! timer->isTiming()) timer->start();
1519 }
1520
1521
1522 void Blackbox::real_reconfigure(void) {
1523 XrmDatabase new_blackboxrc = (XrmDatabase) 0;
1524 char *style = new char[resource.style_file.length() + 20];
1525
1526 sprintf(style, "session.styleFile: %s", getStyleFilename());
1527 XrmPutLineResource(&new_blackboxrc, style);
1528
1529 delete [] style;
1530
1531 XrmDatabase old_blackboxrc = XrmGetFileDatabase(rc_file.c_str());
1532
1533 XrmMergeDatabases(new_blackboxrc, &old_blackboxrc);
1534 XrmPutFileDatabase(old_blackboxrc, rc_file.c_str());
1535 if (old_blackboxrc) XrmDestroyDatabase(old_blackboxrc);
1536
1537 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1538 PointerAssassin());
1539 menuTimestamps.clear();
1540
1541 gcCache()->purge();
1542
1543 std::for_each(screenList.begin(), screenList.end(),
1544 std::mem_fun(&BScreen::reconfigure));
1545 }
1546
1547
1548 void Blackbox::checkMenu(void) {
1549 bool reread = False;
1550 MenuTimestampList::iterator it = menuTimestamps.begin();
1551 for(; it != menuTimestamps.end(); ++it) {
1552 MenuTimestamp *tmp = *it;
1553 struct stat buf;
1554
1555 if (! stat(tmp->filename.c_str(), &buf)) {
1556 if (tmp->timestamp != buf.st_ctime)
1557 reread = True;
1558 } else {
1559 reread = True;
1560 }
1561 }
1562
1563 if (reread) rereadMenu();
1564 }
1565
1566
1567 void Blackbox::rereadMenu(void) {
1568 reread_menu_wait = True;
1569
1570 if (! timer->isTiming()) timer->start();
1571 }
1572
1573
1574 void Blackbox::real_rereadMenu(void) {
1575 std::for_each(menuTimestamps.begin(), menuTimestamps.end(),
1576 PointerAssassin());
1577 menuTimestamps.clear();
1578
1579 std::for_each(screenList.begin(), screenList.end(),
1580 std::mem_fun(&BScreen::rereadMenu));
1581 }
1582
1583
1584 void Blackbox::saveStyleFilename(const string& filename) {
1585 assert(! filename.empty());
1586 resource.style_file = filename;
1587 }
1588
1589
1590 void Blackbox::addMenuTimestamp(const string& filename) {
1591 assert(! filename.empty());
1592 bool found = False;
1593
1594 MenuTimestampList::iterator it = menuTimestamps.begin();
1595 for (; it != menuTimestamps.end() && !found; ++it) {
1596 if ((*it)->filename == filename) found = True;
1597 }
1598 if (! found) {
1599 struct stat buf;
1600
1601 if (! stat(filename.c_str(), &buf)) {
1602 MenuTimestamp *ts = new MenuTimestamp;
1603
1604 ts->filename = filename;
1605 ts->timestamp = buf.st_ctime;
1606
1607 menuTimestamps.push_back(ts);
1608 }
1609 }
1610 }
1611
1612
1613 void Blackbox::timeout(void) {
1614 if (reconfigure_wait)
1615 real_reconfigure();
1616
1617 if (reread_menu_wait)
1618 real_rereadMenu();
1619
1620 reconfigure_wait = reread_menu_wait = False;
1621 }
1622
1623
1624 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1625 if (focused_window && focused_window == win) // nothing to do
1626 return;
1627
1628 BScreen *old_screen = 0;
1629
1630 if (focused_window) {
1631 focused_window->setFocusFlag(False);
1632 old_screen = focused_window->getScreen();
1633 }
1634
1635 if (win && ! win->isIconic()) {
1636 // the active screen is the one with the last focused window...
1637 // this will keep focus on this screen no matter where the mouse goes,
1638 // so multihead keybindings will continue to work on that screen until the
1639 // user focuses a window on a different screen.
1640 active_screen = win->getScreen();
1641 focused_window = win;
1642 } else {
1643 focused_window = 0;
1644 if (! old_screen) {
1645 if (active_screen) {
1646 // set input focus to the toolbar of the screen with mouse
1647 XSetInputFocus(getXDisplay(),
1648 active_screen->getToolbar()->getWindowID(),
1649 RevertToPointerRoot, CurrentTime);
1650 } else {
1651 // set input focus to the toolbar of the first managed screen
1652 XSetInputFocus(getXDisplay(),
1653 screenList.front()->getToolbar()->getWindowID(),
1654 RevertToPointerRoot, CurrentTime);
1655 }
1656 } else {
1657 // set input focus to the toolbar of the last screen
1658 XSetInputFocus(getXDisplay(), old_screen->getToolbar()->getWindowID(),
1659 RevertToPointerRoot, CurrentTime);
1660 }
1661 }
1662
1663 if (active_screen && active_screen->isScreenManaged()) {
1664 active_screen->getToolbar()->redrawWindowLabel(True);
1665 active_screen->updateNetizenWindowFocus();
1666 }
1667
1668 if (old_screen && old_screen != active_screen) {
1669 old_screen->getToolbar()->redrawWindowLabel(True);
1670 old_screen->updateNetizenWindowFocus();
1671 }
1672 }
This page took 0.107824 seconds and 3 git commands to generate.