DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T x

⟦f31027dd1⟧ TextFile

    Length: 19200 (0x4b00)
    Types: TextFile
    Names: »xmoire.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Xmoire/xmoire.c« 

TextFile

/*
 * xmoire.c
 * Copyright 1988 The Student Information Processing Board (SIPB)
 * Written by Mark W. Eichin, begun April 13, 1988.
 *
 * All distribution rights hereby granted, as long as
 *	1) you do not charge for this code or derivatives of it
 *	without my consent;
 *	2) you leave this header comment in place unchanged;
 * 	3) you attempt to inform myself <eichin@athena.mit.edu> or the
 * 	Board <sipb@athena.mit.edu> of any changes or improvements.
 *
 * The idea for this program comes from a public domain `screensaver'
 * for the Mac labeled:
 * * * "Moire V1.1 by John Lim"
 * * * "Algorithm by Anonymous"
 * * * "Portions (c) John Lim and THINK Tech." 
 * After watching it for a short time, it was obvious how to implement
 * a similar (if not identical) program; however, all the code here is
 * my original work, its purpose only being to provide the same look
 * and feel under X11. Due to the eminent simplicity of the concept, I
 * feel I am not stepping on any toes by creating this. In any case,
 * it is a different window system, and the user interface differs in
 * certain ways (unlabeled keys do NOT produce rectangles; space bar
 * does NOT produce an instructional message (yet); curly braces are
 * used to control operation speed, not 0-9) and that this alone may
 * be sufficient to call the look and feel different. The people here
 * who have found it most similar included at least one person who
 * despised the original, and wanted me to port Pyro instead...
 */

/*
 * Mutable comments follow:
 * $Header: xmoire.c,v 1.1 88/04/15 12:51:10 eichin Exp $
 * $Log:	xmoire.c,v $
 * Revision 1.1  88/04/15  12:51:10  eichin
 * Initial revision
 * 
 */

/*
 * Things to add (may be superseded by the above logs):
 * 	geometry spec for the mousetrap window
 * 	password locking (or integration with xscreensaver)
 * Things *not* to add (don't waste time on:)
 * 	number keys to control speed
 */

#include <X11/Xlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <strings.h>

Display *dpy;

#define SIZ 51
/* SIZ is for alloc'ing */
#define MAXSIZ SIZ-1
/* valid indices are <= MAXSIZ, so if (x>MAXSIZ) x=0; */
#define INITSIZ 5
#define MINSIZ 2
#define MAXTIM 1000000
#define MINTIM 1000

#define SLEEPTIME 50000
#define XR 5
#define XRM 1
#define YR 5
#define YRM 1
#define CHCHANCE (25 - 1)

void init_random()
{
  /*
   * We really don't need a VERY random seed, since we are only
   * adjusting the vectors, and that only needs about 4 bits/sample of
   * magnitude change. Low part of time would be ok, I suppose. So
   * what?
   */
  srandom(getpid());
}

/*
 * These are global, so they don't have to be passed between main and
 * the draw/undraw procs. They should at least be made local to a
 * smaller file/set of procs... for now, they just sit here.
 *
 * The routine simply bounces a bounding box around the screen, and
 * then draws the correct image within it; these are the origin and
 * sides of the bounding box.
 */
int xx[SIZ], yy[SIZ], xs[SIZ], ys[SIZ];
void draw(), undraw();

/*
 * pic is all the possible returns from a keyboard entry; it is also
 * all of the possible shapes (a subset.)
 */
typedef enum _pic {
  RECT, CIRC, PENT, DIAM, LEFT, RIGHT, HGLS, PLUS, CROSS, VEE, TRI,
  PUNT, LONG, SHORT, FAST, SLOW,
} pic;
/* HGLS == HourGlass, also H key... */
/*
 * opts are the keys pressed, and popts are the values returned from
 * char2pic for those keys.
 */
char opts[] = "ropd/\\h+xvtQ][}{";
pic popts[] = {
  RECT, CIRC, PENT, DIAM, LEFT, RIGHT, HGLS, PLUS, CROSS, VEE, TRI,
  PUNT, LONG, SHORT, FAST, SLOW,
};

pic char2pic(in,old)
     char in;
     pic old;
{
  char *where;

  where = index(opts, in);
  return(where?popts[where-opts]:old);
}

