Logo Search packages:      
Sourcecode: bbkeys version File versions

bbkeys.cc

// bbkeys.cc for blackbox
// ------ note from the Gee-I'm-Sorry-The-Code-Looks-Ugly department-----
// ------ for vi users-- ":set ts=2"      =:)
//
//    Copyright (c) 1999-2001 by Jason Kasper (vanRijn) vR@movingparts.net
//    Copyright (c) 2001 by Ben Jansens <xor@orodu.net>
//
//    This program is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program; if not, write to the Free Software
//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// (See the included file COPYING / GPL-2.0)
//
// $Id: bbkeys.cc,v 1.36 2002/10/15 19:23:16 vanrijn Exp $

#ifdef            HAVE_CONFIG_H
#      include "config.h"
#endif

#ifdef            HAVE_STDIO_H
#      include <stdio.h>
#endif                                                      // HAVE_STDIO_H

#ifdef            HAVE_CTYPE_H
#      include <ctype.h>
#endif                                                      // HAVE_CTYPE_H

#ifdef            STDC_HEADERS
#      include <stdlib.h>
#      include <string.h>
#endif                                                      // STDC_HEADERS

#if HAVE_STRINGS_H
# include <strings.h>
#endif

#ifdef            HAVE_SYS_TYPES_H
#      include <sys/types.h>
#endif                                                      // HAVE_SYS_TYPES_H

#ifdef            HAVE_SYS_WAIT_H
#      include <sys/wait.h>
#endif                                                      // HAVE_SYS_WAIT_H

#ifdef            HAVE_ERRNO_H
#      include <errno.h>
#endif                                                      // HAVE_ERRNO_H

#ifdef            HAVE_UNISTD_H
#      include <unistd.h>
#endif                                                      // HAVE_UNISTD_H

#ifdef            HAVE_SYS_STAT_H
#      include <sys/stat.h>
#endif                                                      // HAVE_SYS_STAT_H

extern "C" {
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/keysym.h>
}

#include "bbkeys.hh"
#include "stackmenu.hh"
#include "resource.hh"
#include "main.hh"
#include "Timer.hh"
#include "Basemenu.hh"
#include "wminterface.hh"

#include <string>

using std::string;

/*--------------------------------------------------------------------*/

/* Ripped shamelessly from wmaker's xmodifier.c--converted for our use*/

/*--------------------------------------------------------------------*/

/* Grok X modifier mappings for shortcuts.
       
       Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
       The copyright(s) from the original XEmacs code are included below.

       Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */

/* The event_stream interface for X11 with Xt, and/or tty frames.
       Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
       Copyright (C) 1995 Sun Microsystems, Inc.
       Copyright (C) 1996 Ben Wing.

This file is part of XEmacs.

XEmacs is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

XEmacs is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with XEmacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.    */

/************************************************************************/

/*                                                                                  keymap handling                                                                                 */

/************************************************************************/

/* X bogusly doesn't define the interpretations of any bits besides
       ModControl, ModShift, and ModLock; so the Interclient Communication
       Conventions Manual says that we have to bend over backwards to figure
       out what the other modifier bits mean.    According to ICCCM:

       - Any keycode which is assigned ModControl is a "control" key.

       - Any modifier bit which is assigned to a keycode which generates Meta_L
             or Meta_R is the modifier bit meaning "meta".  Likewise for Super, Hyper,
             etc.

       - Any keypress event which contains ModControl in its state should be
             interpreted as a "control" character.

       - Any keypress event which contains a modifier bit in its state which is
             generated by a keycode whose corresponding keysym is Meta_L or Meta_R
             should be interpreted as a "meta" character.    Likewise for Super, Hyper,
             etc.

       - It is illegal for a keysym to be associated with more than one modifier
             bit.

       This means that the only thing that emacs can reasonably interpret as a
       "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
       one of the modifier bits Mod1-Mod5.

       Unfortunately, many keyboards don't have Meta keys in their default
       configuration.    So, if there are no Meta keys, but there are "Alt" keys,
       emacs will interpret Alt as Meta.  If there are both Meta and Alt keys,
       then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
       mean "Symbol," but that just confused the hell out of way too many people).

       This works with the default configurations of the 19 keyboard-types I've
       checked.

       Emacs detects keyboard configurations which violate the above rules, and
       prints an error message on the standard-error-output.      (Perhaps it should
       use a pop-up-window instead.)
 */

static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
static int NumLockMask, ScrollLockMask;

const char *ToolWindow::index_to_name(int indice)
{
       switch (indice) {
       case ShiftMapIndex:
                  return "ModShift";
       case LockMapIndex:
                  return "ModLock";
       case ControlMapIndex:
                  return "ModControl";
       case Mod1MapIndex:
                  return "Mod1";
       case Mod2MapIndex:
                  return "Mod2";
       case Mod3MapIndex:
                  return "Mod3";
       case Mod4MapIndex:
                  return "Mod4";
       case Mod5MapIndex:
                  return "Mod5";
       default:
                  return "???";
       }
}

void ToolWindow::x_reset_modifier_mapping(Display * d)
{
       int modifier_index, modifier_key, column, mkpm;
       int warned_about_overlapping_modifiers = 0;
       int warned_about_predefined_modifiers = 0;
       int warned_about_duplicate_modifiers = 0;
       int meta_bit = 0;
       int hyper_bit = 0;
       int super_bit = 0;
       int alt_bit = 0;
       int mode_bit = 0;
       int num_lock_bit = 0;
       int scroll_lock_bit = 0;
       XModifierKeymap *x_modifier_keymap = XGetModifierMapping(d);

#define modwarn(name,old,other)                                               \
      warned_about_overlapping_modifiers = 1

#define modbarf(name,other)                                             \
      warned_about_predefined_modifiers = 1

#define check_modifier(name,mask)                                       \
            warned_about_predefined_modifiers = 1

#define store_modifier(name,old)                                   \
      if (old && old != modifier_index)                                  \
            warned_about_duplicate_modifiers = 1;                              \
      if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift");          \
      else if (modifier_index == LockMapIndex) modbarf (name,"ModLock");             \
      else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
      else if (sym == XK_Mode_switch)                                    \
            mode_bit = modifier_index; /* Mode_switch is special, see below... */    \
      else if (modifier_index == meta_bit && old != meta_bit)                  \
            modwarn (name, meta_bit, "Meta");                                  \
      else if (modifier_index == super_bit && old != super_bit)                \
            modwarn (name, super_bit, "Super");                                \
      else if (modifier_index == hyper_bit && old != hyper_bit)                \
            modwarn (name, hyper_bit, "Hyper");                                \
      else if (modifier_index == alt_bit && old != alt_bit)                    \
            modwarn (name, alt_bit, "Alt");                                    \
      else                                                         \
            old = modifier_index;

       mkpm = x_modifier_keymap->max_keypermod;
       for (modifier_index = 0; modifier_index < 8; modifier_index++)
                  for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
                        KeySym last_sym = 0;
                        for (column = 0; column < 4; column += 2) {
                               KeyCode code =
                                          x_modifier_keymap->modifiermap[modifier_index * mkpm +
                                                                                                      modifier_key];
                               KeySym sym =
                                          (code ? XKeycodeToKeysym(d, code, column) : 0);
                               if (sym == last_sym)
                                          continue;
                               last_sym = sym;
                               switch (sym) {
                               case XK_Mode_switch:
                                          store_modifier("Mode_switch", mode_bit);
                                          break;
                               case XK_Meta_L:
                                          store_modifier("Meta_L", meta_bit);
                                          break;
                               case XK_Meta_R:
                                          store_modifier("Meta_R", meta_bit);
                                          break;
                               case XK_Super_L:
                                          store_modifier("Super_L", super_bit);
                                          break;
                               case XK_Super_R:
                                          store_modifier("Super_R", super_bit);
                                          break;
                               case XK_Hyper_L:
                                          store_modifier("Hyper_L", hyper_bit);
                                          break;
                               case XK_Hyper_R:
                                          store_modifier("Hyper_R", hyper_bit);
                                          break;
                               case XK_Alt_L:
                                          store_modifier("Alt_L", alt_bit);
                                          break;
                               case XK_Alt_R:
                                          store_modifier("Alt_R", alt_bit);
                                          break;
                               case XK_Num_Lock:
                                          store_modifier("Num_Lock", num_lock_bit);
                                          break;
                               case XK_Scroll_Lock:
                                          store_modifier("Scroll_Lock", scroll_lock_bit);
                                          break;
                               case XK_Control_L:
                                          check_modifier("Control_L", ControlMask);
                                          break;
                               case XK_Control_R:
                                          check_modifier("Control_R", ControlMask);
                                          break;
                               case XK_Shift_L:
                                          check_modifier("Shift_L", ShiftMask);
                                          break;
                               case XK_Shift_R:
                                          check_modifier("Shift_R", ShiftMask);
                                          break;
                               case XK_Shift_Lock:
                                          check_modifier("Shift_Lock", LockMask);
                                          break;
                               case XK_Caps_Lock:
                                          check_modifier("Caps_Lock", LockMask);
                                          break;

                                          /* It probably doesn't make any sense for a modifier bit to be
                                                 assigned to a key that is not one of the above, but OpenWindows
                                                 assigns modifier bits to a couple of random function keys for
                                                 no reason that I can discern, so printing a warning here would
                                                 be annoying. */
                               }
                        }
                  }
