Logo Search packages:      
Sourcecode: nawm version File versions  Download package

bindings.c

/* bindings.c: deal with event bindings, and running the event loop */

/* Copyright (C) 1999 by the Massachusetts Institute of Technology.
 *
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting
 * documentation, and that the name of M.I.T. not be used in
 * advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 */

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "nawm.h"
#include "lang.h"
#include "parser.h"

bindlist *current_bindings;
bindlist *anymode;
extern Window root;
int quit;
extern Display *dpy;
extern variable CURRENTWINDOW, PX, PY;
extern long options;
long eventmask = SubstructureNotifyMask | EnterWindowMask | LeaveWindowMask;
event_handler *eventhandlers = NULL;

bindlist *findmode(char *name);
int interactive(bindlist *mode);

typedef struct _mode {
  char *name;
  bindlist *bindings;
  struct _mode *next;
} mode;
mode *modes;

void initbindings(void)
{
  anymode = NULL;
  current_bindings = NULL;
}

bindlist *mkbinding(int type, char *data, node *cmds)
{
  bindlist *ans = xmalloc(sizeof(bindlist));
  char *p = data;

  ans->cmds = cmds;

  switch(type)
    {
    case KEYPRESS:
    case KEYRELEASE:
      ans->type = (type == KEYPRESS) ? KeyPress : KeyRelease;
      ans->u.key.mods = parse_mods(&p);
      ans->u.key.kc = parse_key(p);
      free(data);
      break;

    case BUTTONPRESS:
    case BUTTONRELEASE:
      ans->type = (type == BUTTONPRESS) ? ButtonPress : ButtonRelease;
      ans->u.button.mods = parse_mods(&p);
      ans->u.button.button = parse_button(p);
      free(data);
      break;

    case ENTER:
    case LEAVE:
      ans->type = (type == ENTER) ? EnterNotify : LeaveNotify;
      ans->u.name = data;
      break;

    case MOTION:
      ans->type = MotionNotify;
      break;

    default:
      ans->type = type;
      break;
    }
      
  return ans;
}

int parse_mods(char **str)
{
  int mods = 0;

  do
    {
      if (!strncasecmp(*str, "shift", 5) && isspace(*(*str + 5)))
      {
        mods |= ShiftMask;
        *str += 5;
      }
      else if (!strncasecmp(*str, "lock", 4) && isspace(*(*str + 4)))
      {
        mods |= LockMask;
        *str += 4;
      }
      else if (!strncasecmp(*str, "control", 7) && isspace(*(*str + 7)))
      {
        mods |= ControlMask;
        *str += 7;
      }
      else if ((!strncasecmp(*str, "mod1", 4) || !strncasecmp(*str, "meta", 4))
             && isspace(*(*str + 4)))
      {
        mods |= Mod1Mask;
        *str += 4;
      }
      else if (!strncasecmp(*str, "mod2", 4) && isspace(*(*str + 4)))
      {
        mods |= Mod2Mask;
        *str += 4;
      }
      else if (!strncasecmp(*str, "mod3", 4) && isspace(*(*str + 4)))
      {
        mods |= Mod3Mask;
        *str += 4;
      }
      else if (!strncasecmp(*str, "mod4", 4) && isspace(*(*str + 4)))
      {
        mods |= Mod4Mask;
        *str += 4;
      }
      else if (!strncasecmp(*str, "mod5", 4) && isspace(*(*str + 4)))
      {
        mods |= Mod5Mask;
        *str += 4;
      }
      else if (!strncasecmp(*str, "any", 3) && isspace(*(*str + 3)))
      {
        mods = AnyModifier;
        *str += 3;
      }
      else break;

      while (isspace(**str))
      (*str)++;
    }
  while (**str);

  return mods;
}


KeyCode parse_key(char *name)
{
  KeySym ks;
  KeyCode kc = 0;
  char *ndup, *p;

  ndup = xstrdup(name);
  for (p = strtok(ndup, "| "); p && !kc; p = strtok(NULL, "| "))
    {
      ks = XStringToKeysym(p);
      if (ks == NoSymbol)
      continue;
      kc = XKeysymToKeycode(dpy, ks);
    }
  free(ndup);

  if (ks == NoSymbol)
    die("Bad keysym name: %s", name);
  else if (!kc)
    die("No keycode for keysym: %s", name);
  return kc;
}