/*
 * again, it is easier to make these global than to pass them to the
 * draw/undraw routines all the time.
 */
GC gc, ungc;
Window win;

/*
 * This could stand to be broken down a bit more. But then, none of
 * the important bottlenecks are here... far too much time was spent
 * writing it in the first place to justify rewriting it. Unless of
 * course we can merge it into the other xscreensaver...
 */
main (argc, argv)
	int argc;
	char **argv;
{
  Window rtwin, scanwin;	/* root and mouse entry windows */
  int scrn;
  XGCValues gc_val;
  pic pictype = RECT;		/* current displayed picture */
  int siz = INITSIZ;
  int start, end, ostart;
  int swid, shi;
  int xxoff, yyoff, xsoff, ysoff;
  unsigned long vmask;
  XSetWindowAttributes wvals;
  int timeout, interval, blanking, exposures; /* screen saver parameters */
  unsigned micr = SLEEPTIME;	/* microseconds between motion */
  
  init_random();		/* start random number generator */
  
  dpy = XOpenDisplay("");
  scrn = DefaultScreen(dpy);
  rtwin = RootWindow(dpy, scrn);

  swid = DisplayWidth(dpy, scrn);
  shi = DisplayHeight(dpy, scrn);
  
  wvals.override_redirect = True;
  wvals.background_pixel = BlackPixel(dpy, scrn);
  
  vmask = CWOverrideRedirect | CWBackPixel;
/*
 * Creating the drawing window to fill the whole screen and get mapped
 * later on.
 */
  win = XCreateWindow(dpy, rtwin, /* excitement window */
		      0, 0,	/* origin */
		      swid, shi, /* size */
		      0,	/* border width */
		      0,	/* depth from parent */
		      InputOutput, /* class */
		      CopyFromParent, /* visual */
		      vmask, &wvals);
  
#define BOXSIZ 50

  vmask = CWOverrideRedirect;
/*
 * Creating the window to catch the mouse motion, into and out of the
 * ``corner''; this perhaps ought to be smaller, and should parse the
 * geometry specification from somwhere as well.
 */
  scanwin = XCreateWindow(dpy, rtwin, /* toggle window */
			  swid-BOXSIZ, 0, /* origin */
			  BOXSIZ, BOXSIZ, /* size */
			  0,	/* border width */
			  0,	/* depth from parent */
			  InputOnly, /* class */
			  CopyFromParent, /* visual */
			  vmask, &wvals);
/*
 * The GC's for draw and undraw. The method used is to draw the first
 * shapes, then erase the last one and repeat.
 */
  gc_val.foreground = (unsigned long) WhitePixel (dpy, scrn); 
  gc_val.background = (unsigned long) BlackPixel (dpy, scrn); 
  gc = XCreateGC (dpy, win, GCForeground|GCBackground, &gc_val);

  gc_val.foreground = (unsigned long) BlackPixel (dpy, scrn); 
  gc_val.background = (unsigned long) WhitePixel (dpy, scrn); 
  ungc = XCreateGC (dpy, win, GCForeground|GCBackground, &gc_val);

  start = 0;			/* duplicated later... */
  xx[start] = 0;		/* initial vals, should read them? */
  yy[start] = 0;
  xs[start] = 100;
  ys[start] = 100;
  
  xxoff = 3;
  yyoff = 3;
  xsoff = 0;
  ysoff = 0;

  for (;;)
    {
      int sizoff;
      /*
       * First we deal with the selector window, then we fall into the
       * drawing window, and then back to the selector window.
       */

      XSelectInput(dpy, scanwin, EnterWindowMask);
      XMapWindow(dpy, scanwin);
      
      for (;;)
	{
	  XEvent event;
	  
	  XNextEvent(dpy, &event);
	  if(event.type == EnterNotify)
	    {
	      break;		/*
				 * they came in to the corner zone...
				 * interesting frob here might be to
				 * check the position on an angle.
				 */
	    }
	}
      /*
       * Nuke the screensaver, for now WE are the screensaver. There
       * really should be a ``screensaver activated'' event of some
       * sort, so we could trigger on this too...
       */
      XGetScreenSaver(dpy, &timeout, &interval, &blanking, &exposures);
      XSetScreenSaver(dpy,	/* all these are zero, but lets do it right */
		      DisableScreenSaver,
		      DisableScreenInterval,
		      DontPreferBlanking,
		      DontAllowExposures); /* disable screen saver */

      /*
       * Now wait for the full-screen drawing window to show up
       */
      XSelectInput(dpy, win, ExposureMask);
      XMapRaised(dpy, win);	/* put it on top */

      /*
       * Turn off entry, just notice when the mouse exits. To make it
       * appear on top again, and to allow other events to leak
       * through, reparent the mousetrap window into the drawing
       * window.
       */

      XSelectInput(dpy, scanwin, LeaveWindowMask);
      XReparentWindow(dpy, scanwin, win, swid-BOXSIZ, 0);
      
      /*
       * always start with one, but make end negative so that we don't
       * start erasing things until we have enough of them there.
       */
      start = 0;
      end = start - siz;
  
      for (;;)
	{
	  XEvent event;
	  
	  XNextEvent(dpy, &event);
	  if(event.type == Expose)
	    {
	      break;		/*
				 * same type of loop as above, but
				 * this time it is waiting for the
				 * mapping to finish. This could be
				 * made MUCH prettier. */
	    }
	}

      /*
       * Now start looking for key presses to change the display. Note
       * that we could just look at scanwin (we know we are in it,
       * right?) but this way is more fun...
       */
      XSelectInput(dpy, win, KeyPressMask);

      for (;;)
	{
	  usleep(micr);		/* bored with the X server, sleeping... */
  
	  if(XPending(dpy))	/* Got one! */
	    {
	      XEvent event;
	  
	      XNextEvent(dpy, &event);
	      if(event.type == KeyPress) /* Could listen to both windows... */
		{
		  char input;
		  pic tmppic;

		  /* just get the first char of the keypress */
		  (void)XLookupString(&event.xkey, &input, 1, NULL, NULL);
	      
		  /* convert it to a picture index */
		  tmppic = char2pic(input, pictype);
	      
		  if (tmppic == pictype)
		    continue;	/* punt if already running that one */

		  if (tmppic == PUNT) /* get out, should check passwd? */
		    {
		      break;	/*
				 * actually a relic from before
				 * mousing stuff worked.
				 */
		    }
		  if (tmppic == LONG) /* make the pattern longer */
		    {
		      sizoff = 1;
		      continue;
		    }
		  if (tmppic == SHORT) /* make it shorter */
		    {
		      sizoff = -1;
		      continue;
		    }
		  if (tmppic == FAST) /* update faster */
		    {
		      micr <<= (micr>=MAXTIM)?0:1;
		      continue;
		    }
		  if (tmppic == SLOW) /* update slower */
		    {
		      micr >>= (micr<=MINTIM)?0:1;
		      continue;
		    }

		  while(start != end) /* ok, it IS a new pattern, wipe old */
		    {
		      undraw(pictype, end);
		      end++;
		      if(end > MAXSIZ) end = 0;
		    }
		  /* set up as a fresh start for the new one */
		  xx[0] = xx[start]; xs[0] = xs[start];
		  yy[0] = yy[start]; ys[0] = ys[start];
		  
		  start = 0;
		  end = start - siz;
		  pictype = tmppic;
		}
	      else if (event.type == LeaveNotify)
		{
		  /* this is the REAL escape method... */
		  break;	/* getting out... Password? */
		}
	      continue;
	    }

	  if(sizoff == -1)
	    {
	      if(siz > MINSIZ)
		{
		  siz--;
		  undraw(pictype, end);
		  end++;
		  if(end > MAXSIZ) end = 0;
		}
	      sizoff = 0;
	    }
	  /* else */
	    {
	      if (sizoff == 0 || siz >= MAXSIZ)
		{
		  undraw(pictype, end);
		  end++;
		  if(end > MAXSIZ) end = 0;
		}
	      if(sizoff == 1 && siz <= MAXSIZ)
		{
		  siz++;
		}
	      sizoff = 0;
	    }
	  
	  draw(pictype, start);	/* actually draw a stage */
	  /*
	   * Now for the common box incrementing code...
	   */
	  ostart = start++;
	  if(start >= SIZ) start = 0;

	  /* jump the bounding box a step... */
	  xx[start] = xx[ostart] + xxoff;
	  xs[start] = xs[ostart] + xsoff;
	  yy[start] = yy[ostart] + yyoff;
	  ys[start] = ys[ostart] + ysoff;
      

	  if(xx[start]+xs[start] + xxoff + xsoff > swid) /* past right edge */
	    {
	      if(xxoff>0) xxoff = -xxoff;
	      if(xsoff>0) xsoff = -xsoff;
	    }
	  if(xx[start]+xxoff < 0) /* past left edge */
	    {
	      xxoff = -xxoff;
	    }
	  if(yy[start]+ys[start] + yyoff + ysoff > shi)	/* below bottom */
	    {
	      if(yyoff>0) yyoff = -yyoff;
	      if(ysoff>0) ysoff = -ysoff;
	    }
	  if(yy[start]+yyoff < 0) /* above top */
	    {
	      yyoff = -yyoff;
	    }
	  if(xs[start]+xsoff < 0) /* too narrow */
	    {
	      xsoff = - xsoff;
	    }
	  if(ys[start]+ysoff < 0) /* too short */
	    {
	      ysoff = - ysoff;
	    }
	  if(!small_random(0,CHCHANCE))	/* 1:20 chance of actual change */
	    {
	      if(small_random(0,1)) /* 1:2 choice... */
		{
		  xxoff =
		    small_random((xxoff>0?XRM:-XR),
				 (xxoff>0?XR:-XRM));
		}
	      else
		{
		  yyoff =
		    small_random((yyoff>0?YRM:-YR),
				 (yyoff>0?YR:-YRM));
		}
	    }
	  if(!small_random(0,CHCHANCE))
	    {
	      if(small_random(0,1)) /* 1:2 choice... */
		{
		  xsoff =
		    2*small_random((xsoff>0?XRM:-XR),
				   (xsoff>0?XR:-XRM));
		}
	      else
		{
		  ysoff =
		    2*small_random((ysoff>0?YRM:-YR),
				   (ysoff>0?YR:-YRM));
		}
	    }
	}
      /* put the special box back in the root window */
      XReparentWindow(dpy, scanwin, rtwin, swid-BOXSIZ, 0);
      /* turn the drawing window off */
      XUnmapWindow(dpy, win);	/*
				 * hide the graphics, and fall up to
				 * the top.
				 */
      /* restore the screensaver to the old defaults */
      XSetScreenSaver(dpy, timeout, interval, blanking, exposures);
    }
}
  
