Logo Search packages:      
Sourcecode: afterstep version File versions

Form.c

/*
 * Copyright (C) 1998 Sasha Vasko <sasha at aftercode.net>
 * Copyright (C) 1998 Makoto Kato <m_kato@ga2.so-net.ne.jp>
 * Copyright (C) 1996 Michael Beam
 * Copyright (C) 1996 Takanori Kubota
 * Copyright (C) 1995 Thomas Zuwei Feng
 *
 * 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.
 *
 */

#include "../../configure.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#define XK_MISCELLANY
#include <X11/keysymdef.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#if defined ___AIX || defined _AIX || defined ___AIXV3
#include <sys/select.h>
#endif
#ifdef I18N
#include <X11/Xlocale.h>
#define XDrawImageString(t,u,v,w,x,y,z) XmbDrawImageString(t,u,FONTSET,v,w,x,y,z)
#endif

#include "../../include/aftersteplib.h"
#include "../../include/style.h"
#include "../../include/screen.h"
#include "../../include/module.h"

void
dummy ()
{
}

#ifdef DEBUG
#define fprintf fprintf
#else
#define fprintf dummy
#endif


#define TEXT_SPC    3
#define BOX_SPC     3
#define ITEM_HSPC   10
#define ITEM_VSPC   5

/* tba: use dynamic buffer expanding */
#define MAX_LINES 64
#define MAX_ITEMS 256
#define ITEMS_PER_LINE 64
#define CHOICES_PER_SEL 64

#define I_TEXT          1
#define I_INPUT         2
#define I_SELECT        3
#define I_CHOICE        4
#define I_BUTTON        5

#define IS_SINGLE       1
#define IS_MULTIPLE     2

#define IB_CONTINUE     1
#define IB_RESTART      2
#define IB_QUIT         3

typedef union _item
{
  int type;             /* item type, one of I_TEXT .. I_BUTTON */
  struct _head
    {                   /* common header */
      int type;
      int win;                /* X window id */
      char *name;       /* identifier name */
      int size_x, size_y;     /* size of bounding box */
      int pos_x, pos_y;       /* position of top-left corner */
    }
  header;
  struct
    {                   /* I_TEXT */
      struct _head head;
      int n;                  /* string length */
      char *value;            /* string to display */
    }
  text;
  struct
    {                   /* I_INPUT */
      struct _head head;
      int buf;                /* input string buffer */
      int n;                  /* string length */
      char *value;            /* input string */
      char *init_value;       /* default string */
      char *blanks;           /* blank string */
      int size;               /* input field size */
      int left;               /* position of the left-most displayed char */
      int o_cursor;           /* store relative cursor position */
    }
  input;
  struct
    {                   /* I_SELECT */
      struct _head head;
      int key;                /* one of IS_MULTIPLE, IS_SINGLE */
      int n;                  /* number of choices */
      union _item **choices;  /* list of choices */
    }
  select;
  struct
    {                   /* I_CHOICE */
      struct _head head;
      int on;                 /* selected or not */
      int init_on;            /* initially selected or not */
      char *value;            /* value if selected */
      int n;                  /* text string length */
      char *text;       /* text string */
      union _item *sel;       /* selection it belongs to */
    }
  choice;
  struct
    {                   /* I_BUTTON */
      struct _head head;
      int key;                /* one of IB_CONTINUE, IB_RESTART, IB_QUIT */
      int n;                  /* # of commands */
      int len;                /* text length */
      char *text;       /* text string */
      int keypress;           /* short cut */
      /* Afterstep command to execute */
      char **commands;
    }
  button;
}
Item;


#define L_LEFT        1
#define L_RIGHT       2
#define L_CENTER      3
#define L_LEFTRIGHT   4

typedef struct _line
  {
    int n;              /* number of items on the line */
    int justify;        /* justification */
    int size_x, size_y;       /* size of bounding rectangle */
    Item **items;       /* list of items */
  }
Line;


/* global variables */
char *MyName;                 /* program name, e.g. Form */

int fd[2];              /* fd for Afterstep<->Module packets */
int fd_err;
FILE *fp_err;

Line lines[MAX_LINES];
int n_lines;
Item items[MAX_ITEMS];
int n_items;
Item def_button;

int grab_server = 0, server_grabbed = 0;
int gx, gy, geom = 0;
int warp_pointer = 0;

Display *dpy;
int fd_x;               /* fd for X connection */

ScreenInfo Scr;

Window root, frame, ref;
Colormap d_cmap;
int screen;
int scr_depth;

int max_width, total_height;  /* frame size */

enum
  {
    c_back, c_fore, c_itemback, c_itemfore, c_itemlo, c_itemhi
  };
char *color_names[4] =
{
  "Light Gray", "Black", "Gray50", "Wheat"
};
long colors[6];

enum
  {
    f_text, f_input, f_button
  };
char *font_names[3] =
{
  "fixed",
  "fixed",
  "fixed"
};
Font fonts[3];
XFontStruct *xfs[3];
#ifdef I18N
XFontSet xfset[3];
#endif

Cursor xc_ibeam, xc_hand;

GC gc_text, gc_input, gc_button;

Item *cur_text;
int abs_cursor;
int rel_cursor;

static char *buf;
static int N = 8;

/* copy a string until '\0', or up to n chars, and delete trailing spaces */
char *
copystring (char *cp, int n)
{
  char *dp, *bp;
  if (n == 0)
    n = strlen (cp);
  bp = dp = (char *) safemalloc (n + 1);
  while (n-- > 0)
    *dp++ = *cp++;
  while (isspace ((unsigned char) *(--dp)));
  *(++dp) = '\0';
  return bp;
}

void
DeadPipe (int nonsense)
{
  exit (0);
}


/* copy a string until '"', or '\n', or '\0' */
char *
CopyQuotedString (char *cp)
{
  char *dp, *bp, c;
  bp = dp = (char *) safemalloc (strlen (cp) + 1);
  while (1)
    {
      switch (c = *(cp++))
      {
      case '\\':
        *(dp++) = *(cp++);
        break;
      case '\"':
      case '\n':
      case '\0':
        *dp = '\0';
        return bp;
        break;
      default:
        *(dp++) = c;
        break;
      }
    }
}

/* copy a string until the first space */
char *
CopySolidString (char *cp)
{
  char *dp, *bp, c;
  bp = dp = (char *) safemalloc (strlen (cp) + 1);
  while (1)
    {
      c = *(cp++);
      if (c == '\\')
      {
        *(dp++) = '\\';
        *(dp++) = *(cp++);
      }
      else if (isspace ((unsigned char) c) || c == '\0')
      {
        *dp = '\0';
        return bp;
      }
      else
      *(dp++) = c;
    }
}

/* get the font height */
int
FontHeight (XFontStruct * xfs)
{
  return (xfs->ascent + xfs->descent);
}

/* get the font width, for fixed-width font only */
int
FontWidth (XFontStruct * xfs)
{
  return (xfs->per_char[0].width);
}

