1 /*
2  * Copyright (C) 1998 Sasha Vasko <sasha at aftercode.net>
3  * Copyright (C) 1998 Makoto Kato <m_kato@ga2.so-net.ne.jp>
4  * Copyright (C) 1996 Michael Beam
5  * Copyright (C) 1996 Takanori Kubota
6  * Copyright (C) 1995 Thomas Zuwei Feng
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #include "../../configure.h"
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <ctype.h>
30 #include <fcntl.h>
31 #include <X11/Xlib.h>
32 #include <X11/X.h>
33 #include <X11/Xutil.h>
34 #include <X11/cursorfont.h>
35 #define XK_MISCELLANY
36 #include <X11/keysymdef.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #if defined ___AIX || defined _AIX || defined ___AIXV3
41 #include <sys/select.h>
42 #endif
43 #ifdef I18N
44 #include <X11/Xlocale.h>
45 #define XDrawImageString(t,u,v,w,x,y,z) XmbDrawImageString(t,u,FONTSET,v,w,x,y,z)
46 #endif
47 
48 #include "../../include/aftersteplib.h"
49 #include "../../include/style.h"
50 #include "../../include/screen.h"
51 #include "../../include/module.h"
52 
53 void
dummy()54 dummy ()
55 {
56 }
57 
58 #ifdef DEBUG
59 #define fprintf fprintf
60 #else
61 #define fprintf dummy
62 #endif
63 
64 
65 #define TEXT_SPC    3
66 #define BOX_SPC     3
67 #define ITEM_HSPC   10
68 #define ITEM_VSPC   5
69 
70 /* tba: use dynamic buffer expanding */
71 #define MAX_LINES 64
72 #define MAX_ITEMS 256
73 #define ITEMS_PER_LINE 64
74 #define CHOICES_PER_SEL 64
75 
76 #define I_TEXT          1
77 #define I_INPUT         2
78 #define I_SELECT        3
79 #define I_CHOICE        4
80 #define I_BUTTON        5
81 
82 #define IS_SINGLE       1
83 #define IS_MULTIPLE     2
84 
85 #define IB_CONTINUE     1
86 #define IB_RESTART      2
87 #define IB_QUIT         3
88 
89 typedef union _item
90 {
91   int type;			/* item type, one of I_TEXT .. I_BUTTON */
92   struct _head
93     {				/* common header */
94       int type;
95       int win;			/* X window id */
96       char *name;		/* identifier name */
97       int size_x, size_y;	/* size of bounding box */
98       int pos_x, pos_y;		/* position of top-left corner */
99     }
100   header;
101   struct
102     {				/* I_TEXT */
103       struct _head head;
104       int n;			/* string length */
105       char *value;		/* string to display */
106     }
107   text;
108   struct
109     {				/* I_INPUT */
110       struct _head head;
111       int buf;			/* input string buffer */
112       int n;			/* string length */
113       char *value;		/* input string */
114       char *init_value;		/* default string */
115       char *blanks;		/* blank string */
116       int size;			/* input field size */
117       int left;			/* position of the left-most displayed char */
118       int o_cursor;		/* store relative cursor position */
119     }
120   input;
121   struct
122     {				/* I_SELECT */
123       struct _head head;
124       int key;			/* one of IS_MULTIPLE, IS_SINGLE */
125       int n;			/* number of choices */
126       union _item **choices;	/* list of choices */
127     }
128   select;
129   struct
130     {				/* I_CHOICE */
131       struct _head head;
132       int on;			/* selected or not */
133       int init_on;		/* initially selected or not */
134       char *value;		/* value if selected */
135       int n;			/* text string length */
136       char *text;		/* text string */
137       union _item *sel;		/* selection it belongs to */
138     }
139   choice;
140   struct
141     {				/* I_BUTTON */
142       struct _head head;
143       int key;			/* one of IB_CONTINUE, IB_RESTART, IB_QUIT */
144       int n;			/* # of commands */
145       int len;			/* text length */
146       char *text;		/* text string */
147       int keypress;		/* short cut */
148       /* Afterstep command to execute */
149       char **commands;
150     }
151   button;
152 }
153 Item;
154 
155 
156 #define L_LEFT        1
157 #define L_RIGHT       2
158 #define L_CENTER      3
159 #define L_LEFTRIGHT   4
160 
161 typedef struct _line
162   {
163     int n;			/* number of items on the line */
164     int justify;		/* justification */
165     int size_x, size_y;		/* size of bounding rectangle */
166     Item **items;		/* list of items */
167   }
168 Line;
169 
170 
171 /* global variables */
172 char *MyName;			/* program name, e.g. Form */
173 
174 int fd[2];			/* fd for Afterstep<->Module packets */
175 int fd_err;
176 FILE *fp_err;
177 
178 Line lines[MAX_LINES];
179 int n_lines;
180 Item items[MAX_ITEMS];
181 int n_items;
182 Item def_button;
183 
184 int grab_server = 0, server_grabbed = 0;
185 int gx, gy, geom = 0;
186 int warp_pointer = 0;
187 
188 Display *dpy;
189 int fd_x;			/* fd for X connection */
190 
191 ScreenInfo Scr;
192 
193 Window root, frame, ref;
194 Colormap d_cmap;
195 int screen;
196 int scr_depth;
197 
198 int max_width, total_height;	/* frame size */
199 
200 enum
201   {
202     c_back, c_fore, c_itemback, c_itemfore, c_itemlo, c_itemhi
203   };
204 char *color_names[4] =
205 {
206   "Light Gray", "Black", "Gray50", "Wheat"
207 };
208 long colors[6];
209 
210 enum
211   {
212     f_text, f_input, f_button
213   };
214 char *font_names[3] =
215 {
216   "fixed",
217   "fixed",
218   "fixed"
219 };
220 Font fonts[3];
221 XFontStruct *xfs[3];
222 #ifdef I18N
223 XFontSet xfset[3];
224 #endif
225 
226 Cursor xc_ibeam, xc_hand;
227 
228 GC gc_text, gc_input, gc_button;
229 
230 Item *cur_text;
231 int abs_cursor;
232 int rel_cursor;
233 
234 static char *buf;
235 static int N = 8;
236 
237 /* copy a string until '\0', or up to n chars, and delete trailing spaces */
238 char *
copystring(char * cp,int n)239 copystring (char *cp, int n)
240 {
241   char *dp, *bp;
242   if (n == 0)
243     n = strlen (cp);
244   bp = dp = (char *) safemalloc (n + 1);
245   while (n-- > 0)
246     *dp++ = *cp++;
247   while (isspace ((unsigned char) *(--dp)));
248   *(++dp) = '\0';
249   return bp;
250 }
251 
252 void
DeadPipe(int nonsense)253 DeadPipe (int nonsense)
254 {
255   exit (0);
256 }
257 
258 
259 /* copy a string until '"', or '\n', or '\0' */
260 char *
CopyQuotedString(char * cp)261 CopyQuotedString (char *cp)
262 {
263   char *dp, *bp, c;
264   bp = dp = (char *) safemalloc (strlen (cp) + 1);
265   while (1)
266     {
267       switch (c = *(cp++))
268 	{
269 	case '\\':
270 	  *(dp++) = *(cp++);
271 	  break;
272 	case '\"':
273 	case '\n':
274 	case '\0':
275 	  *dp = '\0';
276 	  return bp;
277 	  break;
278 	default:
279 	  *(dp++) = c;
280 	  break;
281 	}
282     }
283 }
284 
285 /* copy a string until the first space */
286 char *
CopySolidString(char * cp)287 CopySolidString (char *cp)
288 {
289   char *dp, *bp, c;
290   bp = dp = (char *) safemalloc (strlen (cp) + 1);
291   while (1)
292     {
293       c = *(cp++);
294       if (c == '\\')
295 	{
296 	  *(dp++) = '\\';
297 	  *(dp++) = *(cp++);
298 	}
299       else if (isspace ((unsigned char) c) || c == '\0')
300 	{
301 	  *dp = '\0';
302 	  return bp;
303 	}
304       else
305 	*(dp++) = c;
306     }
307 }
308 
309 /* get the font height */
310 int
FontHeight(XFontStruct * xfs)311 FontHeight (XFontStruct * xfs)
312 {
313   return (xfs->ascent + xfs->descent);
314 }
315 
316 /* get the font width, for fixed-width font only */
317 int
FontWidth(XFontStruct * xfs)318 FontWidth (XFontStruct * xfs)
319 {
320   return (xfs->per_char[0].width);
321 }
322 
323 /* read the configuration file */
324 void
ParseOptions(char * file_name)325 ParseOptions (char *file_name)
326 {
327   FILE *fp, *fopen ();
328   int prog_name_len, i, j, l, extra;
329   char line_buf[MAXLINELENGTH];
330   char *cp;
331   Line *cur_line, *line;
332   Item *item, *cur_sel = NULL, *cur_button = NULL;
333 #ifdef I18N
334   XFontStruct **fs_list;
335   char **ml;
336   int mc;
337   char *ds;
338   char *fn_tmp;
339   int fn_tmp_length;
340 #endif
341 
342 #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; }
343 
344   n_items = 0;
345   n_lines = 0;
346 
347   /* default line in case the first *FFLine is missing */
348   lines[0].n = 0;
349   lines[0].justify = L_CENTER;
350   lines[0].size_x = lines[0].size_y = 0;
351   lines[0].items = (Item **) safemalloc (sizeof (Item *) * ITEMS_PER_LINE);
352   cur_line = lines;
353 
354   /* default button is for initial functions */
355   cur_button = &def_button;
356   def_button.button.n = 0;
357   def_button.button.commands = (char **) safemalloc (sizeof (char *) * MAX_ITEMS);
358   def_button.button.key = IB_CONTINUE;
359 
360   /* default fonts in case the *FFont's are missing */
361 #ifdef I18N
362   xfset[f_text] = xfset[f_input] = xfset[f_button] = XCreateFontSet (dpy, "fixed", &ml, &mc, &ds);
363   XFontsOfFontSet (xfset[f_text], &fs_list, &ml);
364   xfs[f_text] = xfs[f_input] = xfs[f_button] = fs_list[0];
365 #else
366   xfs[f_text] = xfs[f_input] = xfs[f_button] =
367     XLoadQueryFont (dpy, "fixed");
368 #endif
369   fonts[f_text] = fonts[f_input] = fonts[f_button] = xfs[f_text]->fid;
370 
371   if (!(fp = fopen (file_name, "r")))
372     {
373       fprintf (fp_err, "%s: can't open config file %s.\n", MyName, file_name);
374       exit (1);
375     }
376   prog_name_len = strlen (MyName);
377   while (fgets (line_buf, sizeof (line_buf), fp))
378     {
379       cp = line_buf;
380       while (isspace (*cp))
381 	cp++;			/* skip blanks */
382       if (*cp != '*')
383 	continue;
384       if (strncmp (++cp, MyName, prog_name_len) != 0)
385 	continue;
386       cp += prog_name_len;
387       /* at this point we have recognized "*Form" */
388       if (strncmp (cp, "GrabServer", 10) == 0)
389 	{
390 	  grab_server = 1;
391 	  continue;
392 	}
393       else if (strncmp (cp, "WarpPointer", 11) == 0)
394 	{
395 	  warp_pointer = 1;
396 	}
397       else if (strncmp (cp, "Position", 8) == 0)
398 	{
399 	  cp += 8;
400 	  geom = 1;
401 	  while (isspace (*cp))
402 	    cp++;
403 	  gx = atoi (cp);
404 	  while (!isspace (*cp))
405 	    cp++;
406 	  while (isspace (*cp))
407 	    cp++;
408 	  gy = atoi (cp);
409 	  fprintf (fp_err, "Position @ (%d, %d)\n", gx, gy);
410 	  continue;
411 	}
412       else if (strncmp (cp, "Fore", 4) == 0)
413 	{
414 	  cp += 4;
415 	  while (isspace (*cp))
416 	    cp++;
417 	  color_names[c_fore] = copystring (cp, 0);
418 	  fprintf (fp_err, "ColorFore: %s\n", color_names[c_fore]);
419 	  continue;
420 	}
421       else if (strncmp (cp, "Back", 4) == 0)
422 	{
423 	  cp += 4;
424 	  while (isspace (*cp))
425 	    cp++;
426 	  color_names[c_back] = copystring (cp, 0);
427 	  fprintf (fp_err, "ColorBack: %s\n", color_names[c_back]);
428 	  continue;
429 	}
430       else if (strncmp (cp, "ItemFore", 8) == 0)
431 	{
432 	  cp += 8;
433 	  while (isspace (*cp))
434 	    cp++;
435 	  color_names[c_itemfore] = copystring (cp, 0);
436 	  fprintf (fp_err, "ColorItemFore: %s\n", color_names[c_itemfore]);
437 	  continue;
438 	}
439       else if (strncmp (cp, "ItemBack", 8) == 0)
440 	{
441 	  cp += 8;
442 	  while (isspace (*cp))
443 	    cp++;
444 	  color_names[c_itemback] = copystring (cp, 0);
445 	  fprintf (fp_err, "ColorItemBack: %s\n", color_names[c_itemback]);
446 	  continue;
447 	}
448       else if (strncmp (cp, "Font", 4) == 0)
449 	{
450 	  cp += 4;
451 	  while (isspace (*cp))
452 	    cp++;
453 	  font_names[f_text] = copystring (cp, 0);
454 	  fprintf (fp_err, "Font: %s\n", font_names[f_text]);
455 #ifdef I18N
456 	  if ((xfset[f_text] = XCreateFontSet (dpy, font_names[f_text], &ml, &mc,
457 					       &ds)) == NULL)
458 	    {
459 	      fprintf (fp_err, "can't get font %s\n", font_names[f_text]);
460 	      fn_tmp_length = strlen (font_names[f_text]) + strlen (",-*--14-*");
461 	      fn_tmp = safemalloc (fn_tmp_length + 1);
462 	      strcpy (fn_tmp, font_names[f_text]);
463 	      strcat (fn_tmp, ",-*--14-*");
464 	      fprintf (fp_err, "trying...%s\n", fn_tmp);
465 	      if ((xfset[f_text] = XCreateFontSet (dpy, fn_tmp, &ml, &mc, &ds))
466 		  == NULL)
467 		{
468 		  fprintf (fp_err, "can't get font %s\n", fn_tmp);
469 		  fprintf (fp_err, "trying... fixed\n");
470 		  if ((xfset[f_text] = XCreateFontSet (dpy, "fixed,-*--14-*", &ml,
471 						       &mc, &ds)) == NULL)
472 		    {
473 		      fprintf (fp_err, "no fontset available\n");
474 		      exit (1);
475 		    }
476 		}
477 	    }
478 	  XFontsOfFontSet (xfset[f_text], &fs_list, &ml);
479 	  xfs[f_text] = fs_list[0];
480 #else
481 	  xfs[f_text] = XLoadQueryFont (dpy, font_names[f_text]);
482 #endif
483 	  fonts[f_text] = xfs[f_text]->fid;
484 	  continue;
485 	}
486       else if (strncmp (cp, "ButtonFont", 10) == 0)
487 	{
488 	  cp += 10;
489 	  while (isspace (*cp))
490 	    cp++;
491 	  font_names[f_button] = copystring (cp, 0);
492 	  fprintf (fp_err, "ButtonFont: %s\n", font_names[f_button]);
493 #ifdef I18N
494 	  if ((xfset[f_button] = XCreateFontSet (dpy, font_names[f_button], &ml,
495 						 &mc, &ds)) == NULL)
496 	    {
497 	      fprintf (fp_err, "can't get font %s\n", font_names[f_button]);
498 	      fn_tmp_length = strlen (font_names[f_button]) + strlen (",-*--14-*");
499 	      fn_tmp = safemalloc (fn_tmp_length + 1);
500 	      strcpy (fn_tmp, font_names[f_button]);
501 	      strcat (fn_tmp, ",-*--14-*");
502 	      fprintf (fp_err, "trying...%s\n", fn_tmp);
503 	      if ((xfset[f_button] = XCreateFontSet (dpy, fn_tmp, &ml, &mc, &ds))
504 		  == NULL)
505 		{
506 		  fprintf (fp_err, "can't get font %s\n", fn_tmp);
507 		  fprintf (fp_err, "trying... fixed\n");
508 		  if ((xfset[f_button] = XCreateFontSet (dpy, "fixed,-*--14-*", &ml,
509 							 &mc, &ds)) == NULL)
510 		    {
511 		      fprintf (fp_err, "no fontset available\n");
512 		      exit (1);
513 		    }
514 		}
515 	    }
516 	  XFontsOfFontSet (xfset[f_button], &fs_list, &ml);
517 	  xfs[f_button] = fs_list[0];
518 #else
519 	  xfs[f_button] = XLoadQueryFont (dpy, font_names[f_button]);
520 #endif
521 	  fonts[f_button] = xfs[f_button]->fid;
522 	  continue;
523 	}
524       else if (strncmp (cp, "InputFont", 9) == 0)
525 	{
526 	  cp += 9;
527 	  while (isspace (*cp))
528 	    cp++;
529 	  font_names[f_input] = copystring (cp, 0);
530 	  fprintf (fp_err, "InputFont: %s\n", font_names[f_input]);
531 #ifdef I18N
532 	  if ((xfset[f_input] = XCreateFontSet (dpy, font_names[f_input], &ml,
533 						&mc, &ds)) == NULL)
534 	    {
535 	      fprintf (fp_err, "can't get font %s\n", font_names[f_input]);
536 	      fn_tmp_length = strlen (font_names[f_input]) + strlen (",-*--14-*");
537 	      fn_tmp = safemalloc (fn_tmp_length + 1);
538 	      strcpy (fn_tmp, font_names[f_input]);
539 	      strcat (fn_tmp, ",-*--14-*");
540 	      fprintf (fp_err, "trying...%s\n", fn_tmp);
541 	      if ((xfset[f_button] = XCreateFontSet (dpy, fn_tmp, &ml, &mc, &ds))
542 		  == NULL)
543 		{
544 		  fprintf (fp_err, "can't get font %s\n", fn_tmp);
545 		  fprintf (fp_err, "trying... fixed\n");
546 		  if ((xfset[f_button] = XCreateFontSet (dpy, "fixed,-*--14-*", &ml,
547 							 &mc, &ds)) == NULL)
548 		    {
549 		      fprintf (fp_err, "no fontset available\n");
550 		      exit (1);
551 		    }
552 		}
553 	    }
554 	  XFontsOfFontSet (xfset[f_input], &fs_list, &ml);
555 	  xfs[f_input] = fs_list[0];
556 #else
557 	  xfs[f_input] = XLoadQueryFont (dpy, font_names[f_input]);
558 #endif
559 	  fonts[f_input] = xfs[f_input]->fid;
560 	  continue;
561 	}
562       else if (strncmp (cp, "Line", 4) == 0)
563 	{
564 	  cp += 4;
565 	  cur_line = lines + n_lines++;
566 	  while (isspace (*cp))
567 	    cp++;
568 	  if (strncmp (cp, "left", 4) == 0)
569 	    cur_line->justify = L_LEFT;
570 	  else if (strncmp (cp, "right", 5) == 0)
571 	    cur_line->justify = L_RIGHT;
572 	  else if (strncmp (cp, "center", 6) == 0)
573 	    cur_line->justify = L_CENTER;
574 	  else
575 	    cur_line->justify = L_LEFTRIGHT;
576 	  cur_line->n = 0;
577 	  cur_line->items = (Item **) safemalloc (sizeof (Item *) * ITEMS_PER_LINE);
578 	  continue;
579 	}
580       else if (strncmp (cp, "Text", 4) == 0)
581 	{
582 /* syntax: *FFText "<text>" */
583 	  cp += 4;
584 	  item = items + n_items++;
585 	  item->type = I_TEXT;
586 	  item->header.name = "";
587 	  while (isspace (*cp))
588 	    cp++;
589 	  if (*cp == '\"')
590 	    item->text.value = CopyQuotedString (++cp);
591 	  else
592 	    item->text.value = "";
593 	  item->text.n = strlen (item->text.value);
594 #ifdef I18N
595 	  item->header.size_x = XmbTextEscapement (xfset[f_text], item->text.value,
596 					       item->text.n) + 2 * TEXT_SPC;
597 #else
598 	  item->header.size_x = XTextWidth (xfs[f_text], item->text.value,
599 					    item->text.n) + 2 * TEXT_SPC;
600 #endif
601 	  item->header.size_y = FontHeight (xfs[f_text]) + 2 * TEXT_SPC;
602 	  fprintf (fp_err, "Text \"%s\" [%d, %d]\n", item->text.value,
603 		   item->header.size_x, item->header.size_y);
604 	  AddToLine (item);
605 	  continue;
606 	}
607       else if (strncmp (cp, "Input", 5) == 0)
608 	{
609 /* syntax: *FFInput <name> <size> "<init_value>" */
610 	  cp += 5;
611 	  item = items + n_items++;
612 	  item->type = I_INPUT;
613 	  while (isspace (*cp))
614 	    cp++;
615 	  item->header.name = CopySolidString (cp);
616 	  cp += strlen (item->header.name);
617 	  while (isspace (*cp))
618 	    cp++;
619 	  item->input.size = atoi (cp);
620 	  while (!isspace (*cp))
621 	    cp++;
622 	  while (isspace (*cp))
623 	    cp++;
624 	  if (*cp == '\"')
625 	    item->input.init_value = CopyQuotedString (++cp);
626 	  else
627 	    item->input.init_value = "";
628 	  item->input.blanks = (char *) safemalloc (item->input.size);
629 	  for (j = 0; j < item->input.size; j++)
630 	    item->input.blanks[j] = ' ';
631 	  item->input.buf = strlen (item->input.init_value) + 1;
632 	  item->input.value = (char *) safemalloc (item->input.buf);
633 	  item->header.size_x = FontWidth (xfs[f_input]) * item->input.size
634 	    + 2 * TEXT_SPC + 2 * BOX_SPC;
635 	  item->header.size_y = FontHeight (xfs[f_input]) + 3 * TEXT_SPC
636 	    + 2 * BOX_SPC;
637 	  fprintf (fp_err, "Input, %s, [%d], \"%s\"\n", item->header.name,
638 		   item->input.size, item->input.init_value);
639 	  AddToLine (item);
640 	}
641       else if (strncmp (cp, "Selection", 9) == 0)
642 	{
643 /* syntax: *FFSelection <name> single | multiple */
644 	  cp += 9;
645 	  cur_sel = items + n_items++;
646 	  cur_sel->type = I_SELECT;
647 	  while (isspace (*cp))
648 	    cp++;
649 	  cur_sel->header.name = CopySolidString (cp);
650 	  cp += strlen (cur_sel->header.name);
651 	  while (isspace (*cp))
652 	    cp++;
653 	  if (strncmp (cp, "multiple", 8) == 0)
654 	    cur_sel->select.key = IS_MULTIPLE;
655 	  else
656 	    cur_sel->select.key = IS_SINGLE;
657 	  cur_sel->select.n = 0;
658 	  cur_sel->select.choices =
659 	    (Item **) safemalloc (sizeof (Item *) * CHOICES_PER_SEL);
660 	  continue;
661 	}
662       else if (strncmp (cp, "Choice", 6) == 0)
663 	{
664 /* syntax: *FFChoice <name> <value> [on | _off_] ["<text>"] */
665 	  cp += 6;
666 	  item = items + n_items++;
667 	  item->type = I_CHOICE;
668 	  while (isspace (*cp))
669 	    cp++;
670 	  item->header.name = CopySolidString (cp);
671 	  cp += strlen (item->header.name);
672 	  while (isspace (*cp))
673 	    cp++;
674 	  item->choice.value = CopySolidString (cp);
675 	  cp += strlen (item->choice.value);
676 	  while (isspace (*cp))
677 	    cp++;
678 	  if (strncmp (cp, "on", 2) == 0)
679 	    item->choice.init_on = 1;
680 	  else
681 	    item->choice.init_on = 0;
682 	  while (!isspace (*cp))
683 	    cp++;
684 	  while (isspace (*cp))
685 	    cp++;
686 	  if (*cp == '\"')
687 	    item->choice.text = CopyQuotedString (++cp);
688 	  else
689 	    item->choice.text = "";
690 	  item->choice.n = strlen (item->choice.text);
691 	  item->choice.sel = cur_sel;
692 	  cur_sel->select.choices[cur_sel->select.n++] = item;
693 	  item->header.size_y = FontHeight (xfs[f_text]) + 2 * TEXT_SPC;
694 	  item->header.size_x = FontHeight (xfs[f_text]) + 4 * TEXT_SPC +
695 #ifdef I18N
696 	    XmbTextEscapement (xfset[f_text], item->choice.text, item->choice.n);
697 #else
698 	    XTextWidth (xfs[f_text], item->choice.text, item->choice.n);
699 #endif
700 	  fprintf (fp_err, "Choice %s, \"%s\", [%d, %d]\n", item->header.name,
701 	       item->choice.text, item->header.size_x, item->header.size_y);
702 	  AddToLine (item);
703 	  continue;
704 	}
705       else if (strncmp (cp, "Button", 6) == 0)
706 	{
707 /* syntax: *FFButton continue | restart | quit "<text>" */
708 	  cp += 6;
709 	  item = items + n_items++;
710 	  item->type = I_BUTTON;
711 	  item->header.name = "";
712 	  while (isspace (*cp))
713 	    cp++;
714 	  if (strncmp (cp, "restart", 7) == 0)
715 	    item->button.key = IB_RESTART;
716 	  else if (strncmp (cp, "quit", 4) == 0)
717 	    item->button.key = IB_QUIT;
718 	  else
719 	    item->button.key = IB_CONTINUE;
720 	  while (!isspace (*cp))
721 	    cp++;
722 	  while (isspace (*cp))
723 	    cp++;
724 	  if (*cp == '\"')
725 	    {
726 	      item->button.text = CopyQuotedString (++cp);
727 	      cp += strlen (item->button.text) + 1;
728 	      while (isspace (*cp))
729 		cp++;
730 	    }
731 	  else
732 	    item->button.text = "";
733 	  if (*cp == '^')
734 	    item->button.keypress = *(++cp) - '@';
735 	  else if (*cp == 'F')
736 	    item->button.keypress = 256 + atoi (++cp);
737 	  else
738 	    item->button.keypress = -1;
739 	  item->button.len = strlen (item->button.text);
740 	  item->button.n = 0;
741 	  item->button.commands = (char **) safemalloc (sizeof (char *) * MAX_ITEMS);
742 	  item->header.size_y = FontHeight (xfs[f_button]) + 2 * TEXT_SPC
743 	    + 2 * BOX_SPC;
744 	  item->header.size_x = 2 * TEXT_SPC + 2 * BOX_SPC
745 #ifdef I18N
746 	    + XmbTextEscapement (xfset[f_button], item->button.text, item->button.len);
747 #else
748 	    + XTextWidth (xfs[f_button], item->button.text, item->button.len);
749 #endif
750 	  AddToLine (item);
751 	  cur_button = item;
752 	  continue;
753 	}
754       else if (strncmp (cp, "Command", 7) == 0)
755 	{
756 /* syntax: *FFCommand <command> */
757 	  cp += 7;
758 	  while (isspace (*cp))
759 	    cp++;
760 	  cur_button->button.commands[cur_button->button.n++] =
761 	    copystring (cp, 0);
762 	}
763     }				/* end of switch() */
764   /* get the geometry right */
765   max_width = 0;
766   total_height = ITEM_VSPC;
767   for (l = 0; l < n_lines; l++)
768     {
769       line = lines + l;
770       for (i = 0; i < line->n; i++)
771 	{
772 	  line->items[i]->header.pos_y = total_height;
773 	  if (line->items[i]->header.size_y < line->size_y)
774 	    line->items[i]->header.pos_y += (line->size_y - line->items[i]->header.size_y) / 2 + 1;
775 	}
776       total_height += ITEM_VSPC + line->size_y;
777       line->size_x += (line->n + 1) * ITEM_HSPC;
778       if (line->size_x > max_width)
779 	max_width = line->size_x;
780     }
781   for (l = 0; l < n_lines; l++)
782     {
783       int width;
784       line = lines + l;
785       fprintf (fp_err, "Line[%d], %d, %d items\n", l, line->justify, line->n);
786       switch (line->justify)
787 	{
788 	case L_LEFT:
789 	  width = ITEM_HSPC;
790 	  for (i = 0; i < line->n; i++)
791 	    {
792 	      line->items[i]->header.pos_x = width;
793 	      width += ITEM_HSPC + line->items[i]->header.size_x;
794 	    }
795 	  break;
796 	case L_RIGHT:
797 	  width = max_width - line->size_x + ITEM_HSPC;
798 	  for (i = 0; i < line->n; i++)
799 	    {
800 	      line->items[i]->header.pos_x = width;
801 	      width += ITEM_HSPC + line->items[i]->header.size_x;
802 	    }
803 	  break;
804 	case L_CENTER:
805 	  width = (max_width - line->size_x) / 2 + ITEM_HSPC;
806 	  for (i = 0; i < line->n; i++)
807 	    {
808 	      line->items[i]->header.pos_x = width;
809 	      fprintf (fp_err, "Line[%d], Item[%d] @ (%d, %d)\n", l, i,
810 		line->items[i]->header.pos_x, line->items[i]->header.pos_y);
811 	      width += ITEM_HSPC + line->items[i]->header.size_x;
812 	    }
813 	  break;
814 	case L_LEFTRIGHT:
815 	  /* count the number of inputs on the line - the extra space will be
816 	   * shared amongst these if there are any, otherwise it will be added
817 	   * as space in between the elements
818 	   */
819 	  extra = 0;
820 	  for (i = 0; i < line->n; i++)
821 	    {
822 	      if (line->items[i]->type == I_INPUT)
823 		extra++;
824 	    }
825 	  if (extra == 0)
826 	    {
827 	      if (line->n < 2)
828 		{		/* same as L_CENTER */
829 		  width = (max_width - line->size_x) / 2 + ITEM_HSPC;
830 		  for (i = 0; i < line->n; i++)
831 		    {
832 		      line->items[i]->header.pos_x = width;
833 		      width += ITEM_HSPC + line->items[i]->header.size_x;
834 		    }
835 		}
836 	      else
837 		{
838 		  extra = (max_width - line->size_x) / (line->n - 1);
839 		  width = ITEM_HSPC;
840 		  for (i = 0; i < line->n; i++)
841 		    {
842 		      line->items[i]->header.pos_x = width;
843 		      width += ITEM_HSPC + line->items[i]->header.size_x + extra;
844 		    }
845 		}
846 	    }
847 	  else
848 	    {
849 	      extra = (max_width - line->size_x) / extra;
850 	      width = ITEM_HSPC;
851 	      for (i = 0; i < line->n; i++)
852 		{
853 		  line->items[i]->header.pos_x = width;
854 		  if (line->items[i]->type == I_INPUT)
855 		    line->items[i]->header.size_x += extra;
856 		  width += ITEM_HSPC + line->items[i]->header.size_x;
857 		}
858 	    }
859 	  break;
860 	}
861     }
862   fclose (fp);
863 }
864 
865 #define MAX_INTENSITY 65535
866 
867  /* allocate color cells */
868 void
GetColors()869 GetColors ()
870 {
871   Visual *visual = DefaultVisual (dpy, screen);
872   XColor xc_item;
873   int red = 0, green = 0, blue = 0, tmp1, tmp2;
874   if (scr_depth < 8)
875     {
876       colors[c_back] = colors[c_itemback] = WhitePixel (dpy, screen);
877       colors[c_fore] = colors[c_itemfore] = colors[c_itemlo] = colors[c_itemhi]
878 	= BlackPixel (dpy, screen);
879     }
880   else if (visual->class == TrueColor ||
881 	   visual->class == StaticColor ||
882 	   visual->class == StaticGray)
883     {
884       if (XParseColor (dpy, d_cmap, color_names[c_fore], &xc_item) &&
885 	  XAllocColor (dpy, d_cmap, &xc_item))
886 	colors[c_fore] = xc_item.pixel;
887       else
888 	colors[c_fore] = BlackPixel (dpy, screen);
889 
890       if (XParseColor (dpy, d_cmap, color_names[c_back], &xc_item) &&
891 	  XAllocColor (dpy, d_cmap, &xc_item))
892 	colors[c_back] = xc_item.pixel;
893       else
894 	colors[c_back] = WhitePixel (dpy, screen);
895 
896       if (XParseColor (dpy, d_cmap, color_names[c_itemfore], &xc_item) &&
897 	  XAllocColor (dpy, d_cmap, &xc_item))
898 	colors[c_itemfore] = xc_item.pixel;
899       else
900 	colors[c_itemfore] = BlackPixel (dpy, screen);
901 
902       if (XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item) &&
903 	  XAllocColor (dpy, d_cmap, &xc_item))
904 	colors[c_itemback] = xc_item.pixel;
905       else
906 	colors[c_itemback] = WhitePixel (dpy, screen);
907 
908       if (XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item))
909 	{
910 	  red = (int) xc_item.red;
911 	  green = (int) xc_item.green;
912 	  blue = (int) xc_item.blue;
913 	  xc_item.red = (60 * red) / 100;
914 	  xc_item.green = (60 * green) / 100;
915 	  xc_item.blue = (60 * blue) / 100;
916 	  if (XAllocColor (dpy, d_cmap, &xc_item))
917 	    colors[c_itemlo] = xc_item.pixel;
918 	  else
919 	    colors[c_itemlo] = BlackPixel (dpy, screen);
920 	}
921       else
922 	colors[c_itemlo] = BlackPixel (dpy, screen);
923 
924       if (XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item))
925 	{
926 	  tmp1 = (14 * red) / 10;
927 	  if (tmp1 > MAX_INTENSITY)
928 	    tmp1 = MAX_INTENSITY;
929 	  tmp2 = (MAX_INTENSITY + red) / 2;
930 	  xc_item.red = (tmp1 > tmp2) ? tmp1 : tmp2;
931 	  tmp1 = (14 * green) / 10;
932 	  if (tmp1 > MAX_INTENSITY)
933 	    tmp1 = MAX_INTENSITY;
934 	  tmp2 = (MAX_INTENSITY + green) / 2;
935 	  xc_item.green = (tmp1 > tmp2) ? tmp1 : tmp2;
936 	  tmp1 = (14 * blue) / 10;
937 	  if (tmp1 > MAX_INTENSITY)
938 	    tmp1 = MAX_INTENSITY;
939 	  tmp2 = (MAX_INTENSITY + blue) / 2;
940 	  xc_item.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
941 	  if (XAllocColor (dpy, d_cmap, &xc_item))
942 	    colors[c_itemhi] = xc_item.pixel;
943 	  else
944 	    colors[c_itemhi] = BlackPixel (dpy, screen);
945 	}
946       else
947 	colors[c_itemhi] = BlackPixel (dpy, screen);
948     }
949   else if (!XAllocColorCells (dpy, d_cmap, 0, NULL, 0, colors, 6))
950     {
951       colors[c_back] = colors[c_itemback] = WhitePixel (dpy, screen);
952       colors[c_fore] = colors[c_itemfore] = colors[c_itemlo] = colors[c_itemhi]
953 	= BlackPixel (dpy, screen);
954     }
955   else
956     {
957       XStoreNamedColor (dpy, d_cmap, color_names[c_fore], colors[c_fore],
958 			DoRed | DoGreen | DoBlue);
959       XStoreNamedColor (dpy, d_cmap, color_names[c_back], colors[c_back],
960 			DoRed | DoGreen | DoBlue);
961       XStoreNamedColor (dpy, d_cmap, color_names[c_itemfore],
962 			colors[c_itemfore], DoRed | DoGreen | DoBlue);
963       XStoreNamedColor (dpy, d_cmap, color_names[c_itemback],
964 			colors[c_itemback], DoRed | DoGreen | DoBlue);
965       XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item);
966       red = (int) xc_item.red;
967       green = (int) xc_item.green;
968       blue = (int) xc_item.blue;
969       xc_item.red = (60 * red) / 100;
970       xc_item.green = (60 * green) / 100;
971       xc_item.blue = (60 * blue) / 100;
972       xc_item.pixel = colors[c_itemlo];
973       xc_item.flags = DoRed | DoGreen | DoBlue;
974       XStoreColor (dpy, d_cmap, &xc_item);
975       XParseColor (dpy, d_cmap, color_names[c_itemback], &xc_item);
976       tmp1 = (14 * red) / 10;
977       if (tmp1 > MAX_INTENSITY)
978 	tmp1 = MAX_INTENSITY;
979       tmp2 = (MAX_INTENSITY + red) / 2;
980       xc_item.red = (tmp1 > tmp2) ? tmp1 : tmp2;
981       tmp1 = (14 * green) / 10;
982       if (tmp1 > MAX_INTENSITY)
983 	tmp1 = MAX_INTENSITY;
984       tmp2 = (MAX_INTENSITY + green) / 2;
985       xc_item.green = (tmp1 > tmp2) ? tmp1 : tmp2;
986       tmp1 = (14 * blue) / 10;
987       if (tmp1 > MAX_INTENSITY)
988 	tmp1 = MAX_INTENSITY;
989       tmp2 = (MAX_INTENSITY + blue) / 2;
990       xc_item.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
991       xc_item.pixel = colors[c_itemhi];
992       xc_item.flags = DoRed | DoGreen | DoBlue;
993       XStoreColor (dpy, d_cmap, &xc_item);
994     }
995 }
996 
997 
998 /* reset all the values */
999 void
Restart()1000 Restart ()
1001 {
1002   int i;
1003   Item *item;
1004 
1005   cur_text = NULL;
1006   abs_cursor = rel_cursor = 0;
1007   for (i = 0; i < n_items; i++)
1008     {
1009       item = items + i;
1010       switch (item->type)
1011 	{
1012 	case I_INPUT:
1013 	  if (!cur_text)
1014 	    cur_text = item;
1015 	  item->input.n = strlen (item->input.init_value);
1016 	  strcpy (item->input.value, item->input.init_value);
1017 	  item->input.left = 0;
1018 	  item->input.o_cursor = 0;
1019 	  break;
1020 	case I_CHOICE:
1021 	  item->choice.on = item->choice.init_on;
1022 	  break;
1023 	}
1024     }
1025 }
1026 
1027 /* redraw the frame */
1028 void
RedrawFrame()1029 RedrawFrame ()
1030 {
1031   int i, x, y;
1032   Item *item;
1033 
1034   for (i = 0; i < n_items; i++)
1035     {
1036       item = items + i;
1037       switch (item->type)
1038 	{
1039 	case I_TEXT:
1040 	  x = item->header.pos_x + TEXT_SPC;
1041 	  y = item->header.pos_y + TEXT_SPC + xfs[f_text]->ascent;
1042 #undef FONTSET
1043 #define FONTSET xfset[f_text]
1044 	  XDrawImageString (dpy, frame, gc_text, x, y, item->text.value,
1045 			    item->text.n);
1046 	  break;
1047 	case I_CHOICE:
1048 	  x = item->header.pos_x + TEXT_SPC + item->header.size_y;
1049 	  y = item->header.pos_y + TEXT_SPC + xfs[f_text]->ascent;
1050 	  XDrawImageString (dpy, frame, gc_text, x, y, item->choice.text,
1051 			    item->choice.n);
1052 	  break;
1053 	}
1054     }
1055 }
1056 
1057 /* redraw an item */
1058 void
RedrawItem(Item * item,int click)1059 RedrawItem (Item * item, int click)
1060 {
1061   int dx, dy, len, x;
1062   static XSegment xsegs[4];
1063 
1064   switch (item->type)
1065     {
1066     case I_INPUT:
1067       dx = item->header.size_x - 1;
1068       dy = item->header.size_y - 1;
1069       XSetForeground (dpy, gc_button, colors[c_itemlo]);
1070       xsegs[0].x1 = 0, xsegs[0].y1 = 0;
1071       xsegs[0].x2 = 0, xsegs[0].y2 = dy;
1072       xsegs[1].x1 = 0, xsegs[1].y1 = 0;
1073       xsegs[1].x2 = dx, xsegs[1].y2 = 0;
1074       xsegs[2].x1 = 1, xsegs[2].y1 = 1;
1075       xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
1076       xsegs[3].x1 = 1, xsegs[3].y1 = 1;
1077       xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
1078       XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
1079       XSetForeground (dpy, gc_button, colors[c_itemhi]);
1080       xsegs[0].x1 = 1, xsegs[0].y1 = dy;
1081       xsegs[0].x2 = dx, xsegs[0].y2 = dy;
1082       xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
1083       xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
1084       xsegs[2].x1 = dx, xsegs[2].y1 = 1;
1085       xsegs[2].x2 = dx, xsegs[2].y2 = dy;
1086       xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
1087       xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
1088       XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
1089       if (click)
1090 	{
1091 	  x = BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * abs_cursor - 1;
1092 	  XSetForeground (dpy, gc_button, colors[c_itemback]);
1093 	  XDrawLine (dpy, item->header.win, gc_button,
1094 		     x, BOX_SPC, x, dy - BOX_SPC);
1095 	}
1096       len = item->input.n - item->input.left;
1097       if (len > item->input.size)
1098 	len = item->input.size;
1099       else
1100 #undef FONTSET
1101 #define FONTSET xfset[f_input]
1102 	XDrawImageString (dpy, item->header.win, gc_input,
1103 			BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * len,
1104 			  BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
1105 			  item->input.blanks, item->input.size - len);
1106       XDrawImageString (dpy, item->header.win, gc_input,
1107 			BOX_SPC + TEXT_SPC,
1108 			BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
1109 			item->input.value + item->input.left, len);
1110       if (item == cur_text && !click)
1111 	{
1112 	  x = BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * abs_cursor - 1;
1113 	  XDrawLine (dpy, item->header.win, gc_input,
1114 		     x, BOX_SPC, x, dy - BOX_SPC);
1115 	}
1116       break;
1117     case I_CHOICE:
1118       dx = dy = item->header.size_y - 1;
1119       if (item->choice.on)
1120 	{
1121 	  XSetForeground (dpy, gc_button, colors[c_itemfore]);
1122 	  if (item->choice.sel->select.key == IS_MULTIPLE)
1123 	    {
1124 	      xsegs[0].x1 = 5, xsegs[0].y1 = 5;
1125 	      xsegs[0].x2 = dx - 5, xsegs[0].y2 = dy - 5;
1126 	      xsegs[1].x1 = 5, xsegs[1].y1 = dy - 5;
1127 	      xsegs[1].x2 = dx - 5, xsegs[1].y2 = 5;
1128 	      XDrawSegments (dpy, item->header.win, gc_button, xsegs, 2);
1129 	    }
1130 	  else
1131 	    {
1132 	      XDrawArc (dpy, item->header.win, gc_button,
1133 			5, 5, dx - 10, dy - 10, 0, 360 * 64);
1134 	    }
1135 	}
1136       else
1137 	XClearWindow (dpy, item->header.win);
1138       if (item->choice.on)
1139 	XSetForeground (dpy, gc_button, colors[c_itemlo]);
1140       else
1141 	XSetForeground (dpy, gc_button, colors[c_itemhi]);
1142       xsegs[0].x1 = 0, xsegs[0].y1 = 0;
1143       xsegs[0].x2 = 0, xsegs[0].y2 = dy;
1144       xsegs[1].x1 = 0, xsegs[1].y1 = 0;
1145       xsegs[1].x2 = dx, xsegs[1].y2 = 0;
1146       xsegs[2].x1 = 1, xsegs[2].y1 = 1;
1147       xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
1148       xsegs[3].x1 = 1, xsegs[3].y1 = 1;
1149       xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
1150       XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
1151       if (item->choice.on)
1152 	XSetForeground (dpy, gc_button, colors[c_itemhi]);
1153       else
1154 	XSetForeground (dpy, gc_button, colors[c_itemlo]);
1155       xsegs[0].x1 = 1, xsegs[0].y1 = dy;
1156       xsegs[0].x2 = dx, xsegs[0].y2 = dy;
1157       xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
1158       xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
1159       xsegs[2].x1 = dx, xsegs[2].y1 = 1;
1160       xsegs[2].x2 = dx, xsegs[2].y2 = dy;
1161       xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
1162       xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
1163       XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
1164       break;
1165     case I_BUTTON:
1166       dx = item->header.size_x - 1;
1167       dy = item->header.size_y - 1;
1168       if (click)
1169 	XSetForeground (dpy, gc_button, colors[c_itemlo]);
1170       else
1171 	XSetForeground (dpy, gc_button, colors[c_itemhi]);
1172       xsegs[0].x1 = 0, xsegs[0].y1 = 0;
1173       xsegs[0].x2 = 0, xsegs[0].y2 = dy;
1174       xsegs[1].x1 = 0, xsegs[1].y1 = 0;
1175       xsegs[1].x2 = dx, xsegs[1].y2 = 0;
1176       xsegs[2].x1 = 1, xsegs[2].y1 = 1;
1177       xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
1178       xsegs[3].x1 = 1, xsegs[3].y1 = 1;
1179       xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
1180       XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
1181       if (click)
1182 	XSetForeground (dpy, gc_button, colors[c_itemhi]);
1183       else
1184 	XSetForeground (dpy, gc_button, colors[c_itemlo]);
1185       xsegs[0].x1 = 1, xsegs[0].y1 = dy;
1186       xsegs[0].x2 = dx, xsegs[0].y2 = dy;
1187       xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
1188       xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
1189       xsegs[2].x1 = dx, xsegs[2].y1 = 1;
1190       xsegs[2].x2 = dx, xsegs[2].y2 = dy;
1191       xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
1192       xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
1193       XDrawSegments (dpy, item->header.win, gc_button, xsegs, 4);
1194       XSetForeground (dpy, gc_button, colors[c_itemfore]);
1195 #undef FONTSET
1196 #define FONTSET xfset[f_button]
1197       XDrawImageString (dpy, item->header.win, gc_button,
1198 			BOX_SPC + TEXT_SPC,
1199 			BOX_SPC + TEXT_SPC + xfs[f_button]->ascent,
1200 			item->button.text, item->button.len);
1201       break;
1202     }
1203   XFlush (dpy);
1204 }
1205 
1206 void
ToggleChoice(Item * item)1207 ToggleChoice (Item * item)
1208 {
1209   int i;
1210   Item *sel = item->choice.sel;
1211 
1212   if (sel->select.key == IS_SINGLE)
1213     {
1214       if (!item->choice.on)
1215 	{
1216 	  for (i = 0; i < sel->select.n; i++)
1217 	    {
1218 	      if (sel->select.choices[i]->choice.on)
1219 		{
1220 		  sel->select.choices[i]->choice.on = 0;
1221 		  RedrawItem (sel->select.choices[i], 0);
1222 		}
1223 	    }
1224 	  item->choice.on = 1;
1225 	  RedrawItem (item, 0);
1226 	}
1227     }
1228   else
1229     {				/* IS_MULTIPLE */
1230       item->choice.on = !item->choice.on;
1231       RedrawItem (item, 0);
1232     }
1233 }
1234 
1235 /* do var substitution for command string */
1236 void
ParseCommand(int dn,char * sp,char end,int * dn1,char ** sp1)1237 ParseCommand (int dn, char *sp, char end, int *dn1, char **sp1)
1238 #define AddChar(chr) { if (dn >= N) { N *= 2; buf = (char *)realloc(buf, N); } buf[dn++] = (chr); }
1239 {
1240   static char var[256];
1241   char c, x, *wp, *cp, *vp;
1242   int i, j, dn2;
1243   Item *item;
1244 
1245   while (1)
1246     {
1247       c = *(sp++);
1248       if (c == '\0' || c == end)
1249 	{			/* end of substitution */
1250 	  *dn1 = dn;
1251 	  *sp1 = sp;
1252 	  return;
1253 	}
1254       if (c == '\\')
1255 	{			/* escape char */
1256 	  AddChar ('\\');
1257 	  AddChar (*(sp++));
1258 	  goto next_loop;
1259 	}
1260       if (c == '$')
1261 	{			/* variable */
1262 	  if (*sp != '(')
1263 	    goto normal_char;
1264 	  wp = ++sp;
1265 	  vp = var;
1266 	  while (1)
1267 	    {
1268 	      x = *(sp++);
1269 	      if (x == '\\')
1270 		{
1271 		  *(vp++) = '\\';
1272 		  *(vp++) = *(sp++);
1273 		}
1274 	      else if (x == ')' || x == '?' || x == '!')
1275 		{
1276 		  *(vp++) = '\0';
1277 		  break;
1278 		}
1279 	      else if (!isspace (x))
1280 		*(vp++) = x;
1281 	    }
1282 	  for (i = 0; i < n_items; i++)
1283 	    {
1284 	      item = items + i;
1285 	      if (strcmp (var, item->header.name) == 0)
1286 		{
1287 		  switch (item->type)
1288 		    {
1289 		    case I_INPUT:
1290 		      if (x == ')')
1291 			{
1292 			  for (cp = item->input.value; *cp != '\0'; cp++)
1293 			    {
1294 			      if (!isalnum (*cp))
1295 				AddChar ('\\');
1296 			      AddChar (*cp);
1297 			    }
1298 			}
1299 		      else
1300 			{
1301 			  ParseCommand (dn, sp, ')', &dn2, &sp);
1302 			  if ((x == '?' && strlen (item->input.value) > 0) ||
1303 			      (x == '!' && strlen (item->input.value) == 0))
1304 			    dn = dn2;
1305 			}
1306 		      break;
1307 		    case I_CHOICE:
1308 		      if (x == ')')
1309 			{
1310 			  for (cp = item->choice.value; *cp != '\0'; cp++)
1311 			    AddChar (*cp);
1312 			}
1313 		      else
1314 			{
1315 			  ParseCommand (dn, sp, ')', &dn2, &sp);
1316 			  if ((x == '?' && item->choice.on) ||
1317 			      (x == '!' && !item->choice.on))
1318 			    dn = dn2;
1319 			}
1320 		      break;
1321 		    case I_SELECT:
1322 		      if (x != ')')
1323 			ParseCommand (dn, sp, ')', &dn2, &sp);
1324 		      AddChar (' ');
1325 		      for (j = 0; j < item->select.n; j++)
1326 			{
1327 			  if (item->select.choices[j]->choice.on)
1328 			    {
1329 			      for (cp = item->select.choices[j]->choice.value;
1330 				   *cp != '\0'; cp++)
1331 				AddChar (*cp);
1332 			      AddChar (' ');
1333 			    }
1334 			}
1335 		      break;
1336 		    }
1337 		  goto next_loop;
1338 		}
1339 	    }
1340 	  goto next_loop;
1341 	}
1342     normal_char:
1343       AddChar (c);
1344     next_loop:
1345       ;
1346     }
1347 }
1348 
1349 /* execute a command */
1350 void
DoCommand(Item * cmd)1351 DoCommand (Item * cmd)
1352 {
1353   int i, k, dn, len;
1354   char *sp;
1355 
1356   /* pre-command */
1357   if (cmd->button.key == IB_QUIT)
1358     XWithdrawWindow (dpy, frame, screen);
1359 
1360   for (k = 0; k < cmd->button.n; k++)
1361     {
1362       /* construct command */
1363       ParseCommand (0, cmd->button.commands[k], '\0', &dn, &sp);
1364       AddChar ('\0');
1365       fprintf (fp_err, "Final command[%d]: [%s]\n", k, buf);
1366 
1367       /* send command */
1368       write (fd[1], &ref, sizeof (Window));
1369       len = strlen (buf);
1370       write (fd[1], &len, sizeof (int));
1371       write (fd[1], buf, len);
1372       len = 1;
1373       write (fd[1], &len, sizeof (int));
1374     }
1375 
1376   /* post-command */
1377   if (cmd->button.key == IB_QUIT)
1378     {
1379       if (grab_server)
1380 	XUngrabServer (dpy);
1381       exit (0);
1382     }
1383   if (cmd->button.key == IB_RESTART)
1384     {
1385       Restart ();
1386       for (i = 0; i < n_items; i++)
1387 	{
1388 	  if (items[i].type == I_INPUT)
1389 	    {
1390 	      XClearWindow (dpy, items[i].header.win);
1391 	      RedrawItem (items + i, 0);
1392 	    }
1393 	  if (items[i].type == I_CHOICE)
1394 	    RedrawItem (items + i, 0);
1395 	}
1396     }
1397 }
1398 
1399 /* open the windows */
1400 void
OpenWindows()1401 OpenWindows ()
1402 {
1403   int i, x, y;
1404   Item *item;
1405   static XColor xcf, xcb;
1406   static XSetWindowAttributes xswa;
1407   static XGCValues xgcv;
1408   static XWMHints wmh =
1409   {InputHint, True};
1410   static XSizeHints sh =
1411   {PPosition | PSize | USPosition | USSize};
1412   static int xgcv_mask = GCBackground | GCForeground | GCFont;
1413 
1414   xc_ibeam = XCreateFontCursor (dpy, XC_xterm);
1415   xc_hand = XCreateFontCursor (dpy, XC_hand2);
1416   xcf.pixel = WhitePixel (dpy, screen);
1417   XQueryColor (dpy, d_cmap, &xcf);
1418   xcb.pixel = colors[c_itemback];
1419   XQueryColor (dpy, d_cmap, &xcb);
1420   XRecolorCursor (dpy, xc_ibeam, &xcf, &xcb);
1421 
1422   /* the frame window first */
1423   if (geom)
1424     {
1425       if (gx >= 0)
1426 	x = gx;
1427       else
1428 	x = DisplayWidth (dpy, screen) - max_width + gx;
1429       if (gy >= 0)
1430 	y = gy;
1431       else
1432 	y = DisplayHeight (dpy, screen) - total_height + gy;
1433     }
1434   else
1435     {
1436       x = (DisplayWidth (dpy, screen) - max_width) / 2;
1437       y = (DisplayHeight (dpy, screen) - total_height) / 2;
1438     }
1439   frame = XCreateSimpleWindow (dpy, root, x, y, max_width, total_height,
1440 			       0, BlackPixel (dpy, screen), colors[c_back]);
1441   XSelectInput (dpy, frame, KeyPressMask | ExposureMask);
1442   XStoreName (dpy, frame, MyName);
1443   XSetWMHints (dpy, frame, &wmh);
1444   sh.x = x, sh.y = y;
1445   sh.width = max_width, sh.height = total_height;
1446   XSetWMNormalHints (dpy, frame, &sh);
1447 
1448   xgcv.foreground = colors[c_fore];
1449   xgcv.background = colors[c_back];
1450   xgcv.font = fonts[f_text];
1451   gc_text = XCreateGC (dpy, frame, xgcv_mask, &xgcv);
1452   xgcv.background = colors[c_itemback];
1453   xgcv.foreground = colors[c_itemfore];
1454   xgcv.font = fonts[f_input];
1455   gc_input = XCreateGC (dpy, frame, xgcv_mask, &xgcv);
1456   xgcv.font = fonts[f_button];
1457   gc_button = XCreateGC (dpy, frame, xgcv_mask, &xgcv);
1458 
1459   for (i = 0; i < n_items; i++)
1460     {
1461       item = items + i;
1462       switch (item->type)
1463 	{
1464 	case I_INPUT:
1465 	  item->header.win =
1466 	    XCreateSimpleWindow (dpy, frame,
1467 				 item->header.pos_x, item->header.pos_y,
1468 				 item->header.size_x, item->header.size_y,
1469 				 0, colors[c_back], colors[c_itemback]);
1470 	  XSelectInput (dpy, item->header.win, ButtonPressMask | ExposureMask);
1471 	  xswa.cursor = xc_ibeam;
1472 	  XChangeWindowAttributes (dpy, item->header.win, CWCursor, &xswa);
1473 	  break;
1474 	case I_CHOICE:
1475 	  item->header.win =
1476 	    XCreateSimpleWindow (dpy, frame,
1477 				 item->header.pos_x, item->header.pos_y,
1478 				 item->header.size_y, item->header.size_y,
1479 				 0, colors[c_back], colors[c_itemback]);
1480 	  XSelectInput (dpy, item->header.win, ButtonPressMask | ExposureMask);
1481 	  xswa.cursor = xc_hand;
1482 	  XChangeWindowAttributes (dpy, item->header.win, CWCursor, &xswa);
1483 	  break;
1484 	case I_BUTTON:
1485 	  item->header.win =
1486 	    XCreateSimpleWindow (dpy, frame,
1487 				 item->header.pos_x, item->header.pos_y,
1488 				 item->header.size_x, item->header.size_y,
1489 				 0, colors[c_back], colors[c_itemback]);
1490 	  XSelectInput (dpy, item->header.win,
1491 			ButtonPressMask | ExposureMask);
1492 	  xswa.cursor = xc_hand;
1493 	  XChangeWindowAttributes (dpy, item->header.win, CWCursor, &xswa);
1494 	  break;
1495 	}
1496     }
1497   Restart ();
1498   XMapRaised (dpy, frame);
1499   XMapSubwindows (dpy, frame);
1500   if (warp_pointer)
1501     {
1502       XWarpPointer (dpy, None, frame, 0, 0, 0, 0,
1503 		    max_width / 2, total_height - 1);
1504     }
1505   DoCommand (&def_button);
1506 }
1507 
1508 /* read something from Afterstep */
1509 void
ReadAfterstep()1510 ReadAfterstep ()
1511 {
1512   static char buffer[32];
1513   int n;
1514 
1515   n = read (fd[0], buffer, 32);
1516   if (n == 0)
1517     {
1518       if (grab_server)
1519 	XUngrabServer (dpy);
1520       exit (0);
1521     }
1522 }
1523 
1524 /* read an X event */
1525 void
ReadXServer()1526 ReadXServer ()
1527 {
1528   static XEvent event;
1529   int i, old_cursor = 0, keypress;
1530   Item *item, *old_item;
1531   KeySym ks;
1532   char *sp, *dp, *ep;
1533   static char buf[10], n;
1534 
1535   while (XEventsQueued (dpy, QueuedAfterReading))
1536     {
1537       XNextEvent (dpy, &event);
1538       if (event.xany.window == frame)
1539 	{
1540 	  switch (event.type)
1541 	    {
1542 	    case Expose:
1543 	      RedrawFrame ();
1544 	      if (grab_server && !server_grabbed)
1545 		{
1546 		  if (GrabSuccess ==
1547 		      XGrabPointer (dpy, frame, True, 0, GrabModeAsync, GrabModeAsync,
1548 				    None, None, CurrentTime))
1549 		    server_grabbed = 1;
1550 		}
1551 	      break;
1552 	    case KeyPress:	/* we do text input here */
1553 	      n = XLookupString (&event.xkey, buf, 10, &ks, NULL);
1554 	      keypress = buf[0];
1555 	      fprintf (fp_err, "Keypress [%s]\n", buf);
1556 	      if (n == 0)
1557 		{		/* not a regular key, translate it into one */
1558 		  switch (ks)
1559 		    {
1560 		    case XK_Home:
1561 		    case XK_Begin:
1562 		      buf[0] = '\001';	/* ^A */
1563 		      break;
1564 		    case XK_End:
1565 		      buf[0] = '\005';	/* ^E */
1566 		      break;
1567 		    case XK_Left:
1568 		      buf[0] = '\002';	/* ^B */
1569 		      break;
1570 		    case XK_Right:
1571 		      buf[0] = '\006';	/* ^F */
1572 		      break;
1573 		    case XK_Up:
1574 		      buf[0] = '\020';	/* ^P */
1575 		      break;
1576 		    case XK_Down:
1577 		      buf[0] = '\016';	/* ^N */
1578 		      break;
1579 		    default:
1580 		      if (ks >= XK_F1 && ks <= XK_F35)
1581 			{
1582 			  buf[0] = '\0';
1583 			  keypress = 257 + ks - XK_F1;
1584 			}
1585 		      else
1586 			goto no_redraw;		/* no action for this event */
1587 		    }
1588 		}
1589 	      if (!cur_text)
1590 		{		/* no text input fields */
1591 		  for (i = 0; i < n_items; i++)
1592 		    {
1593 		      item = items + i;
1594 		      fprintf (fp_err, "Button[%d], keypress==%d\n", i,
1595 			       item->button.keypress);
1596 		      if (item->type == I_BUTTON && item->button.keypress == buf[0])
1597 			{
1598 			  RedrawItem (item, 1);
1599 			  sleep (1);
1600 			  RedrawItem (item, 0);
1601 			  DoCommand (item);
1602 			  goto no_redraw;
1603 			}
1604 		    }
1605 		  break;
1606 		}
1607 	      switch (buf[0])
1608 		{
1609 		case '\001':	/* ^A */
1610 		  old_cursor = abs_cursor;
1611 		  rel_cursor = 0;
1612 		  abs_cursor = 0;
1613 		  cur_text->input.left = 0;
1614 		  goto redraw_newcursor;
1615 		  break;
1616 		case '\005':	/* ^E */
1617 		  old_cursor = abs_cursor;
1618 		  rel_cursor = cur_text->input.n;
1619 		  if ((cur_text->input.left = rel_cursor - cur_text->input.size) < 0)
1620 		    cur_text->input.left = 0;
1621 		  abs_cursor = rel_cursor - cur_text->input.left;
1622 		  goto redraw_newcursor;
1623 		  break;
1624 		case '\002':	/* ^B */
1625 		  old_cursor = abs_cursor;
1626 		  if (rel_cursor > 0)
1627 		    {
1628 		      rel_cursor--;
1629 		      abs_cursor--;
1630 		      if (abs_cursor <= 0 && rel_cursor > 0)
1631 			{
1632 			  abs_cursor++;
1633 			  cur_text->input.left--;
1634 			}
1635 		    }
1636 		  goto redraw_newcursor;
1637 		  break;
1638 		case '\006':	/* ^F */
1639 		  old_cursor = abs_cursor;
1640 		  if (rel_cursor < cur_text->input.n)
1641 		    {
1642 		      rel_cursor++;
1643 		      abs_cursor++;
1644 		      if (abs_cursor >= cur_text->input.size &&
1645 			  rel_cursor < cur_text->input.n)
1646 			{
1647 			  abs_cursor--;
1648 			  cur_text->input.left++;
1649 			}
1650 		    }
1651 		  goto redraw_newcursor;
1652 		  break;
1653 		case '\010':	/* ^H */
1654 		case '\177':	/* DEL */
1655 		  old_cursor = abs_cursor;
1656 		  if (rel_cursor > 0)
1657 		    {
1658 		      sp = cur_text->input.value + rel_cursor;
1659 		      dp = sp - 1;
1660 		      for (; *dp = *sp, *sp != '\0'; dp++, sp++);
1661 		      cur_text->input.n--;
1662 		      rel_cursor--;
1663 		      if (rel_cursor < abs_cursor)
1664 			{
1665 			  abs_cursor--;
1666 			  if (abs_cursor <= 0 && rel_cursor > 0)
1667 			    {
1668 			      abs_cursor++;
1669 			      cur_text->input.left--;
1670 			    }
1671 			}
1672 		      else
1673 			cur_text->input.left--;
1674 		    }
1675 		  goto redraw_newcursor;
1676 		  break;
1677 		case '\004':	/* ^D */
1678 		  if (rel_cursor < cur_text->input.n)
1679 		    {
1680 		      sp = cur_text->input.value + rel_cursor + 1;
1681 		      dp = sp - 1;
1682 		      for (; *dp = *sp, *sp != '\0'; dp++, sp++);
1683 		      cur_text->input.n--;
1684 		      goto redraw;
1685 		    }
1686 		  break;
1687 		case '\013':	/* ^K */
1688 		  cur_text->input.value[rel_cursor] = '\0';
1689 		  cur_text->input.n = rel_cursor;
1690 		  goto redraw;
1691 		case '\025':	/* ^U */
1692 		  old_cursor = abs_cursor;
1693 		  cur_text->input.value[0] = '\0';
1694 		  cur_text->input.n = cur_text->input.left = 0;
1695 		  rel_cursor = abs_cursor = 0;
1696 		  goto redraw_newcursor;
1697 		case '\t':
1698 		case '\n':
1699 		case '\015':
1700 		case '\016':	/* LINEFEED, TAB, RETURN, ^N, jump to the next field */
1701 		  for (i = (cur_text - items) + 1; i < n_items; i++)
1702 		    {
1703 		      item = items + i;
1704 		      if (item->type == I_INPUT)
1705 			{
1706 			  old_item = cur_text;
1707 			  old_item->input.o_cursor = rel_cursor;
1708 			  cur_text = item;
1709 			  RedrawItem (old_item, 1);
1710 			  rel_cursor = item->input.o_cursor;
1711 			  abs_cursor = rel_cursor - item->input.left;
1712 			  goto redraw;
1713 			}
1714 		    }
1715 		  /* end of all text input fields, check for buttons */
1716 		  for (i = 0; i < n_items; i++)
1717 		    {
1718 		      item = items + i;
1719 		      fprintf (fp_err, "Button[%d], keypress==%d\n", i,
1720 			       item->button.keypress);
1721 		      if (item->type == I_BUTTON && item->button.keypress == buf[0])
1722 			{
1723 			  RedrawItem (item, 1);
1724 			  sleep (1);
1725 			  RedrawItem (item, 0);
1726 			  DoCommand (item);
1727 			  goto no_redraw;
1728 			}
1729 		    }
1730 		  /* goto the first text input field */
1731 		  for (i = 0; i < n_items; i++)
1732 		    {
1733 		      item = items + i;
1734 		      if (item->type == I_INPUT)
1735 			{
1736 			  old_item = cur_text;
1737 			  old_item->input.o_cursor = rel_cursor;
1738 			  cur_text = item;
1739 			  RedrawItem (old_item, 1);
1740 			  rel_cursor = item->input.o_cursor;
1741 			  abs_cursor = rel_cursor - item->input.left;
1742 			  goto redraw;
1743 			}
1744 		    }
1745 		  break;
1746 		default:
1747 		  old_cursor = abs_cursor;
1748 		  if (buf[0] >= ' ' && buf[0] < '\177')
1749 		    {		/* regular char */
1750 		      if (++(cur_text->input.n) >= cur_text->input.buf)
1751 			{
1752 			  cur_text->input.buf += cur_text->input.size;
1753 			  cur_text->input.value =
1754 			    (char *) realloc (cur_text->input.value,
1755 					      cur_text->input.buf);
1756 			}
1757 		      dp = cur_text->input.value + cur_text->input.n;
1758 		      sp = dp - 1;
1759 		      ep = cur_text->input.value + rel_cursor;
1760 		      for (; *dp = *sp, sp != ep; sp--, dp--);
1761 		      *ep = buf[0];
1762 		      rel_cursor++;
1763 		      abs_cursor++;
1764 		      if (abs_cursor >= cur_text->input.size)
1765 			{
1766 			  if (rel_cursor < cur_text->input.n)
1767 			    abs_cursor = cur_text->input.size - 1;
1768 			  else
1769 			    abs_cursor = cur_text->input.size;
1770 			  cur_text->input.left = rel_cursor - abs_cursor;
1771 			}
1772 		      goto redraw_newcursor;
1773 		    }
1774 		  /* unrecognized key press, check for buttons */
1775 		  for (i = 0; i < n_items; i++)
1776 		    {
1777 		      item = items + i;
1778 		      fprintf (fp_err, "Button[%d], keypress==%d\n", i,
1779 			       item->button.keypress);
1780 		      if (item->type == I_BUTTON && item->button.keypress == keypress)
1781 			{
1782 			  RedrawItem (item, 1);
1783 			  sleep (1);	/* .5 seconds */
1784 			  RedrawItem (item, 0);
1785 			  DoCommand (item);
1786 			  goto no_redraw;
1787 			}
1788 		    }
1789 		  break;
1790 		}
1791 	    redraw_newcursor:
1792 	      {
1793 		int x, dy;
1794 		x = BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * old_cursor - 1;
1795 		dy = cur_text->header.size_y - 1;
1796 		XSetForeground (dpy, gc_button, colors[c_itemback]);
1797 		XDrawLine (dpy, cur_text->header.win, gc_button,
1798 			   x, BOX_SPC, x, dy - BOX_SPC);
1799 	      }
1800 	    redraw:
1801 	      {
1802 		int len, x, dy;
1803 		len = cur_text->input.n - cur_text->input.left;
1804 		if (len > cur_text->input.size)
1805 		  len = cur_text->input.size;
1806 		else
1807 #undef FONTSET
1808 #define FONTSET xfset[f_input]
1809 		  XDrawImageString (dpy, cur_text->header.win, gc_input,
1810 				    BOX_SPC + TEXT_SPC +
1811 				    FontWidth (xfs[f_input]) * len,
1812 				  BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
1813 				    cur_text->input.blanks,
1814 				    cur_text->input.size - len);
1815 		XDrawImageString (dpy, cur_text->header.win, gc_input,
1816 				  BOX_SPC + TEXT_SPC,
1817 				  BOX_SPC + TEXT_SPC + xfs[f_input]->ascent,
1818 			 cur_text->input.value + cur_text->input.left, len);
1819 		x = BOX_SPC + TEXT_SPC + FontWidth (xfs[f_input]) * abs_cursor - 1;
1820 		dy = cur_text->header.size_y - 1;
1821 		XDrawLine (dpy, cur_text->header.win, gc_input,
1822 			   x, BOX_SPC, x, dy - BOX_SPC);
1823 	      }
1824 	    no_redraw:
1825 	      break;		/* end of case KeyPress */
1826 	    }			/* end of switch (event.type) */
1827 	  continue;
1828 	}			/* end of if (event.xany.window == frame) */
1829       for (i = 0; i < n_items; i++)
1830 	{
1831 	  item = items + i;
1832 	  if (event.xany.window == item->header.win)
1833 	    {
1834 	      switch (event.type)
1835 		{
1836 		case Expose:
1837 		  RedrawItem (item, 0);
1838 		  break;
1839 		case ButtonPress:
1840 		  if (item->type == I_INPUT)
1841 		    {
1842 		      old_item = cur_text;
1843 		      old_item->input.o_cursor = rel_cursor;
1844 		      cur_text = item;
1845 		      RedrawItem (old_item, 1);
1846 		      abs_cursor = (event.xbutton.x - BOX_SPC -
1847 				    TEXT_SPC + FontWidth (xfs[f_input]) / 2)
1848 			/ FontWidth (xfs[f_input]);
1849 		      if (abs_cursor < 0)
1850 			abs_cursor = 0;
1851 		      if (abs_cursor > item->input.size)
1852 			abs_cursor = item->input.size;
1853 		      rel_cursor = abs_cursor + item->input.left;
1854 		      if (rel_cursor < 0)
1855 			rel_cursor = 0;
1856 		      if (rel_cursor > item->input.n)
1857 			rel_cursor = item->input.n;
1858 		      if (rel_cursor > 0 && rel_cursor == item->input.left)
1859 			item->input.left--;
1860 		      if (rel_cursor < item->input.n &&
1861 			  rel_cursor == item->input.left + item->input.size)
1862 			item->input.left++;
1863 		      abs_cursor = rel_cursor - item->input.left;
1864 		      RedrawItem (item, 0);
1865 		    }
1866 		  if (item->type == I_CHOICE)
1867 		    ToggleChoice (item);
1868 		  if (item->type == I_BUTTON)
1869 		    {
1870 		      RedrawItem (item, 1);
1871 		      XGrabPointer (dpy, item->header.win, False, ButtonReleaseMask,
1872 				    GrabModeAsync, GrabModeAsync,
1873 				    None, None, CurrentTime);
1874 		    }
1875 		  break;
1876 		case ButtonRelease:
1877 		  RedrawItem (item, 0);
1878 		  if (grab_server && server_grabbed)
1879 		    {
1880 		      XGrabPointer (dpy, frame, True, 0, GrabModeAsync, GrabModeAsync,
1881 				    None, None, CurrentTime);
1882 		      XFlush (dpy);
1883 		    }
1884 		  else
1885 		    {
1886 		      XUngrabPointer (dpy, CurrentTime);
1887 		      XFlush (dpy);
1888 		    }
1889 		  if (event.xbutton.x >= 0 &&
1890 		      event.xbutton.x < item->header.size_x &&
1891 		      event.xbutton.y >= 0 &&
1892 		      event.xbutton.y < item->header.size_y)
1893 		    {
1894 		      DoCommand (item);
1895 		    }
1896 		  break;
1897 		}
1898 	    }
1899 	}			/* end of for (i = 0 */
1900     }				/* while loop */
1901 }
1902 
1903 /* main event loop */
1904 void
MainLoop()1905 MainLoop ()
1906 {
1907   fd_set fds;
1908 
1909   while (1)
1910     {
1911       FD_ZERO (&fds);
1912       FD_SET (fd[0], &fds);
1913       FD_SET (fd_x, &fds);
1914 
1915       XFlush (dpy);
1916       if (select (32, &fds, NULL, NULL, NULL) > 0)
1917 	{
1918 	  if (FD_ISSET (fd[0], &fds))
1919 	    ReadAfterstep ();
1920 	  if (FD_ISSET (fd_x, &fds))
1921 	    ReadXServer ();
1922 	}
1923     }
1924 }
1925 
1926 void
version(void)1927 version (void)
1928 {
1929   printf ("%s version %s\n", MyName, VERSION);
1930   exit (0);
1931 }
1932 
1933 void
usage(void)1934 usage (void)
1935 {
1936   printf ("Usage:\n"
1937     "%s [-v|--version] [-h|--help] [--window window-id] [script-name]\n", MyName);
1938   exit (0);
1939 }
1940 
1941 /* main procedure */
1942 int
main(int argc,char ** argv)1943 main (int argc, char **argv)
1944 {
1945   char configfile[255];
1946   char *realconfigfile;
1947   FILE *fdopen ();
1948   char *temp;
1949   int i;
1950   char *global_config_file = NULL;
1951 
1952   buf = (char *) safemalloc (N);	/* some kludge */
1953 
1954 #ifdef DEBUG
1955   fd_err = open (".FormErrors", O_WRONLY | O_CREAT, 0777);
1956   fp_err = fdopen (fd_err, "w");
1957 #else
1958   fd_err = open ("/dev/null", O_WRONLY, 0);
1959   fp_err = fdopen (fd_err, "w");
1960 #endif
1961 
1962 #ifdef I18N
1963   if (setlocale (LC_CTYPE, "") == NULL)
1964     fprintf (fp_err, "can't set locale\n");
1965 #endif
1966 
1967   ref = None;
1968 
1969   /* Save our program name - for error messages */
1970   temp = strrchr (argv[0], '/');
1971   MyName = temp ? temp + 1 : argv[0];
1972 
1973   for (i = 1; i < argc && *argv[i] == '-'; i++)
1974     {
1975       if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help"))
1976 	usage ();
1977       else if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "--version"))
1978 	version ();
1979       else if (!strcmp (argv[i], "-w") || !strcmp (argv[i], "--window"))
1980 	ref = strtol (argv[++i], NULL, 16);
1981       else if (!strcmp (argv[i], "-c") || !strcmp (argv[i], "--context"))
1982 	i++;
1983       else if (!strcmp (argv[i], "-f") && i + 1 < argc)
1984 	global_config_file = argv[++i];
1985     }
1986 
1987   if (i < argc)
1988     MyName = argv[i++];
1989 
1990 #ifdef DEBUG
1991   fprintf (fp_err, "ref == %d\n", ref);
1992 #endif
1993 
1994   if ((dpy = XOpenDisplay ("")) == NULL)
1995     {
1996       fprintf (stderr, "%s: couldn't open display %s\n",
1997 	       MyName, XDisplayName (""));
1998       exit (1);
1999     }
2000   screen = DefaultScreen (dpy);
2001 
2002   /* connect to AfterStep */
2003   temp = module_get_socket_property (RootWindow (dpy, screen));
2004   fd[0] = fd[1] = module_connect (temp);
2005   XFree (temp);
2006   if (fd[0] < 0)
2007     {
2008       fprintf (stderr, "%s: unable to establish connection to AfterStep\n", MyName);
2009       exit (1);
2010     }
2011   temp = safemalloc (9 + strlen (MyName) + 1);
2012   sprintf (temp, "SET_NAME %s", MyName);
2013   SendInfo (fd, temp, None);
2014   free (temp);
2015 
2016   fd_x = XConnectionNumber (dpy);
2017   root = RootWindow (dpy, screen);
2018   scr_depth = DefaultDepth (dpy, screen);
2019   d_cmap = DefaultColormap (dpy, screen);
2020 
2021   if (global_config_file != NULL)
2022     ParseOptions (global_config_file);
2023   else
2024     {
2025       sprintf (configfile, "%s/forms", AFTER_DIR);
2026       realconfigfile = PutHome (configfile);
2027 
2028       if ((CheckFile (realconfigfile)) == -1)
2029 	{
2030 	  free (realconfigfile);
2031 	  sprintf (configfile, "%s/forms", AFTER_SHAREDIR);
2032 	  realconfigfile = PutHome (configfile);
2033 	}
2034       ParseOptions (realconfigfile);
2035     }
2036 
2037   GetColors ();
2038 
2039   OpenWindows ();
2040 
2041   MainLoop ();
2042 
2043   return 0;
2044 }
2045