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