int parse_button(char *name)
{
  if (!strcasecmp(name, "left"))
    return 1;
  else if (!strcasecmp(name, "right"))
    return 3;
  else if (!strcasecmp(name, "middle"))
    return 2;
  else if (*name > '0' && *name < '6' && !*(name + 1))
    return *name - '0';
  die("Bad button name: %s", name);
}

void add_to_anymode(bindlist *b)
{
  b->next = anymode;
  anymode = b;
}

void defmode(char *name, bindlist *bindings)
{
  mode *tmp;

  tmp = xmalloc(sizeof(mode));
  tmp->name = name;
  tmp->bindings = bindings;
  tmp->next = modes;
  modes = tmp;
}

bindlist *findmode(char *name)
{
  mode *m;

  for (m = modes; m; m = m->next)
    {
      if (!strcmp(name, m->name))
      return m->bindings;
    }
  die("No such mode: %s", name);
}

void set_mode(char *mode)
{
  undo_bindings(current_bindings);
  current_bindings = findmode(mode);
  do_bindings(current_bindings);
}


void do_bindings(bindlist *mode)
{
  for (; mode; mode = mode->next)
    {
      switch (mode->type)
      {
      case BEGIN_:
        eval_cmds(mode->cmds);
        break;
      case ButtonPress:
      case ButtonRelease:
        XGrabButton(dpy, mode->u.button.button, mode->u.button.mods, root,
                  False, ButtonPressMask | ButtonReleaseMask,
                  GrabModeAsync, GrabModeAsync, None, None);
        if (mode->u.button.mods != AnyModifier &&
            options & NAWM_OPT_NOCAPSLOCK)
          {
            XGrabButton(dpy, mode->u.button.button,
                    mode->u.button.mods ^ LockMask, root,
                    False, ButtonPressMask | ButtonReleaseMask,
                    GrabModeAsync, GrabModeAsync, None, None);
          }
        break;
      case KeyPress:
      case KeyRelease:
        XGrabKey(dpy, mode->u.key.kc, mode->u.key.mods, root,
               False, GrabModeAsync, GrabModeAsync);
        if (mode->u.key.mods != AnyModifier && options & NAWM_OPT_NOCAPSLOCK)
          {
            XGrabKey(dpy, mode->u.key.kc, mode->u.key.mods ^ LockMask, root,
                   False, GrabModeAsync, GrabModeAsync);
          }
        break;
      case MotionNotify:
        XGrabPointer(dpy, root, False, ButtonPressMask |
                   ButtonReleaseMask | PointerMotionMask,
                   GrabModeAsync, GrabModeAsync, None,
                   None, CurrentTime);
        break;
      }
    }
}

void undo_bindings(bindlist *mode)
{
  for (; mode; mode = mode->next)
    {
      switch (mode->type)
      {
      case END:
        eval_cmds(mode->cmds);
        break;
      case ButtonPress:
      case ButtonRelease:
        XUngrabButton(dpy, mode->u.button.button, mode->u.button.mods, root);
        break;
      case KeyPress:
      case KeyRelease:
        XUngrabKey(dpy, mode->u.key.kc, mode->u.key.mods, root);
        break;
      case MotionNotify:
        XUngrabPointer(dpy, CurrentTime);
        break;
      }
    }
}

int interactive(bindlist *mode)
{
  for (; mode; mode = mode->next)
    {
      if (mode->type != BEGIN_ && mode->type != END)
      return 1;
    }
  return 0;
}

