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