#undef store_modifier
#undef check_modifier
#undef modwarn
#undef modbarf

       /* If there was no Meta key, then try using the Alt key instead.
                  If there is both a Meta key and an Alt key, then the Alt key
                  is not disturbed and remains an Alt key. */
       if (!meta_bit && alt_bit)
                  meta_bit = alt_bit, alt_bit = 0;

       /* mode_bit overrides everything, since it's processed down inside of
                  XLookupString() instead of by us.    If Meta and Mode_switch both
                  generate the same modifier bit (which is an error), then we don't
                  interpret that bit as Meta, because we can't make XLookupString()
                  not interpret it as Mode_switch; and interpreting it as both would
                  be totally wrong. */
       if (mode_bit) {
                  const char *warn = 0;
                  if (mode_bit == meta_bit)
                        warn = "Meta", meta_bit = 0;
                  else if (mode_bit == hyper_bit)
                        warn = "Hyper", hyper_bit = 0;
                  else if (mode_bit == super_bit)
                        warn = "Super", super_bit = 0;
                  else if (mode_bit == alt_bit)
                        warn = "Alt", alt_bit = 0;
                  if (warn) {
                        warned_about_overlapping_modifiers = 1;
                  }
       }

       MetaMask = (meta_bit ? (1 << meta_bit) : 0);
       HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
       SuperMask = (super_bit ? (1 << super_bit) : 0);
       AltMask = (alt_bit ? (1 << alt_bit) : 0);
       ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
       NumLockMask = (num_lock_bit ? (1 << num_lock_bit) : 0);
       ScrollLockMask = (scroll_lock_bit ? (1 << scroll_lock_bit) : 0);

       if (x_modifier_keymap)
                  XFreeModifiermap(x_modifier_keymap);
}


int ToolWindow::translateModifier(char *key)
{
       if (strcasecmp(key, "SHIFT") == 0 && ShiftMask != 0)
                  return ShiftMask;
       else if (strcasecmp(key, "CONTROL") == 0 && ControlMask != 0)
                  return ControlMask;
       else if (strcasecmp(key, "ALT") == 0 && AltMask != 0)
                  return AltMask;
       else if (strcasecmp(key, "META") == 0 && MetaMask != 0)
                  return MetaMask;
       else if (strcasecmp(key, "SUPER") == 0 && SuperMask != 0)
                  return SuperMask;
       else if (strcasecmp(key, "HYPER") == 0 && HyperMask != 0)
                  return HyperMask;
       else if (strcasecmp(key, "MOD1") == 0 && Mod1Mask != 0)
                  return Mod1Mask;
       else if (strcasecmp(key, "MOD2") == 0 && Mod2Mask != 0)
                  return Mod2Mask;
       else if (strcasecmp(key, "MOD3") == 0 && Mod3Mask != 0)
                  return Mod3Mask;
       else if (strcasecmp(key, "MOD4") == 0 && Mod4Mask != 0)
                  return Mod4Mask;
       else if (strcasecmp(key, "MOD5") == 0 && Mod5Mask != 0)
                  return Mod5Mask;
       else if (strcasecmp(key, "NONE") == 0)
                  return None;
       else
                  return -1;
}

/* Wrapper so that we may fit our naming conventions, yet leave the 
       original XEmacs function name in place. */
void ToolWindow::InitializeModifiers(void)
{
       x_reset_modifier_mapping(getXDisplay());
}

/*-----------------------------------------------------------------------*/

/*-- end of shameless rip.    thank you for your support                                              ---*/

/*-----------------------------------------------------------------------*/

void ToolWindow::CheckConfig()
{
       struct stat file_status;

       if (stat(bbkeys_rcfile, &file_status) != 0) {
#ifdef DEBUG
                  fprintf(stderr, "Could not open config file ->%s<-\n",
                               bbkeys_rcfile);
#endif
       } else if (file_status.st_mtime != bbkeys_rcTime) {
                  bbkeys_rcTime = file_status.st_mtime;
                  loadKeygrabs();
                  activateKeygrabs();
       }
}

void ToolWindow::activateKeygrabs(void)
{
       int i = 0;

       if (grabSet.instructCount > 0)
                  XUngrabKey(getXDisplay(), AnyKey, AnyModifier,
                                     getCurrentScreenInfo()->getRootWindow());
       for (i = 0; i < grabSet.instructCount; i++) {
                  if (grabSet.KeyMap[i].keycode == 0)
                        continue;

                  if (grabSet.KeyMap[i].keycode != AnyModifier) {
                        XGrabKey(getXDisplay(), grabSet.KeyMap[i].keycode,
                                          grabSet.KeyMap[i].modMask | LockMask,
                                          getCurrentScreenInfo()->getRootWindow(), True,
                                          GrabModeAsync, GrabModeAsync);

                        /* Also grab all modifier combinations possible that include,
                         * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
                         * work even if the NumLock/ScrollLock key is on.
                         */

                        wHackedGrabKey(grabSet.KeyMap[i].keycode,
                                                      grabSet.KeyMap[i].modMask,
                                                      getCurrentScreenInfo()->getRootWindow(), True,
                                                      GrabModeAsync, GrabModeAsync);
                  }

                  XGrabKey(getXDisplay(), grabSet.KeyMap[i].keycode,
                                    grabSet.KeyMap[i].modMask,
                                    getCurrentScreenInfo()->getRootWindow(), True,
                                    GrabModeAsync, GrabModeAsync);
       }
}

/*---------------------------------------------------------------------------*/

/*--  Snarfed shamelessly from WindowMaker's code-base once again....                --*/

/*---------------------------------------------------------------------------*/
void ToolWindow::wHackedGrabKey(int keycode, unsigned int modifiers,
                                                                  Window grab_window, Bool owner_events,
                                                                  int pointer_mode, int keyboard_mode)
{
       if (modifiers == AnyModifier)
                  return;
       if (keycode == AnyKey)
                  return;

       /* grab all combinations of the modifier with CapsLock, NumLock and
            * ScrollLock. How much memory/CPU does such a monstrosity consume
            * in the server?
            */
       if (_NumLockMask) {
                  XGrabKey(getXDisplay(), keycode, modifiers | _NumLockMask,
                                    grab_window, owner_events, pointer_mode, keyboard_mode);
       }
       if (_ScrollLockMask) {
                  XGrabKey(getXDisplay(), keycode, modifiers | _ScrollLockMask,
                                    grab_window, owner_events, pointer_mode, keyboard_mode);
       }
       if (_NumLockMask && _ScrollLockMask) {
                  XGrabKey(getXDisplay(), keycode,
                                    modifiers | _NumLockMask | _ScrollLockMask, grab_window,
                                    owner_events, pointer_mode, keyboard_mode);
       }
       if (_NumLockMask) {
                  XGrabKey(getXDisplay(), keycode,
                                    modifiers | _NumLockMask | LockMask, grab_window,
                                    owner_events, pointer_mode, keyboard_mode);
       }
       if (_ScrollLockMask) {
                  XGrabKey(getXDisplay(), keycode,
                                    modifiers | _ScrollLockMask | LockMask, grab_window,
                                    owner_events, pointer_mode, keyboard_mode);
       }
       if (_NumLockMask && _ScrollLockMask) {
                  XGrabKey(getXDisplay(), keycode,
                                    modifiers | _NumLockMask | _ScrollLockMask | LockMask,
                                    grab_window, owner_events, pointer_mode, keyboard_mode);
       }
       /* phew, I guess that's all, right? */
}

void ToolWindow::getOffendingModifiers(void)
{
       int i;
       XModifierKeymap *modmap;
       KeyCode nlock, slock;
       static int mask_table[8] = {
                  ShiftMask, LockMask, ControlMask, Mod1Mask,
                  Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
       };

       nlock = XKeysymToKeycode(getXDisplay(), XK_Num_Lock);
       slock = XKeysymToKeycode(getXDisplay(), XK_Scroll_Lock);

       /*
            * Find out the masks for the NumLock and ScrollLock modifiers,
            * so that we can bind the grabs for when they are enabled too.
            */
       modmap = XGetModifierMapping(getXDisplay());

       if (modmap != NULL && modmap->max_keypermod > 0) {
                  for (i = 0; i < 8 * modmap->max_keypermod; i++) {
                        if (modmap->modifiermap[i] == nlock && nlock != 0)
                               _NumLockMask = mask_table[i / modmap->max_keypermod];
                        else if (modmap->modifiermap[i] == slock && slock != 0)
                               _ScrollLockMask = mask_table[i / modmap->max_keypermod];
                  }
       }

       if (modmap)
                  XFreeModifiermap(modmap);
}

/*-------------------------------------------------------------------------*/

/*--  End of shameful code-snarf.....................................          --*/

/*-------------------------------------------------------------------------*/

int ToolWindow::translateAction(char *action)
{
       if (!action)
                  return 0;

       if (!strcasecmp(action, "Minimize"))
                  return grabIconify;
       if (!strcasecmp(action, "Raise"))
                  return grabRaise;
       if (!strcasecmp(action, "Lower"))
                  return grabLower;
       if (!strcasecmp(action, "Close"))
                  return grabClose;
       if (!strcasecmp(action, "Workspace1"))
                  return grabWorkspace1;
       if (!strcasecmp(action, "Workspace2"))
                  return grabWorkspace2;
       if (!strcasecmp(action, "Workspace3"))
                  return grabWorkspace3;
       if (!strcasecmp(action, "Workspace4"))
                  return grabWorkspace4;
       if (!strcasecmp(action, "Workspace5"))
                  return grabWorkspace5;
       if (!strcasecmp(action, "Workspace6"))
                  return grabWorkspace6;
       if (!strcasecmp(action, "Workspace7"))
                  return grabWorkspace7;
       if (!strcasecmp(action, "Workspace8"))
                  return grabWorkspace8;
       if (!strcasecmp(action, "Workspace9"))
                  return grabWorkspace9;
       if (!strcasecmp(action, "Workspace10"))
                  return grabWorkspace10;
       if (!strcasecmp(action, "Workspace11"))
                  return grabWorkspace11;
       if (!strcasecmp(action, "Workspace12"))
                  return grabWorkspace12;
       if (!strcasecmp(action, "NextWorkspace"))
                  return grabNextWorkspace;
       if (!strcasecmp(action, "PrevWorkspace"))
                  return grabPrevWorkspace;
       if (!strcasecmp(action, "UpWorkspace"))
                  return grabUpWorkspace;
       if (!strcasecmp(action, "DownWorkspace"))
                  return grabDownWorkspace;
       if (!strcasecmp(action, "LeftWorkspace"))
                  return grabLeftWorkspace;
       if (!strcasecmp(action, "RightWorkspace"))
                  return grabRightWorkspace;
       if (!strcasecmp(action, "NextWindow"))
                  return grabNextWindow;
       if (!strcasecmp(action, "PrevWindow"))
                  return grabPrevWindow;
       if (!strcasecmp(action, "NextWindowAllWorkspaces"))
                  return grabNextWindowAllWorkspaces;
       if (!strcasecmp(action, "ShadeWindow"))
                  return grabShade;
       if (!strcasecmp(action, "MaximizeWindow"))
                  return grabMaximize;
       if (!strcasecmp(action, "StickWindow"))
                  return grabStick;
       if (!strcasecmp(action, "ExecCommand"))
                  return grabExecute;
       if (!strcasecmp(action, "MaximizeVertical"))
                  return grabVertMax;
       if (!strcasecmp(action, "MaximizeHorizontal"))
                  return grabHorizMax;
       if (!strcasecmp(action, "NudgeRight"))
                  return grabNudgeRight;
       if (!strcasecmp(action, "NudgeLeft"))
                  return grabNudgeLeft;
       if (!strcasecmp(action, "NudgeUp"))
                  return grabNudgeUp;
       if (!strcasecmp(action, "NudgeDown"))
                  return grabNudgeDown;
       if (!strcasecmp(action, "BigNudgeRight"))
                  return grabBigNudgeRight;
       if (!strcasecmp(action, "BigNudgeLeft"))
                  return grabBigNudgeLeft;
       if (!strcasecmp(action, "BigNudgeUp"))
                  return grabBigNudgeUp;
       if (!strcasecmp(action, "BigNudgeDown"))
                  return grabBigNudgeDown;
       if (!strcasecmp(action, "HorizontalIncrement"))
                  return grabHorizInc;
       if (!strcasecmp(action, "VerticalIncrement"))
                  return grabVertInc;
       if (!strcasecmp(action, "HorizontalDecrement"))
                  return grabHorizDec;
       if (!strcasecmp(action, "VerticalDecrement"))
                  return grabVertDec;
       if (!strcasecmp(action, "ToggleDecor"))
                  return grabToggleDecor;


       return 0;
}