/* read the configuration file */
void
ParseOptions (char *file_name)
{
  FILE *fp, *fopen ();
  int prog_name_len, i, j, l, extra;
  char line_buf[MAXLINELENGTH];
  char *cp;
  Line *cur_line, *line;
  Item *item, *cur_sel = NULL, *cur_button = NULL;
#ifdef I18N
  XFontStruct **fs_list;
  char **ml;
  int mc;
  char *ds;
  char *fn_tmp;
  int fn_tmp_length;
#endif

#define AddToLine(item) { cur_line->items[cur_line->n++] = item; cur_line->size_x += item->header.size_x; if (cur_line->size_y < item->header.size_y) cur_line->size_y = item->header.size_y; }

  n_items = 0;
  n_lines = 0;

  /* default line in case the first *FFLine is missing */
  lines[0].n = 0;
  lines[0].justify = L_CENTER;
  lines[0].size_x = lines[0].size_y = 0;
  lines[0].items = (Item **) safemalloc (sizeof (Item *) * ITEMS_PER_LINE);
  cur_line = lines;

  /* default button is for initial functions */
  cur_button = &def_button;
  def_button.button.n = 0;
  def_button.button.commands = (char **) safemalloc (sizeof (char *) * MAX_ITEMS);
  def_button.button.key = IB_CONTINUE;

  /* default fonts in case the *FFont's are missing */
#ifdef I18N
  xfset[f_text] = xfset[f_input] = xfset[f_button] = XCreateFontSet (dpy, "fixed", &ml, &mc, &ds);
  XFontsOfFontSet (xfset[f_text], &fs_list, &ml);
  xfs[f_text] = xfs[f_input] = xfs[f_button] = fs_list[0];
#else
  xfs[f_text] = xfs[f_input] = xfs[f_button] =
    XLoadQueryFont (dpy, "fixed");
#endif
  fonts[f_text] = fonts[f_input] = fonts[f_button] = xfs[f_text]->fid;

  if (!(fp = fopen (file_name, "r")))
    {
      fprintf (fp_err, "%s: can't open config file %s.\n", MyName, file_name);
      exit (1);
    }
  prog_name_len = strlen (MyName);
  while (fgets (line_buf, sizeof (line_buf), fp))
    {
      cp = line_buf;
      while (isspace (*cp))
      cp++;             /* skip blanks */
      if (*cp != '*')
      continue;
      if (strncmp (++cp, MyName, prog_name_len) != 0)
      continue;
      cp += prog_name_len;
      /* at this point we have recognized "*Form" */
      if (strncmp (cp, "GrabServer", 10) == 0)
      {
        grab_server = 1;
        continue;
      }
      else if (strncmp (cp, "WarpPointer", 11) == 0)
      {
        warp_pointer = 1;
      }
      else if (strncmp (cp, "Position", 8) == 0)
      {
        cp += 8;
        geom = 1;
        while (isspace (*cp))
          cp++;
        gx = atoi (cp);
        while (!isspace (*cp))
          cp++;
        while (isspace (*cp))
          cp++;
        gy = atoi (cp);
        fprintf (fp_err, "Position @ (%d, %d)\n", gx, gy);
        continue;
      }
      else if (strncmp (cp, "Fore", 4) == 0)
      {
        cp += 4;
        while (isspace (*cp))
          cp++;
        color_names[c_fore] = copystring (cp, 0);
        fprintf (fp_err, "ColorFore: %s\n", color_names[c_fore]);
        continue;
      }
      else if (strncmp (cp, "Back", 4) == 0)
      {
        cp += 4;
        while (isspace (*cp))
          cp++;
        color_names[c_back] = copystring (cp, 0);
        fprintf (fp_err, "ColorBack: %s\n", color_names[c_back]);
        continue;
      }
      else if (strncmp (cp, "ItemFore", 8) == 0)
      {
        cp += 8;
        while (isspace (*cp))
          cp++;
        color_names[c_itemfore] = copystring (cp, 0);
        fprintf (fp_err, "ColorItemFore: %s\n", color_names[c_itemfore]);
        continue;
      }
      else if (strncmp (cp, "ItemBack", 8) == 0)
      {
        cp += 8;
        while (isspace (*cp))
          cp++;
        color_names[c_itemback] = copystring (cp, 0);
        fprintf (fp_err, "ColorItemBack: %s\n", color_names[c_itemback]);
        continue;
      }
      else if (strncmp (cp, "Font", 4) == 0)
      {
        cp += 4;
        while (isspace (*cp))
          cp++;
        font_names[f_text] = copystring (cp, 0);
        fprintf (fp_err, "Font: %s\n", font_names[f_text]);
#ifdef I18N
        if ((xfset[f_text] = XCreateFontSet (dpy, font_names[f_text], &ml, &mc,
                                     &ds)) == NULL)
          {
            fprintf (fp_err, "can't get font %s\n", font_names[f_text]);
            fn_tmp_length = strlen (font_names[f_text]) + strlen (",-*--14-*");
            fn_tmp = safemalloc (fn_tmp_length + 1);
            strcpy (fn_tmp, font_names[f_text]);
            strcat (fn_tmp, ",-*--14-*");
            fprintf (fp_err, "trying...%s\n", fn_tmp);
            if ((xfset[f_text] = XCreateFontSet (dpy, fn_tmp, &ml, &mc, &ds))
              == NULL)
            {
              fprintf (fp_err, "can't get font %s\n", fn_tmp);
              fprintf (fp_err, "trying... fixed\n");
              if ((xfset[f_text] = XCreateFontSet (dpy, "fixed,-*--14-*", &ml,
                                           &mc, &ds)) == NULL)
                {
                  fprintf (fp_err, "no fontset available\n");
                  exit (1);
                }
            }
          }
        XFontsOfFontSet (xfset[f_text], &fs_list, &ml);
        xfs[f_text] = fs_list[0];
#else
        xfs[f_text] = XLoadQueryFont (dpy, font_names[f_text]);
#endif
        fonts[f_text] = xfs[f_text]->fid;
        continue;
      }
      else if (strncmp (cp, "ButtonFont", 10) == 0)
      {
        cp += 10;
        while (isspace (*cp))
          cp++;
        font_names[f_button] = copystring (cp, 0);
        fprintf (fp_err, "ButtonFont: %s\n", font_names[f_button]);
#ifdef I18N
        if ((xfset[f_button] = XCreateFontSet (dpy, font_names[f_button], &ml,
                                     &mc, &ds)) == NULL)
          {
            fprintf (fp_err, "can't get font %s\n", font_names[f_button]);
            fn_tmp_length = strlen (font_names[f_button]) + strlen (",-*--14-*");
            fn_tmp = safemalloc (fn_tmp_length + 1);
            strcpy (fn_tmp, font_names[f_button]);
            strcat (fn_tmp, ",-*--14-*");
            fprintf (fp_err, "trying...%s\n", fn_tmp);
            if ((xfset[f_button] = XCreateFontSet (dpy, fn_tmp, &ml, &mc, &ds))
              == NULL)
            {
              fprintf (fp_err, "can't get font %s\n", fn_tmp);
              fprintf (fp_err, "trying... fixed\n");
              if ((xfset[f_button] = XCreateFontSet (dpy, "fixed,-*--14-*", &ml,
                                           &mc, &ds)) == NULL)
                {
                  fprintf (fp_err, "no fontset available\n");
                  exit (1);
                }
            }
          }
        XFontsOfFontSet (xfset[f_button], &fs_list, &ml);
        xfs[f_button] = fs_list[0];
#else
        xfs[f_button] = XLoadQueryFont (dpy, font_names[f_button]);
#endif
        fonts[f_button] = xfs[f_button]->fid;
        continue;
      }
      else if (strncmp (cp, "InputFont", 9) == 0)
      {
        cp += 9;
        while (isspace (*cp))
          cp++;
        font_names[f_input] = copystring (cp, 0);
        fprintf (fp_err, "InputFont: %s\n", font_names[f_input]);
#ifdef I18N
        if ((xfset[f_input] = XCreateFontSet (dpy, font_names[f_input], &ml,
                                    &mc, &ds)) == NULL)
          {
            fprintf (fp_err, "can't get font %s\n", font_names[f_input]);
            fn_tmp_length = strlen (font_names[f_input]) + strlen (",-*--14-*");
            fn_tmp = safemalloc (fn_tmp_length + 1);
            strcpy (fn_tmp, font_names[f_input]);
            strcat (fn_tmp, ",-*--14-*");
            fprintf (fp_err, "trying...%s\n", fn_tmp);
            if ((xfset[f_button] = XCreateFontSet (dpy, fn_tmp, &ml, &mc, &ds))
              == NULL)
            {
              fprintf (fp_err, "can't get font %s\n", fn_tmp);
              fprintf (fp_err, "trying... fixed\n");
              if ((xfset[f_button] = XCreateFontSet (dpy, "fixed,-*--14-*", &ml,
                                           &mc, &ds)) == NULL)
                {
                  fprintf (fp_err, "no fontset available\n");
                  exit (1);
                }
            }
          }
        XFontsOfFontSet (xfset[f_input], &fs_list, &ml);
        xfs[f_input] = fs_list[0];
#else
        xfs[f_input] = XLoadQueryFont (dpy, font_names[f_input]);
#endif
        fonts[f_input] = xfs[f_input]->fid;
        continue;
      }
      else if (strncmp (cp, "Line", 4) == 0)
      {
        cp += 4;
        cur_line = lines + n_lines++;
        while (isspace (*cp))
          cp++;
        if (strncmp (cp, "left", 4) == 0)
          cur_line->justify = L_LEFT;
        else if (strncmp (cp, "right", 5) == 0)
          cur_line->justify = L_RIGHT;
        else if (strncmp (cp, "center", 6) == 0)
          cur_line->justify = L_CENTER;
        else
          cur_line->justify = L_LEFTRIGHT;
        cur_line->n = 0;
        cur_line->items = (Item **) safemalloc (sizeof (Item *) * ITEMS_PER_LINE);
        continue;
      }
      else if (strncmp (cp, "Text", 4) == 0)
      {
/* syntax: *FFText "<text>" */
        cp += 4;
        item = items + n_items++;
        item->type = I_TEXT;
        item->header.name = "";
        while (isspace (*cp))
          cp++;
        if (*cp == '\"')
          item->text.value = CopyQuotedString (++cp);
        else
          item->text.value = "";
        item->text.n = strlen (item->text.value);
#ifdef I18N
        item->header.size_x = XmbTextEscapement (xfset[f_text], item->text.value,
                                     item->text.n) + 2 * TEXT_SPC;
#else
        item->header.size_x = XTextWidth (xfs[f_text], item->text.value,
                                  item->text.n) + 2 * TEXT_SPC;
#endif
        item->header.size_y = FontHeight (xfs[f_text]) + 2 * TEXT_SPC;
        fprintf (fp_err, "Text \"%s\" [%d, %d]\n", item->text.value,
               item->header.size_x, item->header.size_y);
        AddToLine (item);
        continue;
      }
      else if (strncmp (cp, "Input", 5) == 0)
      {
/* syntax: *FFInput <name> <size> "<init_value>" */
        cp += 5;
        item = items + n_items++;
        item->type = I_INPUT;
        while (isspace (*cp))
          cp++;
        item->header.name = CopySolidString (cp);
        cp += strlen (item->header.name);
        while (isspace (*cp))
          cp++;
        item->input.size = atoi (cp);
        while (!isspace (*cp))
          cp++;
        while (isspace (*cp))
          cp++;
        if (*cp == '\"')
          item->input.init_value = CopyQuotedString (++cp);
        else
          item->input.init_value = "";
        item->input.blanks = (char *) safemalloc (item->input.size);
        for (j = 0; j < item->input.size; j++)
          item->input.blanks[j] = ' ';
        item->input.buf = strlen (item->input.init_value) + 1;
        item->input.value = (char *) safemalloc (item->input.buf);
        item->header.size_x = FontWidth (xfs[f_input]) * item->input.size
          + 2 * TEXT_SPC + 2 * BOX_SPC;
        item->header.size_y = FontHeight (xfs[f_input]) + 3 * TEXT_SPC
          + 2 * BOX_SPC;
        fprintf (fp_err, "Input, %s, [%d], \"%s\"\n", item->header.name,
               item->input.size, item->input.init_value);
        AddToLine (item);
      }
      else if (strncmp (cp, "Selection", 9) == 0)
      {
/* syntax: *FFSelection <name> single | multiple */
        cp += 9;
        cur_sel = items + n_items++;
        cur_sel->type = I_SELECT;
        while (isspace (*cp))
          cp++;
        cur_sel->header.name = CopySolidString (cp);
        cp += strlen (cur_sel->header.name);
        while (isspace (*cp))
          cp++;
        if (strncmp (cp, "multiple", 8) == 0)
          cur_sel->select.key = IS_MULTIPLE;
        else
          cur_sel->select.key = IS_SINGLE;
        cur_sel->select.n = 0;
        cur_sel->select.choices =
          (Item **) safemalloc (sizeof (Item *) * CHOICES_PER_SEL);
        continue;
      }
      else if (strncmp (cp, "Choice", 6) == 0)
      {
/* syntax: *FFChoice <name> <value> [on | _off_] ["<text>"] */
        cp += 6;
        item = items + n_items++;
        item->type = I_CHOICE;
        while (isspace (*cp))
          cp++;
        item->header.name = CopySolidString (cp);
        cp += strlen (item->header.name);
        while (isspace (*cp))
          cp++;
        item->choice.value = CopySolidString (cp);
        cp += strlen (item->choice.value);
        while (isspace (*cp))
          cp++;
        if (strncmp (cp, "on", 2) == 0)
          item->choice.init_on = 1;
        else
          item->choice.init_on = 0;
        while (!isspace (*cp))
          cp++;
        while (isspace (*cp))
          cp++;
        if (*cp == '\"')
          item->choice.text = CopyQuotedString (++cp);
        else
          item->choice.text = "";
        item->choice.n = strlen (item->choice.text);
        item->choice.sel = cur_sel;
        cur_sel->select.choices[cur_sel->select.n++] = item;
        item->header.size_y = FontHeight (xfs[f_text]) + 2 * TEXT_SPC;
        item->header.size_x = FontHeight (xfs[f_text]) + 4 * TEXT_SPC +
#ifdef I18N
          XmbTextEscapement (xfset[f_text], item->choice.text, item->choice.n);
#else
          XTextWidth (xfs[f_text], item->choice.text, item->choice.n);
#endif
        fprintf (fp_err, "Choice %s, \"%s\", [%d, %d]\n", item->header.name,
             item->choice.text, item->header.size_x, item->header.size_y);
        AddToLine (item);
        continue;
      }
      else if (strncmp (cp, "Button", 6) == 0)
      {
/* syntax: *FFButton continue | restart | quit "<text>" */
        cp += 6;
        item = items + n_items++;
        item->type = I_BUTTON;
        item->header.name = "";
        while (isspace (*cp))
          cp++;
        if (strncmp (cp, "restart", 7) == 0)
          item->button.key = IB_RESTART;
        else if (strncmp (cp, "quit", 4) == 0)
          item->button.key = IB_QUIT;
        else
          item->button.key = IB_CONTINUE;
        while (!isspace (*cp))
          cp++;
        while (isspace (*cp))
          cp++;
        if (*cp == '\"')
          {
            item->button.text = CopyQuotedString (++cp);
            cp += strlen (item->button.text) + 1;
            while (isspace (*cp))
            cp++;
          }
        else
          item->button.text = "";
        if (*cp == '^')
          item->button.keypress = *(++cp) - '@';
        else if (*cp == 'F')
          item->button.keypress = 256 + atoi (++cp);
        else
          item->button.keypress = -1;
        item->button.len = strlen (item->button.text);
        item->button.n = 0;
        item->button.commands = (char **) safemalloc (sizeof (char *) * MAX_ITEMS);
        item->header.size_y = FontHeight (xfs[f_button]) + 2 * TEXT_SPC
          + 2 * BOX_SPC;
        item->header.size_x = 2 * TEXT_SPC + 2 * BOX_SPC
#ifdef I18N
          + XmbTextEscapement (xfset[f_button], item->button.text, item->button.len);
#else
          + XTextWidth (xfs[f_button], item->button.text, item->button.len);
#endif
        AddToLine (item);
        cur_button = item;
        continue;
      }
      else if (strncmp (cp, "Command", 7) == 0)
      {
/* syntax: *FFCommand <command> */
        cp += 7;
        while (isspace (*cp))
          cp++;
        cur_button->button.commands[cur_button->button.n++] =
          copystring (cp, 0);
      }
    }                   /* end of switch() */
  /* get the geometry right */
  max_width = 0;
  total_height = ITEM_VSPC;
  for (l = 0; l < n_lines; l++)
    {
      line = lines + l;
      for (i = 0; i < line->n; i++)
      {
        line->items[i]->header.pos_y = total_height;
        if (line->items[i]->header.size_y < line->size_y)
          line->items[i]->header.pos_y += (line->size_y - line->items[i]->header.size_y) / 2 + 1;
      }
      total_height += ITEM_VSPC + line->size_y;
      line->size_x += (line->n + 1) * ITEM_HSPC;
      if (line->size_x > max_width)
      max_width = line->size_x;
    }
  for (l = 0; l < n_lines; l++)
    {
      int width;
      line = lines + l;
      fprintf (fp_err, "Line[%d], %d, %d items\n", l, line->justify, line->n);
      switch (line->justify)
      {
      case L_LEFT:
        width = ITEM_HSPC;
        for (i = 0; i < line->n; i++)
          {
            line->items[i]->header.pos_x = width;
            width += ITEM_HSPC + line->items[i]->header.size_x;
          }
        break;
      case L_RIGHT:
        width = max_width - line->size_x + ITEM_HSPC;
        for (i = 0; i < line->n; i++)
          {
            line->items[i]->header.pos_x = width;
            width += ITEM_HSPC + line->items[i]->header.size_x;
          }
        break;
      case L_CENTER:
        width = (max_width - line->size_x) / 2 + ITEM_HSPC;
        for (i = 0; i < line->n; i++)
          {
            line->items[i]->header.pos_x = width;
            fprintf (fp_err, "Line[%d], Item[%d] @ (%d, %d)\n", l, i,
            line->items[i]->header.pos_x, line->items[i]->header.pos_y);
            width += ITEM_HSPC + line->items[i]->header.size_x;
          }
        break;
      case L_LEFTRIGHT:
        /* count the number of inputs on the line - the extra space will be
         * shared amongst these if there are any, otherwise it will be added
         * as space in between the elements
         */
        extra = 0;
        for (i = 0; i < line->n; i++)
          {
            if (line->items[i]->type == I_INPUT)
            extra++;
          }
        if (extra == 0)
          {
            if (line->n < 2)
            {           /* same as L_CENTER */
              width = (max_width - line->size_x) / 2 + ITEM_HSPC;
              for (i = 0; i < line->n; i++)
                {
                  line->items[i]->header.pos_x = width;
                  width += ITEM_HSPC + line->items[i]->header.size_x;
                }
            }
            else
            {
              extra = (max_width - line->size_x) / (line->n - 1);
              width = ITEM_HSPC;
              for (i = 0; i < line->n; i++)
                {
                  line->items[i]->header.pos_x = width;
                  width += ITEM_HSPC + line->items[i]->header.size_x + extra;
                }
            }
          }
        else
          {
            extra = (max_width - line->size_x) / extra;
            width = ITEM_HSPC;
            for (i = 0; i < line->n; i++)
            {
              line->items[i]->header.pos_x = width;
              if (line->items[i]->type == I_INPUT)
                line->items[i]->header.size_x += extra;
              width += ITEM_HSPC + line->items[i]->header.size_x;
            }
          }
        break;
      }
    }
  fclose (fp);
}

