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