void ToolWindow::execCommand(char *const ptrCommand)
{
      int pid;
      extern char **environ;

      pid = fork();
      if (pid == -1) {
            fprintf(stderr,
                                    "bbkeys: Could not fork a process for execCommand.\n");
            return;
      }

      if (pid == 0) {
            const char *const argv[] = {
      "sh",
      "-c",
      ptrCommand,
      0
    };
            execve("/bin/sh", (char *const *)argv, environ);
            exit(127);
      }
}

void ToolWindow::setKeygrabs(void)
{
      int res, pid;

      pid = fork();

      if (pid == -1) {
            fprintf(stderr,
            "bbkeys: Could not fork a process for configurator.\n");
            return;
      }
      
      if (pid == 0) {
            if (noQt) {
                  // Make 'bbconf' automagically fail...
                  res = 1;
            } else {
                  string ost = (string)"keybindings:loadfile=" + bbkeys_rcfile;
                  
                  res = execlp("bbconf", "bbconf", "--start-plugin", "key bindings", 
                        "--args", ost.c_str(), NULL);
                  
            }
            
            if (res != 0) {
                  string ost = (string)"bbkeysconf.pl -rcfile " + bbkeys_rcfile;

                  res = execlp("rxvt", "rxvt", "-bg", "black", "-fg", "green",
                        "-e", "sh", "-c", ost.c_str(), NULL);
                  if (res != 0) {
                        execlp("xterm", "xterm", "-bg", "black", "-fg", "green", 
                              "-e", "sh", "-c", ost.c_str(), NULL);
                  }
            }
            exit(0);
      }

}

void ToolWindow::loadKeygrabs(void)
{
       // free up pointers that we get with strdup for execCommand....
       for (register int i = 0; i < grabSet.instructCount; i++) {
                  if (grabSet.KeyMap[i].execCommand != NULL) {
                        free(grabSet.KeyMap[i].execCommand);
                  }
       }
       memset(&actionList, 0, sizeof(actionList));

       /* re-initialize our grabSet count... */
       grabSet.instructCount = 0;

       int count = 0;
       char line[1024];
       char Keytograb[80];
       char Modifier[80];
       char action[80];
       char execCommand[500];
       char *KeytograbBegin;
       char *ModifierBegin;
       char *actionBegin;
       char *execCmdBegin;

       FILE *rc_file = fopen(bbkeys_rcfile, "r");
       if (!rc_file) {
                  fprintf(stderr, "\nDanger!!!  Warning Will Robinson!!!\n"
                        "I can't open your bbkeys rc-file (%s).\n"
                        "Hmm.  That means I don't have anything to do. Please run \n"
                        "the bbkeys configurator of your choice (click my keyhole) \n"
                        "to allow me to do stuff for ya.  \n"
                        "'Cause otherwise, I just sit here feeling sad....\n\n" 
                        , bbkeys_rcfile);
                  return;
       }

       memset(line, '\0', 1024);

       while (fgets(line, 1024, rc_file) && !feof(rc_file) &&
                        count < MaxInstructions) {
                  if (line[0] != '#' && strstr(line, "WithModifier")) {

                        memset(Keytograb, '\0', 80);
                        memset(Modifier, '\0', 80);
                        memset(action, '\0', 80);
                        memset(execCommand, '\0', 500);

                        KeytograbBegin = strchr(line, '(');
                        ModifierBegin = strchr(KeytograbBegin + 1, '(');
                        actionBegin = strchr(ModifierBegin + 1, '(');

                        strncat(Keytograb, KeytograbBegin + 1,
                                          strcspn(KeytograbBegin + 1, ")"));
                        strncpy(Modifier, ModifierBegin + 1,
                                          strcspn(ModifierBegin + 1, ")"));
                        strncpy(action, actionBegin + 1,
                                          strcspn(actionBegin + 1, ")"));

                        grabSet.KeyMap[count].keycode = XKeysymToKeycode(getXDisplay(),
                                                                                                                         XStringToKeysym
                                                                                                                         (Keytograb));

                        char *k;
                        char *tmp = (char *) Modifier;
                        grabSet.KeyMap[count].modMask = 0;
                        while ((k = strchr(tmp, '+')) != NULL) {
                               *k = 0;
                               grabSet.KeyMap[count].modMask |= translateModifier(tmp);
                               tmp = k + 1;
                        }
                        grabSet.KeyMap[count].modMask |= translateModifier(tmp);

                        grabSet.KeyMap[count].action = translateAction(action);
                        // save off a cross-reference for action->grabSet.KeyMap[index]
                        actionList[grabSet.KeyMap[count].action] = count;

                        /* if we're supposed to having an execCommand and we do have
                         * something to put into it                                                                                                   */
                        if (grabSet.KeyMap[count].action == grabExecute) {
                               execCmdBegin = strchr(actionBegin + 1, '(');
                               if (execCmdBegin) {
                                          strncpy(execCommand, execCmdBegin + 1,
                                                       strrchr(execCmdBegin, ')') - execCmdBegin - 1);
                                          grabSet.KeyMap[count].execCommand =
                                                strdup(execCommand);
                               }
                        } else {
                               grabSet.KeyMap[count].execCommand = NULL;
                        }

#ifdef DEBUG
                        fprintf(stdout, "Keysym ->%d<-, Modifier ->0x%lx<-, "
                                          "action ->%d<-, execCommand ->%s<-\n",
                                          grabSet.KeyMap[count].keycode,
                                          grabSet.KeyMap[count].modMask,
                                          grabSet.KeyMap[count].action,
                                          grabSet.KeyMap[count].execCommand);
#endif
                        count++;

                  }
       }
       fclose(rc_file);
       grabSet.instructCount = count;
#ifdef DEBUG
       fprintf(stderr, "loaded ->%d<- instructions.\n", count);
#endif
}

/*****************************************
 *                                                                                                                 *
 * END OF KEY GRABBING/HANDLING ROUTINES *
 *                                                                                                                 *
 *****************************************/

ToolWindow::ToolWindow(int argc, char **argv, struct CMDOPTIONS *options):
                  Basewindow(argc, argv, options), TimeoutHandler()
{
      timer = new BTimer(this, this);
      timer->setTimeout(100);
      timer->fireOnce(True);
      
      if (!(options->bbkeysrc)){
            char *homedir = getenv("HOME");
            bbkeys_rcfile = new char[strlen(homedir) + 32];
            sprintf(bbkeys_rcfile, "%s/.bbkeysrc", homedir);
      } else {
            bbkeys_rcfile = options->bbkeysrc;
      }

      XrmInitialize();

      InitializeModifiers();

      _NumLockMask = 0;
      _ScrollLockMask = 0;

      /*
       * Ignore CapsLock in modifiers
       */
      ValidModMask = 0xff & ~LockMask;

      getOffendingModifiers();
      /*
       * Ignore NumLock and ScrollLock too
       */
      ValidModMask &= ~(_NumLockMask | _ScrollLockMask);

      // initialize it so we don't run into problems later
      grabSet.instructCount = 0;
      loadKeygrabs();
      activateKeygrabs();

      resource = new Resource(this);
      wminterface = new WMInterface(this);
      windowList = new LinkedList < WindowList >;
      desktopList = new LinkedList < DesktopList >;

      // initialize variables
      current_desktop = NULL;
      desktop_count = 0;
      doingCycling = False;
      
      // make draw the bbkeys window
      MakeWindow(False);
      Redraw();
      
      // pass control to the main loop
      eventLoop();
}