#define MAX_INTENSITY 65535

 /* allocate color cells */
void
GetColors ()
{
  Visual *visual = DefaultVisual (dpy, screen);
  XColor xc_item;
  int red = 0, green = 0, blue = 0, tmp1, tmp2;
  if (scr_depth < 8)
    {
      colors[c_back] = colors[c_itemback] = WhitePixel (dpy, screen);
      colors[c_fore] = colors[c_itemfore] = colors[c_itemlo] = colors[c_itemhi]
      = BlackPixel (dpy, screen);
    }
  else if (visual->class == TrueColor ||
         visual->class == StaticColor ||
         visual->class == StaticGray)
    {
      if (XParseColor (dpy, d_cmap, color_names[c_fore], &xc_item) &&
        XAllocColor (dpy, d_cmap, &xc_item))
      colors[c_fore] = xc_item.pixel;
      else
      colors[c_fore] = BlackPixel (dpy, screen);

      if (XParseColor (dpy, d_cmap, color_names[c_back], &xc_item) &&
        XAllocColor (dpy, d_cmap, &xc_item))
      colors[c_back] = xc_item.pixel;
      else
      colors[c_back] = WhitePixel (dpy, screen);

      if (XParseColor (dpy, d_cmap, color_names[c_itemfore], &xc_item) &&
        XAllocColor (dpy, d_cmap, &xc_item))
      colors[c_itemfore] = xc_item.pixel;
      else
      colors[c_itemfore] = BlackPixel (dpy, screen);

      if (XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item) &&
        XAllocColor (dpy, d_cmap, &xc_item))
      colors[c_itemback] = xc_item.pixel;
      else
      colors[c_itemback] = WhitePixel (dpy, screen);

      if (XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item))
      {
        red = (int) xc_item.red;
        green = (int) xc_item.green;
        blue = (int) xc_item.blue;
        xc_item.red = (60 * red) / 100;
        xc_item.green = (60 * green) / 100;
        xc_item.blue = (60 * blue) / 100;
        if (XAllocColor (dpy, d_cmap, &xc_item))
          colors[c_itemlo] = xc_item.pixel;
        else
          colors[c_itemlo] = BlackPixel (dpy, screen);
      }
      else
      colors[c_itemlo] = BlackPixel (dpy, screen);

      if (XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item))
      {
        tmp1 = (14 * red) / 10;
        if (tmp1 > MAX_INTENSITY)
          tmp1 = MAX_INTENSITY;
        tmp2 = (MAX_INTENSITY + red) / 2;
        xc_item.red = (tmp1 > tmp2) ? tmp1 : tmp2;
        tmp1 = (14 * green) / 10;
        if (tmp1 > MAX_INTENSITY)
          tmp1 = MAX_INTENSITY;
        tmp2 = (MAX_INTENSITY + green) / 2;
        xc_item.green = (tmp1 > tmp2) ? tmp1 : tmp2;
        tmp1 = (14 * blue) / 10;
        if (tmp1 > MAX_INTENSITY)
          tmp1 = MAX_INTENSITY;
        tmp2 = (MAX_INTENSITY + blue) / 2;
        xc_item.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
        if (XAllocColor (dpy, d_cmap, &xc_item))
          colors[c_itemhi] = xc_item.pixel;
        else
          colors[c_itemhi] = BlackPixel (dpy, screen);
      }
      else
      colors[c_itemhi] = BlackPixel (dpy, screen);
    }
  else if (!XAllocColorCells (dpy, d_cmap, 0, NULL, 0, colors, 6))
    {
      colors[c_back] = colors[c_itemback] = WhitePixel (dpy, screen);
      colors[c_fore] = colors[c_itemfore] = colors[c_itemlo] = colors[c_itemhi]
      = BlackPixel (dpy, screen);
    }
  else
    {
      XStoreNamedColor (dpy, d_cmap, color_names[c_fore], colors[c_fore],
                  DoRed | DoGreen | DoBlue);
      XStoreNamedColor (dpy, d_cmap, color_names[c_back], colors[c_back],
                  DoRed | DoGreen | DoBlue);
      XStoreNamedColor (dpy, d_cmap, color_names[c_itemfore],
                  colors[c_itemfore], DoRed | DoGreen | DoBlue);
      XStoreNamedColor (dpy, d_cmap, color_names[c_itemback],
                  colors[c_itemback], DoRed | DoGreen | DoBlue);
      XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item);
      red = (int) xc_item.red;
      green = (int) xc_item.green;
      blue = (int) xc_item.blue;
      xc_item.red = (60 * red) / 100;
      xc_item.green = (60 * green) / 100;
      xc_item.blue = (60 * blue) / 100;
      xc_item.pixel = colors[c_itemlo];
      xc_item.flags = DoRed | DoGreen | DoBlue;
      XStoreColor (dpy, d_cmap, &xc_item);
      XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item);
      tmp1 = (14 * red) / 10;
      if (tmp1 > MAX_INTENSITY)
      tmp1 = MAX_INTENSITY;
      tmp2 = (MAX_INTENSITY + red) / 2;
      xc_item.red = (tmp1 > tmp2) ? tmp1 : tmp2;
      tmp1 = (14 * green) / 10;
      if (tmp1 > MAX_INTENSITY)
      tmp1 = MAX_INTENSITY;
      tmp2 = (MAX_INTENSITY + green) / 2;
      xc_item.green = (tmp1 > tmp2) ? tmp1 : tmp2;
      tmp1 = (14 * blue) / 10;
      if (tmp1 > MAX_INTENSITY)
      tmp1 = MAX_INTENSITY;
      tmp2 = (MAX_INTENSITY + blue) / 2;
      xc_item.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
      xc_item.pixel = colors[c_itemhi];
      xc_item.flags = DoRed | DoGreen | DoBlue;
      XStoreColor (dpy, d_cmap, &xc_item);
    }
}


