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