initial import
[bbkeys.git] / bbkeys.cc
blob95e3e0911015376ab4ff58b3b614304e5bd36a22
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-2000 by Jason Kasper (vanRijn) vR@movingparts.net
6 // Copyright (c) 2001 by Ben Jansens <xor@x-o-r.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)
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #ifdef HAVE_STDIO_H
30 # include <stdio.h>
31 #endif // HAVE_STDIO_H
33 #ifdef HAVE_CTYPE_H
34 # include <ctype.h>
35 #endif // HAVE_CTYPE_H
37 #ifdef STDC_HEADERS
38 # include <stdlib.h>
39 # include <string.h>
40 #endif // STDC_HEADERS
42 #if HAVE_STRINGS_H
43 # include <strings.h>
44 #endif
46 #ifdef HAVE_SYS_TYPES_H
47 # include <sys/types.h>
48 #endif // HAVE_SYS_TYPES_H
50 #ifdef HAVE_SYS_WAIT_H
51 # include <sys/wait.h>
52 #endif // HAVE_SYS_WAIT_H
54 #ifdef HAVE_ERRNO_H
55 # include <errno.h>
56 #endif // HAVE_ERRNO_H
58 #ifdef HAVE_UNISTD_H
59 # include <unistd.h>
60 #endif // HAVE_UNISTD_H
62 #ifdef HAVE_SYS_STAT_H
63 # include <sys/stat.h>
64 #endif // HAVE_SYS_STAT_H
66 #include <X11/Xlib.h>
67 #include <X11/Xproto.h>
68 #include <X11/keysym.h>
70 #include "bbkeys.hh"
71 #include "main.hh"
72 #include "Timer.hh"
75 /*--------------------------------------------------------------------*/
77 /* Ripped shamelessly from wmaker's xmodifier.c--converted for our use*/
79 /*--------------------------------------------------------------------*/
81 /* Grok X modifier mappings for shortcuts.
83 Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
84 The copyright(s) from the original XEmacs code are included below.
86 Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */
88 /* The event_stream interface for X11 with Xt, and/or tty frames.
89 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
90 Copyright (C) 1995 Sun Microsystems, Inc.
91 Copyright (C) 1996 Ben Wing.
93 This file is part of XEmacs.
95 XEmacs is free software; you can redistribute it and/or modify it
96 under the terms of the GNU General Public License as published by the
97 Free Software Foundation; either version 2, or (at your option) any
98 later version.
100 XEmacs is distributed in the hope that it will be useful, but WITHOUT
101 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
102 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
103 for more details.
105 You should have received a copy of the GNU General Public License
106 along with XEmacs; see the file COPYING. If not, write to
107 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
108 Boston, MA 02111-1307, USA. */
110 /************************************************************************/
112 /* keymap handling */
114 /************************************************************************/
116 /* X bogusly doesn't define the interpretations of any bits besides
117 ModControl, ModShift, and ModLock; so the Interclient Communication
118 Conventions Manual says that we have to bend over backwards to figure
119 out what the other modifier bits mean. According to ICCCM:
121 - Any keycode which is assigned ModControl is a "control" key.
123 - Any modifier bit which is assigned to a keycode which generates Meta_L
124 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper,
125 etc.
127 - Any keypress event which contains ModControl in its state should be
128 interpreted as a "control" character.
130 - Any keypress event which contains a modifier bit in its state which is
131 generated by a keycode whose corresponding keysym is Meta_L or Meta_R
132 should be interpreted as a "meta" character. Likewise for Super, Hyper,
133 etc.
135 - It is illegal for a keysym to be associated with more than one modifier
136 bit.
138 This means that the only thing that emacs can reasonably interpret as a
139 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
140 one of the modifier bits Mod1-Mod5.
142 Unfortunately, many keyboards don't have Meta keys in their default
143 configuration. So, if there are no Meta keys, but there are "Alt" keys,
144 emacs will interpret Alt as Meta. If there are both Meta and Alt keys,
145 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
146 mean "Symbol," but that just confused the hell out of way too many people).
148 This works with the default configurations of the 19 keyboard-types I've
149 checked.
151 Emacs detects keyboard configurations which violate the above rules, and
152 prints an error message on the standard-error-output. (Perhaps it should
153 use a pop-up-window instead.)
156 static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
158 char *ToolWindow::index_to_name(int indice)
160 switch (indice) {
161 case ShiftMapIndex:
162 return "ModShift";
163 case LockMapIndex:
164 return "ModLock";
165 case ControlMapIndex:
166 return "ModControl";
167 case Mod1MapIndex:
168 return "Mod1";
169 case Mod2MapIndex:
170 return "Mod2";
171 case Mod3MapIndex:
172 return "Mod3";
173 case Mod4MapIndex:
174 return "Mod4";
175 case Mod5MapIndex:
176 return "Mod5";
177 default:
178 return "???";
182 void ToolWindow::x_reset_modifier_mapping(Display * display)
184 int modifier_index, modifier_key, column, mkpm;
185 int warned_about_overlapping_modifiers = 0;
186 int warned_about_predefined_modifiers = 0;
187 int warned_about_duplicate_modifiers = 0;
188 int meta_bit = 0;
189 int hyper_bit = 0;
190 int super_bit = 0;
191 int alt_bit = 0;
192 int mode_bit = 0;
193 XModifierKeymap *x_modifier_keymap = XGetModifierMapping(display);
195 #define modwarn(name,old,other) \
196 warned_about_overlapping_modifiers = 1
198 #define modbarf(name,other) \
199 warned_about_predefined_modifiers = 1
201 #define check_modifier(name,mask) \
202 warned_about_predefined_modifiers = 1
204 #define store_modifier(name,old) \
205 if (old && old != modifier_index) \
206 warned_about_duplicate_modifiers = 1; \
207 if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift"); \
208 else if (modifier_index == LockMapIndex) modbarf (name,"ModLock"); \
209 else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
210 else if (sym == XK_Mode_switch) \
211 mode_bit = modifier_index; /* Mode_switch is special, see below... */ \
212 else if (modifier_index == meta_bit && old != meta_bit) \
213 modwarn (name, meta_bit, "Meta"); \
214 else if (modifier_index == super_bit && old != super_bit) \
215 modwarn (name, super_bit, "Super"); \
216 else if (modifier_index == hyper_bit && old != hyper_bit) \
217 modwarn (name, hyper_bit, "Hyper"); \
218 else if (modifier_index == alt_bit && old != alt_bit) \
219 modwarn (name, alt_bit, "Alt"); \
220 else \
221 old = modifier_index;
223 mkpm = x_modifier_keymap->max_keypermod;
224 for (modifier_index = 0; modifier_index < 8; modifier_index++)
225 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
226 KeySym last_sym = 0;
227 for (column = 0; column < 4; column += 2) {
228 KeyCode code =
229 x_modifier_keymap->modifiermap[modifier_index * mkpm +
230 modifier_key];
231 KeySym sym =
232 (code ? XKeycodeToKeysym(display, code, column) : 0);
233 if (sym == last_sym)
234 continue;
235 last_sym = sym;
236 switch (sym) {
237 case XK_Mode_switch:
238 store_modifier("Mode_switch", mode_bit);
239 break;
240 case XK_Meta_L:
241 store_modifier("Meta_L", meta_bit);
242 break;
243 case XK_Meta_R:
244 store_modifier("Meta_R", meta_bit);
245 break;
246 case XK_Super_L:
247 store_modifier("Super_L", super_bit);
248 break;
249 case XK_Super_R:
250 store_modifier("Super_R", super_bit);
251 break;
252 case XK_Hyper_L:
253 store_modifier("Hyper_L", hyper_bit);
254 break;
255 case XK_Hyper_R:
256 store_modifier("Hyper_R", hyper_bit);
257 break;
258 case XK_Alt_L:
259 store_modifier("Alt_L", alt_bit);
260 break;
261 case XK_Alt_R:
262 store_modifier("Alt_R", alt_bit);
263 break;
264 case XK_Control_L:
265 check_modifier("Control_L", ControlMask);
266 break;
267 case XK_Control_R:
268 check_modifier("Control_R", ControlMask);
269 break;
270 case XK_Shift_L:
271 check_modifier("Shift_L", ShiftMask);
272 break;
273 case XK_Shift_R:
274 check_modifier("Shift_R", ShiftMask);
275 break;
276 case XK_Shift_Lock:
277 check_modifier("Shift_Lock", LockMask);
278 break;
279 case XK_Caps_Lock:
280 check_modifier("Caps_Lock", LockMask);
281 break;
283 /* It probably doesn't make any sense for a modifier bit to be
284 assigned to a key that is not one of the above, but OpenWindows
285 assigns modifier bits to a couple of random function keys for
286 no reason that I can discern, so printing a warning here would
287 be annoying. */
291 #undef store_modifier
292 #undef check_modifier
293 #undef modwarn
294 #undef modbarf
296 /* If there was no Meta key, then try using the Alt key instead.
297 If there is both a Meta key and an Alt key, then the Alt key
298 is not disturbed and remains an Alt key. */
299 if (!meta_bit && alt_bit)
300 meta_bit = alt_bit, alt_bit = 0;
302 /* mode_bit overrides everything, since it's processed down inside of
303 XLookupString() instead of by us. If Meta and Mode_switch both
304 generate the same modifier bit (which is an error), then we don't
305 interpret that bit as Meta, because we can't make XLookupString()
306 not interpret it as Mode_switch; and interpreting it as both would
307 be totally wrong. */
308 if (mode_bit) {
309 const char *warn = 0;
310 if (mode_bit == meta_bit)
311 warn = "Meta", meta_bit = 0;
312 else if (mode_bit == hyper_bit)
313 warn = "Hyper", hyper_bit = 0;
314 else if (mode_bit == super_bit)
315 warn = "Super", super_bit = 0;
316 else if (mode_bit == alt_bit)
317 warn = "Alt", alt_bit = 0;
318 if (warn) {
319 warned_about_overlapping_modifiers = 1;
323 MetaMask = (meta_bit ? (1 << meta_bit) : 0);
324 HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
325 SuperMask = (super_bit ? (1 << super_bit) : 0);
326 AltMask = (alt_bit ? (1 << alt_bit) : 0);
327 ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
329 if (x_modifier_keymap)
330 XFreeModifiermap(x_modifier_keymap);
334 int ToolWindow::translateModifier(char *key)
336 if (strcasecmp(key, "SHIFT") == 0 && ShiftMask != 0)
337 return ShiftMask;
338 else if (strcasecmp(key, "CONTROL") == 0 && ControlMask != 0)
339 return ControlMask;
340 else if (strcasecmp(key, "ALT") == 0 && AltMask != 0)
341 return AltMask;
342 else if (strcasecmp(key, "META") == 0 && MetaMask != 0)
343 return MetaMask;
344 else if (strcasecmp(key, "SUPER") == 0 && SuperMask != 0)
345 return SuperMask;
346 else if (strcasecmp(key, "HYPER") == 0 && HyperMask != 0)
347 return HyperMask;
348 else if (strcasecmp(key, "MOD1") == 0 && Mod1Mask != 0)
349 return Mod1Mask;
350 else if (strcasecmp(key, "MOD2") == 0 && Mod2Mask != 0)
351 return Mod2Mask;
352 else if (strcasecmp(key, "MOD3") == 0 && Mod3Mask != 0)
353 return Mod3Mask;
354 else if (strcasecmp(key, "MOD4") == 0 && Mod4Mask != 0)
355 return Mod4Mask;
356 else if (strcasecmp(key, "MOD5") == 0 && Mod5Mask != 0)
357 return Mod5Mask;
358 else if (strcasecmp(key, "NONE") == 0)
359 return None;
360 else
361 return -1;
364 /* Wrapper so that we may fit our naming conventions, yet leave the
365 original XEmacs function name in place. */
366 void ToolWindow::InitializeModifiers(void)
368 x_reset_modifier_mapping(getXDisplay());
371 /*-----------------------------------------------------------------------*/
373 /*-- end of shameless rip. thank you for your support ---*/
375 /*-----------------------------------------------------------------------*/
377 void ToolWindow::CheckConfig()
379 struct stat file_status;
381 if (stat(bbkeys_rcfile, &file_status) != 0) {
382 #ifdef DEBUG
383 fprintf(stderr, "Could not open config file ->%s<-\n",
384 bbkeys_rcfile);
385 #endif
386 } else if (file_status.st_mtime != bbkeys_rcTime) {
387 bbkeys_rcTime = file_status.st_mtime;
388 loadKeygrabs();
389 activateKeygrabs();
393 void ToolWindow::activateKeygrabs(void)
395 int i = 0;
397 if (grabSet.instructCount > 0)
398 XUngrabKey(getXDisplay(), AnyKey, AnyModifier,
399 getScreenInfo(0)->getRootWindow());
400 for (i = 0; i < grabSet.instructCount; i++) {
401 if (grabSet.KeyMap[i].keycode == 0)
402 continue;
404 if (grabSet.KeyMap[i].keycode != AnyModifier) {
405 XGrabKey(getXDisplay(), grabSet.KeyMap[i].keycode,
406 grabSet.KeyMap[i].modMask | LockMask,
407 getScreenInfo(0)->getRootWindow(), True,
408 GrabModeAsync, GrabModeAsync);
410 /* Also grab all modifier combinations possible that include,
411 * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
412 * work even if the NumLock/ScrollLock key is on.
415 wHackedGrabKey(grabSet.KeyMap[i].keycode,
416 grabSet.KeyMap[i].modMask,
417 getScreenInfo(0)->getRootWindow(), True,
418 GrabModeAsync, GrabModeAsync);
421 XGrabKey(getXDisplay(), grabSet.KeyMap[i].keycode,
422 grabSet.KeyMap[i].modMask,
423 getScreenInfo(0)->getRootWindow(), True, GrabModeAsync,
424 GrabModeAsync);
428 /*---------------------------------------------------------------------------*/
430 /*-- Snarfed shamelessly from WindowMaker's code-base once again.... --*/
432 /*---------------------------------------------------------------------------*/
433 void ToolWindow::wHackedGrabKey(int keycode, unsigned int modifiers,
434 Window grab_window, Bool owner_events,
435 int pointer_mode, int keyboard_mode)
437 if (modifiers == AnyModifier)
438 return;
439 if (keycode == AnyKey)
440 return;
442 /* grab all combinations of the modifier with CapsLock, NumLock and
443 * ScrollLock. How much memory/CPU does such a monstrosity consume
444 * in the server?
446 if (_NumLockMask) {
447 XGrabKey(getXDisplay(), keycode, modifiers | _NumLockMask,
448 grab_window, owner_events, pointer_mode, keyboard_mode);
450 if (_ScrollLockMask) {
451 XGrabKey(getXDisplay(), keycode, modifiers | _ScrollLockMask,
452 grab_window, owner_events, pointer_mode, keyboard_mode);
454 if (_NumLockMask && _ScrollLockMask) {
455 XGrabKey(getXDisplay(), keycode,
456 modifiers | _NumLockMask | _ScrollLockMask, grab_window,
457 owner_events, pointer_mode, keyboard_mode);
459 if (_NumLockMask) {
460 XGrabKey(getXDisplay(), keycode,
461 modifiers | _NumLockMask | LockMask, grab_window,
462 owner_events, pointer_mode, keyboard_mode);
464 if (_ScrollLockMask) {
465 XGrabKey(getXDisplay(), keycode,
466 modifiers | _ScrollLockMask | LockMask, grab_window,
467 owner_events, pointer_mode, keyboard_mode);
469 if (_NumLockMask && _ScrollLockMask) {
470 XGrabKey(getXDisplay(), keycode,
471 modifiers | _NumLockMask | _ScrollLockMask | LockMask,
472 grab_window, owner_events, pointer_mode, keyboard_mode);
474 /* phew, I guess that's all, right? */
477 void ToolWindow::getOffendingModifiers(void)
479 int i;
480 XModifierKeymap *modmap;
481 KeyCode nlock, slock;
482 static int mask_table[8] = {
483 ShiftMask, LockMask, ControlMask, Mod1Mask,
484 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
487 nlock = XKeysymToKeycode(getXDisplay(), XK_Num_Lock);
488 slock = XKeysymToKeycode(getXDisplay(), XK_Scroll_Lock);
491 * Find out the masks for the NumLock and ScrollLock modifiers,
492 * so that we can bind the grabs for when they are enabled too.
494 modmap = XGetModifierMapping(getXDisplay());
496 if (modmap != NULL && modmap->max_keypermod > 0) {
497 for (i = 0; i < 8 * modmap->max_keypermod; i++) {
498 if (modmap->modifiermap[i] == nlock && nlock != 0)
499 _NumLockMask = mask_table[i / modmap->max_keypermod];
500 else if (modmap->modifiermap[i] == slock && slock != 0)
501 _ScrollLockMask = mask_table[i / modmap->max_keypermod];
505 if (modmap)
506 XFreeModifiermap(modmap);
509 /*-------------------------------------------------------------------------*/
511 /*-- End of shameful code-snarf..................................... --*/
513 /*-------------------------------------------------------------------------*/
515 int ToolWindow::translateAction(char *action)
517 if (!action)
518 return 0;
520 if (!strcasecmp(action, "Minimize"))
521 return grabIconify;
522 if (!strcasecmp(action, "Raise"))
523 return grabRaise;
524 if (!strcasecmp(action, "Lower"))
525 return grabLower;
526 if (!strcasecmp(action, "Close"))
527 return grabClose;
528 if (!strcasecmp(action, "Workspace1"))
529 return grabWorkspace1;
530 if (!strcasecmp(action, "Workspace2"))
531 return grabWorkspace2;
532 if (!strcasecmp(action, "Workspace3"))
533 return grabWorkspace3;
534 if (!strcasecmp(action, "Workspace4"))
535 return grabWorkspace4;
536 if (!strcasecmp(action, "Workspace5"))
537 return grabWorkspace5;
538 if (!strcasecmp(action, "Workspace6"))
539 return grabWorkspace6;
540 if (!strcasecmp(action, "Workspace7"))
541 return grabWorkspace7;
542 if (!strcasecmp(action, "Workspace8"))
543 return grabWorkspace8;
544 if (!strcasecmp(action, "Workspace9"))
545 return grabWorkspace9;
546 if (!strcasecmp(action, "Workspace10"))
547 return grabWorkspace10;
548 if (!strcasecmp(action, "Workspace11"))
549 return grabWorkspace11;
550 if (!strcasecmp(action, "Workspace12"))
551 return grabWorkspace12;
552 if (!strcasecmp(action, "NextWorkspace"))
553 return grabNextWorkspace;
554 if (!strcasecmp(action, "PrevWorkspace"))
555 return grabPrevWorkspace;
556 if (!strcasecmp(action, "NextWindow"))
557 return grabNextWindow;
558 if (!strcasecmp(action, "PrevWindow"))
559 return grabPrevWindow;
560 if (!strcasecmp(action, "ShadeWindow"))
561 return grabShade;
562 if (!strcasecmp(action, "MaximizeWindow"))
563 return grabMaximize;
564 if (!strcasecmp(action, "StickWindow"))
565 return grabStick;
566 if (!strcasecmp(action, "ExecCommand"))
567 return grabExecute;
568 if (!strcasecmp(action, "MaximizeVertical"))
569 return grabVertMax;
570 if (!strcasecmp(action, "MaximizeHorizontal"))
571 return grabHorizMax;
572 if (!strcasecmp(action, "NudgeRight"))
573 return grabNudgeRight;
574 if (!strcasecmp(action, "NudgeLeft"))
575 return grabNudgeLeft;
576 if (!strcasecmp(action, "NudgeUp"))
577 return grabNudgeUp;
578 if (!strcasecmp(action, "NudgeDown"))
579 return grabNudgeDown;
580 if (!strcasecmp(action, "BigNudgeRight"))
581 return grabBigNudgeRight;
582 if (!strcasecmp(action, "BigNudgeLeft"))
583 return grabBigNudgeLeft;
584 if (!strcasecmp(action, "BigNudgeUp"))
585 return grabBigNudgeUp;
586 if (!strcasecmp(action, "BigNudgeDown"))
587 return grabBigNudgeDown;
588 if (!strcasecmp(action, "HorizontalIncrement"))
589 return grabHorizInc;
590 if (!strcasecmp(action, "VerticalIncrement"))
591 return grabVertInc;
592 if (!strcasecmp(action, "HorizontalDecrement"))
593 return grabHorizDec;
594 if (!strcasecmp(action, "VerticalDecrement"))
595 return grabVertDec;
596 if (!strcasecmp(action, "ToggleDecor"))
597 return grabToggleDecor;
600 return 0;
603 void ToolWindow::execCommand(char *ptrCommand)
605 int pid;
606 extern char **environ;
608 pid = fork();
609 if (pid == -1) {
610 fprintf(stderr,
611 "bbkeys: Could not fork a process for execCommand.\n");
612 return;
615 if (pid == 0) {
616 char *argv[4];
617 argv[0] = "sh";
618 argv[1] = "-c";
619 argv[2] = ptrCommand;
620 argv[3] = 0;
621 execve("/bin/sh", argv, environ);
622 exit(127);
626 void ToolWindow::setKeygrabs(void)
628 int res, pid, status;
630 pid = fork();
631 if (pid == -1) {
632 fprintf(stderr,
633 "bbkeys: Could not fork a process for configurator.\n");
634 return;
637 if (pid == 0) {
638 if (noQt) {
639 // Make 'bbkeysconf' automagically fail...
640 res = 1;
641 } else {
642 res = execlp("bbkeysconf", "bbkeysconf", NULL);
645 if (res != 0) {
646 res = execlp("bbkeysConfigGtk", "bbkeysConfigGtk", NULL);
647 if (res != 0) {
648 res =
649 execlp("rxvt", "rxvt", "-bg", "black", "-fg", "green",
650 "-e", "bbkeysConfigC", NULL);
651 if (res != 0) {
652 execlp("xterm", "xterm", "-bg", "black", "-fg",
653 "green", "-e", "bbkeysConfigC", NULL);
657 exit(0);
660 do {
661 if (waitpid(pid, &status, 0) == -1) {
662 if (errno != EINTR)
663 return;
664 } else
665 return;
666 } while (1);
670 void ToolWindow::loadKeygrabs(void)
672 // free up pointers that we get with strdup for execCommand....
673 int i = 0;
674 for (i = 0; i < grabSet.instructCount; i++) {
675 if (grabSet.KeyMap[i].execCommand != NULL) {
676 free(grabSet.KeyMap[i].execCommand);
680 /* re-initialize our grabSet count... */
681 grabSet.instructCount = 0;
683 int count = 0;
684 char line[1024];
685 char Keytograb[80];
686 char Modifier[80];
687 char action[80];
688 char execCommand[500];
689 char *KeytograbBegin;
690 char *ModifierBegin;
691 char *actionBegin;
692 char *execCmdBegin;
694 FILE *rc_file = fopen(bbkeys_rcfile, "r");
695 if (!rc_file) {
696 /* fprintf(stderr, "Can't open bbkeys rc-file (%s)\n", bbkeys_rcfile); */
697 return;
700 memset(line, '\0', 1024);
702 while (fgets(line, 1024, rc_file) && !feof(rc_file) &&
703 count < MaxInstructions) {
704 if (line[0] != '#' && strstr(line, "WithModifier")) {
706 memset(Keytograb, '\0', 80);
707 memset(Modifier, '\0', 80);
708 memset(action, '\0', 80);
709 memset(execCommand, '\0', 500);
711 KeytograbBegin = strchr(line, '(');
712 ModifierBegin = strchr(KeytograbBegin + 1, '(');
713 actionBegin = strchr(ModifierBegin + 1, '(');
715 strncat(Keytograb, KeytograbBegin + 1,
716 strcspn(KeytograbBegin + 1, ")"));
717 strncpy(Modifier, ModifierBegin + 1,
718 strcspn(ModifierBegin + 1, ")"));
719 strncpy(action, actionBegin + 1,
720 strcspn(actionBegin + 1, ")"));
722 grabSet.KeyMap[count].keycode = XKeysymToKeycode(getXDisplay(),
723 XStringToKeysym
724 (Keytograb));
726 char *k;
727 char *tmp = (char *) Modifier;
728 grabSet.KeyMap[count].modMask = 0;
729 while ((k = strchr(tmp, '+')) != NULL) {
730 *k = 0;
731 grabSet.KeyMap[count].modMask |= translateModifier(tmp);
732 tmp = k + 1;
734 grabSet.KeyMap[count].modMask |= translateModifier(tmp);
736 grabSet.KeyMap[count].action = translateAction(action);
738 /* if we're supposed to having an execCommand and we do have
739 * something to put into it */
740 if (grabSet.KeyMap[count].action == grabExecute) {
741 execCmdBegin = strchr(actionBegin + 1, '(');
742 if (execCmdBegin) {
743 strncpy(execCommand, execCmdBegin + 1,
744 strcspn(execCmdBegin + 1, ")"));
745 grabSet.KeyMap[count].execCommand =
746 strdup(execCommand);
748 } else {
749 grabSet.KeyMap[count].execCommand = NULL;
752 #ifdef DEBUG
753 fprintf(stdout, "Keysym ->%d<-, Modifier ->0x%lx<-, "
754 "action ->%d<-, execCommand ->%s<-\n",
755 grabSet.KeyMap[count].keycode,
756 grabSet.KeyMap[count].modMask,
757 grabSet.KeyMap[count].action,
758 grabSet.KeyMap[count].execCommand);
759 #endif
760 count++;
764 fclose(rc_file);
765 grabSet.instructCount = count;
766 #ifdef DEBUG
767 fprintf(stderr, "loaded ->%d<- instructions.\n", count);
768 #endif
771 /*****************************************
773 * END OF KEY GRABBING/HANDLING ROUTINES *
775 *****************************************/
777 ToolWindow::ToolWindow(int argc, char **argv, struct CMDOPTIONS *options):
778 Basewindow(argc, argv, options), TimeoutHandler()
780 timer = new BTimer(this, this);
781 timer->setTimeout(100);
782 timer->fireOnce(True);
784 char *homedir = getenv("HOME");
785 bbkeys_rcfile = new char[strlen(homedir) + 32];
786 sprintf(bbkeys_rcfile, "%s/.bbkeysrc", homedir);
788 XrmInitialize();
790 InitializeModifiers();
792 _NumLockMask = 0;
793 _ScrollLockMask = 0;
796 * Ignore CapsLock in modifiers
798 ValidModMask = 0xff & ~LockMask;
800 getOffendingModifiers();
802 * Ignore NumLock and ScrollLock too
804 ValidModMask &= ~(_NumLockMask | _ScrollLockMask);
806 // initialize it so we don't run into problems later
807 grabSet.instructCount = 0;
808 loadKeygrabs();
809 activateKeygrabs();
811 resource = new Resource(this);
812 wminterface = new WMInterface(this);
813 windowList = new LinkedList < WindowList >;
814 desktopList = new LinkedList < DesktopList >;
816 // initialize variables
817 current_desktop = NULL;
818 desktop_count = 0;
820 // make draw the bbkeys window
821 MakeWindow(False);
822 Redraw();
824 // pass control to the main loop
825 eventLoop();
828 ToolWindow::~ToolWindow()
830 XUnmapWindow(getXDisplay(), win_frame);
832 /* destroy pixmaps */
833 if (pixmap.frame)
834 getImageControl()->removeImage(pixmap.frame);
835 if (pixmap.pix_title)
836 getImageControl()->removeImage(pixmap.pix_title);
837 if (pixmap.pix_back)
838 getImageControl()->removeImage(pixmap.pix_back);
839 if (pixmap.pix_configBtn)
840 getImageControl()->removeImage(pixmap.pix_configBtn);
841 if (pixmap.pix_closeBtn)
842 getImageControl()->removeImage(pixmap.pix_closeBtn);
843 if (pixmap.pix_pressedBtn)
844 getImageControl()->removeImage(pixmap.pix_pressedBtn);
846 /* destroy windows */
847 XDestroyWindow(getXDisplay(), win_frame);
848 XDestroyWindow(getXDisplay(), win_back);
849 XDestroyWindow(getXDisplay(), win_title);
850 XDestroyWindow(getXDisplay(), win_configBtn);
851 XDestroyWindow(getXDisplay(), win_closeBtn);
853 /* destroy lists */
854 delete windowList;
855 delete desktopList;
858 void ToolWindow::reconfigure(void)
860 /* destroy pixmaps */
861 if (pixmap.frame)
862 getImageControl()->removeImage(pixmap.frame);
863 if (pixmap.pix_title)
864 getImageControl()->removeImage(pixmap.pix_title);
865 if (pixmap.pix_back)
866 getImageControl()->removeImage(pixmap.pix_back);
867 if (pixmap.pix_configBtn)
868 getImageControl()->removeImage(pixmap.pix_configBtn);
869 if (pixmap.pix_closeBtn)
870 getImageControl()->removeImage(pixmap.pix_closeBtn);
871 if (pixmap.pix_pressedBtn)
872 getImageControl()->removeImage(pixmap.pix_pressedBtn);
874 resource->Reload();
876 MakeWindow(True);
878 XClearWindow(getXDisplay(), win_frame);
879 XClearWindow(getXDisplay(), win_back);
880 Redraw();
883 void ToolWindow::MakeWindow(bool reconfigure)
885 XSetWindowAttributes attrib;
886 XWMHints wmhints;
887 XClassHint classhints;
888 XTextProperty windowname;
890 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
891 CWOverrideRedirect | CWCursor | CWEventMask;
893 // geometry for our windows...................................
895 geom_title.height = resource->label.font->ascent +
896 resource->label.font->descent + 2;
897 if (geom_title.height < 20 && (miniMe || tinyMe))
898 geom_title.height = 20;
899 geom_title.width = XTextWidth(resource->label.font, "bbkeys",
900 strlen("bbkeys")) + (geom_title.height +
902 geom_title.x = 2;
903 geom_title.y = 2;
904 geom_back.width = geom_title.width + 4;
905 geom_back.x = 0;
906 geom_back.y = 0;
907 geom_closeBtn.height = geom_title.height * 7 / 10;
908 geom_closeBtn.width = geom_closeBtn.height;
910 if (miniMe) {
912 geom_back.height = geom_title.height + 2;
913 geom_closeBtn.y = 80; /* put it out of sight. */
914 geom_closeBtn.x = 80;
915 geom_configBtn.height = geom_title.height - 1;
916 geom_configBtn.width = geom_configBtn.height;
917 geom_configBtn.x = geom_title.width - geom_configBtn.width;
918 geom_configBtn.y = geom_title.y;
920 } else if (tinyMe) {
922 geom_title.height = 22;
923 geom_title.width = 22;
924 geom_title.x = 80;
925 geom_title.y = 80;
926 geom_back.width = 22;
927 geom_back.height = 22;
928 geom_closeBtn.y = 80; /* put it out of sight. */
929 geom_closeBtn.x = 80;
930 geom_configBtn.height = 20;
931 geom_configBtn.width = geom_configBtn.height;
932 geom_configBtn.x = 1;
933 geom_configBtn.y = 1;
935 } else {
937 geom_back.height = 3 * (geom_title.height) + 6;
938 geom_closeBtn.x = geom_title.width - geom_closeBtn.width - 1;
939 geom_closeBtn.y = geom_title.y +
940 ((geom_title.height - geom_closeBtn.height) / 2);
941 geom_configBtn.height = (geom_title.height * 2);
942 geom_configBtn.width = geom_title.width - 4;
943 geom_configBtn.x = geom_title.x + 2;
944 geom_configBtn.y = geom_title.height + geom_title.y + 2;
948 frame.height = geom_back.height;
949 frame.width = geom_back.width;
950 frame.x = resource->position.x;
951 frame.y = resource->position.y;
953 // end geometry for our windows...................................
955 if (resource->position.mask & XNegative) {
956 frame.x = getCurrentScreenInfo()->getWidth() +
957 resource->position.x - frame.width;
960 if (resource->position.mask & YNegative) {
961 frame.y = getCurrentScreenInfo()->getHeight() +
962 resource->position.y - frame.height;
966 if (withdrawn) {
967 attrib.override_redirect = False;
968 wmhints.initial_state = WithdrawnState;
969 } else if (iconic) {
970 attrib.override_redirect = False;
971 wmhints.initial_state = IconicState;
972 } else {
973 attrib.override_redirect = False;
974 wmhints.initial_state = NormalState;
977 attrib.background_pixmap = ParentRelative;
979 pixmap.frame =
980 getImageControl()->renderImage(frame.width, frame.height,
981 &resource->frame.texture);
983 pixmap.pix_back =
984 getImageControl()->renderImage(geom_back.width,
985 geom_back.height,
986 &resource->frame.texture);
987 pixmap.pix_title =
988 getImageControl()->renderImage(geom_title.width, geom_title.height,
989 &resource->label.texture);
991 pixmap.pix_configBtn =
992 getImageControl()->renderImage(geom_configBtn.width,
993 geom_configBtn.height,
994 &resource->button.texture);
996 pixmap.pix_closeBtn =
997 getImageControl()->renderImage(geom_closeBtn.width,
998 geom_closeBtn.height,
999 &resource->button.texture);
1000 pixmap.pix_pressedBtn =
1001 getImageControl()->renderImage(geom_configBtn.width,
1002 geom_configBtn.height,
1003 &resource->button.texture_pressed);
1005 attrib.cursor = getSessionCursor();
1006 attrib.event_mask =
1007 ButtonPressMask | ButtonReleaseMask | ExposureMask |
1008 FocusChangeMask | KeyPressMask | StructureNotifyMask |
1009 SubstructureRedirectMask;
1011 if (!reconfigure) {
1012 win_frame = XCreateWindow(getXDisplay(),
1013 getCurrentScreenInfo()->getRootWindow(),
1014 frame.x, frame.y, frame.width,
1015 frame.height, 0,
1016 getCurrentScreenInfo()->getDepth(),
1017 InputOutput,
1018 getCurrentScreenInfo()->getVisual(),
1019 create_mask, &attrib);
1020 win_back = XCreateWindow(getXDisplay(),
1021 win_frame,
1022 geom_back.x,
1023 geom_back.y,
1024 geom_back.width,
1025 geom_back.height, 0,
1026 getCurrentScreenInfo
1027 ()->getDepth(), InputOutput,
1028 getCurrentScreenInfo
1029 ()->getVisual(), create_mask, &attrib);
1030 win_title =
1031 XCreateWindow(getXDisplay(), win_frame, geom_title.x,
1032 geom_title.y, geom_title.width,
1033 geom_title.height, 0,
1034 getCurrentScreenInfo()->getDepth(), InputOutput,
1035 getCurrentScreenInfo()->getVisual(), create_mask,
1036 &attrib);
1037 win_configBtn =
1038 XCreateWindow(getXDisplay(), win_frame, geom_configBtn.x,
1039 geom_configBtn.y, geom_configBtn.width,
1040 geom_configBtn.height, 0,
1041 getCurrentScreenInfo()->getDepth(), InputOutput,
1042 getCurrentScreenInfo()->getVisual(), create_mask,
1043 &attrib);
1044 win_closeBtn =
1045 XCreateWindow(getXDisplay(), win_frame, geom_closeBtn.x,
1046 geom_closeBtn.y, geom_closeBtn.width,
1047 geom_closeBtn.height, 0,
1048 getCurrentScreenInfo()->getDepth(), InputOutput,
1049 getCurrentScreenInfo()->getVisual(), create_mask,
1050 &attrib);
1051 } else if (!withdrawn) {
1052 XMoveResizeWindow(getXDisplay(), win_frame, frame.x, frame.y,
1053 frame.width, frame.height);
1054 XMoveResizeWindow(getXDisplay(), win_back,
1055 geom_back.x, geom_back.y,
1056 geom_back.width, geom_back.height);
1057 XMoveResizeWindow(getXDisplay(), win_title, geom_title.x,
1058 geom_title.y, geom_title.width,
1059 geom_title.height);
1060 XMoveResizeWindow(getXDisplay(), win_configBtn, geom_configBtn.x,
1061 geom_configBtn.y, geom_configBtn.width,
1062 geom_configBtn.height);
1063 XMoveResizeWindow(getXDisplay(), win_closeBtn, geom_closeBtn.x,
1064 geom_closeBtn.y, geom_closeBtn.width,
1065 geom_closeBtn.height);
1067 } else {
1068 XResizeWindow(getXDisplay(), win_frame, frame.width, frame.height);
1069 XResizeWindow(getXDisplay(), win_back,
1070 geom_back.width, geom_back.height);
1071 XResizeWindow(getXDisplay(), win_title, geom_title.width,
1072 geom_title.height);
1073 XMoveResizeWindow(getXDisplay(), win_configBtn, geom_configBtn.x,
1074 geom_configBtn.y, geom_configBtn.width,
1075 geom_configBtn.height);
1076 XMoveResizeWindow(getXDisplay(), win_closeBtn, geom_closeBtn.x,
1077 geom_closeBtn.y, geom_closeBtn.width,
1078 geom_closeBtn.height);
1081 char *name = BBTOOL;
1082 XSizeHints sizehints;
1084 wmhints.flags = StateHint;
1086 classhints.res_name = BBTOOL;
1087 classhints.res_class = "bbtools";
1089 sizehints.x = frame.x; //getResource()->position.x;
1090 sizehints.y = frame.y; //getResource()->position.y;
1092 sizehints.max_width = sizehints.min_width = frame.width;
1093 sizehints.max_height = sizehints.min_height = frame.height;
1094 sizehints.flags = USPosition | PMinSize | PMaxSize;
1096 XStringListToTextProperty(&name, 1, &windowname);
1097 XSetWMProperties(getXDisplay(), win_frame, &windowname, NULL, getArgv(),
1098 getArgc(), &sizehints, &wmhints, &classhints);
1100 // free up allocated memory in XStringListToTextProperty
1101 XFree(windowname.value);
1103 if (!reconfigure) {
1104 Atom wmproto[2];
1105 wmproto[0] = wm_delete_window;
1106 wmproto[1] = getBlackboxStructureMessagesAtom();
1107 XSetWMProtocols(getXDisplay(), win_frame, wmproto, 2);
1110 if (!decorated && !withdrawn) {
1111 BlackboxHints net_hints;
1112 net_hints.decoration = DecorNone;
1113 net_hints.attrib = AttribOmnipresent;
1114 net_hints.flags = AttribDecoration | AttribOmnipresent;
1115 XChangeProperty(getXDisplay(), win_frame, getBlackboxHintsAtom(),
1116 getBlackboxHintsAtom(), 32, PropModeReplace,
1117 (unsigned char *) &net_hints,
1118 PropBlackboxHintsElements);
1121 if (!shape) {
1122 XSetWindowBackgroundPixmap(getXDisplay(), win_frame, pixmap.frame);
1125 XSetWindowBackgroundPixmap(getXDisplay(), win_title, pixmap.pix_title);
1126 XSetWindowBackgroundPixmap(getXDisplay(), win_back, pixmap.pix_back);
1127 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1128 pixmap.pix_configBtn);
1129 XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
1130 pixmap.pix_closeBtn);
1133 if (!withdrawn && resource->report.auto_raise)
1134 XRaiseWindow(getXDisplay(), win_frame);
1136 if (!reconfigure) {
1137 gcv.font = resource->label.font->fid;
1138 gcv.foreground = resource->label.textColor.getPixel();
1139 frameGC =
1140 XCreateGC(getXDisplay(), win_frame, GCFont | GCForeground,
1141 &gcv);
1142 } else {
1143 gcv.font = resource->label.font->fid;
1144 gcv.foreground = resource->label.textColor.getPixel();
1145 XChangeGC(getXDisplay(), frameGC, GCFont | GCForeground, &gcv);
1149 if (!reconfigure) {
1150 XClearWindow(getXDisplay(), win_frame);
1151 XMapWindow(getXDisplay(), win_frame);
1152 XMapSubwindows(getXDisplay(), win_frame);
1153 XSetIconName(getXDisplay(), win_frame, "bbkeys");
1157 void ToolWindow::Redraw()
1159 XClearWindow(getXDisplay(), win_title);
1160 XClearWindow(getXDisplay(), win_configBtn);
1161 XClearWindow(getXDisplay(), win_closeBtn);
1163 char *title = "bbkeys";
1164 XDrawString(getXDisplay(), win_title, frameGC, geom_title.x - 1,
1165 (geom_title.height + resource->label.font->ascent -
1166 resource->label.font->descent) / 2, title, strlen(title));
1168 XPoint pts[3];
1170 if (miniMe || tinyMe) {
1171 pts[0].x = (geom_configBtn.width / 2);
1172 pts[0].y = (geom_configBtn.height / 2) - 2;
1173 pts[1].x = -(geom_configBtn.width / 4);
1174 pts[1].y = (geom_configBtn.height - pts[0].y) - 1;
1175 pts[2].x = (geom_configBtn.width / 2);
1176 pts[2].y = 0;
1178 XFillPolygon(getXDisplay(), win_configBtn, frameGC, pts, 3,
1179 Convex, CoordModePrevious);
1180 XFillArc(getXDisplay(), win_configBtn, frameGC,
1181 geom_configBtn.width / 2 - geom_configBtn.width / 4, 1, // x, y
1182 geom_configBtn.width / 2, geom_configBtn.height / 2, //width,height
1183 0, 360 * 64);
1184 } else {
1185 pts[0].x = (geom_configBtn.width / 2);
1186 pts[0].y = (geom_configBtn.height / 2) - 2;
1187 pts[1].x = -(geom_configBtn.width / 4);
1188 pts[1].y = (geom_configBtn.height - pts[0].y) - 2;
1189 pts[2].x = (geom_configBtn.width / 2);
1190 pts[2].y = 0;
1192 XFillPolygon(getXDisplay(), win_configBtn, frameGC, pts, 3,
1193 Convex, CoordModePrevious);
1194 XFillArc(getXDisplay(), win_configBtn, frameGC,
1195 geom_configBtn.width / 2 - geom_configBtn.width / 4, 1, // x, y
1196 geom_configBtn.width / 2, geom_configBtn.height * 5 / 8, //width,height
1197 0, 360 * 64);
1200 /* Our little close button (drawn twice for a nice thickness) */
1201 XDrawLine(getXDisplay(), win_closeBtn, frameGC, 1, 1,
1202 geom_closeBtn.width - 2, geom_closeBtn.height - 1);
1203 XDrawLine(getXDisplay(), win_closeBtn, frameGC, 1,
1204 geom_closeBtn.height - 1, geom_closeBtn.width - 2, 1);
1206 XDrawLine(getXDisplay(), win_closeBtn, frameGC, 2, 1,
1207 geom_closeBtn.width - 1, geom_closeBtn.height - 1);
1208 XDrawLine(getXDisplay(), win_closeBtn, frameGC, 2,
1209 geom_closeBtn.height - 1, geom_closeBtn.width - 1, 1);
1213 void ToolWindow::process_event(XEvent * e)
1215 switch (e->type) {
1216 case PropertyNotify:
1217 // blah();
1218 break;
1220 case KeyPress: {
1221 int i = 0;
1222 int grabInt = -1;
1223 Window fw_root, fw_child;
1224 int fw_y, fw_x;
1225 unsigned int fw_w, fw_h, fw_b, fw_d;
1227 /* Need to take out this next bit when nyz has 0.60.0 ready, as
1228 we'll then get our focus_window in a ClientMessage */
1229 int revert_to = RevertToPointerRoot;
1230 if (!focus_window) {
1231 XGetInputFocus(getXDisplay(), &focus_window, &revert_to);
1234 /* end temporary focus_window fix */
1236 if (focus_window && focus_window != (int)PointerRoot ) {
1237 XGetGeometry(getXDisplay(), focus_window, &fw_root, &fw_x,
1238 &fw_y, &fw_w, &fw_h, &fw_b, &fw_d);
1239 XTranslateCoordinates(getXDisplay(), focus_window, fw_root,
1240 fw_x, fw_y, &fw_x, &fw_y, &fw_child);
1243 // if our user wants to grab his keystrokes, even though one
1244 // or more of the Lock-Modifiers are pressed, alter the mask
1247 // to make this possible....
1249 if (!honor_modifiers) {
1250 e->xkey.state &= ~_NumLockMask & ~_ScrollLockMask & ~LockMask;
1253 for (i = 0; i < grabSet.instructCount; i++) {
1254 if ((e->xkey.keycode == grabSet.KeyMap[i].keycode) &&
1255 (e->xkey.state == grabSet.KeyMap[i].modMask)) {
1256 grabInt = i;
1257 break;
1261 if (grabInt > -1) {
1262 /* play with colors for nyz =:) */
1263 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1264 pixmap.pix_pressedBtn);
1265 Redraw();
1267 switch (grabSet.KeyMap[grabInt].action) {
1268 case grabIconify:
1269 if (focus_window && focus_window != (int)PointerRoot ) {
1270 XIconifyWindow(getXDisplay(), focus_window, 0);
1272 break;
1274 case grabRaise:
1275 if (focus_window && focus_window != (int)PointerRoot ) {
1276 XRaiseWindow(getXDisplay(), focus_window);
1278 break;
1280 case grabLower:
1281 if (focus_window && focus_window != (int)PointerRoot ) {
1282 XLowerWindow(getXDisplay(), focus_window);
1284 break;
1286 case grabClose:
1287 if (!focus_window)
1288 break;
1290 XEvent ce;
1291 ce.xclient.type = ClientMessage;
1292 ce.xclient.message_type = getWMProtocolsAtom();
1293 ce.xclient.display = getXDisplay();
1294 ce.xclient.window = focus_window;
1295 ce.xclient.format = 32;
1296 ce.xclient.data.l[0] = getWMDeleteAtom();
1297 ce.xclient.data.l[1] = CurrentTime;
1298 ce.xclient.data.l[2] = ce.xclient.data.l[3] =
1299 ce.xclient.data.l[4] = 0l;
1301 XSendEvent(getXDisplay(), focus_window, False, NoEventMask, &ce);
1302 break;
1304 case grabWorkspace1:
1305 wminterface->changeDesktop(0);
1306 break;
1308 case grabWorkspace2:
1309 wminterface->changeDesktop(1);
1310 break;
1312 case grabWorkspace3:
1313 wminterface->changeDesktop(2);
1314 break;
1316 case grabWorkspace4:
1317 wminterface->changeDesktop(3);
1318 break;
1320 case grabWorkspace5:
1321 wminterface->changeDesktop(4);
1322 break;
1324 case grabWorkspace6:
1325 wminterface->changeDesktop(5);
1326 break;
1328 case grabWorkspace7:
1329 wminterface->changeDesktop(6);
1330 break;
1332 case grabWorkspace8:
1333 wminterface->changeDesktop(7);
1334 break;
1336 case grabWorkspace9:
1337 wminterface->changeDesktop(8);
1338 break;
1340 case grabWorkspace10:
1341 wminterface->changeDesktop(9);
1342 break;
1344 case grabWorkspace11:
1345 wminterface->changeDesktop(10);
1346 break;
1348 case grabWorkspace12:
1349 wminterface->changeDesktop(11);
1350 break;
1352 case grabNextWorkspace:
1353 if (current_desktop->number < (desktop_count-1))
1354 wminterface->changeDesktop(current_desktop->number + 1);
1355 else
1356 wminterface->changeDesktop(0);
1357 break;
1359 case grabPrevWorkspace:
1360 if (current_desktop->number > 0)
1361 wminterface->changeDesktop(current_desktop->number - 1);
1362 else
1363 wminterface->changeDesktop(desktop_count - 1);
1364 break;
1366 case grabNextWindow:
1367 cycleWindowFocus(True);
1368 break;
1370 case grabPrevWindow:
1371 cycleWindowFocus(False);
1372 break;
1374 case grabShade:
1375 if (focus_window && focus_window != (int)PointerRoot ) {
1376 wminterface->shadeWindow(focus_window);
1378 break;
1380 case grabStick:
1381 if (focus_window && focus_window != (int)PointerRoot ) {
1382 wminterface->stickWindow(focus_window);
1384 break;
1386 case grabExecute:
1387 execCommand(grabSet.KeyMap[grabInt].execCommand);
1388 break;
1390 case grabMaximize:
1391 if (focus_window && focus_window != (int)PointerRoot ) {
1392 wminterface->maximizeWindow(focus_window, True, True);
1394 break;
1396 case grabVertMax:
1397 if (focus_window && focus_window != (int)PointerRoot ) {
1398 wminterface->maximizeWindow(focus_window, False, True);
1400 break;
1402 case grabHorizMax:
1403 if (focus_window && focus_window != (int)PointerRoot ) {
1404 wminterface->maximizeWindow(focus_window, True, False);
1406 break;
1408 case grabNudgeRight:
1409 if (focus_window && focus_window != (int)PointerRoot ) {
1410 XMoveWindow(getXDisplay(), focus_window, fw_x + 1, fw_y);
1412 break;
1414 case grabNudgeLeft:
1415 if (focus_window && focus_window != (int)PointerRoot ) {
1416 XMoveWindow(getXDisplay(), focus_window, fw_x - 1, fw_y);
1418 break;
1420 case grabNudgeUp:
1421 if (focus_window && focus_window != (int)PointerRoot ) {
1422 XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y - 1);
1424 break;
1426 case grabNudgeDown:
1427 if (focus_window && focus_window != (int)PointerRoot ) {
1428 XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y + 1);
1430 break;
1432 case grabBigNudgeRight:
1433 if (focus_window && focus_window != (int)PointerRoot ) {
1434 XMoveWindow(getXDisplay(), focus_window, fw_x + 10, fw_y);
1436 break;
1438 case grabBigNudgeLeft:
1439 if (focus_window && focus_window != (int)PointerRoot ) {
1440 XMoveWindow(getXDisplay(), focus_window, fw_x - 10, fw_y);
1442 break;
1444 case grabBigNudgeUp:
1445 if (focus_window && focus_window != (int)PointerRoot ) {
1446 XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y - 10);
1448 break;
1450 case grabBigNudgeDown:
1451 if (focus_window && focus_window != (int)PointerRoot ) {
1452 XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y + 10);
1454 break;
1456 case grabHorizInc:
1457 if (focus_window && focus_window != (int)PointerRoot ) {
1458 XWindowAttributes foo;
1459 XGetWindowAttributes(getXDisplay(), focus_window, &foo);
1460 XResizeWindow(getXDisplay(), focus_window,
1461 foo.width + 10, foo.height);
1463 break;
1465 case grabVertInc:
1466 if (focus_window && focus_window != (int)PointerRoot ) {
1467 XWindowAttributes foo;
1468 XGetWindowAttributes(getXDisplay(), focus_window, &foo);
1469 XResizeWindow(getXDisplay(), focus_window,
1470 foo.width, foo.height + 10);
1472 break;
1474 case grabHorizDec:
1475 if (focus_window && focus_window != (int)PointerRoot ) {
1476 XWindowAttributes foo;
1477 XGetWindowAttributes(getXDisplay(), focus_window, &foo);
1478 if (foo.width < 11)
1479 foo.width = 11;
1480 XResizeWindow(getXDisplay(), focus_window,
1481 foo.width - 10, foo.height);
1483 break;
1485 case grabVertDec:
1486 if (focus_window && focus_window != (int)PointerRoot ) {
1487 XWindowAttributes foo;
1488 XGetWindowAttributes(getXDisplay(), focus_window, &foo);
1489 if (foo.height < 11)
1490 foo.height = 11;
1491 XResizeWindow(getXDisplay(), focus_window,
1492 foo.width, foo.height - 10);
1494 break;
1496 case grabToggleDecor:
1497 if (focus_window && focus_window != (int)PointerRoot ) {
1498 wminterface->decorateToggleWindow(focus_window);
1500 break;
1503 timer->start();
1504 break;
1507 case ClientMessage:
1508 if ((unsigned) e->xclient.data.l[0] == wm_delete_window)
1509 shutdown();
1510 wminterface->handleNETEvents(*e);
1511 break;
1513 case Expose:
1514 if (!e->xexpose.count)
1515 reconfigure();
1516 break;
1518 case ButtonPress:
1519 if (e->xbutton.button == LEFT_BUTTON
1520 || e->xbutton.button == RIGHT_BUTTON) {
1521 if (e->xbutton.window == win_configBtn) {
1522 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1523 pixmap.pix_pressedBtn);
1524 Redraw();
1525 } else if (e->xbutton.window == win_closeBtn) {
1526 XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
1527 pixmap.pix_pressedBtn);
1528 Redraw();
1529 } else if (e->xbutton.window == win_title) {
1530 // if (!raised)
1531 XRaiseWindow(getXDisplay(), win_frame);
1532 // raised = True;
1534 } else if (e->xbutton.button == MIDDLE_BUTTON) {
1535 // if (raised)
1536 XLowerWindow(getXDisplay(), win_frame);
1537 // raised = False;
1539 break;
1541 case ButtonRelease:
1542 if (e->xbutton.button == LEFT_BUTTON
1543 || e->xbutton.button == RIGHT_BUTTON) {
1544 if (e->xbutton.window == win_configBtn) {
1545 if ((e->xbutton.x > 0)
1546 && (e->xbutton.x < geom_configBtn.width)
1547 && (e->xbutton.y > 0)
1548 && (e->xbutton.y < geom_configBtn.height)) {
1549 if (grabSet.instructCount > 0) {
1550 XUngrabKey(getXDisplay(), AnyKey, AnyModifier,
1551 getScreenInfo(0)->getRootWindow());
1552 XSync(getXDisplay(), False);
1554 setKeygrabs();
1556 // discard all XEvents (was causing us to go bananas on the
1557 // user before, since we were executing all keygrabs at once
1558 // that the user did when the configuration app was running)
1559 // *cough* undocumented feature *cough*
1562 XEvent event;
1563 while (XPending(getXDisplay())) {
1564 XNextEvent(getXDisplay(), &event);
1567 // carry on then, little soldier
1569 loadKeygrabs();
1570 activateKeygrabs();
1571 timer->start();
1574 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1575 pixmap.pix_configBtn);
1576 Redraw();
1577 } else if (e->xbutton.window == win_closeBtn) {
1578 if ((e->xbutton.x > 0)
1579 && (e->xbutton.x < geom_closeBtn.width)
1580 && (e->xbutton.y > 0)
1581 && (e->xbutton.y < geom_closeBtn.height)) {
1582 if (e->xbutton.button == LEFT_BUTTON) {
1583 shutdown();
1584 } else if (e->xbutton.button == RIGHT_BUTTON) {
1585 if (withdrawn) {
1586 XUnmapWindow(getXDisplay(), win_frame);
1587 withdrawn = False;
1588 iconic = True;
1590 XWMHints wmhints;
1591 wmhints.initial_state = IconicState;
1592 wmhints.flags = StateHint;
1593 XSetWMHints(getXDisplay(), win_frame, &wmhints);
1594 XMapWindow(getXDisplay(), win_frame);
1596 // this should work but doesn't seem to. *shrug*
1597 // reconfigure();
1598 } else {
1599 XIconifyWindow(getXDisplay(), win_frame, 0);
1603 XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
1604 pixmap.pix_configBtn);
1605 Redraw();
1608 break;
1610 case ConfigureNotify:
1611 if ((e->xconfigure.window == win_frame) && e->xconfigure.send_event) {
1612 if (withdrawn)
1613 reconfigure();
1615 int parent_x, parent_y;
1616 Window parent_root;
1617 unsigned int parent_width, parent_height, parent_border_width;
1618 unsigned int parent_depth;
1620 if (withdrawn) {
1621 XGetGeometry(getXDisplay(), e->xconfigure.above,
1622 &parent_root, &parent_x, &parent_y,
1623 &parent_width, &parent_height,
1624 &parent_border_width, &parent_depth);
1625 frame.x = e->xconfigure.x + parent_x;
1626 frame.y = e->xconfigure.y + parent_y;
1629 break;
1633 void ToolWindow::timeout(void)
1635 XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
1636 pixmap.pix_configBtn);
1637 Redraw();
1640 /*--------------------------------*/
1642 /*- window modifying functions -*/
1644 /*--------------------------------*/
1646 void ToolWindow::raiseWindow(Window win)
1650 void ToolWindow::lowerWindow(Window win)
1654 /*---------------------------------------*/
1656 /*- desktop list management functions -*/
1658 /*---------------------------------------*/
1660 void ToolWindow::addDesktop(void)
1662 DesktopList *tmp = new DesktopList;
1664 // get the highest in the list
1665 int highest = -1;
1666 LinkedListIterator<DesktopList> it(desktopList);
1667 for (; it.current(); it++)
1668 if (it.current()->number > highest) {
1669 highest = it.current()->number;
1670 it.reset();
1672 tmp->number = highest + 1;
1674 desktopList->insert(tmp, -1); // add to the end of the list
1676 desktop_count++;
1678 // add sticky windows to this desktop
1679 LinkedListIterator<WindowList> it_win(windowList);
1680 for (; it_win.current(); it_win++)
1681 // only look for sticky windows on desktop 0, this will give us one
1682 // copy of each sticky window
1683 if ((it_win.current()->desktop == 0) && (it_win.current()->sticky)) {
1684 WindowList *win = new WindowList;
1685 win->win = it_win.current()->win;
1686 win->iconic = it_win.current()->iconic;
1687 win->shaded = False;
1688 win->sticky = True;
1689 win->desktop = tmp->number;
1690 windowList->insert(win, -1); // add to the end of the list
1694 void ToolWindow::removeDesktop(int desktop)
1696 LinkedListIterator<DesktopList> it(desktopList);
1697 LinkedListIterator<WindowList> it_win(windowList);
1699 // remove sticky windows from this desktop
1700 for (; it_win.current(); it_win++)
1701 if ((it_win.current()->desktop == desktop)
1702 && (it_win.current()->sticky))
1703 windowList->remove(it_win.current()); // remove just this window
1704 // removeWindow() would remove all
1705 // of the sticky windows.
1707 // remove the desktop from the linked list
1708 for (; it.current(); it++)
1709 if (it.current()->number == desktop) {
1710 desktopList->remove(it.current());
1711 break;
1714 desktop_count--;
1716 // shift the rest to fill in the hole if not the last desktop was rm'd
1717 int check=0;
1718 bool found;
1719 do {
1720 found=False;
1721 it.reset();
1722 for (; it.current(); it++)
1723 if (it.current()->number == check) {
1724 ++check;
1725 found=True;
1727 } while (found);
1729 // check is on the new hole, or desktop_count if there is no hole
1730 // plug the hole by moving all the desktops above down one
1731 while (check < desktop_count) {
1732 it.reset();
1733 for (; it.current(); it++)
1734 if(it.current()->number == (check + 1)) {
1735 it.current()->number = check++;
1736 break;
1741 void ToolWindow::focusDesktop(int desktop)
1743 LinkedListIterator<DesktopList> it(desktopList);
1744 for (; it.current(); it++)
1745 if (it.current()->number == desktop)
1746 current_desktop = it.current();
1749 void ToolWindow::setDesktopCount(int count)
1751 int oldcount = desktop_count;
1752 int delta = count - oldcount;
1754 if (delta > 0) { // added desktops
1755 while(delta-- > 0)
1756 addDesktop();
1758 else { // removed desktops
1759 while(delta++ < 0)
1760 removeDesktop(desktop_count - 1); // remove the last desktop
1764 /*--------------------------------------*/
1766 /*- window list management functions -*/
1768 /*--------------------------------------*/
1770 void ToolWindow::addWindow(Window win, int desktop)
1772 int index = 0; // where the new window will be placed (defaults to the
1773 // top of the list)
1774 int i;
1775 WindowList *newwin = new WindowList;
1776 newwin->win = win;
1777 newwin->iconic = wminterface->isIconicState(win);
1778 newwin->shaded = False;
1779 newwin->sticky = False;
1780 newwin->desktop = desktop;
1781 // insert after the focused window
1782 LinkedListIterator<WindowList> it(windowList);
1783 for (i=0; i<windowList->count(); i++) {
1784 it.set(i);
1785 if ((it.current()->win == focus_window)
1786 && (it.current()->desktop == desktop)) {
1787 // get the index of the focused window
1788 index = i;
1789 break;
1792 windowList->insert(newwin, index);
1795 void ToolWindow::removeWindow(Window win)
1797 LinkedListIterator<WindowList> it(windowList);
1798 for (; it.current(); it++)
1799 if (it.current()->win == win) {
1800 windowList->remove(it.current());
1804 void ToolWindow::focusWindow(Window win)
1806 focus_window = win;
1809 void ToolWindow::moveWinToDesktop(Window win, int desktop)
1811 LinkedListIterator<WindowList> it(windowList);
1812 for (; it.current(); it++)
1813 if (it.current()->win == win) {
1814 if (!it.current()->sticky) {
1815 it.current()->desktop = desktop;
1817 break;
1821 void ToolWindow::windowAttributeChange(Window win)
1825 void ToolWindow::cycleWindowFocus(bool forward)
1827 /*******************************************
1828 This does the oldschool straight rotation
1829 order of cycling windows.
1830 ********************************************/
1831 int desktop = -1;
1832 bool found = False;
1833 WindowList *next = NULL;
1834 int i, max;
1836 LinkedListIterator<WindowList> it(windowList);
1837 max = windowList->count();
1838 for (i=0; i<max; i++) {
1839 if (forward)
1840 it.set(i);
1841 else
1842 it.set(max-1-i);
1843 if (found) {
1844 // find the window after the focused one
1845 if (it.current()->desktop == desktop) {
1846 next = it.current();
1847 break;
1850 if (it.current()->win == focus_window) {
1851 found = True;
1852 desktop = it.current()->desktop;
1855 // if the next window wasn't found, start over at the beginning once more
1856 if (!next)
1858 for (i=0; i<max; i++) {
1859 if (forward)
1860 it.set(i);
1861 else
1862 it.set(max-1-i);
1863 if (it.current()->desktop == desktop) {
1864 next = it.current();
1865 break;
1870 if (next) {
1871 wminterface->setWindowFocus(next->win);
1872 XRaiseWindow(getXDisplay(), next->win);