/* reset all the values */
void
Restart ()
{
  int i;
  Item *item;

  cur_text = NULL;
  abs_cursor = rel_cursor = 0;
  for (i = 0; i < n_items; i++)
    {
      item = items + i;
      switch (item->type)
      {
      case I_INPUT:
        if (!cur_text)
          cur_text = item;
        item->input.n = strlen (item->input.init_value);
        strcpy (item->input.value, item->input.init_value);
        item->input.left = 0;
        item->input.o_cursor = 0;
        break;
      case I_CHOICE:
        item->choice.on = item->choice.init_on;
        break;
      }
    }
}

/* redraw the frame */
void
RedrawFrame ()
{
  int i, x, y;
  Item *item;

  for (i = 0; i < n_items; i++)
    {
      item = items + i;
      switch (item->type)
      {
      case I_TEXT:
        x = item->header.pos_x + TEXT_SPC;
        y = item->header.pos_y + TEXT_SPC + xfs[f_text]->ascent;
#undef FONTSET
#define FONTSET xfset[f_text]
        XDrawImageString (dpy, frame, gc_text, x, y, item->text.value,
                      item->text.n);
        break;
      case I_CHOICE:
        x = item->header.pos_x + TEXT_SPC + item->header.size_y;
        y = item->header.pos_y + TEXT_SPC + xfs[f_text]->ascent;
        XDrawImageString (dpy, frame, gc_text, x, y, item->choice.text,
                      item->choice.n);
        break;
      }
    }
}