ToolWindow::~ToolWindow()
{
      XUnmapWindow(getXDisplay(), win_frame);

      /* destroy pixmaps */
      if (pixmap.frame)
            getImageControl()->removeImage(pixmap.frame);
      if (pixmap.pix_title)
            getImageControl()->removeImage(pixmap.pix_title);
      if (pixmap.pix_back)
            getImageControl()->removeImage(pixmap.pix_back);
      if (pixmap.pix_configBtn)
            getImageControl()->removeImage(pixmap.pix_configBtn);
      if (pixmap.pix_closeBtn)
            getImageControl()->removeImage(pixmap.pix_closeBtn);
      if (pixmap.pix_pressedBtn)
            getImageControl()->removeImage(pixmap.pix_pressedBtn);

      /* destroy windows */
      XDestroyWindow(getXDisplay(), win_frame);
      XDestroyWindow(getXDisplay(), win_back);
      XDestroyWindow(getXDisplay(), win_title);
      XDestroyWindow(getXDisplay(), win_configBtn);
      XDestroyWindow(getXDisplay(), win_closeBtn);

      /* destroy GC's */
      if (frameGC) XFreeGC(getXDisplay(),frameGC);
  if (menuGC) XFreeGC(getXDisplay(),menuGC);
      if (menuHiBGGC) XFreeGC(getXDisplay(),menuHiBGGC);
      if (menuHiGC) XFreeGC(getXDisplay(),menuHiGC);
      if (menuFrameGC) XFreeGC(getXDisplay(),menuFrameGC);


      /* destroy lists */
      delete windowList;
      delete desktopList;
}

void ToolWindow::reconfigure(void)
{
      /* destroy pixmaps */
      if (pixmap.frame)
            getImageControl()->removeImage(pixmap.frame);
      if (pixmap.pix_title)
            getImageControl()->removeImage(pixmap.pix_title);
      if (pixmap.pix_back)
            getImageControl()->removeImage(pixmap.pix_back);
      if (pixmap.pix_configBtn)
            getImageControl()->removeImage(pixmap.pix_configBtn);
      if (pixmap.pix_closeBtn)
            getImageControl()->removeImage(pixmap.pix_closeBtn);
      if (pixmap.pix_pressedBtn)
            getImageControl()->removeImage(pixmap.pix_pressedBtn);

      resource->Reload();
      MakeWindow(True);

      stackMenu->reconfigure();

      XClearWindow(getXDisplay(), win_frame);
      XClearWindow(getXDisplay(), win_back);
      Redraw();
}

void ToolWindow::MakeWindow(bool reconfigure)
{
       XSetWindowAttributes attrib;
       XWMHints wmhints;
       XClassHint classhints;
       XTextProperty windowname;

       unsigned long create_mask = CWBackPixmap | CWBorderPixel |
                  CWOverrideRedirect | CWCursor | CWEventMask;

       // geometry for our windows...................................

       geom_title.height = resource->label.font->ascent +
                  resource->label.font->descent + 2;
       if (geom_title.height < 20 && (miniMe || tinyMe))
                  geom_title.height = 20;
       geom_title.width = XTextWidth(resource->label.font, "bbkeys",
                                                                   strlen("bbkeys")) + (geom_title.height +
                                                                                                             5);
       geom_title.x = 2;
       geom_title.y = 2;
       geom_back.width = geom_title.width + 4;
       geom_back.x = 0;
       geom_back.y = 0;
       geom_closeBtn.height = geom_title.height * 7 / 10;
       geom_closeBtn.width = geom_closeBtn.height;

       if (miniMe) {

                  geom_back.height = geom_title.height + 2;
                  geom_closeBtn.y = 80;         /* put it out of sight. */
                  geom_closeBtn.x = 80;
                  geom_configBtn.height = geom_title.height - 1;
                  geom_configBtn.width = geom_configBtn.height;
                  geom_configBtn.x = geom_title.width - geom_configBtn.width;
                  geom_configBtn.y = geom_title.y;

       } else if (tinyMe) {

                  geom_title.height = 22;
                  geom_title.width = 22;
                  geom_title.x = 80;
                  geom_title.y = 80;
                  geom_back.width = 22;
                  geom_back.height = 22;
                  geom_closeBtn.y = 80;         /* put it out of sight. */
                  geom_closeBtn.x = 80;
                  geom_configBtn.height = 20;
                  geom_configBtn.width = geom_configBtn.height;
                  geom_configBtn.x = 1;
                  geom_configBtn.y = 1;

       } else {

                  geom_back.height = 3 * (geom_title.height) + 6;
                  geom_closeBtn.x = geom_title.width - geom_closeBtn.width - 1;
                  geom_closeBtn.y = geom_title.y +
                        ((geom_title.height - geom_closeBtn.height) / 2);
                  geom_configBtn.height = (geom_title.height * 2);
                  geom_configBtn.width = geom_title.width - 4;
                  geom_configBtn.x = geom_title.x + 2;
                  geom_configBtn.y = geom_title.height + geom_title.y + 2;

       }

       frame.height = geom_back.height;
       frame.width = geom_back.width;
       frame.x = resource->position.x;
       frame.y = resource->position.y;

       // end geometry for our windows...................................

       if (resource->position.mask & XNegative) {
                  frame.x = getCurrentScreenInfo()->getWidth() +
                        resource->position.x - frame.width;
       }

       if (resource->position.mask & YNegative) {
                  frame.y = getCurrentScreenInfo()->getHeight() +
                        resource->position.y - frame.height;

       }

       if (withdrawn) {
                  attrib.override_redirect = False;
                  wmhints.initial_state = WithdrawnState;
       } else if (iconic) {
                  attrib.override_redirect = False;
                  wmhints.initial_state = IconicState;
       } else {
                  attrib.override_redirect = False;
                  wmhints.initial_state = NormalState;
       }

       attrib.background_pixmap = ParentRelative;

       pixmap.frame =
                  getImageControl()->renderImage(frame.width, frame.height,
                                                                              &resource->frame.texture);

       pixmap.pix_back =
                  getImageControl()->renderImage(geom_back.width,
                                                                              geom_back.height,
                                                                              &resource->frame.texture);
       pixmap.pix_title =
                  getImageControl()->renderImage(geom_title.width, geom_title.height,
                                                                              &resource->label.texture);

       pixmap.pix_configBtn =
                  getImageControl()->renderImage(geom_configBtn.width,
                                                                              geom_configBtn.height,
                                                                              &resource->button.texture);

       pixmap.pix_closeBtn =
                  getImageControl()->renderImage(geom_closeBtn.width,
                                                                              geom_closeBtn.height,
                                                                              &resource->button.texture);
       pixmap.pix_pressedBtn =
                  getImageControl()->renderImage(geom_configBtn.width,
                                                                              geom_configBtn.height,
                                                                              &resource->button.texture_pressed);

       attrib.cursor = getSessionCursor();
       attrib.event_mask =
                  ButtonPressMask | ButtonReleaseMask | ExposureMask |
                  FocusChangeMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask |
                  SubstructureRedirectMask;

       if (!reconfigure) {
                  win_frame = XCreateWindow(getXDisplay(),
                                                                  getCurrentScreenInfo()->getRootWindow(),
                                                                  frame.x, frame.y, frame.width,
                                                                  frame.height, 0,
                                                                  getCurrentScreenInfo()->getDepth(),
                                                                  InputOutput,
                                                                  getCurrentScreenInfo()->getVisual(),
                                                                  create_mask, &attrib);
                  win_back = XCreateWindow(getXDisplay(),
                                                                  win_frame,
                                                                  geom_back.x,
                                                                  geom_back.y,
                                                                  geom_back.width,
                                                                  geom_back.height, 0,
                                                                  getCurrentScreenInfo
                                                                  ()->getDepth(), InputOutput,
                                                                  getCurrentScreenInfo
                                                                  ()->getVisual(), create_mask, &attrib);
                  win_title =
                        XCreateWindow(getXDisplay(), win_frame, geom_title.x,
                                                      geom_title.y, geom_title.width,
                                                      geom_title.height, 0,
                                                      getCurrentScreenInfo()->getDepth(), InputOutput,
                                                      getCurrentScreenInfo()->getVisual(), create_mask,
                                                      &attrib);
                  win_configBtn =
                        XCreateWindow(getXDisplay(), win_frame, geom_configBtn.x,
                                                      geom_configBtn.y, geom_configBtn.width,
                                                      geom_configBtn.height, 0,
                                                      getCurrentScreenInfo()->getDepth(), InputOutput,
                                                      getCurrentScreenInfo()->getVisual(), create_mask,
                                                      &attrib);
                  win_closeBtn =
                        XCreateWindow(getXDisplay(), win_frame, geom_closeBtn.x,
                                                      geom_closeBtn.y, geom_closeBtn.width,
                                                      geom_closeBtn.height, 0,
                                                      getCurrentScreenInfo()->getDepth(), InputOutput,
                                                      getCurrentScreenInfo()->getVisual(), create_mask,
                                                      &attrib);
       } else if (!withdrawn) {
                  XMoveResizeWindow(getXDisplay(), win_frame, frame.x, frame.y,
                                                      frame.width, frame.height);
                  XMoveResizeWindow(getXDisplay(), win_back,
                                                      geom_back.x, geom_back.y,
                                                      geom_back.width, geom_back.height);
                  XMoveResizeWindow(getXDisplay(), win_title, geom_title.x,
                                                      geom_title.y, geom_title.width,
                                                      geom_title.height);
                  XMoveResizeWindow(getXDisplay(), win_configBtn, geom_configBtn.x,
                                                      geom_configBtn.y, geom_configBtn.width,
                                                      geom_configBtn.height);
                  XMoveResizeWindow(getXDisplay(), win_closeBtn, geom_closeBtn.x,
                                                      geom_closeBtn.y, geom_closeBtn.width,
                                                      geom_closeBtn.height);

       } else {
                  XResizeWindow(getXDisplay(), win_frame, frame.width, frame.height);
                  XResizeWindow(getXDisplay(), win_back,
                                           geom_back.width, geom_back.height);
                  XResizeWindow(getXDisplay(), win_title, geom_title.width,
                                           geom_title.height);
                  XMoveResizeWindow(getXDisplay(), win_configBtn, geom_configBtn.x,
                                                      geom_configBtn.y, geom_configBtn.width,
                                                      geom_configBtn.height);
                  XMoveResizeWindow(getXDisplay(), win_closeBtn, geom_closeBtn.x,
                                                      geom_closeBtn.y, geom_closeBtn.width,
                                                      geom_closeBtn.height);
       }

       char *name = (char *)BBTOOL;
       XSizeHints sizehints;

       wmhints.flags = StateHint;

       classhints.res_name = (char *)BBTOOL;
       classhints.res_class = (char *)"bbtools";

       sizehints.x = frame.x;             //getResource()->position.x;
       sizehints.y = frame.y;             //getResource()->position.y;

       sizehints.max_width = sizehints.min_width = frame.width;
       sizehints.max_height = sizehints.min_height = frame.height;
       sizehints.flags = USPosition | PMinSize | PMaxSize;

       XStringListToTextProperty(&name, 1, &windowname);
       XSetWMProperties(getXDisplay(), win_frame, &windowname, NULL, getArgv(),
                                          getArgc(), &sizehints, &wmhints, &classhints);

       // free up allocated memory in XStringListToTextProperty
       XFree(windowname.value);

       if (!reconfigure) {
                  Atom wmproto[2];
                  wmproto[0] = wm_delete_window;
                  wmproto[1] = getBlackboxStructureMessagesAtom();
                  XSetWMProtocols(getXDisplay(), win_frame, wmproto, 2);
       }

       if (!decorated && !withdrawn) {
                  BlackboxHints net_hints;
                  net_hints.decoration = DecorNone;
                  net_hints.attrib = AttribOmnipresent;
                  net_hints.flags = AttribDecoration | AttribOmnipresent;
                  XChangeProperty(getXDisplay(), win_frame, getBlackboxHintsAtom(),
                                                getBlackboxHintsAtom(), 32, PropModeReplace,
                                                (unsigned char *) &net_hints,
                                                PropBlackboxHintsElements);
       }

       if (!shape) {
                  XSetWindowBackgroundPixmap(getXDisplay(), win_frame, pixmap.frame);
       }

       XSetWindowBackgroundPixmap(getXDisplay(), win_title, pixmap.pix_title);
       XSetWindowBackgroundPixmap(getXDisplay(), win_back, pixmap.pix_back);
       XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
                                                             pixmap.pix_configBtn);
       XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
                                                             pixmap.pix_closeBtn);


      if (!reconfigure) {
            gcv.font = resource->label.font->fid;
            gcv.foreground = resource->label.textColor.getPixel();
            frameGC =
                        XCreateGC(getXDisplay(), win_frame, GCFont | GCForeground, &gcv);

            gcv.font = resource->menu.font->fid;                        
      gcv.foreground = resource->menu.texture.getColor()->getPixel();
        menuGC = XCreateGC(getXDisplay(), win_frame,GCFont|GCForeground, &gcv);

        gcv.foreground = resource->menu.highlightColor.getPixel();
    gcv.arc_mode = ArcChord;
            gcv.fill_style = FillSolid;
            menuHiBGGC = XCreateGC(getXDisplay(), win_frame,GCForeground|
                           GCFillStyle|GCArcMode, &gcv);

        gcv.foreground = resource->menu.hiTextColor.getPixel();                           
        menuHiGC = XCreateGC(getXDisplay(), win_frame, GCFont|GCForeground, &gcv);

        gcv.foreground = resource->menu.textColor.getPixel();                       
            menuFrameGC = XCreateGC(getXDisplay(), win_frame,GCFont|GCForeground, &gcv);

            stackMenu = new Stackmenu(this);
            stackMenu->update();
      } else {
            gcv.font = resource->label.font->fid;
            gcv.foreground = resource->label.textColor.getPixel();
            XChangeGC(getXDisplay(), frameGC, GCFont | GCForeground, &gcv);

            gcv.font = resource->menu.font->fid;                        
      gcv.foreground = resource->menu.texture.getColor()->getPixel();
            XChangeGC(getXDisplay(), menuGC, GCFont | GCForeground, &gcv);

        gcv.foreground = resource->menu.highlightColor.getPixel();
            XChangeGC(getXDisplay(), menuHiBGGC, GCFont | GCForeground, &gcv);

        gcv.foreground = resource->menu.hiTextColor.getPixel();                           
            XChangeGC(getXDisplay(), menuHiGC, GCFont | GCForeground, &gcv);

        gcv.foreground = resource->menu.textColor.getPixel();                       
            XChangeGC(getXDisplay(), menuFrameGC, GCFont | GCForeground, &gcv);

       }


       if (!reconfigure) {
                  XClearWindow(getXDisplay(), win_frame);
                  XMapWindow(getXDisplay(), win_frame);
                  XMapSubwindows(getXDisplay(), win_frame);
                  XSetIconName(getXDisplay(), win_frame, "bbkeys");
       }
}

