]> Dogcows Code - chaz/openbox/blob - src/blackbox.cc
xeventhandler can handle everything except client messages now.
[chaz/openbox] / src / blackbox.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif // HAVE_CONFIG_H
6
7 extern "C" {
8 #include <X11/Xlib.h>
9 #include <X11/Xutil.h>
10 #include <X11/Xatom.h>
11 #include <X11/cursorfont.h>
12 #include <X11/keysym.h>
13
14 #ifdef SHAPE
15 #include <X11/extensions/shape.h>
16 #endif // SHAPE
17
18 #ifdef HAVE_STDIO_H
19 # include <stdio.h>
20 #endif // HAVE_STDIO_H
21
22 #ifdef HAVE_STDLIB_H
23 # include <stdlib.h>
24 #endif // HAVE_STDLIB_H
25
26 #ifdef HAVE_STRING_H
27 # include <string.h>
28 #endif // HAVE_STRING_H
29
30 #ifdef HAVE_UNISTD_H
31 # include <sys/types.h>
32 # include <unistd.h>
33 #endif // HAVE_UNISTD_H
34
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif // HAVE_SYS_PARAM_H
38
39 #ifdef HAVE_SYS_SELECT_H
40 # include <sys/select.h>
41 #endif // HAVE_SYS_SELECT_H
42
43 #ifdef HAVE_SIGNAL_H
44 # include <signal.h>
45 #endif // HAVE_SIGNAL_H
46
47 #ifdef HAVE_SYS_SIGNAL_H
48 # include <sys/signal.h>
49 #endif // HAVE_SYS_SIGNAL_H
50
51 #ifdef HAVE_SYS_STAT_H
52 # include <sys/types.h>
53 # include <sys/stat.h>
54 #endif // HAVE_SYS_STAT_H
55
56 #ifdef TIME_WITH_SYS_TIME
57 # include <sys/time.h>
58 # include <time.h>
59 #else // !TIME_WITH_SYS_TIME
60 # ifdef HAVE_SYS_TIME_H
61 # include <sys/time.h>
62 # else // !HAVE_SYS_TIME_H
63 # include <time.h>
64 # endif // HAVE_SYS_TIME_H
65 #endif // TIME_WITH_SYS_TIME
66
67 #ifdef HAVE_LIBGEN_H
68 # include <libgen.h>
69 #endif // HAVE_LIBGEN_H
70 }
71
72 #include <assert.h>
73
74 #include <algorithm>
75 #include <string>
76 using std::string;
77
78 #include "blackbox.hh"
79 #include "otk/gccache.hh"
80 #include "otk/image.hh"
81 #include "otk/assassin.hh"
82 #include "screen.hh"
83 #include "util.hh"
84 #include "window.hh"
85 #include "workspace.hh"
86 #include "xatom.hh"
87
88 namespace ob {
89
90 Blackbox *blackbox;
91
92
93 Blackbox::Blackbox(int argc, char **m_argv, char *rc)
94 : Openbox(argc, m_argv) {
95
96 if (! XSupportsLocale())
97 fprintf(stderr, "X server does not support locale\n");
98
99 if (XSetLocaleModifiers("") == NULL)
100 fprintf(stderr, "cannot set locale modifiers\n");
101
102 ob::blackbox = this;
103 argv = m_argv;
104
105 // try to make sure the ~/.openbox directory exists
106 mkdir(expandTilde("~/.openbox").c_str(), S_IREAD | S_IWRITE | S_IEXEC |
107 S_IRGRP | S_IWGRP | S_IXGRP |
108 S_IROTH | S_IWOTH | S_IXOTH);
109
110 if (! rc) rc = "~/.openbox/rc3";
111 rc_file = expandTilde(rc);
112 config.setFile(rc_file);
113
114 no_focus = False;
115
116 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
117
118 active_screen = 0;
119 focused_window = changing_window = (BlackboxWindow *) 0;
120
121 load_rc();
122
123 xatom = new XAtom(otk::OBDisplay::display);
124
125 cursor.session = XCreateFontCursor(otk::OBDisplay::display, XC_left_ptr);
126 cursor.move = XCreateFontCursor(otk::OBDisplay::display, XC_fleur);
127 cursor.ll_angle = XCreateFontCursor(otk::OBDisplay::display, XC_ll_angle);
128 cursor.lr_angle = XCreateFontCursor(otk::OBDisplay::display, XC_lr_angle);
129 cursor.ul_angle = XCreateFontCursor(otk::OBDisplay::display, XC_ul_angle);
130 cursor.ur_angle = XCreateFontCursor(otk::OBDisplay::display, XC_ur_angle);
131
132 for (int i = 0; i < ScreenCount(otk::OBDisplay::display); i++) {
133 BScreen *screen = new BScreen(this, i);
134
135 if (! screen->isScreenManaged()) {
136 delete screen;
137 continue;
138 }
139
140 screenList.push_back(screen);
141 }
142
143 if (screenList.empty()) {
144 fprintf(stderr,
145 "Blackbox::Blackbox: no managable screens found, aborting.\n");
146 ::exit(3);
147 }
148
149 // save current settings and default values
150 save_rc();
151
152 // set the screen with mouse to the first managed screen
153 active_screen = screenList.front();
154 setFocusedWindow(0);
155
156 XSynchronize(otk::OBDisplay::display, False);
157 XSync(otk::OBDisplay::display, False);
158
159 reconfigure_wait = False;
160
161 timer = new otk::OBTimer(Openbox::instance->timerManager(),
162 (otk::OBTimeoutHandler)timeout,
163 this);
164 timer->setTimeout(0l);
165 }
166
167
168 Blackbox::~Blackbox(void) {
169 std::for_each(screenList.begin(), screenList.end(), otk::PointerAssassin());
170
171 delete xatom;
172
173 delete timer;
174 }
175
176
177 void Blackbox::process_event(XEvent *e) {
178 switch (e->type) {
179 case ButtonPress: {
180 // strip the lock key modifiers
181 //e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
182
183 last_time = e->xbutton.time;
184
185 BlackboxWindow *win = (BlackboxWindow *) 0;
186 BScreen *scrn = (BScreen *) 0;
187
188 if ((win = searchWindow(e->xbutton.window))) {
189 win->buttonPressEvent(&e->xbutton);
190
191 /* XXX: is this sane on low colour desktops? */
192 if (e->xbutton.button == 1)
193 win->installColormap(True);
194 } else if ((scrn = searchScreen(e->xbutton.window))) {
195 scrn->buttonPressEvent(&e->xbutton);
196 if (active_screen != scrn) {
197 active_screen = scrn;
198 // first, set no focus window on the old screen
199 setFocusedWindow(0);
200 // and move focus to this screen
201 setFocusedWindow(0);
202 }
203 }
204 break;
205 }
206
207 case ButtonRelease: {
208 // strip the lock key modifiers
209 //e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask);
210
211 last_time = e->xbutton.time;
212
213 BlackboxWindow *win = (BlackboxWindow *) 0;
214
215 if ((win = searchWindow(e->xbutton.window)))
216 win->buttonReleaseEvent(&e->xbutton);
217
218 break;
219 }
220
221 case ConfigureRequest: {
222 BlackboxWindow *win = (BlackboxWindow *) 0;
223
224 if ((win = searchWindow(e->xconfigurerequest.window))) {
225 win->configureRequestEvent(&e->xconfigurerequest);
226 } else {
227 if (validateWindow(e->xconfigurerequest.window)) {
228 XWindowChanges xwc;
229
230 xwc.x = e->xconfigurerequest.x;
231 xwc.y = e->xconfigurerequest.y;
232 xwc.width = e->xconfigurerequest.width;
233 xwc.height = e->xconfigurerequest.height;
234 xwc.border_width = e->xconfigurerequest.border_width;
235 xwc.sibling = e->xconfigurerequest.above;
236 xwc.stack_mode = e->xconfigurerequest.detail;
237
238 XConfigureWindow(otk::OBDisplay::display, e->xconfigurerequest.window,
239 e->xconfigurerequest.value_mask, &xwc);
240 }
241 }
242
243 break;
244 }
245
246 case MapRequest: {
247 #ifdef DEBUG
248 fprintf(stderr, "Blackbox::process_event(): MapRequest for 0x%lx\n",
249 e->xmaprequest.window);
250 #endif // DEBUG
251
252 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
253
254 if (win) {
255 bool focus = False;
256 if (win->isIconic()) {
257 win->deiconify();
258 focus = True;
259 }
260 if (win->isShaded()) {
261 win->shade();
262 focus = True;
263 }
264
265 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
266 win->isVisible())
267 win->setInputFocus();
268 } else {
269 BScreen *screen = searchScreen(e->xmaprequest.parent);
270
271 if (! screen) {
272 /*
273 we got a map request for a window who's parent isn't root. this
274 can happen in only one circumstance:
275
276 a client window unmapped a managed window, and then remapped it
277 somewhere between unmapping the client window and reparenting it
278 to root.
279
280 regardless of how it happens, we need to find the screen that
281 the window is on
282 */
283 XWindowAttributes wattrib;
284 if (! XGetWindowAttributes(otk::OBDisplay::display, e->xmaprequest.window,
285 &wattrib)) {
286 // failed to get the window attributes, perhaps the window has
287 // now been destroyed?
288 break;
289 }
290
291 screen = searchScreen(wattrib.root);
292 assert(screen != 0); // this should never happen
293 }
294
295 screen->manageWindow(e->xmaprequest.window);
296 }
297
298 break;
299 }
300
301 case UnmapNotify: {
302 BlackboxWindow *win = (BlackboxWindow *) 0;
303 BScreen *screen = (BScreen *) 0;
304
305 if ((win = searchWindow(e->xunmap.window))) {
306 win->unmapNotifyEvent(&e->xunmap);
307 } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
308 screen->removeSystrayWindow(e->xunmap.window);
309 }
310
311 break;
312 }
313
314 case DestroyNotify: {
315 BlackboxWindow *win = (BlackboxWindow *) 0;
316 BScreen *screen = (BScreen *) 0;
317 BWindowGroup *group = (BWindowGroup *) 0;
318
319 if ((win = searchWindow(e->xdestroywindow.window))) {
320 win->destroyNotifyEvent(&e->xdestroywindow);
321 } else if ((group = searchGroup(e->xdestroywindow.window))) {
322 delete group;
323 } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
324 screen->removeSystrayWindow(e->xunmap.window);
325 }
326
327 break;
328 }
329
330 case ReparentNotify: {
331 /*
332 this event is quite rare and is usually handled in unmapNotify
333 however, if the window is unmapped when the reparent event occurs
334 the window manager never sees it because an unmap event is not sent
335 to an already unmapped window.
336 */
337 BlackboxWindow *win = searchWindow(e->xreparent.window);
338 if (win)
339 win->reparentNotifyEvent(&e->xreparent);
340 break;
341 }
342
343 case MotionNotify: {
344 // motion notify compression...
345 XEvent realevent;
346 unsigned int i = 0;
347 while (XCheckTypedWindowEvent(otk::OBDisplay::display, e->xmotion.window,
348 MotionNotify, &realevent)) {
349 i++;
350 }
351
352 // if we have compressed some motion events, use the last one
353 if ( i > 0 )
354 e = &realevent;
355
356 // the pointer is on the wrong screen
357 if (! e->xmotion.same_screen)
358 break;
359
360 // strip the lock key modifiers
361 //e->xmotion.state &= ~(NumLockMask | ScrollLockMask | LockMask);
362
363 last_time = e->xmotion.time;
364
365 BlackboxWindow *win = (BlackboxWindow *) 0;
366
367 if ((win = searchWindow(e->xmotion.window)))
368 win->motionNotifyEvent(&e->xmotion);
369
370 break;
371 }
372
373 case PropertyNotify: {
374 last_time = e->xproperty.time;
375
376 BlackboxWindow *win = (BlackboxWindow *) 0;
377 BScreen *screen = (BScreen *) 0;
378
379 if ((win = searchWindow(e->xproperty.window)))
380 win->propertyNotifyEvent(&e->xproperty);
381 else if ((screen = searchScreen(e->xproperty.window)))
382 screen->propertyNotifyEvent(&e->xproperty);
383 break;
384 }
385
386 case EnterNotify: {
387 last_time = e->xcrossing.time;
388
389 BScreen *screen = (BScreen *) 0;
390 BlackboxWindow *win = (BlackboxWindow *) 0;
391
392 if (e->xcrossing.mode == NotifyGrab) break;
393
394 if ((e->xcrossing.window == e->xcrossing.root) &&
395 (screen = searchScreen(e->xcrossing.window))) {
396 screen->getImageControl()->installRootColormap();
397 } else if ((win = searchWindow(e->xcrossing.window))) {
398 if (! no_focus)
399 win->enterNotifyEvent(&e->xcrossing);
400 }
401 break;
402 }
403
404 case LeaveNotify: {
405 last_time = e->xcrossing.time;
406
407 BlackboxWindow *win = (BlackboxWindow *) 0;
408
409 if ((win = searchWindow(e->xcrossing.window)))
410 win->leaveNotifyEvent(&e->xcrossing);
411 break;
412 }
413
414 case Expose: {
415 // compress expose events
416 XEvent realevent;
417 unsigned int i = 0;
418 int ex1, ey1, ex2, ey2;
419 ex1 = e->xexpose.x;
420 ey1 = e->xexpose.y;
421 ex2 = ex1 + e->xexpose.width - 1;
422 ey2 = ey1 + e->xexpose.height - 1;
423 while (XCheckTypedWindowEvent(otk::OBDisplay::display, e->xexpose.window,
424 Expose, &realevent)) {
425 i++;
426
427 // merge expose area
428 ex1 = std::min(realevent.xexpose.x, ex1);
429 ey1 = std::min(realevent.xexpose.y, ey1);
430 ex2 = std::max(realevent.xexpose.x + realevent.xexpose.width - 1, ex2);
431 ey2 = std::max(realevent.xexpose.y + realevent.xexpose.height - 1, ey2);
432 }
433 if ( i > 0 )
434 e = &realevent;
435
436 // use the merged area
437 e->xexpose.x = ex1;
438 e->xexpose.y = ey1;
439 e->xexpose.width = ex2 - ex1 + 1;
440 e->xexpose.height = ey2 - ey1 + 1;
441
442 BlackboxWindow *win = (BlackboxWindow *) 0;
443
444 if ((win = searchWindow(e->xexpose.window)))
445 win->exposeEvent(&e->xexpose);
446
447 break;
448 }
449
450 case KeyPress: {
451 break;
452 }
453
454 case ColormapNotify: {
455 BScreen *screen = searchScreen(e->xcolormap.window);
456
457 if (screen)
458 screen->setRootColormapInstalled((e->xcolormap.state ==
459 ColormapInstalled) ? True : False);
460
461 break;
462 }
463
464 case FocusIn: {
465 if (e->xfocus.detail != NotifyNonlinear &&
466 e->xfocus.detail != NotifyAncestor) {
467 /*
468 don't process FocusIns when:
469 1. the new focus window isn't an ancestor or inferior of the old
470 focus window (NotifyNonlinear)
471 make sure to allow the FocusIn when the old focus window was an
472 ancestor but didn't have a parent, such as root (NotifyAncestor)
473 */
474 break;
475 }
476
477 BlackboxWindow *win = searchWindow(e->xfocus.window);
478 if (win) {
479 if (! win->isFocused())
480 win->setFocusFlag(True);
481
482 /*
483 set the event window to None. when the FocusOut event handler calls
484 this function recursively, it uses this as an indication that focus
485 has moved to a known window.
486 */
487 e->xfocus.window = None;
488
489 no_focus = False; // focusing is back on
490 }
491
492 break;
493 }
494
495 case FocusOut: {
496 if (e->xfocus.detail != NotifyNonlinear) {
497 /*
498 don't process FocusOuts when:
499 2. the new focus window isn't an ancestor or inferior of the old
500 focus window (NotifyNonlinear)
501 */
502 break;
503 }
504
505 BlackboxWindow *win = searchWindow(e->xfocus.window);
506 if (win && win->isFocused()) {
507 /*
508 before we mark "win" as unfocused, we need to verify that focus is
509 going to a known location, is in a known location, or set focus
510 to a known location.
511 */
512
513 XEvent event;
514 // don't check the current focus if FocusOut was generated during a grab
515 bool check_focus = (e->xfocus.mode == NotifyNormal);
516
517 /*
518 First, check if there is a pending FocusIn event waiting. if there
519 is, process it and determine if focus has moved to another window
520 (the FocusIn event handler sets the window in the event
521 structure to None to indicate this).
522 */
523 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
524
525 process_event(&event);
526 if (event.xfocus.window == None) {
527 // focus has moved
528 check_focus = False;
529 }
530 }
531
532 if (check_focus) {
533 /*
534 Second, we query the X server for the current input focus.
535 to make sure that we keep a consistent state.
536 */
537 BlackboxWindow *focus;
538 Window w;
539 int revert;
540 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
541 focus = searchWindow(w);
542 if (focus) {
543 /*
544 focus got from "win" to "focus" under some very strange
545 circumstances, and we need to make sure that the focus indication
546 is correct.
547 */
548 setFocusedWindow(focus);
549 } else {
550 // we have no idea where focus went... so we set it to somewhere
551 setFocusedWindow(0);
552 }
553 }
554 }
555
556 break;
557 }
558
559 case ClientMessage: {
560 if (e->xclient.format == 32) {
561 if (e->xclient.message_type == xatom->getAtom(XAtom::wm_change_state)) {
562 // WM_CHANGE_STATE message
563 BlackboxWindow *win = searchWindow(e->xclient.window);
564 if (! win || ! win->validateClient()) return;
565
566 if (e->xclient.data.l[0] == IconicState)
567 win->iconify();
568 if (e->xclient.data.l[0] == NormalState)
569 win->deiconify();
570 } else if (e->xclient.message_type ==
571 xatom->getAtom(XAtom::blackbox_change_workspace) ||
572 e->xclient.message_type ==
573 xatom->getAtom(XAtom::net_current_desktop)) {
574 // NET_CURRENT_DESKTOP message
575 BScreen *screen = searchScreen(e->xclient.window);
576
577 unsigned int workspace = e->xclient.data.l[0];
578 if (screen && workspace < screen->getWorkspaceCount())
579 screen->changeWorkspaceID(workspace);
580 } else if (e->xclient.message_type ==
581 xatom->getAtom(XAtom::blackbox_change_window_focus)) {
582 // TEMP HACK TO KEEP BBKEYS WORKING
583 BlackboxWindow *win = searchWindow(e->xclient.window);
584
585 if (win && win->isVisible() && win->setInputFocus())
586 win->installColormap(True);
587 } else if (e->xclient.message_type ==
588 xatom->getAtom(XAtom::net_active_window)) {
589 // NET_ACTIVE_WINDOW
590 BlackboxWindow *win = searchWindow(e->xclient.window);
591
592 if (win) {
593 BScreen *screen = win->getScreen();
594
595 if (win->isIconic())
596 win->deiconify(False, False);
597 if (! win->isStuck() &&
598 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
599 no_focus = True;
600 screen->changeWorkspaceID(win->getWorkspaceNumber());
601 }
602 if (win->isVisible() && win->setInputFocus()) {
603 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
604 raiseWindow(win);
605 win->installColormap(True);
606 }
607 }
608 } else if (e->xclient.message_type ==
609 xatom->getAtom(XAtom::blackbox_cycle_window_focus)) {
610 // BLACKBOX_CYCLE_WINDOW_FOCUS
611 BScreen *screen = searchScreen(e->xclient.window);
612
613 if (screen) {
614 if (! e->xclient.data.l[0])
615 screen->prevFocus();
616 else
617 screen->nextFocus();
618 }
619 } else if (e->xclient.message_type ==
620 xatom->getAtom(XAtom::net_wm_desktop)) {
621 // NET_WM_DESKTOP
622 BlackboxWindow *win = searchWindow(e->xclient.window);
623
624 if (win) {
625 BScreen *screen = win->getScreen();
626 unsigned long wksp = (unsigned) e->xclient.data.l[0];
627 if (wksp < screen->getWorkspaceCount()) {
628 if (win->isIconic()) win->deiconify(False, True);
629 if (win->isStuck()) win->stick();
630 if (wksp != screen->getCurrentWorkspaceID())
631 win->withdraw();
632 else
633 win->show();
634 screen->reassociateWindow(win, wksp, True);
635 } else if (wksp == 0xfffffffe || // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
636 wksp == 0xffffffff) {
637 if (win->isIconic()) win->deiconify(False, True);
638 if (! win->isStuck()) win->stick();
639 if (! win->isVisible()) win->show();
640 }
641 }
642 } else if (e->xclient.message_type ==
643 xatom->getAtom(XAtom::blackbox_change_attributes)) {
644 // BLACKBOX_CHANGE_ATTRIBUTES
645 BlackboxWindow *win = searchWindow(e->xclient.window);
646
647 if (win && win->validateClient()) {
648 BlackboxHints net;
649 net.flags = e->xclient.data.l[0];
650 net.attrib = e->xclient.data.l[1];
651 net.workspace = e->xclient.data.l[2];
652 net.stack = e->xclient.data.l[3];
653 net.decoration = e->xclient.data.l[4];
654
655 win->changeBlackboxHints(&net);
656 }
657 } else if (e->xclient.message_type ==
658 xatom->getAtom(XAtom::net_number_of_desktops)) {
659 // NET_NUMBER_OF_DESKTOPS
660 BScreen *screen = searchScreen(e->xclient.window);
661
662 if (e->xclient.data.l[0] > 0)
663 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
664 } else if (e->xclient.message_type ==
665 xatom->getAtom(XAtom::net_close_window)) {
666 // NET_CLOSE_WINDOW
667 BlackboxWindow *win = searchWindow(e->xclient.window);
668 if (win && win->validateClient())
669 win->close(); // could this be smarter?
670 } else if (e->xclient.message_type ==
671 xatom->getAtom(XAtom::net_wm_moveresize)) {
672 // NET_WM_MOVERESIZE
673 BlackboxWindow *win = searchWindow(e->xclient.window);
674 if (win && win->validateClient()) {
675 int x_root = e->xclient.data.l[0],
676 y_root = e->xclient.data.l[1];
677 if ((Atom) e->xclient.data.l[2] ==
678 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
679 win->beginMove(x_root, y_root);
680 } else {
681 if ((Atom) e->xclient.data.l[2] ==
682 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
683 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
684 else if ((Atom) e->xclient.data.l[2] ==
685 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
686 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
687 else if ((Atom) e->xclient.data.l[2] ==
688 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
689 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
690 else if ((Atom) e->xclient.data.l[2] ==
691 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
692 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
693 }
694 }
695 } else if (e->xclient.message_type ==
696 xatom->getAtom(XAtom::net_wm_state)) {
697 // NET_WM_STATE
698 BlackboxWindow *win = searchWindow(e->xclient.window);
699 if (win && win->validateClient()) {
700 const Atom action = (Atom) e->xclient.data.l[0];
701 const Atom state[] = { (Atom) e->xclient.data.l[1],
702 (Atom) e->xclient.data.l[2] };
703
704 for (int i = 0; i < 2; ++i) {
705 if (! state[i])
706 continue;
707
708 if ((Atom) e->xclient.data.l[0] == 1) {
709 // ADD
710 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
711 win->setModal(True);
712 } else if (state[i] ==
713 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
714 if (win->isMaximizedHoriz()) {
715 win->maximize(0); // unmaximize
716 win->maximize(1); // full
717 } else if (! win->isMaximized()) {
718 win->maximize(2); // vert
719 }
720 } else if (state[i] ==
721 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
722 if (win->isMaximizedVert()) {
723 win->maximize(0); // unmaximize
724 win->maximize(1); // full
725 } else if (! win->isMaximized()) {
726 win->maximize(3); // horiz
727 }
728 } else if (state[i] ==
729 xatom->getAtom(XAtom::net_wm_state_shaded)) {
730 if (! win->isShaded())
731 win->shade();
732 } else if (state[i] ==
733 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
734 win->setSkipTaskbar(True);
735 } else if (state[i] ==
736 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
737 win->setSkipPager(True);
738 } else if (state[i] ==
739 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
740 win->setFullscreen(True);
741 }
742 } else if (action == 0) {
743 // REMOVE
744 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
745 win->setModal(False);
746 } else if (state[i] ==
747 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
748 if (win->isMaximizedFull()) {
749 win->maximize(0); // unmaximize
750 win->maximize(3); // horiz
751 } else if (win->isMaximizedVert()) {
752 win->maximize(0); // unmaximize
753 }
754 } else if (state[i] ==
755 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
756 if (win->isMaximizedFull()) {
757 win->maximize(0); // unmaximize
758 win->maximize(2); // vert
759 } else if (win->isMaximizedHoriz()) {
760 win->maximize(0); // unmaximize
761 }
762 } else if (state[i] ==
763 xatom->getAtom(XAtom::net_wm_state_shaded)) {
764 if (win->isShaded())
765 win->shade();
766 } else if (state[i] ==
767 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
768 win->setSkipTaskbar(False);
769 } else if (state[i] ==
770 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
771 win->setSkipPager(False);
772 } else if (state[i] ==
773 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
774 win->setFullscreen(False);
775 }
776 } else if (action == 2) {
777 // TOGGLE
778 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
779 win->setModal(! win->isModal());
780 } else if (state[i] ==
781 xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
782 if (win->isMaximizedFull()) {
783 win->maximize(0); // unmaximize
784 win->maximize(3); // horiz
785 } else if (win->isMaximizedVert()) {
786 win->maximize(0); // unmaximize
787 } else if (win->isMaximizedHoriz()) {
788 win->maximize(0); // unmaximize
789 win->maximize(1); // full
790 } else {
791 win->maximize(2); // vert
792 }
793 } else if (state[i] ==
794 xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
795 if (win->isMaximizedFull()) {
796 win->maximize(0); // unmaximize
797 win->maximize(2); // vert
798 } else if (win->isMaximizedHoriz()) {
799 win->maximize(0); // unmaximize
800 } else if (win->isMaximizedVert()) {
801 win->maximize(0); // unmaximize
802 win->maximize(1); // full
803 } else {
804 win->maximize(3); // horiz
805 }
806 } else if (state[i] ==
807 xatom->getAtom(XAtom::net_wm_state_shaded)) {
808 win->shade();
809 } else if (state[i] ==
810 xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
811 win->setSkipTaskbar(! win->skipTaskbar());
812 } else if (state[i] ==
813 xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
814 win->setSkipPager(! win->skipPager());
815 } else if (state[i] ==
816 xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
817 win->setFullscreen(! win->isFullscreen());
818 }
819 }
820 }
821 }
822 }
823 }
824
825 break;
826 }
827
828 case NoExpose:
829 case ConfigureNotify:
830 case MapNotify:
831 break; // not handled, just ignore
832
833 default: {
834 #ifdef SHAPE
835 if (e->type == getShapeEventBase()) {
836 XShapeEvent *shape_event = (XShapeEvent *) e;
837 BlackboxWindow *win = searchWindow(e->xany.window);
838
839 if (win && shape_event->kind == ShapeBounding)
840 win->shapeEvent(shape_event);
841 }
842 #endif // SHAPE
843 }
844 } // switch
845 }
846
847
848 bool Blackbox::handleSignal(int sig) {
849 switch (sig) {
850 case SIGHUP:
851 reconfigure();
852 break;
853
854 case SIGUSR1:
855 restart();
856 break;
857
858 case SIGUSR2:
859 break;
860
861 case SIGPIPE:
862 case SIGSEGV:
863 case SIGFPE:
864 case SIGINT:
865 case SIGTERM:
866 shutdown();
867
868 default:
869 return False;
870 }
871
872 return True;
873 }
874
875
876 bool Blackbox::validateWindow(Window window) {
877 XEvent event;
878 if (XCheckTypedWindowEvent(otk::OBDisplay::display, window, DestroyNotify, &event)) {
879 XPutBackEvent(otk::OBDisplay::display, &event);
880
881 return False;
882 }
883
884 return True;
885 }
886
887
888 BScreen *Blackbox::searchScreen(Window window) {
889 ScreenList::iterator it = screenList.begin();
890
891 for (; it != screenList.end(); ++it) {
892 BScreen *s = *it;
893 if (s->getRootWindow() == window)
894 return s;
895 }
896
897 return (BScreen *) 0;
898 }
899
900
901 BScreen *Blackbox::searchSystrayWindow(Window window) {
902 WindowScreenLookup::iterator it = systraySearchList.find(window);
903 if (it != systraySearchList.end())
904 return it->second;
905
906 return (BScreen*) 0;
907 }
908
909
910 BlackboxWindow *Blackbox::searchWindow(Window window) {
911 WindowLookup::iterator it = windowSearchList.find(window);
912 if (it != windowSearchList.end())
913 return it->second;
914
915 return (BlackboxWindow*) 0;
916 }
917
918
919 BWindowGroup *Blackbox::searchGroup(Window window) {
920 GroupLookup::iterator it = groupSearchList.find(window);
921 if (it != groupSearchList.end())
922 return it->second;
923
924 return (BWindowGroup *) 0;
925 }
926
927
928 void Blackbox::saveSystrayWindowSearch(Window window, BScreen *screen) {
929 systraySearchList.insert(WindowScreenLookupPair(window, screen));
930 }
931
932
933 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
934 windowSearchList.insert(WindowLookupPair(window, data));
935 }
936
937
938 void Blackbox::saveGroupSearch(Window window, BWindowGroup *data) {
939 groupSearchList.insert(GroupLookupPair(window, data));
940 }
941
942
943 void Blackbox::removeSystrayWindowSearch(Window window) {
944 systraySearchList.erase(window);
945 }
946
947
948 void Blackbox::removeWindowSearch(Window window) {
949 windowSearchList.erase(window);
950 }
951
952
953 void Blackbox::removeGroupSearch(Window window) {
954 groupSearchList.erase(window);
955 }
956
957
958 void Blackbox::restart(const char *prog) {
959 shutdown();
960
961 if (prog) {
962 putenv(const_cast<char *>(screenList.front()->displayString().c_str()));
963 execlp(prog, prog, NULL);
964 perror(prog);
965 }
966
967 // fall back in case the above execlp doesn't work
968 execvp(argv[0], argv);
969 string name = ::basename(argv[0]);
970 execvp(name.c_str(), argv);
971 }
972
973
974 void Blackbox::shutdown(void) {
975 Openbox::shutdown();
976
977 XSetInputFocus(otk::OBDisplay::display, PointerRoot, None, CurrentTime);
978
979 std::for_each(screenList.begin(), screenList.end(),
980 std::mem_fun(&BScreen::shutdown));
981
982 XSync(otk::OBDisplay::display, False);
983 }
984
985
986 #ifdef XINERAMA
987 void Blackbox::saveXineramaPlacement(bool x) {
988 resource.xinerama_placement = x;
989 config.setValue("session.xineramaSupport.windowPlacement",
990 resource.xinerama_placement);
991 reconfigure(); // make sure all screens get this
992
993 void Blackbox::saveXineramaMaximizing(bool x) {
994 resource.xinerama_maximize = x;
995 config.setValue("session.xineramaSupport.windowMaximizing",
996 resource.xinerama_maximize);
997 reconfigure(); // make sure all screens get this change
998 }
999
1000
1001 void Blackbox::saveXineramaSnapping(bool x) {
1002 resource.xinerama_snap = x;
1003 config.setValue("session.xineramaSupport.windowSnapping",
1004 resource.xinerama_snap);
1005 reconfigure(); // make sure all screens get this change
1006 }
1007 #endif // XINERAMA
1008
1009
1010 /*
1011 * Save all values as they are so that the defaults will be written to the rc
1012 * file
1013 */
1014 void Blackbox::save_rc(void) {
1015 config.setAutoSave(false);
1016
1017 config.setValue("session.colorsPerChannel", resource.colors_per_channel);
1018 config.setValue("session.doubleClickInterval",
1019 resource.double_click_interval);
1020 config.setValue("session.autoRaiseDelay",
1021 ((resource.auto_raise_delay.tv_sec * 1000) +
1022 (resource.auto_raise_delay.tv_usec / 1000)));
1023 config.setValue("session.cacheLife", resource.cache_life / 60000);
1024 config.setValue("session.cacheMax", resource.cache_max);
1025 config.setValue("session.styleFile", resource.style_file);
1026 config.setValue("session.titlebarLayout", resource.titlebar_layout);
1027
1028 string s;
1029 if (resource.mod_mask & Mod1Mask) s += "Mod1-";
1030 if (resource.mod_mask & Mod2Mask) s += "Mod2-";
1031 if (resource.mod_mask & Mod3Mask) s += "Mod3-";
1032 if (resource.mod_mask & Mod4Mask) s += "Mod4-";
1033 if (resource.mod_mask & Mod5Mask) s += "Mod5-";
1034 if (resource.mod_mask & ShiftMask) s += "Shift-";
1035 if (resource.mod_mask & ControlMask) s += "Control-";
1036 s.resize(s.size() - 1); // drop the last '-'
1037 config.setValue("session.modifierMask", s);
1038
1039 #ifdef XINERAMA
1040 saveXineramaPlacement(resource.xinerama_placement);
1041 saveXineramaMaximizing(resource.xinerama_maximize);
1042 saveXineramaSnapping(resource.xinerama_snap);
1043 #endif // XINERAMA
1044
1045 std::for_each(screenList.begin(), screenList.end(),
1046 std::mem_fun(&BScreen::save_rc));
1047
1048 config.setAutoSave(true);
1049 config.save();
1050 }
1051
1052
1053 void Blackbox::load_rc(void) {
1054 if (! config.load())
1055 config.create();
1056
1057 string s;
1058
1059 if (! config.getValue("session.colorsPerChannel",
1060 resource.colors_per_channel))
1061 resource.colors_per_channel = 4;
1062 if (resource.colors_per_channel < 2) resource.colors_per_channel = 2;
1063 else if (resource.colors_per_channel > 6) resource.colors_per_channel = 6;
1064
1065 if (config.getValue("session.styleFile", s))
1066 resource.style_file = expandTilde(s);
1067 else
1068 resource.style_file = DEFAULTSTYLE;
1069
1070 if (! config.getValue("session.doubleClickInterval",
1071 resource.double_click_interval));
1072 resource.double_click_interval = 250;
1073
1074 if (! config.getValue("session.autoRaiseDelay",
1075 resource.auto_raise_delay.tv_usec))
1076 resource.auto_raise_delay.tv_usec = 400;
1077 resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
1078 resource.auto_raise_delay.tv_usec -=
1079 (resource.auto_raise_delay.tv_sec * 1000);
1080 resource.auto_raise_delay.tv_usec *= 1000;
1081
1082 if (! config.getValue("session.cacheLife", resource.cache_life))
1083 resource.cache_life = 5;
1084 resource.cache_life *= 60000;
1085
1086 if (! config.getValue("session.cacheMax", resource.cache_max))
1087 resource.cache_max = 200;
1088
1089 if (! config.getValue("session.titlebarLayout", resource.titlebar_layout))
1090 resource.titlebar_layout = "ILMC";
1091
1092 #ifdef XINERAMA
1093 if (! config.getValue("session.xineramaSupport.windowPlacement",
1094 resource.xinerama_placement))
1095 resource.xinerama_placement = false;
1096
1097 if (! config.getValue("session.xineramaSupport.windowMaximizing",
1098 resource.xinerama_maximize))
1099 resource.xinerama_maximize = false;
1100
1101 if (! config.getValue("session.xineramaSupport.windowSnapping",
1102 resource.xinerama_snap))
1103 resource.xinerama_snap = false;
1104 #endif // XINERAMA
1105
1106 resource.mod_mask = 0;
1107 if (config.getValue("session.modifierMask", s)) {
1108 if (s.find("Mod1") != string::npos)
1109 resource.mod_mask |= Mod1Mask;
1110 if (s.find("Mod2") != string::npos)
1111 resource.mod_mask |= Mod2Mask;
1112 if (s.find("Mod3") != string::npos)
1113 resource.mod_mask |= Mod3Mask;
1114 if (s.find("Mod4") != string::npos)
1115 resource.mod_mask |= Mod4Mask;
1116 if (s.find("Mod5") != string::npos)
1117 resource.mod_mask |= Mod5Mask;
1118 if (s.find("Shift") != string::npos)
1119 resource.mod_mask |= ShiftMask;
1120 if (s.find("Control") != string::npos)
1121 resource.mod_mask |= ControlMask;
1122 }
1123 if (! resource.mod_mask)
1124 resource.mod_mask = Mod1Mask;
1125 }
1126
1127
1128 void Blackbox::reconfigure(void) {
1129 // don't reconfigure while saving the initial rc file, it's a waste and it
1130 // breaks somethings (workspace names)
1131 if (state() == Openbox::State_Starting) return;
1132
1133 reconfigure_wait = True;
1134
1135 if (! timer->timing()) timer->start();
1136 }
1137
1138
1139 void Blackbox::real_reconfigure(void) {
1140 load_rc();
1141
1142 otk::OBDisplay::gcCache()->purge();
1143
1144 std::for_each(screenList.begin(), screenList.end(),
1145 std::mem_fun(&BScreen::reconfigure));
1146 }
1147
1148
1149 void Blackbox::saveStyleFilename(const string& filename) {
1150 assert(! filename.empty());
1151 resource.style_file = filename;
1152 config.setValue("session.styleFile", resource.style_file);
1153 }
1154
1155
1156 void Blackbox::timeout(Blackbox *t) {
1157 if (t->reconfigure_wait)
1158 t->real_reconfigure();
1159
1160 t->reconfigure_wait = False;
1161 }
1162
1163
1164 void Blackbox::setChangingWindow(BlackboxWindow *win) {
1165 // make sure one of the two is null and the other isn't
1166 assert((! changing_window && win) || (! win && changing_window));
1167 changing_window = win;
1168 }
1169
1170
1171 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
1172 if (focused_window && focused_window == win) // nothing to do
1173 return;
1174
1175 BScreen *old_screen = 0;
1176
1177 if (focused_window) {
1178 focused_window->setFocusFlag(False);
1179 old_screen = focused_window->getScreen();
1180 }
1181
1182 if (win && ! win->isIconic()) {
1183 // the active screen is the one with the last focused window...
1184 // this will keep focus on this screen no matter where the mouse goes,
1185 // so multihead keybindings will continue to work on that screen until the
1186 // user focuses a window on a different screen.
1187 active_screen = win->getScreen();
1188 focused_window = win;
1189 } else {
1190 focused_window = 0;
1191 if (! old_screen) {
1192 if (active_screen) {
1193 // set input focus to the toolbar of the screen with mouse
1194 XSetInputFocus(otk::OBDisplay::display,
1195 active_screen->getRootWindow(),
1196 RevertToPointerRoot, CurrentTime);
1197 } else {
1198 // set input focus to the toolbar of the first managed screen
1199 XSetInputFocus(otk::OBDisplay::display,
1200 screenList.front()->getRootWindow(),
1201 RevertToPointerRoot, CurrentTime);
1202 }
1203 } else {
1204 // set input focus to the toolbar of the last screen
1205 XSetInputFocus(otk::OBDisplay::display, old_screen->getRootWindow(),
1206 RevertToPointerRoot, CurrentTime);
1207 }
1208 }
1209
1210 if (active_screen && active_screen->isScreenManaged()) {
1211 active_screen->updateNetizenWindowFocus();
1212 }
1213
1214 if (old_screen && old_screen != active_screen) {
1215 old_screen->updateNetizenWindowFocus();
1216 }
1217 }
1218
1219
1220 }
This page took 0.089092 seconds and 4 git commands to generate.