/* redraw an item */
void
RedrawItem (Item * item, int click)
{
  int dx, dy, len, x;
  static XSegment xsegs[4];

  switch (item->type)
    {
    case I_INPUT:
      dx = item->header.size_x - 1;
      dy = item->header.size_y - 1;
      XSetForeground (dpy, gc_button, colors[c_itemlo]);
      xsegs[0].x1 = 0, xsegs[0].y1 = 0;
      xsegs[0].x2 = 0, xsegs[0].y2 = dy;
      xsegs[1].x1 = 0, xsegs[1].y1 = 0;
      xsegs[1].x2 = dx, xsegs[1].y2 = 0;
      xsegs[2].x1 = 1, xsegs[2].y1 = 1;
      xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
      xsegs[3].x1 = 1, xsegs[3].y1 = 1;
      xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
      XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
      XSetForeground (dpy, gc_button, colors[c_itemhi]);
      xsegs[0].x1 = 1, xsegs[0].y1 = dy;
      xsegs[0].x2 = dx, xsegs[0].y2 = dy;
      xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
      xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
      xsegs[2].x1 = dx, xsegs[2].y1 = 1;
      xsegs[2].x2 = dx, xsegs[2].y2 = dy;
      xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
      xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
      XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
      if (click)
      {
        x = BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * abs_cursor - 1;
        XSetForeground (dpy, gc_button, colors[c_itemback]);
        XDrawLine (dpy, item->header.win, gc_button,
                 x, BOX_SPC, x, dy - BOX_SPC);
      }
      len = item->input.n - item->input.left;
      if (len > item->input.size)
      len = item->input.size;
      else
#undef FONTSET
#define FONTSET xfset[f_input]
      XDrawImageString (dpy, item->header.win, gc_input,
                  BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * len,
                    BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
                    item->input.blanks, item->input.size - len);
      XDrawImageString (dpy, item->header.win, gc_input,
                  BOX_SPC + TEXT_SPC,
                  BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
                  item->input.value + item->input.left, len);
      if (item == cur_text && !click)
      {
        x = BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * abs_cursor - 1;
        XDrawLine (dpy, item->header.win, gc_input,
                 x, BOX_SPC, x, dy - BOX_SPC);
      }
      break;
    case I_CHOICE:
      dx = dy = item->header.size_y - 1;
      if (item->choice.on)
      {
        XSetForeground (dpy, gc_button, colors[c_itemfore]);
        if (item->choice.sel->select.key == IS_MULTIPLE)
          {
            xsegs[0].x1 = 5, xsegs[0].y1 = 5;
            xsegs[0].x2 = dx - 5, xsegs[0].y2 = dy - 5;
            xsegs[1].x1 = 5, xsegs[1].y1 = dy - 5;
            xsegs[1].x2 = dx - 5, xsegs[1].y2 = 5;
            XDrawSegments (dpy, item->header.win, gc_button, xsegs, 2);
          }
        else
          {
            XDrawArc (dpy, item->header.win, gc_button,
                  5, 5, dx - 10, dy - 10, 0, 360 * 64);
          }
      }
      else
      XClearWindow (dpy, item->header.win);
      if (item->choice.on)
      XSetForeground (dpy, gc_button, colors[c_itemlo]);
      else
      XSetForeground (dpy, gc_button, colors[c_itemhi]);
      xsegs[0].x1 = 0, xsegs[0].y1 = 0;
      xsegs[0].x2 = 0, xsegs[0].y2 = dy;
      xsegs[1].x1 = 0, xsegs[1].y1 = 0;
      xsegs[1].x2 = dx, xsegs[1].y2 = 0;
      xsegs[2].x1 = 1, xsegs[2].y1 = 1;
      xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
      xsegs[3].x1 = 1, xsegs[3].y1 = 1;
      xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
      XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
      if (item->choice.on)
      XSetForeground (dpy, gc_button, colors[c_itemhi]);
      else
      XSetForeground (dpy, gc_button, colors[c_itemlo]);
      xsegs[0].x1 = 1, xsegs[0].y1 = dy;
      xsegs[0].x2 = dx, xsegs[0].y2 = dy;
      xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
      xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
      xsegs[2].x1 = dx, xsegs[2].y1 = 1;
      xsegs[2].x2 = dx, xsegs[2].y2 = dy;
      xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
      xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
      XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
      break;
    case I_BUTTON:
      dx = item->header.size_x - 1;
      dy = item->header.size_y - 1;
      if (click)
      XSetForeground (dpy, gc_button, colors[c_itemlo]);
      else
      XSetForeground (dpy, gc_button, colors[c_itemhi]);
      xsegs[0].x1 = 0, xsegs[0].y1 = 0;
      xsegs[0].x2 = 0, xsegs[0].y2 = dy;
      xsegs[1].x1 = 0, xsegs[1].y1 = 0;
      xsegs[1].x2 = dx, xsegs[1].y2 = 0;
      xsegs[2].x1 = 1, xsegs[2].y1 = 1;
      xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
      xsegs[3].x1 = 1, xsegs[3].y1 = 1;
      xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
      XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
      if (click)
      XSetForeground (dpy, gc_button, colors[c_itemhi]);
      else
      XSetForeground (dpy, gc_button, colors[c_itemlo]);
      xsegs[0].x1 = 1, xsegs[0].y1 = dy;
      xsegs[0].x2 = dx, xsegs[0].y2 = dy;
      xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
      xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
      xsegs[2].x1 = dx, xsegs[2].y1 = 1;
      xsegs[2].x2 = dx, xsegs[2].y2 = dy;
      xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
      xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
      XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
      XSetForeground (dpy, gc_button, colors[c_itemfore]);
#undef FONTSET
#define FONTSET xfset[f_button]
      XDrawImageString (dpy, item->header.win, gc_button,
                  BOX_SPC + TEXT_SPC,
                  BOX_SPC + TEXT_SPC + xfs[f_button]->ascent,
                  item->button.text, item->button.len);
      break;
    }
  XFlush (dpy);
}

void
ToggleChoice (Item * item)
{
  int i;
  Item *sel = item->choice.sel;

  if (sel->select.key == IS_SINGLE)
    {
      if (!item->choice.on)
      {
        for (i = 0; i < sel->select.n; i++)
          {
            if (sel->select.choices[i]->choice.on)
            {
              sel->select.choices[i]->choice.on = 0;
              RedrawItem (sel->select.choices[i], 0);
            }
          }
        item->choice.on = 1;
        RedrawItem (item, 0);
      }
    }
  else
    {                   /* IS_MULTIPLE */
      item->choice.on = !item->choice.on;
      RedrawItem (item, 0);
    }
}