void ToolWindow::Redraw()
{
      XClearWindow(getXDisplay(), win_title);
      XClearWindow(getXDisplay(), win_configBtn);
      XClearWindow(getXDisplay(), win_closeBtn);

      char *title = (char *)"bbkeys";
      XDrawString(getXDisplay(), win_title, frameGC, geom_title.x - 1,
                  (geom_title.height + resource->label.font->ascent -
                  resource->label.font->descent) / 2, title, strlen(title));

      XPoint pts[3];

      if (miniMe || tinyMe) {
            pts[0].x = (geom_configBtn.width / 2);
            pts[0].y = (geom_configBtn.height / 2) - 2;
            pts[1].x = -(geom_configBtn.width / 4);
            pts[1].y = (geom_configBtn.height - pts[0].y) - 1;
            pts[2].x = (geom_configBtn.width / 2);
            pts[2].y = 0;

            XFillPolygon(getXDisplay(), win_configBtn, frameGC, pts, 3,
                        Convex, CoordModePrevious);
            XFillArc(getXDisplay(), win_configBtn, frameGC,
                        geom_configBtn.width / 2 - geom_configBtn.width / 4, 1, // x, y
                        geom_configBtn.width / 2, geom_configBtn.height / 2,        //width,height
                        0, 360 * 64);
      } else {
            pts[0].x = (geom_configBtn.width / 2);
            pts[0].y = (geom_configBtn.height / 2) - 2;
            pts[1].x = -(geom_configBtn.width / 4);
            pts[1].y = (geom_configBtn.height - pts[0].y) - 2;
            pts[2].x = (geom_configBtn.width / 2);
            pts[2].y = 0;

            XFillPolygon(getXDisplay(), win_configBtn, frameGC, pts, 3,
                        Convex, CoordModePrevious);
            XFillArc(getXDisplay(), win_configBtn, frameGC,
                        geom_configBtn.width / 2 - geom_configBtn.width / 4, 1,           // x, y
                        geom_configBtn.width / 2, geom_configBtn.height * 5 / 8,    //width,height
                        0, 360 * 64);
      }

      /* Our little close button (drawn twice for a nice thickness) */
      XDrawLine(getXDisplay(), win_closeBtn, frameGC, 1, 1,
                  geom_closeBtn.width - 2, geom_closeBtn.height - 1);
      XDrawLine(getXDisplay(), win_closeBtn, frameGC, 1,
                  geom_closeBtn.height - 1, geom_closeBtn.width - 2, 1);

      XDrawLine(getXDisplay(), win_closeBtn, frameGC, 2, 1,
            geom_closeBtn.width - 1, geom_closeBtn.height - 1);
      XDrawLine(getXDisplay(), win_closeBtn, frameGC, 2,
                  geom_closeBtn.height - 1, geom_closeBtn.width - 1, 1);

}

unsigned int ToolWindow::KeycodeToModmask(unsigned int code)
{
      switch (XKeycodeToKeysym(getXDisplay(), code, 0)) {
            case XK_Shift_L:
            case XK_Shift_R:
                  return ShiftMask;

            case XK_Caps_Lock:
            case XK_Shift_Lock:
                  return LockMask;

            case XK_Control_L:
            case XK_Control_R:
                  return ControlMask;

            case XK_Alt_L:
            case XK_Alt_R:
      return AltMask ? AltMask : MetaMask;

            case XK_Num_Lock:
      return NumLockMask;

            case XK_Super_L:
            case XK_Super_R:
      return SuperMask;

            case XK_Hyper_L:
            case XK_Hyper_R:
      return HyperMask;

            case XK_Meta_L:
            case XK_Meta_R:
      return MetaMask;

            case XK_Scroll_Lock:
      return ScrollLockMask;
      }
      return (unsigned int)-1;
}


void ToolWindow::findFramePosition(Window window, int &x, int &y) {
  Window win = window, parent, root, last = None;
  Window *children = 0;
  unsigned int nchildren;
  int gravity, top, bottom, left, right;
  XWindowAttributes wattr;
  XSizeHints size;
  long ret;
  unsigned int cwidth, cheight;
  
  // get the location, size and gravity of the client window
  if (! XGetWindowAttributes(getXDisplay(), window, &wattr)) return;
  cwidth = wattr.width;
  cheight = wattr.height;
  if (! XGetWMNormalHints(getXDisplay(), window, &size, &ret)) return;
  if (size.flags & PWinGravity)
    gravity = size.win_gravity;
  else
    gravity = NorthWestGravity;
    
  while (XQueryTree(getXDisplay(), win, &root, &parent, &children,
                    &nchildren)) {
    if (children && nchildren > 0)
      XFree(children); // don't care about the children

    if (! parent) // no parent!?
      return;

    // if the parent window is the root window, stop here
    if (parent == root)
      break;

    last = win;
    win = parent;
  }

  if (! (XTranslateCoordinates(getXDisplay(), last, win, 0, 0, &left, &top,
                               &parent) &&
         XGetWindowAttributes(getXDisplay(), win, &wattr)))
    return;

  right = wattr.width - cwidth - left;
  bottom = wattr.height - cheight - top;

  left += wattr.border_width;
  right += wattr.border_width;
  top += wattr.border_width;
  bottom += wattr.border_width;

  // find the client's location
  x = wattr.x + left;
  y = wattr.y + top;

  // this makes things work. why? i don't know. but you need them.
  right -= 2;
  bottom -= 2;

  // find the frame's reference position based on the window's gravity
  switch (gravity) {
  case NorthWestGravity:
    x -= left;
    y -= top;
    break;
  case NorthGravity:
    x += (left + right) / 2;
    y -= top;
    break;
  case NorthEastGravity:
    x += right;
    y -= top;
  case WestGravity:
    x -= left;
    y += (top + bottom) / 2;
    break;
  case CenterGravity:
    x += (left + right) / 2;
    y += (top + bottom) / 2;
    break;
  case EastGravity:
    x += right;
    y += (top + bottom) / 2;
  case SouthWestGravity:
    x -= left;
    y += bottom;
    break;
  case SouthGravity:
    x += (left + right) / 2;
    y += bottom;
    break;
  case SouthEastGravity:
    x += right;
    y += bottom;
    break;
  default:
    break;
  }
}


