- changing MaxInstructions to 100 for cthulhain (crazy nut) =:)
[bbkeys.git] / src / bbkeys.cc
blob3015c3603efb16ff94427c5656e697c7fad8b450
1 // bbkeys.cc for blackbox
2 // ------ note from the Gee-I'm-Sorry-The-Code-Looks-Ugly department-----
3 // ------ for vi users-- ":set ts=2" =:)
4 //
5 // Copyright (c) 1999-2001 by Jason Kasper (vanRijn) vR@movingparts.net
6 // Copyright (c) 2001 by Ben Jansens <xor@orodu.net>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 // (See the included file COPYING / GPL-2.0)
24 // $Id$
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #ifdef HAVE_STDIO_H
31 # include <stdio.h>
32 #endif // HAVE_STDIO_H
34 #ifdef HAVE_CTYPE_H
35 # include <ctype.h>
36 #endif // HAVE_CTYPE_H
38 #ifdef STDC_HEADERS
39 # include <stdlib.h>
40 # include <string.h>
41 #endif // STDC_HEADERS
43 #if HAVE_STRINGS_H
44 # include <strings.h>
45 #endif
47 #ifdef HAVE_SYS_TYPES_H
48 # include <sys/types.h>
49 #endif // HAVE_SYS_TYPES_H
51 #ifdef HAVE_SYS_WAIT_H
52 # include <sys/wait.h>
53 #endif // HAVE_SYS_WAIT_H
55 #ifdef HAVE_ERRNO_H
56 # include <errno.h>
57 #endif // HAVE_ERRNO_H
59 #ifdef HAVE_UNISTD_H
60 # include <unistd.h>
61 #endif // HAVE_UNISTD_H
63 #ifdef HAVE_SYS_STAT_H
64 # include <sys/stat.h>
65 #endif // HAVE_SYS_STAT_H
67 #include <X11/Xlib.h>
68 #include <X11/Xproto.h>
69 #include <X11/keysym.h>
71 #include "bbkeys.hh"
72 #include "main.hh"
73 #include "Timer.hh"
74 #include "Basemenu.hh"
76 /*--------------------------------------------------------------------*/
78 /* Ripped shamelessly from wmaker's xmodifier.c--converted for our use*/
80 /*--------------------------------------------------------------------*/
82 /* Grok X modifier mappings for shortcuts.
84 Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
85 The copyright(s) from the original XEmacs code are included below.
87 Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */
89 /* The event_stream interface for X11 with Xt, and/or tty frames.
90 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
91 Copyright (C) 1995 Sun Microsystems, Inc.
92 Copyright (C) 1996 Ben Wing.
94 This file is part of XEmacs.
96 XEmacs is free software; you can redistribute it and/or modify it
97 under the terms of the GNU General Public License as published by the
98 Free Software Foundation; either version 2, or (at your option) any
99 later version.
101 XEmacs is distributed in the hope that it will be useful, but WITHOUT
102 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
103 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
104 for more details.
106 You should have received a copy of the GNU General Public License
107 along with XEmacs; see the file COPYING. If not, write to
108 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
109 Boston, MA 02111-1307, USA. */
111 /************************************************************************/
113 /* keymap handling */
115 /************************************************************************/
117 /* X bogusly doesn't define the interpretations of any bits besides
118 ModControl, ModShift, and ModLock; so the Interclient Communication
119 Conventions Manual says that we have to bend over backwards to figure
120 out what the other modifier bits mean. According to ICCCM:
122 - Any keycode which is assigned ModControl is a "control" key.
124 - Any modifier bit which is assigned to a keycode which generates Meta_L
125 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper,
126 etc.
128 - Any keypress event which contains ModControl in its state should be
129 interpreted as a "control" character.
131 - Any keypress event which contains a modifier bit in its state which is
132 generated by a keycode whose corresponding keysym is Meta_L or Meta_R
133 should be interpreted as a "meta" character. Likewise for Super, Hyper,
134 etc.
136 - It is illegal for a keysym to be associated with more than one modifier
137 bit.
139 This means that the only thing that emacs can reasonably interpret as a
140 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
141 one of the modifier bits Mod1-Mod5.
143 Unfortunately, many keyboards don't have Meta keys in their default
144 configuration. So, if there are no Meta keys, but there are "Alt" keys,
145 emacs will interpret Alt as Meta. If there are both Meta and Alt keys,
146 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
147 mean "Symbol," but that just confused the hell out of way too many people).
149 This works with the default configurations of the 19 keyboard-types I've
150 checked.
152 Emacs detects keyboard configurations which violate the above rules, and
153 prints an error message on the standard-error-output. (Perhaps it should
154 use a pop-up-window instead.)
157 static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
158 static int NumLockMask, ScrollLockMask;
160 char *ToolWindow::index_to_name(int indice)
162 switch (indice) {
163 case ShiftMapIndex:
164 return "ModShift";
165 case LockMapIndex:
166 return "ModLock";
167 case ControlMapIndex:
168 return "ModControl";
169 case Mod1MapIndex:
170 return "Mod1";
171 case Mod2MapIndex:
172 return "Mod2";
173 case Mod3MapIndex:
174 return "Mod3";
175 case Mod4MapIndex:
176 return "Mod4";
177 case Mod5MapIndex:
178 return "Mod5";
179 default:
180 return "???";
184 void ToolWindow::x_reset_modifier_mapping(Display * display)
186 int modifier_index, modifier_key, column, mkpm;
187 int warned_about_overlapping_modifiers = 0;
188 int warned_about_predefined_modifiers = 0;
189 int warned_about_duplicate_modifiers = 0;
190 int meta_bit = 0;
191 int hyper_bit = 0;
192 int super_bit = 0;
193 int alt_bit = 0;
194 int mode_bit = 0;
195 int num_lock_bit = 0;
196 int scroll_lock_bit = 0;
197 XModifierKeymap *x_modifier_keymap = XGetModifierMapping(display);
199 #define modwarn(name,old,other) \
200 warned_about_overlapping_modifiers = 1
202 #define modbarf(name,other) \
203 warned_about_predefined_modifiers = 1
205 #define check_modifier(name,mask) \
206 warned_about_predefined_modifiers = 1
208 #define store_modifier(name,old) \
209 if (old && old != modifier_index) \
210 warned_about_duplicate_modifiers = 1; \
211 if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift"); \
212 else if (modifier_index == LockMapIndex) modbarf (name,"ModLock"); \
213 else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
214 else if (sym == XK_Mode_switch) \
215 mode_bit = modifier_index; /* Mode_switch is special, see below... */ \
216 else if (modifier_index == meta_bit && old != meta_bit) \
217 modwarn (name, meta_bit, "Meta"); \
218 else if (modifier_index == super_bit && old != super_bit) \
219 modwarn (name, super_bit, "Super"); \
220 else if (modifier_index == hyper_bit && old != hyper_bit) \
221 modwarn (name, hyper_bit, "Hyper"); \
222 else if (modifier_index == alt_bit && old != alt_bit) \
223 modwarn (name, alt_bit, "Alt"); \
224 else \
225 old = modifier_index;
227 mkpm = x_modifier_keymap->max_keypermod;
228 for (modifier_index = 0; modifier_index < 8; modifier_index++)
229 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
230 KeySym last_sym = 0;
231 for (column = 0; column < 4; column += 2) {
232 KeyCode code =
233 x_modifier_keymap->modifiermap[modifier_index * mkpm +
234 modifier_key];
235 KeySym sym =
236 (code ? XKeycodeToKeysym(display, code, column) : 0);
237 if (sym == last_sym)
238 continue;
239 last_sym = sym;
240 switch (sym) {
241 case XK_Mode_switch:
242 store_modifier("Mode_switch", mode_bit);
243 break;
244 case XK_Meta_L:
245 store_modifier("Meta_L", meta_bit);
246 break;
247 case XK_Meta_R:
248 store_modifier("Meta_R", meta_bit);
249 break;
250 case XK_Super_L:
251 store_modifier("Super_L", super_bit);
252 break;
253 case XK_Super_R:
254 store_modifier("Super_R", super_bit);
255 break;
256 case XK_Hyper_L:
257 store_modifier("Hyper_L", hyper_bit);
258 break;
259 case XK_Hyper_R:
260 store_modifier("Hyper_R", hyper_bit);
261 break;
262 case XK_Alt_L:
263 store_modifier("Alt_L", alt_bit);
264 break;
265 case XK_Alt_R:
266 store_modifier("Alt_R", alt_bit);
267 break;
268 case XK_Num_Lock:
269 store_modifier("Num_Lock", num_lock_bit);
270 break;
271 case XK_Scroll_Lock:
272 store_modifier("Scroll_Lock", scroll_lock_bit);
273 break;
274 case XK_Control_L:
275 check_modifier("Control_L", ControlMask);
276 break;
277 case XK_Control_R:
278 check_modifier("Control_R", ControlMask);
279 break;
280 case XK_Shift_L:
281 check_modifier("Shift_L", ShiftMask);
282 break;
283 case XK_Shift_R:
284 check_modifier("Shift_R", ShiftMask);
285 break;
286 case XK_Shift_Lock:
287 check_modifier("Shift_Lock", LockMask);
288 break;
289 case XK_Caps_Lock:
290 check_modifier("Caps_Lock", LockMask);
291 break;
293 /* It probably doesn't make any sense for a modifier bit to be
294 assigned to a key that is not one of the above, but OpenWindows
295 assigns modifier bits to a couple of random function keys for
296 no reason that I can discern, so printing a warning here would
297 be annoying. */
301 #undef store_modifier
302 #undef check_modifier
303 #undef modwarn
304 #undef modbarf
306 /* If there was no Meta key, then try using the Alt key instead.
307 If there is both a Meta key and an Alt key, then the Alt key
308 is not disturbed and remains an Alt key. */
309 if (!meta_bit && alt_bit)
310 meta_bit = alt_bit, alt_bit = 0;
312 /* mode_bit overrides everything, since it's processed down inside of
313 XLookupString() instead of by us. If Meta and Mode_switch both
314 generate the same modifier bit (which is an error), then we don't
315 interpret that bit as Meta, because we can't make XLookupString()
316 not interpret it as Mode_switch; and interpreting it as both would
317 be totally wrong. */
318 if (mode_bit) {
319 const char *warn = 0;
320 if (mode_bit == meta_bit)
321 warn = "Meta", meta_bit = 0;
322 else if (mode_bit == hyper_bit)
323 warn = "Hyper", hyper_bit = 0;
324 else if (mode_bit == super_bit)
325 warn = "Super", super_bit = 0;
326 else if (mode_bit == alt_bit)
327 warn = "Alt", alt_bit = 0;
328 if (warn) {
329 warned_about_overlapping_modifiers = 1;
333 MetaMask = (meta_bit ? (1 << meta_bit) : 0);
334 HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
335 SuperMask = (super_bit ? (1 << super_bit) : 0);
336 AltMask = (alt_bit ? (1 << alt_bit) : 0);
337 ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
338 NumLockMask = (num_lock_bit ? (1 << num_lock_bit) : 0);
339 ScrollLockMask = (scroll_lock_bit ? (1 << scroll_lock_bit) : 0);
341 if (x_modifier_keymap)
342 XFreeModifiermap(x_modifier_keymap);
346 int ToolWindow::translateModifier(char *key)
348 if (strcasecmp(key, "SHIFT") == 0 && ShiftMask != 0)
349 return ShiftMask;
350 else if (strcasecmp(key, "CONTROL") == 0 && ControlMask != 0)
351 return ControlMask;
352 else if (strcasecmp(key, "ALT") == 0 && AltMask != 0)
353 return AltMask;
354 else if (strcasecmp(key, "META") == 0 && MetaMask != 0)
355 return MetaMask;
356 else if (strcasecmp(key, "SUPER") == 0 && SuperMask != 0)
357 return SuperMask;
358 else if (strcasecmp(key, "HYPER") == 0 && HyperMask != 0)
359 return HyperMask;
360 else if (strcasecmp(key, "MOD1") == 0 && Mod1Mask != 0)
361 return Mod1Mask;
362 else if (strcasecmp(key, "MOD2") == 0 && Mod2Mask != 0)
363 return Mod2Mask;
364 else if (strcasecmp(key, "MOD3") == 0 && Mod3Mask != 0)
365 return Mod3Mask;
366 else if (strcasecmp(key, "MOD4") == 0 && Mod4Mask != 0)
367 return Mod4Mask;
368 else if (strcasecmp(key, "MOD5") == 0 && Mod5Mask != 0)
369 return Mod5Mask;
370 else if (strcasecmp(key, "NONE") == 0)
371 return None;
372 else
373 return -1;
376 /* Wrapper so that we may fit our naming conventions, yet leave the
377 original XEmacs function name in place. */
378 void ToolWindow::InitializeModifiers(void)
380 x_reset_modifier_mapping(getXDisplay());
383 /*-----------------------------------------------------------------------*/
385 /*-- end of shameless rip. thank you for your support ---*/
387 /*-----------------------------------------------------------------------*/
389 void ToolWindow::CheckConfig()
391 struct stat file_status;
393 if (stat(bbkeys_rcfile, &file_status) != 0) {
394 #ifdef DEBUG
395 fprintf(stderr, "Could not open config file ->%s<-\n",
396 bbkeys_rcfile);
397 #endif
398 } else if (file_status.st_mtime != bbkeys_rcTime) {
399 bbkeys_rcTime = file_status.st_mtime;
400 loadKeygrabs();
401 activateKeygrabs();
405 void ToolWindow::activateKeygrabs(void)
407 int i = 0;
409 if (grabSet.instructCount > 0)
410 XUngrabKey(getXDisplay(), AnyKey, AnyModifier,
411 getScreenInfo(0)->getRootWindow());
412 for (i = 0; i < grabSet.instructCount; i++) {
413 if (grabSet.KeyMap[i].keycode == 0)
414 continue;
416 if (grabSet.KeyMap[i].keycode != AnyModifier) {
417 XGrabKey(getXDisplay(), grabSet.KeyMap[i].keycode,
418 grabSet.KeyMap[i].modMask | LockMask,
419 getCurrentScreenInfo()->getRootWindow(), True,
420 GrabModeAsync, GrabModeAsync);
422 /* Also grab all modifier combinations possible that include,
423 * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
424 * work even if the NumLock/ScrollLock key is on.
427 wHackedGrabKey(grabSet.KeyMap[i].keycode,
428 grabSet.KeyMap[i].modMask,
429 getCurrentScreenInfo()->getRootWindow(), True,
430 GrabModeAsync, GrabModeAsync);
433 XGrabKey(getXDisplay(), grabSet.KeyMap[i].keycode,
434 grabSet.KeyMap[i].modMask,
435 getCurrentScreenInfo()->getRootWindow(), True,
436 GrabModeAsync, GrabModeAsync);
440 /*---------------------------------------------------------------------------*/
442 /*-- Snarfed shamelessly from WindowMaker's code-base once again.... --*/
444 /*---------------------------------------------------------------------------*/
445 void ToolWindow::wHackedGrabKey(int keycode, unsigned int modifiers,
446 Window grab_window, Bool owner_events,
447 int pointer_mode, int keyboard_mode)
449 if (modifiers == AnyModifier)
450 return;
451 if (keycode == AnyKey)
452 return;
454 /* grab all combinations of the modifier with CapsLock, NumLock and
455 * ScrollLock. How much memory/CPU does such a monstrosity consume
456 * in the server?
458 if (_NumLockMask) {
459 XGrabKey(getXDisplay(), keycode, modifiers | _NumLockMask,
460 grab_window, owner_events, pointer_mode, keyboard_mode);
462 if (_ScrollLockMask) {
463 XGrabKey(getXDisplay(), keycode, modifiers | _ScrollLockMask,
464 grab_window, owner_events, pointer_mode, keyboard_mode);
466 if (_NumLockMask && _ScrollLockMask) {
467 XGrabKey(getXDisplay(), keycode,
468 modifiers | _NumLockMask | _ScrollLockMask, grab_window,
469 owner_events, pointer_mode, keyboard_mode);
471 if (_NumLockMask) {
472 XGrabKey(getXDisplay(), keycode,
473 modifiers | _NumLockMask | LockMask, grab_window,
474 owner_events, pointer_mode, keyboard_mode);
476 if (_ScrollLockMask) {
477 XGrabKey(getXDisplay(), keycode,
478 modifiers | _ScrollLockMask | LockMask, grab_window,
479 owner_events, pointer_mode, keyboard_mode);
481 if (_NumLockMask && _ScrollLockMask) {
482 XGrabKey(getXDisplay(), keycode,
483 modifiers | _NumLockMask | _ScrollLockMask | LockMask,
484 grab_window, owner_events, pointer_mode, keyboard_mode);
486 /* phew, I guess that's all, right? */
489 void ToolWindow::getOffendingModifiers(void)
491 int i;
492 XModifierKeymap *modmap;
493 KeyCode nlock, slock;
494 static int mask_table[8] = {
495 ShiftMask, LockMask, ControlMask, Mod1Mask,
496 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
499 nlock = XKeysymToKeycode(getXDisplay(), XK_Num_Lock);
500 slock = XKeysymToKeycode(getXDisplay(), XK_Scroll_Lock);
503 * Find out the masks for the NumLock and ScrollLock modifiers,
504 * so that we can bind the grabs for when they are enabled too.
506 modmap = XGetModifierMapping(getXDisplay());
508 if (modmap != NULL && modmap->max_keypermod > 0) {
509 for (i = 0; i < 8 * modmap->max_keypermod; i++) {
510 if (modmap->modifiermap[i] == nlock && nlock != 0)
511 _NumLockMask = mask_table[i / modmap->max_keypermod];
512 else if (modmap->modifiermap[i] == slock && slock != 0)
513 _ScrollLockMask = mask_table[i / modmap->max_keypermod];
517 if (modmap)
518 XFreeModifiermap(modmap);
521 /*-------------------------------------------------------------------------*/
523 /*-- End of shameful code-snarf..................................... --*/
525 /*-------------------------------------------------------------------------*/
527 int ToolWindow::translateAction(char *action)
529 if (!action)
530 return 0;
532 if (!strcasecmp(action, "Minimize"))
533 return grabIconify;
534 if (!strcasecmp(action, "Raise"))
535 return grabRaise;
536 if (!strcasecmp(action, "Lower"))
537 return grabLower;
538 if (!strcasecmp(action, "Close"))
539 return grabClose;
540 if (!strcasecmp(action, "Workspace1"))
541 return grabWorkspace1;
542 if (!strcasecmp(action, "Workspace2"))
543 return grabWorkspace2;
544 if (!strcasecmp(action, "Workspace3"))
545 return grabWorkspace3;
546 if (!strcasecmp(action, "Workspace4"))
547 return grabWorkspace4;
548 if (!strcasecmp(action, "Workspace5"))
549 return grabWorkspace5;
550 if (!strcasecmp(action, "Workspace6"))
551 return grabWorkspace6;
552 if (!strcasecmp(action, "Workspace7"))
553 return grabWorkspace7;
554 if (!strcasecmp(action, "Workspace8"))
555 return grabWorkspace8;
556 if (!strcasecmp(action, "Workspace9"))
557 return grabWorkspace9;
558 if (!strcasecmp(action, "Workspace10"))
559 return grabWorkspace10;
560 if (!strcasecmp(action, "Workspace11"))
561 return grabWorkspace11;
562 if (!strcasecmp(action, "Workspace12"))
563 return grabWorkspace12;
564 if (!strcasecmp(action, "NextWorkspace"))
565 return grabNextWorkspace;
566 if (!strcasecmp(action, "PrevWorkspace"))
567 return grabPrevWorkspace;
568 if (!strcasecmp(action, "UpWorkspace"))
569 return grabUpWorkspace;
570 if (!strcasecmp(action, "DownWorkspace"))
571 return grabDownWorkspace;
572 if (!strcasecmp(action, "LeftWorkspace"))
573 return grabLeftWorkspace;
574 if (!strcasecmp(action, "RightWorkspace"))
575 return grabRightWorkspace;
576 if (!strcasecmp(action, "NextWindow"))
577 return grabNextWindow;
578 if (!strcasecmp(action, "PrevWindow"))
579 return grabPrevWindow;
580 if (!strcasecmp(action, "NextWindowAllWorkspaces"))
581 return grabNextWindowAllWorkspaces;
582 if (!strcasecmp(action, "ShadeWindow"))
583 return grabShade;
584 if (!strcasecmp(action, "MaximizeWindow"))
585 return grabMaximize;
586 if (!strcasecmp(action, "StickWindow"))
587 return grabStick;
588 if (!strcasecmp(action, "ExecCommand"))
589 return grabExecute;
590 if (!strcasecmp(action, "MaximizeVertical"))
591 return grabVertMax;
592 if (!strcasecmp(action, "MaximizeHorizontal"))
593 return grabHorizMax;
594 if (!strcasecmp(action, "NudgeRight"))
595 return grabNudgeRight;
596 if (!strcasecmp(action, "NudgeLeft"))
597 return grabNudgeLeft;
598 if (!strcasecmp(action, "NudgeUp"))
599 return grabNudgeUp;
600 if (!strcasecmp(action, "NudgeDown"))
601 return grabNudgeDown;
602 if (!strcasecmp(action, "BigNudgeRight"))
603 return grabBigNudgeRight;
604 if (!strcasecmp(action, "BigNudgeLeft"))
605 return grabBigNudgeLeft;
606 if (!strcasecmp(action, "BigNudgeUp"))
607 return grabBigNudgeUp;
608 if (!strcasecmp(action, "BigNudgeDown"))
609 return grabBigNudgeDown;
610 if (!strcasecmp(action, "HorizontalIncrement"))
611 return grabHorizInc;
612 if (!strcasecmp(action, "VerticalIncrement"))
613 return grabVertInc;
614 if (!strcasecmp(action, "HorizontalDecrement"))
615 return grabHorizDec;
616 if (!strcasecmp(action, "VerticalDecrement"))
617 return grabVertDec;
618 if (!strcasecmp(action, "ToggleDecor"))
619 return grabToggleDecor;
622 return 0;
625 void ToolWindow::execCommand(char *ptrCommand)
627 int pid;
628 extern char **environ;
630 pid = fork();
631 if (pid == -1) {
632 fprintf(stderr,
633 "bbkeys: Could not fork a process for execCommand.\n");
634 return;
637 if (pid == 0) {
638 char *argv[4];
639 argv[0] = "sh";
640 argv[1] = "-c";
641 argv[2] = ptrCommand;
642 argv[3] = 0;
643 execve("/bin/sh", argv, environ);
644 exit(127);
648 void ToolWindow::setKeygrabs(void)
650 int res, pid;
652 pid = fork();
653 if (pid == -1) {
654 fprintf(stderr,
655 "bbkeys: Could not fork a process for configurator.\n");
656 return;
659 if (pid == 0) {
660 if (noQt) {
661 // Make 'bbconf' automagically fail...
662 res = 1;
663 } else {
664 char *begin="keybindings:loadfile=";
665 char *args = new char[strlen(begin) + strlen(bbkeys_rcfile) +1];
666 sprintf(args, "%s%s", begin, bbkeys_rcfile);
668 res = execlp("bbconf", "bbconf", "--start-plugin", "key bindings",
669 "--args", args, NULL);
671 delete args;
674 if (res != 0) {
675 char *begin="bbkeysconf.pl -rcfile ";
676 char *args = new char[strlen(begin) + strlen(bbkeys_rcfile) +1];
677 sprintf(args, "%s%s", begin, bbkeys_rcfile);
678 res = execlp("rxvt", "rxvt", "-bg", "black", "-fg", "red",
679 "-e", args, NULL);
680 if (res != 0) {
681 execlp("xterm", "xterm", "-bg", "black", "-fg",
682 "red", "-e", args, NULL);
684 delete args;
686 exit(0);
690 do {
691 if (waitpid(pid, &status, 0) == -1) {
692 if (errno != EINTR)
693 return;
694 } else
695 return;
696 } while (1);
701 void ToolWindow::loadKeygrabs(void)
703 // free up pointers that we get with strdup for execCommand....
704 for (register int i = 0; i < grabSet.instructCount; i++) {
705 if (grabSet.KeyMap[i].execCommand != NULL) {
706 free(grabSet.KeyMap[i].execCommand);
709 memset(&actionList, 0, sizeof(actionList));
711 /* re-initialize our grabSet count... */
712 grabSet.instructCount = 0;
714 int count = 0;
715 char line[1024];
716 char Keytograb[80];
717 char Modifier[80];
718 char action[80];
719 char execCommand[500];
720 char *KeytograbBegin;
721 char *ModifierBegin;
722 char *actionBegin;
723 char *execCmdBegin;
725 FILE *rc_file = fopen(bbkeys_rcfile, "r");
726 if (!rc_file) {
727 fprintf(stderr, "\nDanger!!! Warning Will Robinson!!!\n"
728 "I can't open your bbkeys rc-file (%s).\n"
729 "Hmm. That means I don't have anything to do. Please run \n"
730 "the bbkeys configurator of your choice (click my keyhole) \n"
731 "to allow me to do stuff for ya. \n"
732 "'Cause otherwise, I just sit here feeling sad....\n\n"
733 , bbkeys_rcfile);
734 return;
737 memset(line, '\0', 1024);
739 while (fgets(line, 1024, rc_file) && !feof(rc_file) &&
740 count < MaxInstructions) {
741 if (line[0] != '#' && strstr(line, "WithModifier")) {
743 memset(Keytograb, '\0', 80);
744 memset(Modifier, '\0', 80);
745 memset(action, '\0', 80);
746 memset(execCommand, '\0', 500);
748 KeytograbBegin = strchr(line, '(');
749 ModifierBegin = strchr(KeytograbBegin + 1, '(');
750 actionBegin = strchr(ModifierBegin + 1, '(');
752 strncat(Keytograb, KeytograbBegin + 1,
753 strcspn(KeytograbBegin + 1, ")"));
754 strncpy(Modifier, ModifierBegin + 1,
755 strcspn(ModifierBegin + 1, ")"));
756 strncpy(action, actionBegin + 1,
757 strcspn(actionBegin + 1, ")"));
759 grabSet.KeyMap[count].keycode = XKeysymToKeycode(getXDisplay(),
760 XStringToKeysym
761 (Keytograb));
763 char *k;
764 char *tmp = (char *) Modifier;
765 grabSet.KeyMap[count].modMask = 0;
766 while ((k = strchr(tmp, '+')) != NULL) {
767 *k = 0;
768 grabSet.KeyMap[count].modMask |= translateModifier(tmp);
769 tmp = k + 1;
771 grabSet.KeyMap[count].modMask |= translateModifier(tmp);
773 grabSet.KeyMap[count].action = translateAction(action);
774 // save off a cross-reference for action->grabSet.KeyMap[index]
775 actionList[grabSet.KeyMap[count].action] = count;
777 /* if we're supposed to having an execCommand and we do have
778 * something to put into it */
779 if (grabSet.KeyMap[count].action == grabExecute) {
780 execCmdBegin = strchr(actionBegin + 1, '(');
781 if (execCmdBegin) {
782 strncpy(execCommand, execCmdBegin + 1,
783 strcspn(execCmdBegin + 1, ")"));
784 grabSet.KeyMap[count].execCommand =
785 strdup(execCommand);
787 } else {
788 grabSet.KeyMap[count].execCommand = NULL;
791 #ifdef DEBUG
792 fprintf(stdout, "Keysym ->%d<-, Modifier ->0x%lx<-, "
793 "action ->%d<-, execCommand ->%s<-\n",
794 grabSet.KeyMap[count].keycode,
795 grabSet.KeyMap[count].modMask,
796 grabSet.KeyMap[count].action,
797 grabSet.KeyMap[count].execCommand);
798 #endif
799 count++;
803 fclose(rc_file);
804 grabSet.instructCount = count;
805 #ifdef DEBUG
806 fprintf(stderr, "loaded ->%d<- instructions.\n", count);
807 #endif
810 /*****************************************
812 * END OF KEY GRABBING/HANDLING ROUTINES *
814 *****************************************/
816 ToolWindow::ToolWindow(int argc, char **argv, struct CMDOPTIONS *options):
817 Basewindow(argc, argv, options), TimeoutHandler()
819 timer = new BTimer(this, this);
820 timer->setTimeout(100);
821 timer->fireOnce(True);
823 if (!(options->bbkeysrc)){
824 char *homedir = getenv("HOME");
825 bbkeys_rcfile = new char[strlen(homedir) + 32];
826 sprintf(bbkeys_rcfile, "%s/.bbkeysrc", homedir);
827 } else {
828 bbkeys_rcfile = options->bbkeysrc;
831 XrmInitialize();
833 InitializeModifiers();
835 _NumLockMask = 0;
836 _ScrollLockMask = 0;
839 * Ignore CapsLock in modifiers
841 ValidModMask = 0xff & ~LockMask;
843 getOffendingModifiers();
845 * Ignore NumLock and ScrollLock too
847 ValidModMask &= ~(_NumLockMask | _ScrollLockMask);
849 // initialize it so we don't run into problems later
850 grabSet.instructCount = 0;
851 loadKeygrabs();
852 activateKeygrabs();
854 resource = new Resource(this);
855 wminterface = new WMInterface(this);
856 windowList = new LinkedList < WindowList >;
857 desktopList = new LinkedList < DesktopList >;
859 // initialize variables
860 current_desktop = NULL;
861 desktop_count = 0;
862 doingCycling = False;
864 // make draw the bbkeys window
865 MakeWindow(False);
866 Redraw();
868 // pass control to the main loop
869 eventLoop();
872 ToolWindow::~ToolWindow()
874 XUnmapWindow(getXDisplay(), win_frame);
876 /* destroy pixmaps */
877 if (pixmap.frame)
878 getImageControl()->removeImage(pixmap.frame);
879 if (pixmap.pix_title)
880 getImageControl()->removeImage(pixmap.pix_title);
881 if (pixmap.pix_back)
882 getImageControl()->removeImage(pixmap.pix_back);
883 if (pixmap.pix_configBtn)
884 getImageControl()->removeImage(pixmap.pix_configBtn);
885 if (pixmap.pix_closeBtn)
886 getImageControl()->removeImage(pixmap.pix_closeBtn);
887 if (pixmap.pix_pressedBtn)
888 getImageControl()->removeImage(pixmap.pix_pressedBtn);
890 /* destroy windows */
891 XDestroyWindow(getXDisplay(), win_frame);
892 XDestroyWindow(getXDisplay(), win_back);
893 XDestroyWindow(getXDisplay(), win_title);
894 XDestroyWindow(getXDisplay(), win_configBtn);
895 XDestroyWindow(getXDisplay(), win_closeBtn);
897 /* destroy GC's */
898 if (frameGC) XFreeGC(getXDisplay(),frameGC);
899 if (menuGC) XFreeGC(getXDisplay(),menuGC);
900 if (menuHiBGGC) XFreeGC(getXDisplay(),menuHiBGGC);
901 if (menuHiGC) XFreeGC(getXDisplay(),menuHiGC);
902 if (menuFrameGC) XFreeGC(getXDisplay(),menuFrameGC);
905 /* destroy lists */
906 delete windowList;
907 delete desktopList;
910 void ToolWindow::reconfigure(void)
912 /* destroy pixmaps */
913 if (pixmap.frame)
914 getImageControl()->removeImage(pixmap.frame);
915 if (pixmap.pix_title)
916 getImageControl()->removeImage(pixmap.pix_title);
917 if (pixmap.pix_back)
918 getImageControl()->removeImage(pixmap.pix_back);
919 if (pixmap.pix_configBtn)
920 getImageControl()->removeImage(pixmap.pix_configBtn);
921 if (pixmap.pix_closeBtn)
922 getImageControl()->removeImage(pixmap.pix_closeBtn);
923 if (pixmap.pix_pressedBtn)
924 getImageControl()->removeImage(pixmap.pix_pressedBtn);
926 resource->Reload();
927 MakeWindow(True);
929 stackMenu->reconfigure();
931 XClearWindow(getXDisplay(), win_frame);
932 XClearWindow(getXDisplay(), win_back);
933 Redraw();
936 void ToolWindow::MakeWindow(bool reconfigure)
938 XSetWindowAttributes attrib;
939 XWMHints wmhints;
940 XClassHint classhints;
941 XTextProperty windowname;
943 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
944 CWOverrideRedirect | CWCursor | CWEventMask;
946 // geometry for our windows...................................
948 geom_title.height = resource->label.font->ascent +
949 resource->label.font->descent + 2;
950 if (geom_title.height < 20 && (miniMe || tinyMe))
951 geom_title.height = 20;
952 geom_title.width = XTextWidth(resource->label.font, "bbkeys",
953 strlen("bbkeys")) + (geom_title.height +
955 geom_title.x = 2;
956 geom_title.y = 2;
957 geom_back.width = geom_title.width + 4;
958 geom_back.x = 0;
959 geom_back.y = 0;
960 geom_closeBtn.height = geom_title.height * 7 / 10;
961 geom_closeBtn.width = geom_closeBtn.height;
963 if (miniMe) {
965 geom_back.height = geom_title.height + 2;
966 geom_closeBtn.y = 80; /* put it out of sight. */
967 geom_closeBtn.x = 80;
968 geom_configBtn.height = geom_title.height - 1;
969 geom_configBtn.width = geom_configBtn.height;
970 geom_configBtn.x = geom_title.width - geom_configBtn.width;
971 geom_configBtn.y = geom_title.y;
973 } else if (tinyMe) {
975 geom_title.height = 22;
976 geom_title.width = 22;
977 geom_title.x = 80;
978 geom_title.y = 80;
979 geom_back.width = 22;
980 geom_back.height = 22;
981 geom_closeBtn.y = 80; /* put it out of sight. */
982 geom_closeBtn.x = 80;
983 geom_configBtn.height = 20;
984 geom_configBtn.width = geom_configBtn.height;
985 geom_configBtn.x = 1;
986 geom_configBtn.y = 1;
988 } else {
990 geom_back.height = 3 * (geom_title.height) + 6;
991 geom_closeBtn.x = geom_title.width - geom_closeBtn.width - 1;
992 geom_closeBtn.y = geom_title.y +
993 ((geom_title.height - geom_closeBtn.height) / 2);
994 geom_configBtn.height = (geom_title.height * 2);
995 geom_configBtn.width = geom_title.width - 4;
996 geom_configBtn.x = geom_title.x + 2;
997 geom_configBtn.y = geom_title.height + geom_title.y + 2;
1001 frame.height = geom_back.height;
1002 frame.width = geom_back.width;
1003 frame.x = resource->position.x;
1004 frame.y = resource->position.y;
1006 // end geometry for our windows...................................
1008 if (resource->position.mask & XNegative) {
1009 frame.x = getCurrentScreenInfo()->getWidth() +
1010 resource->position.x - frame.width;
1013 if (resource->position.mask & YNegative) {
1014 frame.y = getCurrentScreenInfo()->getHeight() +
1015 resource->position.y - frame.height;
1019 if (withdrawn) {
1020 attrib.override_redirect = False;
1021 wmhints.initial_state = WithdrawnState;
1022 } else if (iconic) {
1023 attrib.override_redirect = False;
1024 wmhints.initial_state = IconicState;
1025 } else {
1026 attrib.override_redirect = False;
1027 wmhints.initial_state = NormalState;
1030 attrib.background_pixmap = ParentRelative;
1032 pixmap.frame =
1033 getImageControl()->renderImage(frame.width, frame.height,
1034 &resource->frame.texture);
1036 pixmap.pix_back =
1037 getImageControl()->renderImage(geom_back.width,
1038 geom_back.height,
1039 &resource->frame.texture);
1040 pixmap.pix_title =
1041 getImageControl()->renderImage(geom_title.width, geom_title.height,
1042 &resource->label.texture);
1044 pixmap.pix_configBtn =
1045 getImageControl()->renderImage(geom_configBtn.width,
1046 geom_configBtn.height,
1047 &resource->button.texture);
1049 pixmap.pix_closeBtn =
1050 getImageControl()->renderImage(geom_closeBtn.width,
1051 geom_closeBtn.height,
1052 &resource->button.texture);
1053 pixmap.pix_pressedBtn =
1054 getImageControl()->renderImage(geom_configBtn.width,
1055 geom_configBtn.height,
1056 &resource->button.texture_pressed);
1058 attrib.cursor = getSessionCursor();
1059 attrib.event_mask =
1060 ButtonPressMask | ButtonReleaseMask | ExposureMask |
1061 FocusChangeMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask |
1062 SubstructureRedirectMask;
1064 if (!reconfigure) {
1065 win_frame = XCreateWindow(getXDisplay(),
1066 getCurrentScreenInfo()->getRootWindow(),
1067 frame.x, frame.y, frame.width,
1068 frame.height, 0,
1069 getCurrentScreenInfo()->getDepth(),
1070 InputOutput,
1071 getCurrentScreenInfo()->getVisual(),
1072 create_mask, &attrib);
1073 win_back = XCreateWindow(getXDisplay(),
1074 win_frame,
1075 geom_back.x,
1076 geom_back.y,
1077 geom_back.width,
1078 geom_back.height, 0,
1079 getCurrentScreenInfo
1080 ()->getDepth(), InputOutput,
1081 getCurrentScreenInfo
1082 ()->getVisual(), create_mask, &attrib);
1083 win_title =
1084 XCreateWindow(getXDisplay(), win_frame, geom_title.x,
1085 geom_title.y, geom_title.width,
1086 geom_title.height, 0,
1087 getCurrentScreenInfo()->getDepth(), InputOutput,
1088 getCurrentScreenInfo()->getVisual(), create_mask,
1089 &attrib);
1090 win_configBtn =
1091 XCreateWindow(getXDisplay(), win_frame, geom_configBtn.x,
1092 geom_configBtn.y, geom_configBtn.width,
1093 geom_configBtn.height, 0,
1094 getCurrentScreenInfo()->getDepth(), InputOutput,
1095 getCurrentScreenInfo()->getVisual(), create_mask,
1096 &attrib);
1097 win_closeBtn =
1098 XCreateWindow(getXDisplay(), win_frame, geom_closeBtn.x,
1099 geom_closeBtn.y, geom_closeBtn.width,
1100 geom_closeBtn.height, 0,
1101 getCurrentScreenInfo()->getDepth(), InputOutput,
1102 getCurrentScreenInfo()->getVisual(), create_mask,
1103 &attrib);
1104 } else if (!withdrawn) {
1105 XMoveResizeWindow(getXDisplay(), win_frame, frame.x, frame.y,
1106 frame.width, frame.height);
1107 XMoveResizeWindow(getXDisplay(), win_back,
1108 geom_back.x, geom_back.y,
1109 geom_back.width, geom_back.height);
1110 XMoveResizeWindow(getXDisplay(), win_title, geom_title.x,
1111 geom_title.y, geom_title.width,
1112 geom_title.height);
1113 XMoveResizeWindow(getXDisplay(), win_configBtn, geom_configBtn.x,
1114 geom_configBtn.y, geom_configBtn.width,
1115 geom_configBtn.height);
1116 XMoveResizeWindow(getXDisplay(), win_closeBtn, geom_closeBtn.x,
1117 geom_closeBtn.y, geom_closeBtn.width,
1118 geom_closeBtn.height);
1120 } else {
1121 XResizeWindow(getXDisplay(), win_frame, frame.width, frame.height);
1122 XResizeWindow(getXDisplay(), win_back,
1123 geom_back.width, geom_back.height);
1124 XResizeWindow(getXDisplay(), win_title, geom_title.width,
1125 geom_title.height);
1126 XMoveResizeWindow(getXDisplay(), win_configBtn, geom_configBtn.x,
1127 geom_configBtn.y, geom_configBtn.width,
1128 geom_configBtn.height);
1129 XMoveResizeWindow(getXDisplay(), win_closeBtn, geom_closeBtn.x,
1130 geom_closeBtn.y, geom_closeBtn.width,
1131 geom_closeBtn.height);
1134 char *name = BBTOOL;
1135 XSizeHints sizehints;
1137 wmhints.flags = StateHint;
1139 classhints.res_name = BBTOOL;
1140 classhints.res_class = "bbtools";
1142 sizehints.x = frame.x; //getResource()->position.x;
1143 sizehints.y = frame.y; //getResource()->position.y;
1145 sizehints.max_width = sizehints.min_width = frame.width;
1146 sizehints.max_height = sizehints.min_height = frame.height;
1147 sizehints.flags = USPosition | PMinSize | PMaxSize;
1149 XStringListToTextProperty(&name, 1, &windowname);
1150 XSetWMProperties(getXDisplay(), win_frame, &windowname, NULL, getArgv(),
1151 getArgc(), &sizehints, &wmhints, &classhints);
1153 // free up allocated memory in XStringListToTextProperty
1154 XFree(windowname.value);
1156 if (!reconfigure) {
1157 Atom wmproto[2];
1158 wmproto[0] = wm_delete_window;
1159 wmproto[1] = getBlackboxStructureMessagesAtom();
1160 XSetWMProtocols(getXDisplay(), win_frame, wmproto, 2);
1163 if (!decorated && !withdrawn) {
1164 BlackboxHints net_hints;
1165 net_hints.decoration = DecorNone;
1166 net_hints.attrib = AttribOmnipresent;
1167 net_hints.flags = AttribDecoration | AttribOmnipresent;
1168 XChangeProperty(getXDisplay(), win_frame, getBlackboxHintsAtom(),
1169 getBlackboxHintsAtom(), 32, PropModeReplace,
1170 (unsigned char *) &net_hints,
1171 PropBlackboxHintsElements);
1174 if (!shape) {
1175 XSetWindowBackgroundPixmap(getXDisplay(), win_frame, pixmap.frame);
1178 XSetWindowBackgroundPixmap(getXDisplay(), win_title, pixmap.pix_title);
1179 XSetWindowBackgroundPixmap(getXDisplay(), win_back, pixmap.pix_back);
1180 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1181 pixmap.pix_configBtn);
1182 XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
1183 pixmap.pix_closeBtn);
1186 if (!reconfigure) {
1187 gcv.font = resource->label.font->fid;
1188 gcv.foreground = resource->label.textColor.getPixel();
1189 frameGC =
1190 XCreateGC(getXDisplay(), win_frame, GCFont | GCForeground, &gcv);
1192 gcv.font = resource->menu.font->fid;
1193 gcv.foreground = resource->menu.texture.getColor()->getPixel();
1194 menuGC = XCreateGC(getXDisplay(), win_frame,GCFont|GCForeground, &gcv);
1196 gcv.foreground = resource->menu.highlightColor.getPixel();
1197 gcv.arc_mode = ArcChord;
1198 gcv.fill_style = FillSolid;
1199 menuHiBGGC = XCreateGC(getXDisplay(), win_frame,GCForeground|
1200 GCFillStyle|GCArcMode, &gcv);
1202 gcv.foreground = resource->menu.hiTextColor.getPixel();
1203 menuHiGC = XCreateGC(getXDisplay(), win_frame, GCFont|GCForeground, &gcv);
1205 gcv.foreground = resource->menu.textColor.getPixel();
1206 menuFrameGC = XCreateGC(getXDisplay(), win_frame,GCFont|GCForeground, &gcv);
1208 stackMenu = new Stackmenu(this);
1209 stackMenu->update();
1210 } else {
1211 gcv.font = resource->label.font->fid;
1212 gcv.foreground = resource->label.textColor.getPixel();
1213 XChangeGC(getXDisplay(), frameGC, GCFont | GCForeground, &gcv);
1215 gcv.font = resource->menu.font->fid;
1216 gcv.foreground = resource->menu.texture.getColor()->getPixel();
1217 XChangeGC(getXDisplay(), menuGC, GCFont | GCForeground, &gcv);
1219 gcv.foreground = resource->menu.highlightColor.getPixel();
1220 XChangeGC(getXDisplay(), menuHiBGGC, GCFont | GCForeground, &gcv);
1222 gcv.foreground = resource->menu.hiTextColor.getPixel();
1223 XChangeGC(getXDisplay(), menuHiGC, GCFont | GCForeground, &gcv);
1225 gcv.foreground = resource->menu.textColor.getPixel();
1226 XChangeGC(getXDisplay(), menuFrameGC, GCFont | GCForeground, &gcv);
1231 if (!reconfigure) {
1232 XClearWindow(getXDisplay(), win_frame);
1233 XMapWindow(getXDisplay(), win_frame);
1234 XMapSubwindows(getXDisplay(), win_frame);
1235 XSetIconName(getXDisplay(), win_frame, "bbkeys");
1239 void ToolWindow::Redraw()
1241 XClearWindow(getXDisplay(), win_title);
1242 XClearWindow(getXDisplay(), win_configBtn);
1243 XClearWindow(getXDisplay(), win_closeBtn);
1245 char *title = "bbkeys";
1246 XDrawString(getXDisplay(), win_title, frameGC, geom_title.x - 1,
1247 (geom_title.height + resource->label.font->ascent -
1248 resource->label.font->descent) / 2, title, strlen(title));
1250 XPoint pts[3];
1252 if (miniMe || tinyMe) {
1253 pts[0].x = (geom_configBtn.width / 2);
1254 pts[0].y = (geom_configBtn.height / 2) - 2;
1255 pts[1].x = -(geom_configBtn.width / 4);
1256 pts[1].y = (geom_configBtn.height - pts[0].y) - 1;
1257 pts[2].x = (geom_configBtn.width / 2);
1258 pts[2].y = 0;
1260 XFillPolygon(getXDisplay(), win_configBtn, frameGC, pts, 3,
1261 Convex, CoordModePrevious);
1262 XFillArc(getXDisplay(), win_configBtn, frameGC,
1263 geom_configBtn.width / 2 - geom_configBtn.width / 4, 1, // x, y
1264 geom_configBtn.width / 2, geom_configBtn.height / 2, //width,height
1265 0, 360 * 64);
1266 } else {
1267 pts[0].x = (geom_configBtn.width / 2);
1268 pts[0].y = (geom_configBtn.height / 2) - 2;
1269 pts[1].x = -(geom_configBtn.width / 4);
1270 pts[1].y = (geom_configBtn.height - pts[0].y) - 2;
1271 pts[2].x = (geom_configBtn.width / 2);
1272 pts[2].y = 0;
1274 XFillPolygon(getXDisplay(), win_configBtn, frameGC, pts, 3,
1275 Convex, CoordModePrevious);
1276 XFillArc(getXDisplay(), win_configBtn, frameGC,
1277 geom_configBtn.width / 2 - geom_configBtn.width / 4, 1, // x, y
1278 geom_configBtn.width / 2, geom_configBtn.height * 5 / 8, //width,height
1279 0, 360 * 64);
1282 /* Our little close button (drawn twice for a nice thickness) */
1283 XDrawLine(getXDisplay(), win_closeBtn, frameGC, 1, 1,
1284 geom_closeBtn.width - 2, geom_closeBtn.height - 1);
1285 XDrawLine(getXDisplay(), win_closeBtn, frameGC, 1,
1286 geom_closeBtn.height - 1, geom_closeBtn.width - 2, 1);
1288 XDrawLine(getXDisplay(), win_closeBtn, frameGC, 2, 1,
1289 geom_closeBtn.width - 1, geom_closeBtn.height - 1);
1290 XDrawLine(getXDisplay(), win_closeBtn, frameGC, 2,
1291 geom_closeBtn.height - 1, geom_closeBtn.width - 1, 1);
1295 unsigned int ToolWindow::KeycodeToModmask(unsigned int code)
1297 switch (XKeycodeToKeysym(getXDisplay(), code, 0)) {
1298 case XK_Shift_L:
1299 case XK_Shift_R:
1300 return ShiftMask;
1302 case XK_Caps_Lock:
1303 case XK_Shift_Lock:
1304 return LockMask;
1306 case XK_Control_L:
1307 case XK_Control_R:
1308 return ControlMask;
1310 case XK_Alt_L:
1311 case XK_Alt_R:
1312 return AltMask ? AltMask : MetaMask;
1314 case XK_Num_Lock:
1315 return NumLockMask;
1317 case XK_Super_L:
1318 case XK_Super_R:
1319 return SuperMask;
1321 case XK_Hyper_L:
1322 case XK_Hyper_R:
1323 return HyperMask;
1325 case XK_Meta_L:
1326 case XK_Meta_R:
1327 return MetaMask;
1329 case XK_Scroll_Lock:
1330 return ScrollLockMask;
1332 return (unsigned int)-1;
1335 void ToolWindow::process_event(XEvent * e)
1337 switch (e->type) {
1338 case PropertyNotify:
1339 windowAttributeChange(e->xproperty.window);
1340 break;
1342 case VisibilityNotify:
1343 // **** This will need to change to a better method of keeping the **** //
1344 // **** menu on top when blackbox provides another way! **** //
1345 if (e->xvisibility.window == stackMenu->getWindowID())
1346 if (e->xvisibility.state != VisibilityUnobscured)
1347 XRaiseWindow(getXDisplay(), stackMenu->getWindowID());
1348 break;
1350 case KeyRelease: {
1351 // if stacked cycling is going on..
1352 if (doingCycling) {
1353 unsigned int mask = KeycodeToModmask(e->xkey.keycode);
1354 unsigned int state = e->xkey.state;
1356 // get the index for grabSet.KeyMay's prev/next entries, but make
1357 // sure we're not just getting 0 because we don't have keybindings
1358 // for one of them--also, we can't use > 0 as a test for next/prev
1359 // because 0 might very well be the valid index for those bindings
1360 int i = actionList[grabNextWindow];
1361 int next = grabSet.KeyMap[i].action == grabNextWindow ? i : -1;
1362 int j = actionList[grabNextWindowAllWorkspaces];
1363 int nextAll = grabSet.KeyMap[j].action == grabNextWindowAllWorkspaces ? j : -1;
1364 int k = actionList[grabPrevWindow];
1365 int prev = grabSet.KeyMap[k].action == grabPrevWindow ? k : -1;
1367 // if the key released was the last modifier being held
1368 // and being a member of the nextMask or PrevMask, then select
1369 // the item in the menu that is currently focued.
1370 if (next > -1 && ((state & grabSet.KeyMap[next].modMask) == mask))
1371 stackMenu->selectFocused(True);
1372 else if (nextAll > -1 && ((state & grabSet.KeyMap[nextAll].modMask) == mask))
1373 stackMenu->selectFocused(True);
1374 else if (prev > -1 && ((state & grabSet.KeyMap[prev].modMask) == mask))
1375 stackMenu->selectFocused(True);
1377 break;
1380 case KeyPress: {
1382 int i = 0;
1383 int grabInt = -1;
1384 Window fw_root, fw_child;
1385 int fw_y, fw_x;
1386 unsigned int fw_w, fw_h, fw_b, fw_d;
1388 /* Need to take out this next bit when nyz has 0.60.0 ready, as
1389 we'll then get our focus_window in a ClientMessage */
1390 int revert_to = RevertToPointerRoot;
1391 if (!focus_window) {
1392 XGetInputFocus(getXDisplay(), &focus_window, &revert_to);
1395 /* end temporary focus_window fix */
1397 if (focus_window && focus_window != (int)PointerRoot ) {
1398 XGetGeometry(getXDisplay(), focus_window, &fw_root, &fw_x,
1399 &fw_y, &fw_w, &fw_h, &fw_b, &fw_d);
1400 XTranslateCoordinates(getXDisplay(), focus_window, fw_root,
1401 fw_x, fw_y, &fw_x, &fw_y, &fw_child);
1404 // if our user wants to grab his keystrokes, even though one
1405 // or more of the Lock-Modifiers are pressed, alter the mask
1408 // to make this possible....
1410 if (!honor_modifiers) {
1411 e->xkey.state &= ~_NumLockMask & ~_ScrollLockMask & ~LockMask;
1414 for (i = 0; i < grabSet.instructCount; i++) {
1415 if ((e->xkey.keycode == grabSet.KeyMap[i].keycode) &&
1416 (e->xkey.state == grabSet.KeyMap[i].modMask)) {
1417 grabInt = i;
1418 break;
1422 if (doingCycling) {
1423 if (e->xkey.keycode == XKeysymToKeycode(getXDisplay(), XK_Escape)) {
1424 stackMenu->hide();
1425 // reset focus to the window we were focused on before window
1426 // cycling began
1427 wminterface->setWindowFocus(focus_window);
1428 } else if (e->xkey.keycode == XKeysymToKeycode(getXDisplay(), XK_Return))
1429 stackMenu->selectFocused(True);
1430 else
1431 stackMenu->key_press(grabSet.KeyMap[grabInt].action);
1432 } else if (grabInt > -1) {
1434 /* play with colors for nyz =:) */
1435 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1436 pixmap.pix_pressedBtn);
1437 Redraw();
1439 switch (grabSet.KeyMap[grabInt].action) {
1440 case grabIconify:
1441 if (focus_window && focus_window != (int)PointerRoot ) {
1442 XIconifyWindow(getXDisplay(), focus_window, 0);
1444 break;
1446 case grabRaise:
1447 if (focus_window && focus_window != (int)PointerRoot ) {
1448 XRaiseWindow(getXDisplay(), focus_window);
1450 break;
1452 case grabLower:
1453 if (focus_window && focus_window != (int)PointerRoot ) {
1454 XLowerWindow(getXDisplay(), focus_window);
1456 break;
1458 case grabClose:
1459 if (!focus_window)
1460 break;
1461 XEvent ce;
1462 ce.xclient.type = ClientMessage;
1463 ce.xclient.message_type = getWMProtocolsAtom();
1464 ce.xclient.display = getXDisplay();
1465 ce.xclient.window = focus_window;
1466 ce.xclient.format = 32;
1467 ce.xclient.data.l[0] = getWMDeleteAtom();
1468 ce.xclient.data.l[1] = CurrentTime;
1469 ce.xclient.data.l[2] = ce.xclient.data.l[3] =
1470 ce.xclient.data.l[4] = 0l;
1471 XSendEvent(getXDisplay(), focus_window, False, NoEventMask, &ce);
1472 break;
1474 case grabWorkspace1:
1475 wminterface->changeDesktop(0);
1476 break;
1478 case grabWorkspace2:
1479 wminterface->changeDesktop(1);
1480 break;
1482 case grabWorkspace3:
1483 wminterface->changeDesktop(2);
1484 break;
1486 case grabWorkspace4:
1487 wminterface->changeDesktop(3);
1488 break;
1490 case grabWorkspace5:
1491 wminterface->changeDesktop(4);
1492 break;
1494 case grabWorkspace6:
1495 wminterface->changeDesktop(5);
1496 break;
1498 case grabWorkspace7:
1499 wminterface->changeDesktop(6);
1500 break;
1502 case grabWorkspace8:
1503 wminterface->changeDesktop(7);
1504 break;
1506 case grabWorkspace9:
1507 wminterface->changeDesktop(8);
1508 break;
1510 case grabWorkspace10:
1511 wminterface->changeDesktop(9);
1512 break;
1514 case grabWorkspace11:
1515 wminterface->changeDesktop(10);
1516 break;
1518 case grabWorkspace12:
1519 wminterface->changeDesktop(11);
1520 break;
1522 case grabNextWorkspace:
1523 if (current_desktop->number < (desktop_count-1))
1524 wminterface->changeDesktop(current_desktop->number + 1);
1525 else
1526 wminterface->changeDesktop(0);
1527 break;
1529 case grabPrevWorkspace:
1530 if (current_desktop->number > 0)
1531 wminterface->changeDesktop(current_desktop->number - 1);
1532 else
1533 wminterface->changeDesktop(desktop_count - 1);
1534 break;
1536 case grabUpWorkspace:
1537 if (resource->columns > 1) { //ie columns given
1538 if (getCurrentDesktopNr()-resource->columns<0) {
1539 if (getDesktopCount()-1-(getDesktopCount()-1)%resource->columns +
1540 getCurrentDesktopNr()%resource->columns > getDesktopCount() - 1) {
1542 wminterface->changeDesktop(getDesktopCount() - 1 -
1543 (getDesktopCount() - 1)%resource->columns +
1544 getCurrentDesktopNr()%resource->columns -resource->columns);
1546 } else {
1547 wminterface->changeDesktop(getDesktopCount() - 1 -
1548 (getDesktopCount() - 1)%resource->columns +
1549 getCurrentDesktopNr()%resource->columns );
1551 } else {
1552 wminterface->changeDesktop(getCurrentDesktopNr() - resource->columns);
1554 } else if (resource->rows > 1) { //ie rows given
1555 if (getCurrentDesktopNr()%resource->rows==0) {// if row=1
1556 if (getCurrentDesktopNr() + resource->rows > getDesktopCount())
1557 //incomplete last col?
1558 wminterface->changeDesktop(getDesktopCount() - 1); //last desktop
1559 else //complete col
1560 wminterface->changeDesktop(getCurrentDesktopNr() +resource->rows - 1);
1561 //last in column
1562 } else // row>1
1563 wminterface->changeDesktop(getCurrentDesktopNr() - 1);
1564 } else {} //no arrangement -> insert fallback solution here
1566 break;
1568 case grabDownWorkspace:
1569 if (resource->columns > 1) { //ie columns given
1570 if (getCurrentDesktopNr() + resource->columns > getDesktopCount() - 1)
1571 wminterface->changeDesktop(getCurrentDesktopNr()%resource->columns);
1572 else
1573 wminterface->changeDesktop(getCurrentDesktopNr() +resource->columns);
1574 } else if (resource->rows > 1) { //ie rows given
1575 if (getCurrentDesktopNr()%resource->rows + 1 == resource->rows ||
1576 getCurrentDesktopNr() + 1 == getDesktopCount()) {
1577 //last row or last in incomplete col
1578 wminterface->changeDesktop(getCurrentDesktopNr() -
1579 getCurrentDesktopNr()%resource->rows);
1580 //first in col
1581 } else
1582 wminterface->changeDesktop(getCurrentDesktopNr() + 1);
1583 } else {} //no arrangement -> fallback solution
1585 break;
1588 case grabLeftWorkspace:
1589 if (resource->columns > 1) { //ie columns given
1590 if (getCurrentDesktopNr()%resource->columns==0) {
1591 if (getCurrentDesktopNr() + resource->columns > getDesktopCount())
1592 wminterface->changeDesktop(getDesktopCount() -1);
1593 else
1594 wminterface->changeDesktop(getCurrentDesktopNr() + resource->columns - 1);
1595 } else
1596 wminterface->changeDesktop(getCurrentDesktopNr() - 1);
1597 } else if (resource->rows > 1) { //ie rows given
1598 if (getCurrentDesktopNr() - resource->rows<0) {// first col
1599 if (getDesktopCount() - 1 - (getDesktopCount()-1)%resource->rows +
1600 getCurrentDesktopNr()%resource->rows > getDesktopCount() - 1)
1601 //incomplete row
1602 wminterface->changeDesktop(getDesktopCount() - 1 -
1603 (getDesktopCount() - 1)%resource->rows +
1604 getCurrentDesktopNr()%resource->rows - resource->rows);
1605 else
1606 wminterface->changeDesktop(getDesktopCount() - 1 -
1607 (getDesktopCount() - 1)%resource->rows +
1608 getCurrentDesktopNr()%resource->rows );
1609 } else
1610 wminterface->changeDesktop(getCurrentDesktopNr() - resource->rows);
1611 } else {} //no arrangement -> fallback solution
1613 break;
1616 case grabRightWorkspace:
1617 if (resource->columns > 1) { //ie columns given
1618 if (getCurrentDesktopNr()%resource->columns + 1 == resource->columns ||
1619 getCurrentDesktopNr() + 1 == getDesktopCount())
1620 wminterface->changeDesktop(getCurrentDesktopNr() -
1621 getCurrentDesktopNr()%resource->columns);
1622 else
1623 wminterface->changeDesktop(getCurrentDesktopNr() + 1);
1624 } else if (resource->rows > 1) { //ie rows given
1625 if (getCurrentDesktopNr() + resource->rows > getDesktopCount() - 1)
1626 // last in row
1627 wminterface->changeDesktop(getCurrentDesktopNr()%resource->rows);
1628 // first col
1629 else
1630 wminterface->changeDesktop(getCurrentDesktopNr() + resource->rows);
1631 } else {} //no arrangement -> fallback solution
1633 break;
1635 case grabNextWindow:
1636 showAllWorkspaces=false;
1637 cycleWindowFocus(True);
1638 break;
1640 case grabNextWindowAllWorkspaces:
1641 showAllWorkspaces=true;
1642 cycleWindowFocus(True);
1643 break;
1645 case grabPrevWindow:
1646 cycleWindowFocus(False);
1647 break;
1649 case grabShade:
1650 if (focus_window && focus_window != (int)PointerRoot ) {
1651 wminterface->shadeWindow(focus_window);
1653 break;
1655 case grabStick:
1656 if (focus_window && focus_window != (int)PointerRoot ) {
1657 wminterface->stickWindow(focus_window);
1659 break;
1661 case grabExecute:
1662 execCommand(grabSet.KeyMap[grabInt].execCommand);
1663 break;
1665 case grabMaximize:
1666 if (focus_window && focus_window != (int)PointerRoot )
1667 wminterface->maximizeWindow(focus_window, True, True);
1668 break;
1670 case grabVertMax:
1671 if (focus_window && focus_window != (int)PointerRoot )
1672 wminterface->maximizeWindow(focus_window, False, True);
1673 break;
1675 case grabHorizMax:
1676 if (focus_window && focus_window != (int)PointerRoot )
1677 wminterface->maximizeWindow(focus_window, True, False);
1678 break;
1680 case grabNudgeRight:
1681 if (focus_window && focus_window != (int)PointerRoot )
1682 XMoveWindow(getXDisplay(), focus_window, fw_x + 1, fw_y);
1683 break;
1685 case grabNudgeLeft:
1686 if (focus_window && focus_window != (int)PointerRoot )
1687 XMoveWindow(getXDisplay(), focus_window, fw_x - 1, fw_y);
1688 break;
1690 case grabNudgeUp:
1691 if (focus_window && focus_window != (int)PointerRoot )
1692 XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y - 1);
1693 break;
1695 case grabNudgeDown:
1696 if (focus_window && focus_window != (int)PointerRoot )
1697 XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y + 1);
1698 break;
1700 case grabBigNudgeRight:
1701 if (focus_window && focus_window != (int)PointerRoot )
1702 XMoveWindow(getXDisplay(), focus_window, fw_x + 10, fw_y);
1703 break;
1705 case grabBigNudgeLeft:
1706 if (focus_window && focus_window != (int)PointerRoot )
1707 XMoveWindow(getXDisplay(), focus_window, fw_x - 10, fw_y);
1708 break;
1710 case grabBigNudgeUp:
1711 if (focus_window && focus_window != (int)PointerRoot )
1712 XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y - 10);
1713 break;
1715 case grabBigNudgeDown:
1716 if (focus_window && focus_window != (int)PointerRoot )
1717 XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y + 10);
1718 break;
1720 case grabHorizInc:
1721 if (focus_window && focus_window != (int)PointerRoot ) {
1722 XWindowAttributes foo;
1723 XGetWindowAttributes(getXDisplay(), focus_window, &foo);
1724 XResizeWindow(getXDisplay(), focus_window,
1725 foo.width + 10, foo.height);
1727 break;
1729 case grabVertInc:
1730 if (focus_window && focus_window != (int)PointerRoot ) {
1731 XWindowAttributes foo;
1732 XGetWindowAttributes(getXDisplay(), focus_window, &foo);
1733 XResizeWindow(getXDisplay(), focus_window,
1734 foo.width, foo.height + 10);
1736 break;
1738 case grabHorizDec:
1739 if (focus_window && focus_window != (int)PointerRoot ) {
1740 XWindowAttributes foo;
1741 XGetWindowAttributes(getXDisplay(), focus_window, &foo);
1742 if (foo.width < 11)
1743 foo.width = 11;
1744 XResizeWindow(getXDisplay(), focus_window,
1745 foo.width - 10, foo.height);
1747 break;
1749 case grabVertDec:
1750 if (focus_window && focus_window != (int)PointerRoot ) {
1751 XWindowAttributes foo;
1752 XGetWindowAttributes(getXDisplay(), focus_window, &foo);
1753 if (foo.height < 11)
1754 foo.height = 11;
1755 XResizeWindow(getXDisplay(), focus_window,
1756 foo.width, foo.height - 10);
1758 break;
1760 case grabToggleDecor:
1761 if (focus_window && focus_window != (int)PointerRoot ) {
1762 wminterface->decorateToggleWindow(focus_window);
1764 break;
1767 timer->start();
1768 break;
1771 case ClientMessage:
1772 if ((unsigned) e->xclient.data.l[0] == wm_delete_window)
1773 shutdown();
1774 wminterface->handleNETEvents(*e);
1775 break;
1777 case Expose:
1778 if (!e->xexpose.count)
1779 reconfigure();
1780 break;
1782 case ButtonPress:
1783 if (e->xbutton.button == LEFT_BUTTON
1784 || e->xbutton.button == RIGHT_BUTTON) {
1785 if (e->xbutton.window == win_configBtn) {
1786 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1787 pixmap.pix_pressedBtn);
1788 Redraw();
1789 } else if (e->xbutton.window == win_closeBtn) {
1790 XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
1791 pixmap.pix_pressedBtn);
1792 Redraw();
1793 } else if (e->xbutton.window == win_title) {
1794 // if (!raised)
1795 XRaiseWindow(getXDisplay(), win_frame);
1796 // raised = True;
1798 } else if (e->xbutton.button == MIDDLE_BUTTON) {
1799 // if (raised)
1800 XLowerWindow(getXDisplay(), win_frame);
1801 // raised = False;
1803 break;
1805 case ButtonRelease:
1806 if (e->xbutton.button == LEFT_BUTTON
1807 || e->xbutton.button == RIGHT_BUTTON) {
1808 if (e->xbutton.window == win_configBtn) {
1809 if ((e->xbutton.x > 0)
1810 && (e->xbutton.x < geom_configBtn.width)
1811 && (e->xbutton.y > 0)
1812 && (e->xbutton.y < geom_configBtn.height)) {
1813 if (grabSet.instructCount > 0) {
1814 XUngrabKey(getXDisplay(), AnyKey, AnyModifier,
1815 getScreenInfo(0)->getRootWindow());
1816 XSync(getXDisplay(), False);
1818 setKeygrabs();
1820 // discard all XEvents (was causing us to go bananas on the
1821 // user before, since we were executing all keygrabs at once
1822 // that the user did when the configuration app was running)
1823 // *cough* undocumented feature *cough*
1826 XEvent event;
1827 while (XPending(getXDisplay())) {
1828 XNextEvent(getXDisplay(), &event);
1831 // carry on then, little soldier
1833 loadKeygrabs();
1834 activateKeygrabs();
1835 timer->start();
1838 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1839 pixmap.pix_configBtn);
1840 Redraw();
1841 } else if (e->xbutton.window == win_closeBtn) {
1842 if ((e->xbutton.x > 0)
1843 && (e->xbutton.x < geom_closeBtn.width)
1844 && (e->xbutton.y > 0)
1845 && (e->xbutton.y < geom_closeBtn.height)) {
1846 if (e->xbutton.button == LEFT_BUTTON) {
1847 shutdown();
1848 } else if (e->xbutton.button == RIGHT_BUTTON) {
1849 if (withdrawn) {
1850 XUnmapWindow(getXDisplay(), win_frame);
1851 withdrawn = False;
1852 iconic = True;
1854 XWMHints wmhints;
1855 wmhints.initial_state = IconicState;
1856 wmhints.flags = StateHint;
1857 XSetWMHints(getXDisplay(), win_frame, &wmhints);
1858 XMapWindow(getXDisplay(), win_frame);
1860 // this should work but doesn't seem to. *shrug*
1861 // reconfigure();
1862 } else {
1863 XIconifyWindow(getXDisplay(), win_frame, 0);
1867 XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
1868 pixmap.pix_configBtn);
1869 Redraw();
1872 break;
1874 case ConfigureNotify:
1875 if ((e->xconfigure.window == win_frame) && e->xconfigure.send_event) {
1876 if (withdrawn)
1877 reconfigure();
1879 int parent_x, parent_y;
1880 Window parent_root;
1881 unsigned int parent_width, parent_height, parent_border_width;
1882 unsigned int parent_depth;
1884 if (withdrawn) {
1885 XGetGeometry(getXDisplay(), e->xconfigure.above,
1886 &parent_root, &parent_x, &parent_y,
1887 &parent_width, &parent_height,
1888 &parent_border_width, &parent_depth);
1889 frame.x = e->xconfigure.x + parent_x;
1890 frame.y = e->xconfigure.y + parent_y;
1893 break;
1897 void ToolWindow::timeout(void)
1899 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1900 pixmap.pix_configBtn);
1901 Redraw();
1904 /*--------------------------------*/
1906 /*- window modifying functions -*/
1908 /*--------------------------------*/
1910 void ToolWindow::raiseWindow(Window win)
1914 void ToolWindow::lowerWindow(Window win)
1918 /*---------------------------------------*/
1920 /*- desktop list management functions -*/
1922 /*---------------------------------------*/
1924 void ToolWindow::addDesktop(void)
1926 DesktopList *tmp = new DesktopList;
1928 // get the highest in the list
1929 int highest = -1;
1930 LinkedListIterator<DesktopList> it(desktopList);
1931 for (; it.current(); it++)
1932 if (it.current()->number > highest) {
1933 highest = it.current()->number;
1934 it.reset();
1936 tmp->number = highest + 1;
1938 desktopList->insert(tmp, -1); // add to the end of the list
1940 desktop_count++;
1942 // add sticky windows to this desktop
1943 LinkedListIterator<WindowList> it_win(windowList);
1944 for (; it_win.current(); it_win++)
1945 // only look for sticky windows on desktop 0, this will give us one
1946 // copy of each sticky window
1947 if ((it_win.current()->desktop == 0) && (it_win.current()->sticky)) {
1948 WindowList *win = new WindowList;
1949 win->win = it_win.current()->win;
1950 win->iconic = it_win.current()->iconic;
1951 win->shaded = False;
1952 win->sticky = True;
1953 win->desktop = tmp->number;
1954 windowList->insert(win, -1); // add to the end of the list
1958 void ToolWindow::removeDesktop(int desktop)
1960 LinkedListIterator<DesktopList> it(desktopList);
1961 LinkedListIterator<WindowList> it_win(windowList);
1963 // remove sticky windows from this desktop
1964 for (; it_win.current(); it_win++)
1965 if ((it_win.current()->desktop == desktop)
1966 && (it_win.current()->sticky))
1967 windowList->remove(it_win.current()); // remove just this window
1968 // removeWindow() would remove all
1969 // of the sticky windows.
1971 // remove the desktop from the linked list
1972 for (; it.current(); it++)
1973 if (it.current()->number == desktop) {
1974 desktopList->remove(it.current());
1975 break;
1978 desktop_count--;
1980 // shift the rest to fill in the hole if not the last desktop was rm'd
1981 int check=0;
1982 bool found;
1983 do {
1984 found=False;
1985 it.reset();
1986 for (; it.current(); it++)
1987 if (it.current()->number == check) {
1988 ++check;
1989 found=True;
1991 } while (found);
1993 // check is on the new hole, or desktop_count if there is no hole
1994 // plug the hole by moving all the desktops above down one
1995 while (check < desktop_count) {
1996 it.reset();
1997 for (; it.current(); it++)
1998 if(it.current()->number == (check + 1)) {
1999 it.current()->number = check++;
2000 break;
2005 void ToolWindow::focusDesktop(int desktop)
2007 LinkedListIterator<DesktopList> it(desktopList);
2008 for (; it.current(); it++)
2009 if (it.current()->number == desktop)
2010 current_desktop = it.current();
2013 void ToolWindow::setDesktopCount(int count)
2015 int oldcount = desktop_count;
2016 int delta = count - oldcount;
2018 if (delta > 0) { // added desktops
2019 while(delta-- > 0)
2020 addDesktop();
2022 else { // removed desktops
2023 while(delta++ < 0)
2024 removeDesktop(desktop_count - 1); // remove the last desktop
2028 /*--------------------------------------*/
2030 /*- window list management functions -*/
2032 /*--------------------------------------*/
2034 void ToolWindow::removeWindow(Window win)
2036 if (focus_window == win)
2037 focusWindow(0);
2038 LinkedListIterator<WindowList> it(windowList);
2039 for (; it.current(); it++)
2040 if (it.current()->win == win) {
2041 windowList->remove(it.current());
2045 void ToolWindow::focusWindow(Window win)
2047 // have to only do this when the menu isn't visible, because we're
2048 // setting focus while we're cycling.... Unfortunately, a side-effect
2049 // of this is that we don't get a final focusWindow hit when we raise
2050 // the selected window when done cycling, so we do an explicit
2051 // bbtool->focusWindow() call from Stackmenu::selectFocused() after we
2052 // XRaise the window....
2054 if (! doingCycling ) {
2055 focus_window = win;
2056 if (resource->getMenuStackedCycling())
2057 focus_stack(win);
2061 void ToolWindow::moveWinToDesktop(Window win, int desktop)
2063 LinkedListIterator<WindowList> it(windowList);
2064 for (; it.current(); it++)
2065 if (it.current()->win == win) {
2066 if (!it.current()->sticky) {
2067 it.current()->desktop = desktop;
2069 break;
2073 void ToolWindow::addSticky(WindowList *win) {
2074 win->sticky = True;
2075 LinkedListIterator<DesktopList> it(desktopList);
2076 for (; it.current(); it++)
2077 if (win->desktop != it.current()->number) {
2078 WindowList *copy = new WindowList;
2079 copy->win = win->win;
2080 copy->iconic = win->iconic;
2081 copy->shaded = win->shaded;
2082 copy->sticky = True;
2083 copy->desktop = it.current()->number;
2084 windowList->insert(copy, -1);
2088 void ToolWindow::removeSticky(const Window win, const int desktop) {
2089 LinkedListIterator<WindowList> it(windowList);
2090 for (register int i=0; i < desktop_count; i++) {
2091 it.reset();
2092 for (; it.current(); it++)
2093 if (it.current()->win == win)
2094 if (it.current()->desktop != desktop)
2095 windowList->remove(it.current());
2096 else
2097 it.current()->sticky = False;
2101 void ToolWindow::windowAttributeChange(Window win) {
2102 Atom real_type;
2103 int format;
2104 unsigned long n, extra;
2105 WindowList *window = NULL;
2106 BlackboxHints *net_hint;
2107 LinkedListIterator<WindowList> it(windowList);
2109 for (; it.current(); it++) // find the window that's changed
2110 if (it.current()->win == win)
2111 window = it.current();
2112 if (!window)
2113 return;
2114 if (!(XGetWindowProperty(getXDisplay(), window->win,
2115 getBlackboxAttributesAtom(), 0L,
2116 PropBlackboxHintsElements, False,
2117 getBlackboxAttributesAtom(), &real_type,
2118 &format, &n, &extra, (unsigned char**)&net_hint)
2119 == Success && net_hint))
2120 return;
2121 if (n != PropBlackboxHintsElements)
2122 return;
2124 if (net_hint->flags & AttribShaded) {
2125 if (net_hint->attrib & AttribShaded)
2126 window->shaded = True;
2127 } else if (window->shaded)
2128 window->shaded = False;
2130 if (wminterface->isIconicState(window->win) != window->iconic &&
2131 !window->shaded)
2132 window->iconic = !window->iconic;
2134 if (net_hint->flags & AttribOmnipresent) {
2135 if (net_hint->attrib & AttribOmnipresent)
2136 if (!window->sticky) addSticky(window);
2137 } else if (window->sticky)
2138 if (window->sticky) removeSticky(window->win, getCurrentDesktopNr());
2141 void ToolWindow::addWindow(Window win, int desktop)
2143 WindowList *newwin = new WindowList;
2144 newwin->win = win;
2145 newwin->iconic = wminterface->isIconicState(win);
2146 newwin->shaded = False;
2147 newwin->sticky = False;
2148 newwin->desktop = desktop;
2149 XSelectInput(getXDisplay(),newwin->win,
2150 PropertyChangeMask);
2151 if (resource->getMenuStackedCycling())
2152 add_stack(newwin);
2153 else
2154 add_linear(newwin);
2157 void ToolWindow::cycleWindowFocus(bool forward)
2159 if (resource->getMenuStackedCycling())
2160 cycle_stack(forward);
2161 else
2162 cycle_linear(forward);
2165 /*******************************************************************************
2167 LINEAR CYCLING FUNCTIONS
2169 *******************************************************************************/
2171 void ToolWindow::add_linear(WindowList *newwin)
2173 int i;
2174 int index = 0; // where the new window will be placed (defaults to the
2175 // top of the list)
2176 // insert after the focused window
2177 LinkedListIterator<WindowList> it(windowList);
2178 for (i=0; i<windowList->count(); i++) {
2179 it.set(i);
2180 if (it.current()->win == focus_window) {
2181 // get the index of the focused window
2182 index = i+1;
2183 break;
2186 windowList->insert(newwin, index);
2189 void ToolWindow::cycle_linear(bool forward)
2191 /*******************************************
2192 This does the oldschool straight rotation
2193 order of cycling windows.
2194 ********************************************/
2195 int desktop = -1;
2196 bool found = False;
2197 WindowList *next = NULL;
2198 int i, max;
2200 LinkedListIterator<WindowList> it(windowList);
2201 max = windowList->count();
2202 for (i=0; i<max; i++) {
2203 if (forward)
2204 it.set(i);
2205 else
2206 it.set(max-1-i);
2207 if (found) {
2208 // find the window after the focused one
2209 if (it.current()->desktop == desktop) {
2210 next = it.current();
2211 break;
2214 if (it.current()->win == focus_window) {
2215 found = True;
2216 desktop = it.current()->desktop;
2219 // if the next window wasn't found, start over at the beginning once more
2220 if (!next)
2222 for (i=0; i<max; i++) {
2223 if (forward)
2224 it.set(i);
2225 else
2226 it.set(max-1-i);
2227 if (it.current()->desktop == desktop) {
2228 next = it.current();
2229 break;
2234 if (next) {
2235 wminterface->setWindowFocus(next->win);
2236 XRaiseWindow(getXDisplay(), next->win);
2240 /*******************************************************************************
2242 STACK CYCLING FUNCTIONS
2244 *******************************************************************************/
2246 void ToolWindow::add_stack(WindowList *newwin) {
2247 windowList->insert(newwin, 0); // insert at the top of the list
2248 stackMenu->setMenuItems();
2251 void ToolWindow::cycle_stack(bool forward) {
2252 register bool showMenu = resource->getMenuShowCycleMenu() ? True : False;
2253 stackMenu->show(forward, showMenu);
2256 void ToolWindow::focus_stack(Window win)
2258 WindowList *window = new WindowList;
2259 LinkedListIterator<WindowList> it(windowList);
2260 for (; it.current(); it++) {
2261 if (it.current()->win == win)
2262 if ((!it.current()->sticky) ||
2263 (it.current()->desktop == getCurrentDesktopNr()))
2264 break;
2266 if (it.current()) {
2267 window->win = it.current()->win;
2268 window->shaded = it.current()->shaded;
2269 window->sticky = it.current()->sticky;
2270 window->iconic = it.current()->iconic;
2271 window->desktop = it.current()->desktop;
2272 windowList->remove(it.current()); // remove it
2273 windowList->insert(window, 0); // add it to the top
2277 void ToolWindow::saveMenuSearch(Window window, Basemenu *menu)
2279 menuWin = window;
2282 void ToolWindow::removeMenuSearch(Window window)
2284 menuWin = (Window)NULL;
2287 void ToolWindow::p()
2289 printf("window | stick | shade | icon | desk\n");
2290 LinkedListIterator<WindowList> it(windowList);
2291 for (; it.current(); it++)
2292 printf("%010i | %d | %d | %d | %d\n", (int)it.current()->win,
2293 it.current()->sticky, it.current()->shaded, it.current()->iconic,
2294 it.current()->desktop);