/* do var substitution for command string */
void
ParseCommand (int dn, char *sp, char end, int *dn1, char **sp1)
#define AddChar(chr) { if (dn >= N) { N *= 2; buf = (char *)realloc(buf, N); } buf[dn++] = (chr); }
{
  static char var[256];
  char c, x, *wp, *cp, *vp;
  int i, j, dn2;
  Item *item;

  while (1)
    {
      c = *(sp++);
      if (c == '\0' || c == end)
      {                 /* end of substitution */
        *dn1 = dn;
        *sp1 = sp;
        return;
      }
      if (c == '\\')
      {                 /* escape char */
        AddChar ('\\');
        AddChar (*(sp++));
        goto next_loop;
      }
      if (c == '$')
      {                 /* variable */
        if (*sp != '(')
          goto normal_char;
        wp = ++sp;
        vp = var;
        while (1)
          {
            x = *(sp++);
            if (x == '\\')
            {
              *(vp++) = '\\';
              *(vp++) = *(sp++);
            }
            else if (x == ')' || x == '?' || x == '!')
            {
              *(vp++) = '\0';
              break;
            }
            else if (!isspace (x))
            *(vp++) = x;
          }
        for (i = 0; i < n_items; i++)
          {
            item = items + i;
            if (strcmp (var, item->header.name) == 0)
            {
              switch (item->type)
                {
                case I_INPUT:
                  if (x == ')')
                  {
                    for (cp = item->input.value; *cp != '\0'; cp++)
                      {
                        if (!isalnum (*cp))
                        AddChar ('\\');
                        AddChar (*cp);
                      }
                  }
                  else
                  {
                    ParseCommand (dn, sp, ')', &dn2, &sp);
                    if ((x == '?' && strlen (item->input.value) > 0) ||
                        (x == '!' && strlen (item->input.value) == 0))
                      dn = dn2;
                  }
                  break;
                case I_CHOICE:
                  if (x == ')')
                  {
                    for (cp = item->choice.value; *cp != '\0'; cp++)
                      AddChar (*cp);
                  }
                  else
                  {
                    ParseCommand (dn, sp, ')', &dn2, &sp);
                    if ((x == '?' && item->choice.on) ||
                        (x == '!' && !item->choice.on))
                      dn = dn2;
                  }
                  break;
                case I_SELECT:
                  if (x != ')')
                  ParseCommand (dn, sp, ')', &dn2, &sp);
                  AddChar (' ');
                  for (j = 0; j < item->select.n; j++)
                  {
                    if (item->select.choices[j]->choice.on)
                      {
                        for (cp = item->select.choices[j]->choice.value;
                           *cp != '\0'; cp++)
                        AddChar (*cp);
                        AddChar (' ');
                      }
                  }
                  break;
                }
              goto next_loop;
            }
          }
        goto next_loop;
      }
    normal_char:
      AddChar (c);
    next_loop:
      ;
    }
}

/* execute a command */
void
DoCommand (Item * cmd)
{
  int i, k, dn, len;
  char *sp;

  /* pre-command */
  if (cmd->button.key == IB_QUIT)
    XWithdrawWindow (dpy, frame, screen);

  for (k = 0; k < cmd->button.n; k++)
    {
      /* construct command */
      ParseCommand (0, cmd->button.commands[k], '\0', &dn, &sp);
      AddChar ('\0');
      fprintf (fp_err, "Final command[%d]: [%s]\n", k, buf);

      /* send command */
      write (fd[1], &ref, sizeof (Window));
      len = strlen (buf);
      write (fd[1], &len, sizeof (int));
      write (fd[1], buf, len);
      len = 1;
      write (fd[1], &len, sizeof (int));
    }

  /* post-command */
  if (cmd->button.key == IB_QUIT)
    {
      if (grab_server)
      XUngrabServer (dpy);
      exit (0);
    }
  if (cmd->button.key == IB_RESTART)
    {
      Restart ();
      for (i = 0; i < n_items; i++)
      {
        if (items[i].type == I_INPUT)
          {
            XClearWindow (dpy, items[i].header.win);
            RedrawItem (items + i, 0);
          }
        if (items[i].type == I_CHOICE)
          RedrawItem (items + i, 0);
      }
    }
}

/* open the windows */
void
OpenWindows ()
{
  int i, x, y;
  Item *item;
  static XColor xcf, xcb;
  static XSetWindowAttributes xswa;
  static XGCValues xgcv;
  static XWMHints wmh =
  {InputHint, True};
  static XSizeHints sh =
  {PPosition | PSize | USPosition | USSize};
  static int xgcv_mask = GCBackground | GCForeground | GCFont;

  xc_ibeam = XCreateFontCursor (dpy, XC_xterm);
  xc_hand = XCreateFontCursor (dpy, XC_hand2);
  xcf.pixel = WhitePixel (dpy, screen);
  XQueryColor (dpy, d_cmap, &xcf);
  xcb.pixel = colors[c_itemback];
  XQueryColor (dpy, d_cmap, &xcb);
  XRecolorCursor (dpy, xc_ibeam, &xcf, &xcb);

  /* the frame window first */
  if (geom)
    {
      if (gx >= 0)
      x = gx;
      else
      x = DisplayWidth (dpy, screen) - max_width + gx;
      if (gy >= 0)
      y = gy;
      else
      y = DisplayHeight (dpy, screen) - total_height + gy;
    }
  else
    {
      x = (DisplayWidth (dpy, screen) - max_width) / 2;
      y = (DisplayHeight (dpy, screen) - total_height) / 2;
    }
  frame = XCreateSimpleWindow (dpy, root, x, y, max_width, total_height,
                         0, BlackPixel (dpy, screen), colors[c_back]);
  XSelectInput (dpy, frame, KeyPressMask | ExposureMask);
  XStoreName (dpy, frame, MyName);
  XSetWMHints (dpy, frame, &wmh);
  sh.x = x, sh.y = y;
  sh.width = max_width, sh.height = total_height;
  XSetWMNormalHints (dpy, frame, &sh);

  xgcv.foreground = colors[c_fore];
  xgcv.background = colors[c_back];
  xgcv.font = fonts[f_text];
  gc_text = XCreateGC (dpy, frame, xgcv_mask, &xgcv);
  xgcv.background = colors[c_itemback];
  xgcv.foreground = colors[c_itemfore];
  xgcv.font = fonts[f_input];
  gc_input = XCreateGC (dpy, frame, xgcv_mask, &xgcv);
  xgcv.font = fonts[f_button];
  gc_button = XCreateGC (dpy, frame, xgcv_mask, &xgcv);

  for (i = 0; i < n_items; i++)
    {
      item = items + i;
      switch (item->type)
      {
      case I_INPUT:
        item->header.win =
          XCreateSimpleWindow (dpy, frame,
                         item->header.pos_x, item->header.pos_y,
                         item->header.size_x, item->header.size_y,
                         0, colors[c_back], colors[c_itemback]);
        XSelectInput (dpy, item->header.win, ButtonPressMask | ExposureMask);
        xswa.cursor = xc_ibeam;
        XChangeWindowAttributes (dpy, item->header.win, CWCursor, &xswa);
        break;
      case I_CHOICE:
        item->header.win =
          XCreateSimpleWindow (dpy, frame,
                         item->header.pos_x, item->header.pos_y,
                         item->header.size_y, item->header.size_y,
                         0, colors[c_back], colors[c_itemback]);
        XSelectInput (dpy, item->header.win, ButtonPressMask | ExposureMask);
        xswa.cursor = xc_hand;
        XChangeWindowAttributes (dpy, item->header.win, CWCursor, &xswa);
        break;
      case I_BUTTON:
        item->header.win =
          XCreateSimpleWindow (dpy, frame,
                         item->header.pos_x, item->header.pos_y,
                         item->header.size_x, item->header.size_y,
                         0, colors[c_back], colors[c_itemback]);
        XSelectInput (dpy, item->header.win,
                  ButtonPressMask | ExposureMask);
        xswa.cursor = xc_hand;
        XChangeWindowAttributes (dpy, item->header.win, CWCursor, &xswa);
        break;
      }
    }
  Restart ();
  XMapRaised (dpy, frame);
  XMapSubwindows (dpy, frame);
  if (warp_pointer)
    {
      XWarpPointer (dpy, None, frame, 0, 0, 0, 0,
                max_width / 2, total_height - 1);
    }
  DoCommand (&def_button);
}