void ToolWindow::process_event(XEvent * e)
{
      switch (e->type) {
      case PropertyNotify:
            windowAttributeChange(e->xproperty.window);
            break;
      
      case VisibilityNotify:
            // **** This will need to change to a better method of keeping the **** //
            // **** menu on top when blackbox provides another way!            **** //
            if (e->xvisibility.window == stackMenu->getWindowID())
                  if (e->xvisibility.state != VisibilityUnobscured)
                        XRaiseWindow(getXDisplay(), stackMenu->getWindowID());
            break;
      
      case KeyRelease: {
            // if stacked cycling is going on..
            if (doingCycling) {
                  unsigned int mask = KeycodeToModmask(e->xkey.keycode);
                  unsigned int state = e->xkey.state;
                  
                  // get the index for grabSet.KeyMay's prev/next entries, but make
                  // sure we're not just getting 0 because we don't have keybindings
                  // for one of them--also, we can't use > 0 as a test for next/prev
                  // because 0 might very well be the valid index for those bindings
                  int i = actionList[grabNextWindow];
                  int next = grabSet.KeyMap[i].action == grabNextWindow ? i : -1;
                  int j = actionList[grabNextWindowAllWorkspaces];
                  int nextAll = grabSet.KeyMap[j].action == grabNextWindowAllWorkspaces ? j : -1;
                  int k = actionList[grabPrevWindow];
                  int prev = grabSet.KeyMap[k].action == grabPrevWindow ? k : -1;

                  // if the key released was the last modifier being held
                  // and being a member of the nextMask or PrevMask, then select
                  // the item in the menu that is currently focued.
                  if (next > -1 && ((state & grabSet.KeyMap[next].modMask) == mask))
                        stackMenu->selectFocused(True);
                  else if (nextAll > -1 && ((state & grabSet.KeyMap[nextAll].modMask) == mask))
                        stackMenu->selectFocused(True);
                  else if (prev > -1 && ((state & grabSet.KeyMap[prev].modMask) == mask))
                        stackMenu->selectFocused(True);
            }
            break;
      }

      case KeyPress: {

            int i = 0;
            int grabInt = -1;
            int fw_y, fw_x;

            if (focus_window) {
      findFramePosition(focus_window, fw_x, fw_y);
    }
            
            // if our user wants to grab his keystrokes, even though one
            // or more of the Lock-Modifiers are pressed, alter the mask


      // to make this possible....

            if (!honor_modifiers) {
                  e->xkey.state &= ~_NumLockMask & ~_ScrollLockMask & ~LockMask;
            }

            for (i = 0; i < grabSet.instructCount; i++) {
                  if ((e->xkey.keycode == grabSet.KeyMap[i].keycode) &&
                              (e->xkey.state == grabSet.KeyMap[i].modMask)) {
                        grabInt = i;
                        break;
                  }
            }

            if (doingCycling) {
                  if (e->xkey.keycode == XKeysymToKeycode(getXDisplay(), XK_Escape)) {
                        stackMenu->hide();
                        // reset focus to the window we were focused on before window
                        // cycling began
                        wminterface->setWindowFocus(focus_window);
                  } else if (e->xkey.keycode == XKeysymToKeycode(getXDisplay(), XK_Return))
                        stackMenu->selectFocused(True);
                  else
                        stackMenu->key_press(grabSet.KeyMap[grabInt].action);
            } else if (grabInt > -1) {
            
                  /* play with colors for nyz =:) */
                  XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
                              pixmap.pix_pressedBtn);
                  Redraw();

                  switch (grabSet.KeyMap[grabInt].action) {
                  case grabIconify:
                        if (focus_window)
                              XIconifyWindow(getXDisplay(), focus_window, 0);
                        break;

                  case grabRaise:
                        if (focus_window)
                              XRaiseWindow(getXDisplay(), focus_window);
                        break;

                  case grabLower:
                        if (focus_window)
                              XLowerWindow(getXDisplay(), focus_window);
                        break;

                  case grabClose:
                        if (!focus_window)
                              break;
                        XEvent ce;
                        ce.xclient.type = ClientMessage;
                        ce.xclient.message_type = getWMProtocolsAtom();
                        ce.xclient.display = getXDisplay();
                        ce.xclient.window = focus_window;
                        ce.xclient.format = 32;
                        ce.xclient.data.l[0] = getWMDeleteAtom();
                        ce.xclient.data.l[1] = CurrentTime;
                        ce.xclient.data.l[2] = ce.xclient.data.l[3] =
                        ce.xclient.data.l[4] = 0l;
                        XSendEvent(getXDisplay(), focus_window, False, NoEventMask, &ce);
                        break;

                  case grabWorkspace1:
                        wminterface->changeDesktop(0);
                        break;

                  case grabWorkspace2:
                        wminterface->changeDesktop(1);
                        break;

                  case grabWorkspace3:
                        wminterface->changeDesktop(2);
                        break;

                  case grabWorkspace4:
                        wminterface->changeDesktop(3);
                        break;

                  case grabWorkspace5:
                        wminterface->changeDesktop(4);
                        break;

                  case grabWorkspace6:
                        wminterface->changeDesktop(5);
                        break;

                  case grabWorkspace7:
                        wminterface->changeDesktop(6);
                        break;

                  case grabWorkspace8:
                        wminterface->changeDesktop(7);
                        break;

                  case grabWorkspace9:
                        wminterface->changeDesktop(8);
                        break;

                  case grabWorkspace10:
                        wminterface->changeDesktop(9);
                        break;

                  case grabWorkspace11:
                        wminterface->changeDesktop(10);
                        break;

                  case grabWorkspace12:
                        wminterface->changeDesktop(11);
                        break;

                  case grabNextWorkspace:
                        if (current_desktop->number < (desktop_count-1))
                              wminterface->changeDesktop(current_desktop->number + 1);
                        else
                              wminterface->changeDesktop(0);
                        break;

                  case grabPrevWorkspace:
                        if (current_desktop->number > 0)
                              wminterface->changeDesktop(current_desktop->number - 1);
                        else
                              wminterface->changeDesktop(desktop_count - 1);
                        break;

                  case grabUpWorkspace:
                        if (resource->columns > 1) { //ie columns given
                              if (getCurrentDesktopNr()-resource->columns<0) {
                                    if (getDesktopCount()-1-(getDesktopCount()-1)%resource->columns +
                                                getCurrentDesktopNr()%resource->columns  > getDesktopCount() - 1) {

                                          wminterface->changeDesktop(getDesktopCount() - 1 -
                                                (getDesktopCount() - 1)%resource->columns +
                                                getCurrentDesktopNr()%resource->columns  -resource->columns);

                                    } else {
                                          wminterface->changeDesktop(getDesktopCount() - 1 -
                                                (getDesktopCount() - 1)%resource->columns +
                                                getCurrentDesktopNr()%resource->columns );
                                    }
                              } else {
                                    wminterface->changeDesktop(getCurrentDesktopNr() - resource->columns);
                              }
                        } else if (resource->rows > 1) { //ie rows given 
                              if (getCurrentDesktopNr()%resource->rows==0) {// if row=1
                                          if (getCurrentDesktopNr() + resource->rows > getDesktopCount())
                                                      //incomplete last col?
                                                      wminterface->changeDesktop(getDesktopCount() - 1); //last desktop
                                          else //complete col
                                                      wminterface->changeDesktop(getCurrentDesktopNr() +resource->rows - 1);
                        //last in column
                        } else  // row>1
                              wminterface->changeDesktop(getCurrentDesktopNr() - 1);
                        } else {} //no arrangement -> insert fallback solution here

                        break;
                  
                  case grabDownWorkspace:
                        if (resource->columns > 1) { //ie columns given
                              if (getCurrentDesktopNr() + resource->columns > getDesktopCount() - 1)
                                    wminterface->changeDesktop(getCurrentDesktopNr()%resource->columns);
                              else
                                    wminterface->changeDesktop(getCurrentDesktopNr() +resource->columns);
                        } else if (resource->rows > 1) { //ie rows given
                              if (getCurrentDesktopNr()%resource->rows + 1 == resource->rows ||
                                          getCurrentDesktopNr() + 1 == getDesktopCount()) {
                                          //last row or last in incomplete col
                                          wminterface->changeDesktop(getCurrentDesktopNr() -
                                          getCurrentDesktopNr()%resource->rows);
                                          //first in col
                              } else
                                    wminterface->changeDesktop(getCurrentDesktopNr() + 1);
                        } else {} //no arrangement -> fallback solution

                        break;
                  
                  
                  case grabLeftWorkspace:
                        if (resource->columns > 1) {   //ie columns given
                              if (getCurrentDesktopNr()%resource->columns==0) {
                                    if (getCurrentDesktopNr() + resource->columns > getDesktopCount())
                                          wminterface->changeDesktop(getDesktopCount() -1);
                                    else
                                          wminterface->changeDesktop(getCurrentDesktopNr() + resource->columns - 1);
                              } else
                                    wminterface->changeDesktop(getCurrentDesktopNr() - 1);
                        } else if (resource->rows > 1) { //ie rows given
                              if (getCurrentDesktopNr() - resource->rows<0) {// first col
                                          if (getDesktopCount() - 1 - (getDesktopCount()-1)%resource->rows +
                                                      getCurrentDesktopNr()%resource->rows  > getDesktopCount() - 1)
                                                      //incomplete row
                                                wminterface->changeDesktop(getDesktopCount() - 1 -
                                                            (getDesktopCount() - 1)%resource->rows +
                                                            getCurrentDesktopNr()%resource->rows  - resource->rows);
                                          else
                                                wminterface->changeDesktop(getDesktopCount() - 1 -
                                                      (getDesktopCount() - 1)%resource->rows +
                                                      getCurrentDesktopNr()%resource->rows );
                              } else
                                    wminterface->changeDesktop(getCurrentDesktopNr() - resource->rows);
                        } else {} //no arrangement -> fallback solution

                        break;
                  
                  
                  case grabRightWorkspace:
                        if (resource->columns > 1) { //ie columns given
                              if (getCurrentDesktopNr()%resource->columns + 1 == resource->columns ||
                                          getCurrentDesktopNr() + 1 == getDesktopCount())
                                    wminterface->changeDesktop(getCurrentDesktopNr() -
                                          getCurrentDesktopNr()%resource->columns);
                              else
                                    wminterface->changeDesktop(getCurrentDesktopNr() + 1);
                        } else if (resource->rows > 1) { //ie rows given
                              if (getCurrentDesktopNr() + resource->rows > getDesktopCount() - 1)
                                    // last in row
                                    wminterface->changeDesktop(getCurrentDesktopNr()%resource->rows);
                              // first col
                              else
                                    wminterface->changeDesktop(getCurrentDesktopNr() + resource->rows);
                        } else {} //no arrangement -> fallback solution

                        break;
                  
                  case grabNextWindow:
                        showAllWorkspaces=false;
                        cycleWindowFocus(True);
                        break;

                  case grabNextWindowAllWorkspaces:
                        showAllWorkspaces=true;
                        cycleWindowFocus(True);
                        break;

                  case grabPrevWindow:
                        cycleWindowFocus(False);
                        break;

                  case grabShade:
                        if (focus_window)
                              wminterface->shadeWindow(focus_window);
                        break;

                  case grabStick:
                        if (focus_window)
                              wminterface->stickWindow(focus_window);
                        break;

                  case grabExecute:
                        execCommand((char *const)grabSet.KeyMap[grabInt].execCommand);
                        break;

                  case grabMaximize:
                        if (focus_window)
                              wminterface->maximizeWindow(focus_window, True, True);
                        break;

                  case grabVertMax:
                        if (focus_window)
                              wminterface->maximizeWindow(focus_window, False, True);
                        break;

                  case grabHorizMax:
                        if (focus_window)
                              wminterface->maximizeWindow(focus_window, True, False);
                        break;
            
                  case grabNudgeRight:
                        if (focus_window)
                              XMoveWindow(getXDisplay(), focus_window, fw_x + 1, fw_y);
                        break;

                  case grabNudgeLeft:
                        if (focus_window)
                              XMoveWindow(getXDisplay(), focus_window, fw_x - 1, fw_y);
                        break;

                  case grabNudgeUp:
                        if (focus_window)
                              XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y - 1);
                        break;

                  case grabNudgeDown:
                        if (focus_window)
                              XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y + 1);
                        break;

                  case grabBigNudgeRight:
                        if (focus_window)
                              XMoveWindow(getXDisplay(), focus_window, fw_x + 10, fw_y);
                        break;

                  case grabBigNudgeLeft:
                        if (focus_window)
                              XMoveWindow(getXDisplay(), focus_window, fw_x - 10, fw_y);
                        break;

                  case grabBigNudgeUp:
                        if (focus_window)
                              XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y - 10);
                        break;

                  case grabBigNudgeDown:
                        if (focus_window)
                              XMoveWindow(getXDisplay(), focus_window, fw_x, fw_y + 10);
                        break;

                  case grabHorizInc:
                        if (focus_window) {
                              XWindowAttributes foo;
                              XGetWindowAttributes(getXDisplay(), focus_window, &foo);
                              XResizeWindow(getXDisplay(), focus_window,
                                          foo.width + 10, foo.height);
                        }
                        break;

                  case grabVertInc:
                        if (focus_window) {
                              XWindowAttributes foo;
                              XGetWindowAttributes(getXDisplay(), focus_window, &foo);
                              XResizeWindow(getXDisplay(), focus_window,
                                          foo.width, foo.height + 10);
                        }
                        break;

                  case grabHorizDec:
                        if (focus_window) {
                              XWindowAttributes foo;
                              XGetWindowAttributes(getXDisplay(), focus_window, &foo);
                              if (foo.width < 11)
                                    foo.width = 11;
                              XResizeWindow(getXDisplay(), focus_window,
                                    foo.width - 10, foo.height);
                        }
                        break;

                  case grabVertDec:
                        if (focus_window) {
                              XWindowAttributes foo;
                              XGetWindowAttributes(getXDisplay(), focus_window, &foo);
                              if (foo.height < 11)
                                    foo.height = 11;
                              XResizeWindow(getXDisplay(), focus_window,
                                          foo.width, foo.height - 10);
                        }
                        break;

                  case grabToggleDecor:
                        if (focus_window)
                              wminterface->decorateToggleWindow(focus_window);
                        break;
                  }
            }
            timer->start();
            break;
      }

      case ClientMessage:
            if ((unsigned) e->xclient.data.l[0] == wm_delete_window)
                  shutdown();
            wminterface->handleNETEvents(*e);
            break;

      case Expose:
            if (!e->xexpose.count)
                  reconfigure();
            break;

      case ButtonPress:
            if (e->xbutton.button == LEFT_BUTTON 
                        || e->xbutton.button == RIGHT_BUTTON) {
                  if (e->xbutton.window == win_configBtn) {
                        XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
                                    pixmap.pix_pressedBtn);
                              Redraw();
                  } else if (e->xbutton.window == win_closeBtn) {
                        XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
                                    pixmap.pix_pressedBtn);
                        Redraw();
                  } else if (e->xbutton.window == win_title) {
//                      if (!raised)
                              XRaiseWindow(getXDisplay(), win_frame);
//                            raised = True;
                  }
            } else if (e->xbutton.button == MIDDLE_BUTTON) {
//                if (raised)
                         XLowerWindow(getXDisplay(), win_frame);
//                       raised = False;
            }
            break;

      case ButtonRelease:
            if (e->xbutton.button == LEFT_BUTTON
                        || e->xbutton.button == RIGHT_BUTTON) {
                  if (e->xbutton.window == win_configBtn) {
                        if ((e->xbutton.x > 0)
                                    && (e->xbutton.x < geom_configBtn.width)
                                    && (e->xbutton.y > 0)
                                    && (e->xbutton.y < geom_configBtn.height)) {
                              if (grabSet.instructCount > 0) {
                                    XUngrabKey(getXDisplay(), AnyKey, AnyModifier,
                                                getScreenInfo(0)->getRootWindow());
                                    XSync(getXDisplay(), False);
                              }
                              setKeygrabs();

                              //     discard all XEvents (was causing us to go bananas on the
                              //     user before, since we were executing all keygrabs at once
                              //     that the user did when the configuration app was running)
                              //     *cough* undocumented feature *cough*
                              //

                              XEvent event;
                              while (XPending(getXDisplay())) {
                                    XNextEvent(getXDisplay(), &event);
                              }

                              // carry on then, little soldier

                              loadKeygrabs();
                              activateKeygrabs();
                              timer->start();
                        }

                        XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
                                    pixmap.pix_configBtn);
                        Redraw();
                  } else if (e->xbutton.window == win_closeBtn) {
                        if ((e->xbutton.x > 0)
                                    && (e->xbutton.x < geom_closeBtn.width)
                                    && (e->xbutton.y > 0)
                                    && (e->xbutton.y < geom_closeBtn.height)) {
                              if (e->xbutton.button == LEFT_BUTTON) {
                                          shutdown();
                              } else if (e->xbutton.button == RIGHT_BUTTON) {
                                    if (withdrawn) {
                                          XUnmapWindow(getXDisplay(), win_frame);
                                          withdrawn = False;
                                          iconic = True;

                                          XWMHints wmhints;
                                          wmhints.initial_state = IconicState;
                                          wmhints.flags = StateHint;
                                          XSetWMHints(getXDisplay(), win_frame, &wmhints);
                                          XMapWindow(getXDisplay(), win_frame);

                                          // this should work but doesn't seem to.  *shrug*
                                          // reconfigure();
                                    } else {
                                          XIconifyWindow(getXDisplay(), win_frame, 0);
                                    }
                              }
                        }
                        XSetWindowBackgroundPixmap(getXDisplay(), win_closeBtn,
                                    pixmap.pix_configBtn);
                        Redraw();
                  }
            }
            break;

      case ConfigureNotify:
            if ((e->xconfigure.window == win_frame) && e->xconfigure.send_event) {
                  if (withdrawn)
                         reconfigure();

                  int parent_x, parent_y;
                  Window parent_root;
                  unsigned int parent_width, parent_height, parent_border_width;
                  unsigned int parent_depth;

                  if (withdrawn) {
                        XGetGeometry(getXDisplay(), e->xconfigure.above,
                                                      &parent_root, &parent_x, &parent_y,
                                                      &parent_width, &parent_height,
                                                      &parent_border_width, &parent_depth);
                        frame.x = e->xconfigure.x + parent_x;
                        frame.y = e->xconfigure.y + parent_y;
                  }
            }
            break;
      }
}