void undraw(ptype, ind)
     pic ptype;
     int ind;
{
  switch(ptype)
    {
    case RECT:
      if (ind>=0)
	{
	  XDrawRectangle(dpy, win, ungc,
			 xx[ind], yy[ind],
			 xs[ind], ys[ind]);
	}
      break;
    case CIRC:
      if(ind>=0) XDrawArc(dpy, win, ungc,
			  xx[ind], yy[ind],
			  xs[ind], ys[ind],
			  0, 360*64);
      break;
    case PENT:
      if(ind>=0)
	{
	  XPoint xps[6];

	  xps[5].x = xps[0].x = xx[ind]+xs[ind]/2;
	  xps[5].y = xps[0].y = yy[ind];
	  xps[2].x = xx[ind];
	  xps[2].y = yy[ind]+ys[ind]/2;
	  xps[3].x = xx[ind]+xs[ind];
	  xps[3].y = yy[ind]+ys[ind]/2;
	  xps[4].x = xx[ind]+xs[ind]/3;
	  xps[4].y = yy[ind]+ys[ind];
	  xps[1].x = xx[ind]+2*xs[ind]/3;
	  xps[1].y = yy[ind]+ys[ind];
	    
	  XDrawLines(dpy, win, ungc, xps, 6, CoordModeOrigin);
	}
      break;
    case DIAM:
      if(ind>=0)
	{
	  XPoint xps[5];

	  xps[4].x = xps[0].x = xx[ind]+xs[ind]/2;
	  xps[4].y = xps[0].y = yy[ind];
	  xps[1].x = xx[ind]+xs[ind];
	  xps[1].y = yy[ind]+ys[ind]/2;
	  xps[2].x = xx[ind]+xs[ind]/2;
	  xps[2].y = yy[ind]+ys[ind];
	  xps[3].x = xx[ind];
	  xps[3].y = yy[ind]+ys[ind]/2;

	  XDrawLines(dpy, win, ungc, xps, 5, CoordModeOrigin);
	}
      break;
    case LEFT:			/* / */
      if(ind>=0) XDrawLine(dpy, win, ungc,
			   xx[ind], yy[ind]+ys[ind],
			   xx[ind]+xs[ind], yy[ind]);
      break;
    case RIGHT:			/* \ */
      if(ind>=0) XDrawLine(dpy, win, ungc,
			   xx[ind], yy[ind],
			   xx[ind]+xs[ind], yy[ind]+ys[ind]);
      break;
    case HGLS:
      if(ind>=0)
	{
	  XPoint xps[5];

	  xps[4].x = xps[0].x = xx[ind];
	  xps[4].y = xps[0].y = yy[ind];
	  xps[1].x = xx[ind]+xs[ind];
	  xps[1].y = yy[ind];
	  xps[2].x = xx[ind];
	  xps[2].y = yy[ind]+ys[ind];
	  xps[3].x = xx[ind]+xs[ind];
	  xps[3].y = yy[ind]+ys[ind];

	  XDrawLines(dpy, win, ungc, xps, 5, CoordModeOrigin);
	}
      break;
    case PLUS:
      if(ind>=0)
	{
	  XDrawLine(dpy, win, ungc, /* - */
		    xx[ind], yy[ind]+ys[ind]/2,
		    xx[ind]+xs[ind], yy[ind]+ys[ind]/2);
	  XDrawLine(dpy, win, ungc, /* | */
		    xx[ind]+xs[ind]/2, yy[ind],
		    xx[ind]+xs[ind]/2, yy[ind]+ys[ind]);
	}
      break;
      
    case CROSS:
      if(ind>=0)
	{
	  XDrawLine(dpy, win, ungc, /* / */
		    xx[ind], yy[ind]+ys[ind],
		    xx[ind]+xs[ind], yy[ind]);
	  XDrawLine(dpy, win, ungc, /* \ */
		    xx[ind], yy[ind],
		    xx[ind]+xs[ind], yy[ind]+ys[ind]);
	}
      break;
    case VEE:
      if(ind>=0)
	{
	  XDrawLine(dpy, win, ungc, /* \ */
		    xx[ind], yy[ind],
		    xx[ind]+xs[ind]/2, yy[ind]+ys[ind]);
	  XDrawLine(dpy, win, ungc, /* / */
		    xx[ind]+xs[ind], yy[ind],
		    xx[ind]+xs[ind]/2, yy[ind]+ys[ind]);
	}
      break;
    case TRI:
      if(ind>=0)
	{
	  XPoint xps[4];

	  xps[3].x = xps[0].x = xx[ind]+xs[ind]/2;
	  xps[3].y = xps[0].y = yy[ind];
	  xps[1].x = xx[ind]+xs[ind];
	  xps[1].y = yy[ind]+ys[ind];
	  xps[2].x = xx[ind];
	  xps[2].y = yy[ind]+ys[ind];

	  XDrawLines(dpy, win, ungc, xps, 4, CoordModeOrigin);
	}
      break;
      
      /* , TRI, */
    default:
      break;
    }
}