/* read something from Afterstep */
void
ReadAfterstep ()
{
  static char buffer[32];
  int n;

  n = read (fd[0], buffer, 32);
  if (n == 0)
    {
      if (grab_server)
      XUngrabServer (dpy);
      exit (0);
    }
}

/* read an X event */
void
ReadXServer ()
{
  static XEvent event;
  int i, old_cursor = 0, keypress;
  Item *item, *old_item;
  KeySym ks;
  char *sp, *dp, *ep;
  static char buf[10], n;

  while (XEventsQueued (dpy, QueuedAfterReading))
    {
      XNextEvent (dpy, &event);
      if (event.xany.window == frame)
      {
        switch (event.type)
          {
          case Expose:
            RedrawFrame ();
            if (grab_server && !server_grabbed)
            {
              if (GrabSuccess ==
                  XGrabPointer (dpy, frame, True, 0, GrabModeAsync, GrabModeAsync,
                            None, None, CurrentTime))
                server_grabbed = 1;
            }
            break;
          case KeyPress:      /* we do text input here */
            n = XLookupString (&event.xkey, buf, 10, &ks, NULL);
            keypress = buf[0];
            fprintf (fp_err, "Keypress [%s]\n", buf);
            if (n == 0)
            {           /* not a regular key, translate it into one */
              switch (ks)
                {
                case XK_Home:
                case XK_Begin:
                  buf[0] = '\001';  /* ^A */
                  break;
                case XK_End:
                  buf[0] = '\005';  /* ^E */
                  break;
                case XK_Left:
                  buf[0] = '\002';  /* ^B */
                  break;
                case XK_Right:
                  buf[0] = '\006';  /* ^F */
                  break;
                case XK_Up:
                  buf[0] = '\020';  /* ^P */
                  break;
                case XK_Down:
                  buf[0] = '\016';  /* ^N */
                  break;
                default:
                  if (ks >= XK_F1 && ks <= XK_F35)
                  {
                    buf[0] = '\0';
                    keypress = 257 + ks - XK_F1;
                  }
                  else
                  goto no_redraw;         /* no action for this event */
                }
            }
            if (!cur_text)
            {           /* no text input fields */
              for (i = 0; i < n_items; i++)
                {
                  item = items + i;
                  fprintf (fp_err, "Button[%d], keypress==%d\n", i,
                         item->button.keypress);
                  if (item->type == I_BUTTON && item->button.keypress == buf[0])
                  {
                    RedrawItem (item, 1);
                    sleep (1);
                    RedrawItem (item, 0);
                    DoCommand (item);
                    goto no_redraw;
                  }
                }
              break;
            }
            switch (buf[0])
            {
            case '\001':      /* ^A */
              old_cursor = abs_cursor;
              rel_cursor = 0;
              abs_cursor = 0;
              cur_text->input.left = 0;
              goto redraw_newcursor;
              break;
            case '\005':      /* ^E */
              old_cursor = abs_cursor;
              rel_cursor = cur_text->input.n;
              if ((cur_text->input.left = rel_cursor - cur_text->input.size) < 0)
                cur_text->input.left = 0;
              abs_cursor = rel_cursor - cur_text->input.left;
              goto redraw_newcursor;
              break;
            case '\002':      /* ^B */
              old_cursor = abs_cursor;
              if (rel_cursor > 0)
                {
                  rel_cursor--;
                  abs_cursor--;
                  if (abs_cursor <= 0 && rel_cursor > 0)
                  {
                    abs_cursor++;
                    cur_text->input.left--;
                  }
                }
              goto redraw_newcursor;
              break;
            case '\006':      /* ^F */
              old_cursor = abs_cursor;
              if (rel_cursor < cur_text->input.n)
                {
                  rel_cursor++;
                  abs_cursor++;
                  if (abs_cursor >= cur_text->input.size &&
                    rel_cursor < cur_text->input.n)
                  {
                    abs_cursor--;
                    cur_text->input.left++;
                  }
                }
              goto redraw_newcursor;
              break;
            case '\010':      /* ^H */
            case '\177':      /* DEL */
              old_cursor = abs_cursor;
              if (rel_cursor > 0)
                {
                  sp = cur_text->input.value + rel_cursor;
                  dp = sp - 1;
                  for (; *dp = *sp, *sp != '\0'; dp++, sp++);
                  cur_text->input.n--;
                  rel_cursor--;
                  if (rel_cursor < abs_cursor)
                  {
                    abs_cursor--;
                    if (abs_cursor <= 0 && rel_cursor > 0)
                      {
                        abs_cursor++;
                        cur_text->input.left--;
                      }
                  }
                  else
                  cur_text->input.left--;
                }
              goto redraw_newcursor;
              break;
            case '\004':      /* ^D */
              if (rel_cursor < cur_text->input.n)
                {
                  sp = cur_text->input.value + rel_cursor + 1;
                  dp = sp - 1;
                  for (; *dp = *sp, *sp != '\0'; dp++, sp++);
                  cur_text->input.n--;
                  goto redraw;
                }
              break;
            case '\013':      /* ^K */
              cur_text->input.value[rel_cursor] = '\0';
              cur_text->input.n = rel_cursor;
              goto redraw;
            case '\025':      /* ^U */
              old_cursor = abs_cursor;
              cur_text->input.value[0] = '\0';
              cur_text->input.n = cur_text->input.left = 0;
              rel_cursor = abs_cursor = 0;
              goto redraw_newcursor;
            case '\t':
            case '\n':
            case '\015':
            case '\016':      /* LINEFEED, TAB, RETURN, ^N, jump to the next field */
              for (i = (cur_text - items) + 1; i < n_items; i++)
                {
                  item = items + i;
                  if (item->type == I_INPUT)
                  {
                    old_item = cur_text;
                    old_item->input.o_cursor = rel_cursor;
                    cur_text = item;
                    RedrawItem (old_item, 1);
                    rel_cursor = item->input.o_cursor;
                    abs_cursor = rel_cursor - item->input.left;
                    goto redraw;
                  }
                }
              /* end of all text input fields, check for buttons */
              for (i = 0; i < n_items; i++)
                {
                  item = items + i;
                  fprintf (fp_err, "Button[%d], keypress==%d\n", i,
                         item->button.keypress);
                  if (item->type == I_BUTTON && item->button.keypress == buf[0])
                  {
                    RedrawItem (item, 1);
                    sleep (1);
                    RedrawItem (item, 0);
                    DoCommand (item);
                    goto no_redraw;
                  }
                }
              /* goto the first text input field */
              for (i = 0; i < n_items; i++)
                {
                  item = items + i;
                  if (item->type == I_INPUT)
                  {
                    old_item = cur_text;
                    old_item->input.o_cursor = rel_cursor;
                    cur_text = item;
                    RedrawItem (old_item, 1);
                    rel_cursor = item->input.o_cursor;
                    abs_cursor = rel_cursor - item->input.left;
                    goto redraw;
                  }
                }
              break;
            default:
              old_cursor = abs_cursor;
              if (buf[0] >= ' ' && buf[0] < '\177')
                {       /* regular char */
                  if (++(cur_text->input.n) >= cur_text->input.buf)
                  {
                    cur_text->input.buf += cur_text->input.size;
                    cur_text->input.value =
                      (char *) realloc (cur_text->input.value,
                                    cur_text->input.buf);
                  }
                  dp = cur_text->input.value + cur_text->input.n;
                  sp = dp - 1;
                  ep = cur_text->input.value + rel_cursor;
                  for (; *dp = *sp, sp != ep; sp--, dp--);
                  *ep = buf[0];
                  rel_cursor++;
                  abs_cursor++;
                  if (abs_cursor >= cur_text->input.size)
                  {
                    if (rel_cursor < cur_text->input.n)
                      abs_cursor = cur_text->input.size - 1;
                    else
                      abs_cursor = cur_text->input.size;
                    cur_text->input.left = rel_cursor - abs_cursor;
                  }
                  goto redraw_newcursor;
                }
              /* unrecognized key press, check for buttons */
              for (i = 0; i < n_items; i++)
                {
                  item = items + i;
                  fprintf (fp_err, "Button[%d], keypress==%d\n", i,
                         item->button.keypress);
                  if (item->type == I_BUTTON && item->button.keypress == keypress)
                  {
                    RedrawItem (item, 1);
                    sleep (1);      /* .5 seconds */
                    RedrawItem (item, 0);
                    DoCommand (item);
                    goto no_redraw;
                  }
                }
              break;
            }
          redraw_newcursor:
            {
            int x, dy;
            x = BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * old_cursor - 1;
            dy = cur_text->header.size_y - 1;
            XSetForeground (dpy, gc_button, colors[c_itemback]);
            XDrawLine (dpy, cur_text->header.win, gc_button,
                     x, BOX_SPC, x, dy - BOX_SPC);
            }
          redraw:
            {
            int len, x, dy;
            len = cur_text->input.n - cur_text->input.left;
            if (len > cur_text->input.size)
              len = cur_text->input.size;
            else
#undef FONTSET
#define FONTSET xfset[f_input]
              XDrawImageString (dpy, cur_text->header.win, gc_input,
                            BOX_SPC + TEXT_SPC +
                            FontWidth (xfs[f_input]) * len,
                          BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
                            cur_text->input.blanks,
                            cur_text->input.size - len);
            XDrawImageString (dpy, cur_text->header.win, gc_input,
                          BOX_SPC + TEXT_SPC,
                          BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
                   cur_text->input.value + cur_text->input.left, len);
            x = BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * abs_cursor - 1;
            dy = cur_text->header.size_y - 1;
            XDrawLine (dpy, cur_text->header.win, gc_input,
                     x, BOX_SPC, x, dy - BOX_SPC);
            }
          no_redraw:
            break;            /* end of case KeyPress */
          }             /* end of switch (event.type) */
        continue;
      }                 /* end of if (event.xany.window == frame) */
      for (i = 0; i < n_items; i++)
      {
        item = items + i;
        if (event.xany.window == item->header.win)
          {
            switch (event.type)
            {
            case Expose:
              RedrawItem (item, 0);
              break;
            case ButtonPress:
              if (item->type == I_INPUT)
                {
                  old_item = cur_text;
                  old_item->input.o_cursor = rel_cursor;
                  cur_text = item;
                  RedrawItem (old_item, 1);
                  abs_cursor = (event.xbutton.x - BOX_SPC -
                            TEXT_SPC + FontWidth (xfs[f_input]) / 2)
                  / FontWidth (xfs[f_input]);
                  if (abs_cursor < 0)
                  abs_cursor = 0;
                  if (abs_cursor > item->input.size)
                  abs_cursor = item->input.size;
                  rel_cursor = abs_cursor + item->input.left;
                  if (rel_cursor < 0)
                  rel_cursor = 0;
                  if (rel_cursor > item->input.n)
                  rel_cursor = item->input.n;
                  if (rel_cursor > 0 && rel_cursor == item->input.left)
                  item->input.left--;
                  if (rel_cursor < item->input.n &&
                    rel_cursor == item->input.left + item->input.size)
                  item->input.left++;
                  abs_cursor = rel_cursor - item->input.left;
                  RedrawItem (item, 0);
                }
              if (item->type == I_CHOICE)
                ToggleChoice (item);
              if (item->type == I_BUTTON)
                {
                  RedrawItem (item, 1);
                  XGrabPointer (dpy, item->header.win, False, ButtonReleaseMask,
                            GrabModeAsync, GrabModeAsync,
                            None, None, CurrentTime);
                }
              break;
            case ButtonRelease:
              RedrawItem (item, 0);
              if (grab_server && server_grabbed)
                {
                  XGrabPointer (dpy, frame, True, 0, GrabModeAsync, GrabModeAsync,
                            None, None, CurrentTime);
                  XFlush (dpy);
                }
              else
                {
                  XUngrabPointer (dpy, CurrentTime);
                  XFlush (dpy);
                }
              if (event.xbutton.x >= 0 &&
                  event.xbutton.x < item->header.size_x &&
                  event.xbutton.y >= 0 &&
                  event.xbutton.y < item->header.size_y)
                {
                  DoCommand (item);
                }
              break;
            }
          }
      }                 /* end of for (i = 0 */
    }                   /* while loop */
}

