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