void ToolWindow::timeout(void)
{
      XSetWindowBackgroundPixmap(getXDisplay(), win_configBtn,
                                                             pixmap.pix_configBtn);
      Redraw();
}

/*--------------------------------*/

/*-    window modifying functions    -*/

/*--------------------------------*/

void ToolWindow::raiseWindow(Window)
{
}

void ToolWindow::lowerWindow(Window)
{
}

/*---------------------------------------*/

/*-    desktop list management functions  -*/

/*---------------------------------------*/

void ToolWindow::addDesktop(void)
{
      DesktopList *tmp = new DesktopList;

      // get the highest in the list
      int highest = -1;
      LinkedListIterator<DesktopList> it(desktopList);
      for (; it.current(); it++)
            if (it.current()->number > highest) {
                  highest = it.current()->number;
                  it.reset();
            }
      tmp->number = highest + 1;

      desktopList->insert(tmp, -1); // add to the end of the list

      desktop_count++;

      // add sticky windows to this desktop
      LinkedListIterator<WindowList> it_win(windowList);
      for (; it_win.current(); it_win++)
            // only look for sticky windows on desktop 0, this will give us one
            // copy of each sticky window
            if ((it_win.current()->desktop == 0) && (it_win.current()->sticky)) {
                  WindowList *win = new WindowList;
                  win->win = it_win.current()->win;
                  win->iconic = it_win.current()->iconic;
                  win->shaded = False;
                  win->sticky = True;
                  win->desktop = tmp->number;
                  windowList->insert(win, -1);  // add to the end of the list
            }
}