void draw(ptype, ind)
     pic ptype;
     int ind;
{
  switch(ptype)
    {
    case RECT:
      XDrawRectangle(dpy, win, gc,
		     xx[ind], yy[ind],
		     xs[ind], ys[ind]);
      break;
    case CIRC:
      XDrawArc(dpy, win, gc,
	       xx[ind], yy[ind],
	       xs[ind], ys[ind],
	       0, 360*64);
      break;
    case PENT:
      /*
       * Pentagon: five points.
       * Top center,
       * upper left/right (same y, diff. x)
       * lower left/right (same y, diff. x)
       * This should fit in a rectangle...
       * tc = (xx+xs/2, yy)
       * ul = (xx, yy+ys/2) ur = (xx+xs, yy+ys/2)
       * ll = (xx+xs/3, yy+ys) lr = (xx+2xs/3, yy+ys)
       * draw tc->lr->ul->ur->ll->tc.
       */
      {
	XPoint xps[6];

	xps[5].x = xps[0].x = xx[ind]+xs[ind]/2;
	xps[5].y = xps[0].y = yy[ind];
	xps[2].x = xx[ind];
	xps[2].y = yy[ind]+ys[ind]/2;
	xps[3].x = xx[ind]+xs[ind];
	xps[3].y = yy[ind]+ys[ind]/2;
	xps[4].x = xx[ind]+xs[ind]/3;
	xps[4].y = yy[ind]+ys[ind];
	xps[1].x = xx[ind]+2*xs[ind]/3;
	xps[1].y = yy[ind]+ys[ind];
	    
	XDrawLines(dpy, win, gc, xps, 6, CoordModeOrigin);
      }
      break;
    case DIAM:
      {
	XPoint xps[5];

	xps[4].x = xps[0].x = xx[ind]+xs[ind]/2;
	xps[4].y = xps[0].y = yy[ind];
	xps[1].x = xx[ind]+xs[ind];
	xps[1].y = yy[ind]+ys[ind]/2;
	xps[2].x = xx[ind]+xs[ind]/2;
	xps[2].y = yy[ind]+ys[ind];
	xps[3].x = xx[ind];
	xps[3].y = yy[ind]+ys[ind]/2;

	XDrawLines(dpy, win, gc, xps, 5, CoordModeOrigin);
      }
      break;
    case LEFT:			/* / */
      XDrawLine(dpy, win, gc,
		xx[ind], yy[ind]+ys[ind],
		xx[ind]+xs[ind], yy[ind]);
      break;
    case RIGHT:			/* \ */
      XDrawLine(dpy, win, gc,
		xx[ind], yy[ind],
		xx[ind]+xs[ind], yy[ind]+ys[ind]);
      break;
    case HGLS:
      {
	XPoint xps[5];

	xps[4].x = xps[0].x = xx[ind];
	xps[4].y = xps[0].y = yy[ind];
	xps[1].x = xx[ind]+xs[ind];
	xps[1].y = yy[ind];
	xps[2].x = xx[ind];
	xps[2].y = yy[ind]+ys[ind];
	xps[3].x = xx[ind]+xs[ind];
	xps[3].y = yy[ind]+ys[ind];

	XDrawLines(dpy, win, gc, xps, 5, CoordModeOrigin);
      }
      break;
    case PLUS:
      XDrawLine(dpy, win, gc, /* - */
		xx[ind], yy[ind]+ys[ind]/2,
		xx[ind]+xs[ind], yy[ind]+ys[ind]/2);
      XDrawLine(dpy, win, gc, /* | */
		xx[ind]+xs[ind]/2, yy[ind],
		xx[ind]+xs[ind]/2, yy[ind]+ys[ind]);
      break;
    case CROSS:
      XDrawLine(dpy, win, gc, /* / */
		xx[ind], yy[ind]+ys[ind],
		xx[ind]+xs[ind], yy[ind]);
      XDrawLine(dpy, win, gc, /* \ */
		xx[ind], yy[ind],
		xx[ind]+xs[ind], yy[ind]+ys[ind]);
      break;
    case VEE:
      XDrawLine(dpy, win, gc, /* \ */
		xx[ind], yy[ind],
		xx[ind]+xs[ind]/2, yy[ind]+ys[ind]);
      XDrawLine(dpy, win, gc, /* / */
		xx[ind]+xs[ind], yy[ind],
		xx[ind]+xs[ind]/2, yy[ind]+ys[ind]);
      break;
    case TRI:
      {
	XPoint xps[4];
      
	xps[3].x = xps[0].x = xx[ind]+xs[ind]/2;
	xps[3].y = xps[0].y = yy[ind];
	xps[1].x = xx[ind]+xs[ind];
	xps[1].y = yy[ind]+ys[ind];
	xps[2].x = xx[ind];
	xps[2].y = yy[ind]+ys[ind];

	XDrawLines(dpy, win, gc, xps, 4, CoordModeOrigin);
      }
      break;
    default:
      break;
    }
}

int small_random(low, high)	/* low <= s_r <= high */
     int low, high;
{
  long r;

  r = random();
  return((r % (high-low+1))+low);
}