void run(void)
{
  XEvent ev;
  bindlist *binding;
  Window rr, cr;
  int rx, ry, cx, cy;
  unsigned int mr;
  event_handler *eh;

  quit = 0;
  do_bindings(anymode);
  XSelectInput(dpy, root, eventmask);

  while (!quit && (interactive(anymode) || interactive(current_bindings)))
    {
      XNextEvent(dpy, &ev);

      XQueryPointer(dpy, root, &rr, &cr, &rx, &ry, &cx, &cy, &mr);
      if (cr)
      assign_var(&CURRENTWINDOW, (nawmval)client_window(cr));
      else
      assign_var(&CURRENTWINDOW, 0);

      switch (ev.type)
      {
      case MappingNotify:
        update_keymap();
        break;

      case CreateNotify:
      case DestroyNotify:
      case ConfigureNotify:
      case UnmapNotify:
      case MapNotify:
        update_cache(&ev);
        break;

      case MotionNotify:
        for (binding = current_bindings; binding; binding = binding->next)
          {
            if (binding->type == ev.type)
            eval_cmds(binding->cmds);
          }
        for (binding = anymode; binding; binding = binding->next)
          {
            if (binding->type == ev.type)
            eval_cmds(binding->cmds);
          }
        break;

      case KeyPress:
      case KeyRelease:
        if (options & NAWM_OPT_NOCAPSLOCK)
          ev.xkey.state &= ~LockMask;
        for (binding = current_bindings; binding; binding = binding->next)
          {
            if (binding->type == ev.type &&
              binding->u.key.kc == ev.xkey.keycode &&
              (binding->u.key.mods == ev.xkey.state ||
               binding->u.key.mods == AnyModifier))
            eval_cmds(binding->cmds);
          }
        for (binding = anymode; binding; binding = binding->next)
          {
            if(binding->type == ev.type &&
             binding->u.key.kc == ev.xkey.keycode &&
             (binding->u.key.mods == ev.xkey.state ||
              binding->u.key.mods == AnyModifier))
            eval_cmds(binding->cmds);
          }
        break;

      case ButtonPress:
      case ButtonRelease:
        if (ev.type == ButtonRelease)
          ev.xkey.state &= ~(1 << (ev.xbutton.button + 7));
        if (options & NAWM_OPT_NOCAPSLOCK)
          ev.xkey.state &= ~LockMask;
        for (binding = current_bindings; binding; binding = binding->next)
          {
            if (binding->type == ev.type &&
              binding->u.button.button == ev.xbutton.button &&
              (binding->u.button.mods == ev.xbutton.state ||
               binding->u.button.mods == AnyModifier))
            eval_cmds(binding->cmds);
          }
        for (binding = anymode; binding; binding = binding->next)
          {
            if (binding->type == ev.type &&
              binding->u.button.button == ev.xbutton.button &&
              (binding->u.button.mods == ev.xbutton.state ||
               binding->u.button.mods == AnyModifier))
            eval_cmds(binding->cmds);
          }
        break;

      case EnterNotify:
        for (binding = current_bindings; binding; binding = binding->next)
          {
            if (binding->type == ev.type &&
              (!binding->u.name || hasname(ev.xcrossing.window,
                                     binding->u.name)))
            eval_cmds(binding->cmds);
          }
        for (binding = anymode; binding; binding = binding->next)
          {
            if (binding->type == ev.type &&
              (!binding->u.name || hasname(ev.xcrossing.window,
                                     binding->u.name)))
            eval_cmds(binding->cmds);
          }
        break;

      case LeaveNotify:
        for (binding = current_bindings; binding; binding = binding->next)
          {
            if (binding->type == ev.type &&
              (!binding->u.name || hasname(ev.xcrossing.window,
                                     binding->u.name)))
            {
              assign_var(&CURRENTWINDOW, (nawmval)ev.xcrossing.window);
              eval_cmds(binding->cmds);
            }
          }
        for (binding = anymode; binding; binding = binding->next)
          {
            if (binding->type == ev.type &&
              (!binding->u.name || hasname(ev.xcrossing.window,
                                     binding->u.name)))
            {
              assign_var(&CURRENTWINDOW, (nawmval)ev.xcrossing.window);
              eval_cmds(binding->cmds);
            }
          }
        break;

      }

      for (eh = eventhandlers; eh; eh = eh->next)
      eh->handler(&ev);
    }

  undo_bindings(anymode);
}

Generated by  Doxygen 1.6.0   Back to index