/* main event loop */
void
MainLoop ()
{
  fd_set fds;

  while (1)
    {
      FD_ZERO (&fds);
      FD_SET (fd[0], &fds);
      FD_SET (fd_x, &fds);

      XFlush (dpy);
      if (select (32, &fds, NULL, NULL, NULL) > 0)
      {
        if (FD_ISSET (fd[0], &fds))
          ReadAfterstep ();
        if (FD_ISSET (fd_x, &fds))
          ReadXServer ();
      }
    }
}

void
version (void)
{
  printf ("%s version %s\n", MyName, VERSION);
  exit (0);
}

void
usage (void)
{
  printf ("Usage:\n"
    "%s [-v|--version] [-h|--help] [--window window-id] [script-name]\n", MyName);
  exit (0);
}

/* main procedure */
int
main (int argc, char **argv)
{
  char configfile[255];
  char *realconfigfile;
  FILE *fdopen ();
  char *temp;
  int i;
  char *global_config_file = NULL;

  buf = (char *) safemalloc (N);    /* some kludge */

#ifdef DEBUG
  fd_err = open (".FormErrors", O_WRONLY | O_CREAT, 0777);
  fp_err = fdopen (fd_err, "w");
#else
  fd_err = open ("/dev/null", O_WRONLY, 0);
  fp_err = fdopen (fd_err, "w");
#endif

#ifdef I18N
  if (setlocale (LC_CTYPE, "") == NULL)
    fprintf (fp_err, "can't set locale\n");
#endif

  ref = None;

  /* Save our program name - for error messages */
  temp = strrchr (argv[0], '/');
  MyName = temp ? temp + 1 : argv[0];

  for (i = 1; i < argc && *argv[i] == '-'; i++)
    {
      if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help"))
      usage ();
      else if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "--version"))
      version ();
      else if (!strcmp (argv[i], "-w") || !strcmp (argv[i], "--window"))
      ref = strtol (argv[++i], NULL, 16);
      else if (!strcmp (argv[i], "-c") || !strcmp (argv[i], "--context"))
      i++;
      else if (!strcmp (argv[i], "-f") && i + 1 < argc)
      global_config_file = argv[++i];
    }

  if (i < argc)
    MyName = argv[i++];

#ifdef DEBUG
  fprintf (fp_err, "ref == %d\n", ref);
#endif

  if ((dpy = XOpenDisplay ("")) == NULL)
    {
      fprintf (stderr, "%s: couldn't open display %s\n",
             MyName, XDisplayName (""));
      exit (1);
    }
  screen = DefaultScreen (dpy);

  /* connect to AfterStep */
  temp = module_get_socket_property (RootWindow (dpy, screen));
  fd[0] = fd[1] = module_connect (temp);
  XFree (temp);
  if (fd[0] < 0)
    {
      fprintf (stderr, "%s: unable to establish connection to AfterStep\n", MyName);
      exit (1);
    }
  temp = safemalloc (9 + strlen (MyName) + 1);
  sprintf (temp, "SET_NAME %s", MyName);
  SendInfo (fd, temp, None);
  free (temp);

  fd_x = XConnectionNumber (dpy);
  root = RootWindow (dpy, screen);
  scr_depth = DefaultDepth (dpy, screen);
  d_cmap = DefaultColormap (dpy, screen);

  if (global_config_file != NULL)
    ParseOptions (global_config_file);
  else
    {
      sprintf (configfile, "%s/forms", AFTER_DIR);
      realconfigfile = PutHome (configfile);

      if ((CheckFile (realconfigfile)) == -1)
      {
        free (realconfigfile);
        sprintf (configfile, "%s/forms", AFTER_SHAREDIR);
        realconfigfile = PutHome (configfile);
      }
      ParseOptions (realconfigfile);
    }

  GetColors ();

  OpenWindows ();

  MainLoop ();

  return 0;
}

Generated by  Doxygen 1.6.0   Back to index