void ToolWindow::removeDesktop(int desktop)
{
      LinkedListIterator<DesktopList> it(desktopList);
      LinkedListIterator<WindowList> it_win(windowList);

      // remove sticky windows from this desktop
      for (; it_win.current(); it_win++)
            if ((it_win.current()->desktop == desktop)
                        && (it_win.current()->sticky))
                  windowList->remove(it_win.current()); // remove just this window
                                                                                                                                    // removeWindow() would remove all
                                                                                                                                    // of the sticky windows.

      // remove the desktop from the linked list
      for (; it.current(); it++)
            if (it.current()->number == desktop) {
                  desktopList->remove(it.current());
                  break;
            }

      desktop_count--;

      // shift the rest to fill in the hole if not the last desktop was rm'd
      int check=0;
      bool found;
      do {
            found=False;
            it.reset();
            for (; it.current(); it++)
                  if (it.current()->number == check) {
                        ++check;
                        found=True;
                  }
      } while (found);

      // check is on the new hole, or desktop_count if there is no hole
      // plug the hole by moving all the desktops above down one
      while (check < desktop_count) {
            it.reset();
            for (; it.current(); it++)
                  if(it.current()->number == (check + 1)) {
                        it.current()->number = check++;
                        break;
                  }
      }
}

void ToolWindow::focusDesktop(int desktop)
{
      LinkedListIterator<DesktopList> it(desktopList);
      for (; it.current(); it++)
            if (it.current()->number == desktop)
                  current_desktop = it.current();
}

void ToolWindow::setDesktopCount(int count)
{
      int oldcount = desktop_count;
      int delta = count - oldcount;

      if (delta > 0) {  // added desktops
            while(delta-- > 0)
                  addDesktop();
      }
      else {                                    // removed desktops
            while(delta++ < 0)
                  removeDesktop(desktop_count - 1); // remove the last desktop
      }
}

/*--------------------------------------*/

/*-    window list management functions    -*/

/*--------------------------------------*/

void ToolWindow::clearWindows(void)
{
      focusWindow(0);
      while (! windowList->empty())
            windowList->remove(0);
}

void ToolWindow::removeWindow(Window win)
{
      if (focus_window == win)
            focusWindow(0);
      for (int i = 0; i < windowList->count(); ++i)
            if (windowList->find(i)->win == win)
                  windowList->remove(i--);
}

void ToolWindow::focusWindow(Window win)
{
      // have to only do this when the menu isn't visible, because we're
      // setting focus while we're cycling....  Unfortunately, a side-effect
      // of this is that we don't get a final focusWindow hit when we raise
      // the selected window when done cycling, so we do an explicit
      // bbtool->focusWindow() call from Stackmenu::selectFocused() after we
      // XRaise the window....

      if (! doingCycling ) { 
            focus_window = win;
            if (resource->getMenuStackedCycling())
                  focus_stack(win);
      }
}

void ToolWindow::moveWinToDesktop(Window win, int desktop)
{
      LinkedListIterator<WindowList> it(windowList);
      for (; it.current(); it++)
            if (it.current()->win == win) {
                  if (!it.current()->sticky) {
                        it.current()->desktop = desktop;
                  }
                  break;
            }
}

void ToolWindow::addSticky(WindowList *win) {
      win->sticky = True;
      LinkedListIterator<DesktopList> it(desktopList);
      for (; it.current(); it++)
            if (win->desktop != it.current()->number) {
                  WindowList *copy = new WindowList;
                  copy->win = win->win;
                  copy->iconic = win->iconic;
                  copy->shaded = win->shaded;
                  copy->sticky = True;
                  copy->desktop = it.current()->number;
                  windowList->insert(copy, -1);
            }
}

void ToolWindow::removeSticky(const Window win, const int desktop) {
      LinkedListIterator<WindowList> it(windowList);
      for (register int i=0; i < desktop_count; i++) {
            it.reset();
            for (; it.current(); it++)
                  if (it.current()->win == win)
                        if (it.current()->desktop != desktop)
                              windowList->remove(it.current());
                        else
                              it.current()->sticky = False;
      }
}

void ToolWindow::windowAttributeChange(Window win) {
      Atom real_type;
      int format;
      unsigned long n, extra;
      WindowList *window = NULL;
      BlackboxHints *net_hint;
      LinkedListIterator<WindowList> it(windowList);
      
      for (; it.current(); it++)    // find the window that's changed
            if (it.current()->win == win)
                  window = it.current();
      if (!window)
            return;
      if (!(XGetWindowProperty(getXDisplay(), window->win,
                  getBlackboxAttributesAtom(), 0L,
                  PropBlackboxHintsElements, False,
                  getBlackboxAttributesAtom(), &real_type,
                  &format, &n, &extra, (unsigned char**)&net_hint)
                  == Success && net_hint))
            return;
      if (n != PropBlackboxHintsElements)
            return;

      if (net_hint->flags & AttribShaded) {
            if (net_hint->attrib & AttribShaded)
                  window->shaded = True;
      } else if (window->shaded)
            window->shaded = False;
      
      if (wminterface->isIconicState(window->win) != window->iconic &&
                  !window->shaded)
            window->iconic = !window->iconic;

      if (net_hint->flags & AttribOmnipresent) {
            if (net_hint->attrib & AttribOmnipresent)
                  if (!window->sticky) addSticky(window);
      } else if (window->sticky)
                  if (window->sticky) removeSticky(window->win, getCurrentDesktopNr());
}

void ToolWindow::addWindow(Window win, int desktop)
{
      WindowList *newwin = new WindowList;
      newwin->win = win;
      newwin->iconic = wminterface->isIconicState(win);
      newwin->shaded = False;
      newwin->sticky = False;
      newwin->desktop = desktop;
      XSelectInput(getXDisplay(),newwin->win,
                  PropertyChangeMask);
      if (resource->getMenuStackedCycling())
            add_stack(newwin);
      else
            add_linear(newwin);
}

void ToolWindow::cycleWindowFocus(bool forward)
{
      if (resource->getMenuStackedCycling())
            cycle_stack(forward);
      else
            cycle_linear(forward);
}

/*******************************************************************************

                          LINEAR CYCLING FUNCTIONS

*******************************************************************************/

void ToolWindow::add_linear(WindowList *newwin)
{
      int i;
      int index = 0;    // where the new window will be placed (defaults to the
                                                      // top of the list)
      // insert after the focused window
      LinkedListIterator<WindowList> it(windowList);
      for (i=0; i<windowList->count(); i++) {
            it.set(i);
            if (it.current()->win == focus_window) {
                  // get the index of the focused window
                  index = i+1;
                  break;
            }
      }
      windowList->insert(newwin, index);
}

void ToolWindow::cycle_linear(bool forward)
{
/*******************************************
      This does the oldschool straight rotation
      order of cycling windows.
********************************************/
      int desktop = -1;
      bool found = False;
      WindowList *next = NULL;
      int i, max;

      LinkedListIterator<WindowList> it(windowList);
      max = windowList->count();
      for (i=0; i<max; i++) {
            if (forward)
                  it.set(i);
            else
                  it.set(max-1-i);
            if (found) {
                  // find the window after the focused one
                  if (it.current()->desktop == desktop) {
                        next = it.current();
                        break;
                  }                       
            }
            if (it.current()->win == focus_window) {
                  found = True;
                  desktop = it.current()->desktop;
            }
      }
      // if the next window wasn't found, start over at the beginning once more
      if (!next)
      {
            for (i=0; i<max; i++) {
                  if (forward)
                        it.set(i);
                  else
                        it.set(max-1-i);
                  if (it.current()->desktop == desktop) {
                        next = it.current();
                        break;
                  }
            }
      }

      if (next) {
            wminterface->setWindowFocus(next->win);
            XRaiseWindow(getXDisplay(), next->win);
      }
}

/*******************************************************************************

                            STACK CYCLING FUNCTIONS

*******************************************************************************/

void ToolWindow::add_stack(WindowList *newwin) {
      windowList->insert(newwin, 0); // insert at the top of the list
            stackMenu->setMenuItems();
}

void ToolWindow::cycle_stack(bool forward) {
      register bool showMenu = resource->getMenuShowCycleMenu() ? True : False;
      stackMenu->show(forward, showMenu);
}

void ToolWindow::focus_stack(Window win)
{
      WindowList *window = new WindowList;
      LinkedListIterator<WindowList> it(windowList);
      for (; it.current(); it++) {
            if (it.current()->win == win)
                  if ((!it.current()->sticky) ||
                  (it.current()->desktop == getCurrentDesktopNr()))
                        break;
      }
      if (it.current()) {
            window->win = it.current()->win;
            window->shaded = it.current()->shaded;
            window->sticky = it.current()->sticky;
            window->iconic = it.current()->iconic;
            window->desktop = it.current()->desktop;
            windowList->remove(it.current());   // remove it
            windowList->insert(window, 0);            // add it to the top
      }
}

void ToolWindow::saveMenuSearch(Window window, Basemenu *)
{
      menuWin = window;
}

void ToolWindow::removeMenuSearch(Window)
{
      menuWin = (Window)NULL;
}

void ToolWindow::p()
{
printf("window     | stick | shade | icon | desk\n");
LinkedListIterator<WindowList> it(windowList);
for (; it.current(); it++)
      printf("%010i | %d     | %d     | %d    | %d\n", (int)it.current()->win,
            it.current()->sticky, it.current()->shaded, it.current()->iconic,
            it.current()->desktop);
}


Generated by  Doxygen 1.6.0   Back to index