[comp.sources.x] v04i091: Aquarium, Part01/02

argv@island.uu.net (Dan Heller) (08/18/89)

Submitted-by: uunet!umd5.umd.edu!jonnyg (Jon Greenblatt)
Posting-number: Volume 4, Issue 91
Archive-name: aquarium/part01

	This is a color/monocrome living aquarium program. The original
author is unknown. The command line parsing needs to be fixed but
other than that things seem to be in good shape. After unarchiving this
and setting up the Makefile, type "make unshar" to uncompress the
bitmap file.

					JonnyG.

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by rover.umd.edu!jonnyg on Wed Aug 16 10:53:04 EDT 1989
# Contents:  FIRST.README Imakefile Makefile xfish.c
 
echo x - FIRST.README
sed 's/^@//' > "FIRST.README" <<'@//E*O*F FIRST.README//'

Ported from X10R4 to X11R3 by Jonathan Roger Greenblatt (jonnyg@rover.umd.edu)
	8/10/89

Original Author of the X10 version is Unknown.

				 XAquarium
				===========
XAquarium is an X Windows application which creates a full-screen background
window complete with color fish and translucent bubbles.  This program is
not to be confused with the older 'xfish' which featured small monochrome
fish on a monochrome background.  On the contrary.  XAquarium features
highly detailed fish in living color, translucent bubbles, and a full color
background.  With that confusion removed, the program will be referred to
as 'XFish' from this point forward.

Scientific Note: Research has shown that a moving aquarium background creates
a soothing and relaxing atmosphere, thereby reducing the stresses associated
with day-to-day workstation usage.  A corresponding increase in productivity
should result, although this is yet to be shown.


XFish Creation
--------------
The package includes four files ...
	* FIRST.README	(this file)
	* Makefile	(makefile for complete compilation)
	* xfish.c	(application code)
	* xfishy.c	(fairly large file containing pixmaps and bitmaps)

After unpacking the shell archive, running 'make' is all that is required
to compile XFish.


XFish Usage
-----------
usage: xfish [-b limit][-c color][-f limit][-i mult][-r rate][-s][host:display]

XFish is designed to run efficiently on defaults alone, but like any good X
program, command line options are provided ...
	* -b specifies the bubble limit (default = 32)
	* -c specifies the background color (default = MediumAquamarine)
	* -f specifies the fish limit (default = 2, for historical reasons)
        * -i specifies the increment multipler (default = 1.0)
	* -r specifies the update rate (default = 1.0 seconds)
	* -s activates secure mode, raising the window for use with xsecure
	* host:display is the standard X server specifier

as well as ~/.Xdefault options for all of the above ...
	* xfish.BubbleLimit:		32
	* xfish.Color:			MediumAquamarine
	* xfish.FishLimit:		2
        * xfish.IncMult:                1.0
	* xfish.Rate:			1.0
	* xfish.Secure:			No

A few notes on XFish performance ...

	* Bubbles are something of a CPU drain.  Overall performance can
	  be improved by using low bubble limits.  If the bubbles appear
	  to be flashing, try fewer bubbles, or turn off bubbles using -b0.

	* Off-screen display memory is used for fish if available.  This
	  results in astonishing performance gains.  For this reason,
	  fish are not much of a CPU drain, and higher fish limits can
	  easily be used.

	* Changing the update rate is the most effective way to control
	  impact on system performance.  The default of 1 second results
	  in less than a 10% CPU usage on a single user 350.  Higher values
	  may be desirable on more burdened system.

	* A zero update rate using -r0 creates some great looking displays.
	  Try 'xfish -r0 -f0' and 'xfish -r0 -b0 -f8' (the latter really
	  shows off the capabilities of the Topcat board, and is simply
	  astounding on the Catseye board).

	* Decreasing the increment multiplier, using -i 0.1 for example, is
	  especially  useful in conjunction with a zero update rate.  If you
	  prefer '911 Turbo' fish, use a multiplier of greater than one.

	* The aquarium window obscures most of the root window.  A one pixel
	  border is provided around the window to allow quick access to the
	  root window.  An alternative, which proves very useful with the
          secure option, is to iconize the aquarium (until ready to xsecBure).

	* Sending SIGUSR1 (16) to the XFish process (using 'kill -16 <pid>')
	  will toggle the raise-lower mode.  Using this technique, xsecure
	  can be started without the need to restart XFish.


XFish Enhancements
------------------
XFish was intended to be run as a background window, and as such it was
designed to minimize CPU impact.  Although enhancement requests will be
cheerfully accepted, it is unlikely that features will be added to the
detriment of overall performance.  On the other hand, any recommendations
which could benefit overall performance will be utilized.
@//E*O*F FIRST.README//
chmod u=r,g=r,o=r FIRST.README
 
echo x - Imakefile
sed 's/^@//' > "Imakefile" <<'@//E*O*F Imakefile//'
       INCLUDES = -I. -I$(TOP) -I$(TOP)/X11
LOCAL_LIBRARIES = $(XLIB)
  SYS_LIBRARIES = -lm

           SRCS = xfish.c xfishy.c
           OBJS = xfish.o xfishy.o

ComplexProgramTarget(xfish)

# Make the export sharchive.
shar: xaqua.shar

xaqua.shar: xaqua.shar1 xaqua.shar2

xaqua.shar1: FIRST.README Imakefile Makefile xfish.c
	shar FIRST.README Imakefile Makefile xfish.c >xaqua.shar1

xfishy.c.Z: xfishy.c
	compress -c xfishy.c >xfishy.c.Z

xfishy.c.Z.uu: xfishy.c.Z
	uuencode xfishy.c.Z xfishy.c.Z >xfishy.c.Z.uu

xaqua.shar2: xfishy.c.Z.uu
	shar xfishy.c.Z.uu >xaqua.shar2

# Unpack the compressed, uuencoded, shared bitmap.
unshar:
	uudecode xfishy.c.Z.uu
	uncompress xfishy.c.Z

# Make the export tarchive.
tar: xaqua.tar.Z

xaqua.tar.Z: xaqua.tar
	rm -f xaqua.tar.Z
	compress xaqua.tar

xaqua.tar: FIRST.README Imakefile Makefile xfish.c xfishy.c
	tar chf xaqua.tar FIRST.README Imakefile Makefile xfish.c xfishy.c
@//E*O*F Imakefile//
chmod u=r,g=r,o=r Imakefile
 
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
# Makefile generated by imake - do not edit!
# $XConsortium: imake.c,v 1.37 88/10/08 20:08:30 jim Exp $

###########################################################################
# X Window System Makefile generated from template file Imake.tmpl
# $XConsortium: Imake.tmpl,v 1.91 88/10/23 22:37:10 jim Exp $
#
# Do not change the body of the imake template file.  Server-specific
# parameters may be set in the appropriate .macros file; site-specific
# parameters (but shared by all servers) may be set in site.def.  If you
# make any changes, you'll need to rebuild the makefiles using
# "make World" (at best) or "make Makefile; make Makefiles" (at least) in
# the top level directory.
#
# If your C preprocessor doesn't define any unique symbols, you'll need
# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
# "make Makefile", "make Makefiles", or "make World").
#
# If you absolutely can't get imake to work, you'll need to set the
# variables at the top of each Makefile as well as the dependencies at the
# bottom (makedepend will do this automatically).
#

###########################################################################
# platform-specific configuration parameters - edit Rt.macros to change

# platform:  $XConsortium: Rt.macros,v 1.47 88/10/25 18:39:43 keith Exp $

# platform:  $XConsortium: IBM.macros,v 1.22 88/10/25 18:39:31 keith Exp $

             AS = as
            CPP = /lib/cpp
             LD = ld
           LINT = lint
           MAKE = make
        INSTALL = install
           TAGS = ctags
             RM = rm -f
             MV = mv
             LS = ls
             CP = cp
STD_CPP_DEFINES =
    STD_DEFINES =

BOOTSTRAPCFLAGS =
             CC = hc
 LDCOMBINEFLAGS = -X -r
             LN = ln -s
         RANLIB = ranlib
RANLIBINSTFLAGS = -t
             AR = ar cq
       LINTOPTS = -axz
    LINTLIBFLAG = -C

            PCC = pcc

###########################################################################
# site-specific configuration parameters - edit site.def to change

# site:  $XConsortium: site.def,v 1.16 88/10/12 10:30:24 jim Exp $

###########################################################################
# definitions common to all Makefiles - do not edit

          SHELL = 	/bin/sh

        DESTDIR =
      USRLIBDIR = $(DESTDIR)/usr/lib
         BINDIR = $(DESTDIR)/usr/bin/X11
         INCDIR = $(DESTDIR)/usr/include/X11
         ADMDIR = $(DESTDIR)/usr/adm
         LIBDIR = $(USRLIBDIR)/X11
     LINTLIBDIR = $(USRLIBDIR)/lint
        FONTDIR = $(LIBDIR)/fonts
       XINITDIR = $(LIBDIR)/xinit
         XDMDIR = $(LIBDIR)/xdm
         UWMDIR = $(LIBDIR)/uwm
         AWMDIR = $(LIBDIR)/awm
         TWMDIR = $(LIBDIR)/twm
        MANPATH = $(DESTDIR)/usr/man
  MANSOURCEPATH = $(MANPATH)/man
         MANDIR = $(MANSOURCEPATH)n
      LIBMANDIR = $(MANSOURCEPATH)3
    XAPPLOADDIR = $(LIBDIR)/app-defaults

   INSTBINFLAGS = -m 0755
   INSTUIDFLAGS = -m 4755
   INSTLIBFLAGS = -m 0664
   INSTINCFLAGS = -m 0444
   INSTMANFLAGS = -m 0444
   INSTAPPFLAGS = -m 0444
  INSTKMEMFLAGS = -m 4755
        FCFLAGS = -t
    CDEBUGFLAGS = -O

        PATHSEP = /
         DEPEND = $(DEPENDSRC)/makedepend
          IMAKE = $(IMAKESRC)/imake
            RGB = $(RGBSRC)/rgb
             FC = $(BDFTOSNFSRC)/bdftosnf
      MKFONTDIR = $(MKFONTDIRSRC)/mkfontdir
      MKDIRHIER = $(SCRIPTSSRC)/mkdirhier.sh

         CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(DEFINES)
      LINTFLAGS = $(LINTOPTS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) -DLINT
        LDFLAGS = $(CDEBUGFLAGS) $(SYS_LIBRARIES) $(SYSAUX_LIBRARIES)
            TOP = ./../../..
      CLIENTSRC = $(TOP)/clients
        DEMOSRC = $(TOP)/demos
         LIBSRC = $(TOP)/lib
        FONTSRC = $(TOP)/fonts
     INCLUDESRC = $(TOP)/X11
      SERVERSRC = $(TOP)/server
        UTILSRC = $(TOP)/util
     SCRIPTSSRC = $(UTILSRC)/scripts
     EXAMPLESRC = $(TOP)/examples
     CONTRIBSRC = $(TOP)/contrib
         DOCSRC = $(TOP)/doc
         RGBSRC = $(TOP)/rgb
      DEPENDSRC = $(UTILSRC)/makedepend
       IMAKESRC = $(UTILSRC)/imake
       IRULESRC = $(UTILSRC)/imake.includes
        XLIBSRC = $(LIBSRC)/X
         XMUSRC = $(LIBSRC)/Xmu
     TOOLKITSRC = $(LIBSRC)/Xt
     AWIDGETSRC = $(LIBSRC)/Xaw
     OLDXLIBSRC = $(LIBSRC)/oldX
    BDFTOSNFSRC = $(FONTSRC)/bdftosnf
   MKFONTDIRSRC = $(FONTSRC)/mkfontdir
   EXTENSIONSRC = $(TOP)/extensions
   EXTENSIONLIB = $(EXTENSIONSRC)/lib/libXext.a
           XLIB = $(XLIBSRC)/libX11.a
         XMULIB = $(XMUSRC)/libXmu.a
        OLDXLIB = $(OLDXLIBSRC)/liboldX.a
       XTOOLLIB = $(TOOLKITSRC)/libXt.a
         XAWLIB = $(AWIDGETSRC)/libXaw.a
       LINTXLIB = $(XLIBSRC)/llib-lX11.ln
        LINTXMU = $(XMUSRC)/llib-lXmu.ln
      LINTXTOOL = $(TOOLKITSRC)/llib-lXt.ln
        LINTXAW = $(AWIDGETSRC)/llib-lXaw.ln
       INCLUDES = -I$(TOP)
      MACROFILE = Rt.macros
   ICONFIGFILES = $(IRULESRC)/Imake.tmpl \
			$(IRULESRC)/$(MACROFILE) $(IRULESRC)/site.def
  IMAKE_DEFINES =
      IMAKE_CMD = $(NEWTOP)$(IMAKE) -TImake.tmpl -I$(NEWTOP)$(IRULESRC) \
			-s Makefile $(IMAKE_DEFINES)
         RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a \
			.emacs_* tags TAGS make.log MakeOut

###########################################################################
# rules:  $XConsortium: Imake.rules,v 1.71 88/10/23 22:46:34 jim Exp $

###########################################################################
# start of Imakefile

       INCLUDES = -I. -I$(TOP) -I$(TOP)/X11
LOCAL_LIBRARIES = $(XLIB)
  SYS_LIBRARIES = -lm

           SRCS = xfish.c xfishy.c
           OBJS = xfish.o xfishy.o

        PROGRAM = xfish

all:: xfish

xfish: $(OBJS) $(LOCAL_LIBRARIES)
	$(RM) $@
	$(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS) $(SYSLAST_LIBRARIES)

relink::
	$(RM) $(PROGRAM)
	$(MAKE) $(MFLAGS) $(PROGRAM)

install:: xfish
	$(INSTALL) -c $(INSTALLFLAGS) xfish $(BINDIR)

install.man:: xfish.man
	$(INSTALL) -c $(INSTMANFLAGS) xfish.man $(MANDIR)/xfish.n

depend:: $(DEPEND)

depend::
	$(DEPEND) -s "# DO NOT DELETE" -- $(CFLAGS) -- $(SRCS)

$(DEPEND):
	@echo "making $@"; \
	cd $(DEPENDSRC); $(MAKE)

clean::
	$(RM) $(PROGRAM)

# Make the export sharchive.
shar: xaqua.shar

xaqua.shar: xaqua.shar1 xaqua.shar2

xaqua.shar1: FIRST.README Imakefile Makefile xfish.c
	shar FIRST.README Imakefile Makefile xfish.c >xaqua.shar1

xfishy.c.Z: xfishy.c
	compress -c xfishy.c >xfishy.c.Z

xfishy.c.Z.uu: xfishy.c.Z
	uuencode xfishy.c.Z xfishy.c.Z >xfishy.c.Z.uu

xaqua.shar2: xfishy.c.Z.uu
	shar xfishy.c.Z.uu >xaqua.shar2

# Unpack the compressed, uuencoded, shared bitmap.
unshar:
	uudecode xfishy.c.Z.uu
	uncompress xfishy.c.Z

# Make the export tarchive.
tar: xaqua.tar.Z

xaqua.tar.Z: xaqua.tar
	rm -f xaqua.tar.Z
	compress xaqua.tar

xaqua.tar: FIRST.README Imakefile Makefile xfish.c xfishy.c
	tar chf xaqua.tar FIRST.README Imakefile Makefile xfish.c xfishy.c

###########################################################################
# Imake.tmpl common rules for all Makefiles - do not edit

emptyrule::

clean::
	$(RM_CMD) \#*

Makefile:: $(IMAKE)

Makefile:: Imakefile \
	$(IRULESRC)/Imake.tmpl \
	$(IRULESRC)/Imake.rules \
	$(IRULESRC)/site.def \
	$(IRULESRC)/$(MACROFILE)
	-@if [ -f Makefile ]; then \
		echo "$(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \
		$(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
	else exit 0; fi
	$(IMAKE_CMD) -DTOPDIR=$(TOP)

$(IMAKE):
	@echo "making $@"; \
	cd $(IMAKESRC); $(MAKE) BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS)

tags::
	$(TAGS) -w *.[ch]
	$(TAGS) -xw *.[ch] > TAGS

###########################################################################
# empty rules for directories that do not have SUBDIRS - do not edit

install::
	@echo "install done"

install.man::
	@echo "install.man done"

Makefiles::

###########################################################################
# dependencies generated by makedepend

# DO NOT DELETE

xfish.o: /usr/include/sys/time.h /usr/include/sys/time.h /usr/include/stdio.h
xfish.o: /usr/include/signal.h ./../../../X11/Xlib.h /usr/include/sys/types.h
xfish.o: ./../../../X11/X.h ./../../../X11/Xutil.h
xfishy.o: ./../../../X11/Xlib.h /usr/include/sys/types.h ./../../../X11/X.h
@//E*O*F Makefile//
chmod u=rw,g=rw,o=rw Makefile
 
echo x - xfish.c
sed 's/^@//' > "xfish.c" <<'@//E*O*F xfish.c//'
static char ident[] = "@(#)$Header: XFish release 3, revision 1, 11 Aug 1989 $";

/*

  *	Original Author Unknow.

  *	8/10/88 - Ported from X10 to X11R3 by:

		Jonathan Greenblatt (jonnyg@rover.umd.edu)

  *	Cleaned up by Dave Lemke (lemke@sun.com)

  *	Ported to monocrome by Jonathan Greenblatt (jonnyg@rover.umd.edu)

  TODO:

	Parameter parsing needs to be redone.

*/

#ifndef HPUX
#include <sys/time.h>
#else
#include <time.h>
#endif

#include <stdio.h>
#include <signal.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

/* constants are based on rand(3C) returning an integer between 0 and 32767 */

#ifndef HPUX
#define  RAND_I_1_16   134217728
#define  RAND_F_1_8    268435455.875
#define  RAND_I_1_4    536870911
#define  RAND_I_1_2   1073741823
#define  RAND_I_3_4   1610612735
#define  RAND_F_MAX   2147483647.0
#else
#define  RAND_I_1_16   2048
#define  RAND_F_1_8    4096.0
#define  RAND_I_1_4    8096
#define  RAND_I_1_2   16384
#define  RAND_I_3_4   24575
#define  RAND_F_MAX   32767.0
#endif

/* externals for pixmap and bimaps from xfishy.c */
extern int  rwidth,
            rheight,
            rcolors,
            rback,
            rreds[],
            rgreens[],
            rblues[];
extern short xfishRaster[];
extern unsigned char xbBits[9][8];
extern char fish_bits[], fishl_bits[];
int mono;


/* typedefs for bubble and fish structures, also caddr_t (not used in X.h) */
typedef struct {
    int         x,
                y,
                s,
                i;
}           bubble;
typedef struct {
    int         x,
                y,
                d,
                i;
}           fish;
typedef unsigned char *caddrt;


/* bubble increment and yes check tables */
int         binc[] = {0, 64, 56, 48, 40, 32, 24, 16, 8};
char       *yess[] = {"yes", "Yes", "YES", "on", "On", "ON"};


char       *pname,		/* program name from argv[0] */
            sname[64],		/* host:display specification */
            cname[64];		/* colorname specification */
int         blimit = 32,	/* bubble limit */
            flimit = 2,		/* fish limit */
            pmode = 1,		/* pop mode, (1 for lower, 0 for raise) */
            width,		/* width of initial window in pixels */
            height,		/* height of initial window in pixels */
            screen;		/* Default screen of this display */
Init_B,
*cmap;				/* Initialize bubbles with random y value */
double      rate = 1.0,		/* update interval in seconds */
            smooth = 1.0;	/* smoothness increment multiplier */
bubble     *binfo;		/* bubble info structures, allocated 
				 * dynamically  */
fish       *finfo;		/* fish info structures, allocated dynamically */
Display    *Dpy;
XImage     *xfish[3];		/* fish pixmaps (1 is left-fish, 2 is
				 * right-fish) */
Pixmap      pfish[3] = {0, 0, 0};
Pixmap      xbubbles[9];	/* bubbles bitmaps (1 to 8, by size in pixels)*/
Window      wid;		/* aqaurium window */
unsigned long white, black,bcolor;
Colormap    colormap;
GC          gc,
            bgc;


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Output desired error message and exit.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
msgdie(message)
    char       *message;
{
    fprintf(stderr, "%s: %s\n", pname, message);
    exit(1);
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Set up program defaults, get X defaults, parse command line using getopts.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
parse(argc, argv)
    int         argc;
    char      **argv;
{
    int         c,
                i;
    char       *p;
    extern int  optind;
    extern char *optarg;
    extern double atof();

    pname = argv[0];
    strcpy(sname, getenv("DISPLAY"));
    strcpy(cname, "MediumAquamarine");

    if ((p = XGetDefault(Dpy, pname, "BubbleLimit")) != NULL)
	blimit = atoi(p);
    if ((p = XGetDefault(Dpy, pname, "Color")) != NULL)
	strcpy(cname, p);
    if ((p = XGetDefault(Dpy, pname, "FishLimit")) != NULL)
	flimit = atoi(p);
    if ((p = XGetDefault(Dpy, pname, "IncMult")) != NULL)
	smooth = atof(p);
    if ((p = XGetDefault(Dpy, pname, "Rate")) != NULL)
	rate = atof(p);
    if ((p = XGetDefault(Dpy, pname, "Secure")) != NULL)
	for (i = 0; i < 6; i++)
	    if (strcmp(p, yess[i]) == 0)
		pmode = 0;

    while ((c = getopt(argc, argv, "b:c:f:i:r:s")) != EOF) {
	switch (c) {
	case 'b':
	    blimit = atoi(optarg);
	    break;
	case 'c':
	    strcpy(cname, optarg);
	    break;
	case 'f':
	    flimit = atoi(optarg);
	    break;
	case 'i':
	    smooth = atof(optarg);
	    break;
	case 'r':
	    rate = atof(optarg);
	    break;
	case 's':
	    pmode = 0;
	    break;
	case '?':
	    fprintf(stderr, "usage: %s [-b limit][-c color][-f limit][-i mult][-r rate][-s][host:display]\n", pname);
	    exit(1);
	}
    }

    if (optind < argc)
	strcpy(sname, argv[optind]);
}

putfish(f)
    fish       *f;
{
    if (pfish[f->d])
	XCopyArea(Dpy, pfish[f->d], wid, gc, 0, 0, rwidth, rheight, f->x, f->y);
    else
	XPutImage(Dpy, wid, gc, xfish[f->d], 0, 0, f->x, f->y, rwidth, rheight);
}

putbubble(b, s, c)
    bubble     *b;
    int         s;
    unsigned long c;
{
    XGCValues   gcv;

    gcv.foreground = c;
    gcv.clip_mask = xbubbles[s];
    gcv.clip_x_origin = b->x;
    gcv.clip_y_origin = b->y;
    XChangeGC(Dpy, bgc, GCForeground | GCClipMask | GCClipXOrigin |
	      GCClipYOrigin, &gcv);
    XFillRectangle(Dpy, wid, bgc, b->x, b->y, s, s);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Initialize colormap for background color and required fish colors.
The fish colors are coded in xfishy.c as a trio of tables.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
init_colormap()
{
    int         i;
    XColor      hdef,
                edef;
    extern char *malloc();

    colormap = XDefaultColormap(Dpy, screen);

    if (colormap == NULL)
	return;
    cmap = (int *) malloc((rcolors + 1) * sizeof(int));
    if (!mono) {
	XAllocNamedColor(Dpy, colormap, cname, &hdef, &edef);
	cmap[0] = hdef.pixel;

	for (i = 0; i < rcolors; i++) {
		hdef.red = rreds[i];
		hdef.green = rgreens[i];
		hdef.blue = rblues[i];
		XAllocColor(Dpy, colormap, &hdef);
		cmap[i + 1] = hdef.pixel;
		}
	bcolor = white;
	}
    else {
	for (i = 0; i < (rcolors+1); i++)
		cmap[i] = black;
	cmap[0] = cmap[rback] = white;
	bcolor = black;
	}
    cmap[rback] = cmap[0];
    }



/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Calibrate the pixmaps and bimaps.  The left-fish data is coded in xfishy.c,
this is transformed to create the right-fish.  The eight bubbles are coded
in xfishy.c as a two dimensional array.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
init_pixmap()
{
    register caddrt p,
                q,
                x1,
                x2;
    register int i,
                j;
    extern char *malloc();


    j = rwidth * rheight;
    x1 = p = (caddrt) xfishRaster;
    for (i = 0; i < j; i++, p++)
	*p = cmap[*p];

    x2 = (caddrt) malloc(rwidth * rheight);

    for (i = 0; i < rheight; i++) {
	p = x1 + i * rwidth;
	q = x2 + (i + 1) * rwidth - 1;
	for (j = 0; j < rwidth; j++)
	    *q-- = *p++;
	}

    xfish[1] = XCreateImage(Dpy, DefaultVisual(Dpy, screen), 8, ZPixmap,
	0, x1, rwidth, rheight, 8, rwidth);
    xfish[2] = XCreateImage(Dpy, DefaultVisual(Dpy, screen), 8, ZPixmap, 
	0, x2, rwidth, rheight, 8, rwidth);

    if (!mono) { /* Color Dislay */
	i = DisplayPlanes(Dpy, screen);

	pfish[1] = XCreatePixmap(Dpy, wid, rwidth, rheight, i);
	if (pfish[1])
		pfish[2] = XCreatePixmap(Dpy, wid, rwidth, rheight, i);
	if (pfish[1])
	   XPutImage(Dpy, pfish[1], gc, xfish[1], 0, 0, 0, 0, rwidth, rheight);
	if (pfish[2])
	   XPutImage(Dpy, pfish[2], gc, xfish[2], 0, 0, 0, 0, rwidth, rheight);
	if (pfish[1])
		XDestroyImage(xfish[1]);
	if (pfish[2])
		XDestroyImage(xfish[2]);
	xfish[1] = XCreateImage(Dpy, DefaultVisual(Dpy, screen), 8, ZPixmap,
		0, x1, rwidth, rheight, 8, rwidth);
	xfish[2] = XCreateImage(Dpy, DefaultVisual(Dpy, screen), 8, ZPixmap, 
		0, x2, rwidth, rheight, 8, rwidth);
	}
    else { /* Mono Display */
	pfish[1] = XCreateBitmapFromData(Dpy,wid,fish_bits,rwidth,rheight);
	pfish[2] = XCreateBitmapFromData(Dpy,wid,fishl_bits,rwidth,rheight);
	}

    for (i = 1; i <= 8; i++)
	xbubbles[i] = XCreateBitmapFromData(Dpy, wid, xbBits[i], i, i);
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Toggle secure mode on receipt of signal
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
toggle_secure()
{
    pmode = !pmode;
    if (pmode)
	XLowerWindow(Dpy, wid);
    else
	XRaiseWindow(Dpy, wid);
    XFlush(Dpy);
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Initialize signal so that SIGUSR1 causes secure mode to toggle.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
init_signals()
{
    struct sigvec vec;

    vec.sv_handler = toggle_secure;
    vec.sv_mask = 0;
    vec.sv_onstack = 0;

#ifndef HPUX
    sigvec(SIGUSR1, &vec, &vec);
#else
    sigvector(SIGUSR1, &vec, &vec);
#endif
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Variety of initialization calls, including getting the window up and running.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
initialize()
{
    XWindowAttributes winfo;
    XSetWindowAttributes attr;
    XGCValues   vals;
    extern char *malloc();
    XSizeHints  xsh;

    XGetWindowAttributes(Dpy, DefaultRootWindow(Dpy), &winfo);
    width = winfo.width;
    height = winfo.height;

    init_colormap();
    attr.override_redirect = True;
    attr.background_pixel = cmap[0];

    wid = XCreateWindow(Dpy, DefaultRootWindow(Dpy),
	1, 1, width - 2, height - 2, 0,
	CopyFromParent, CopyFromParent, CopyFromParent, 
	CWBackPixel | CWOverrideRedirect, &attr);

    if (!wid)
	msgdie("XCreateWindow failed");

    vals.foreground = vals.background = cmap[0];
    vals.graphics_exposures = False;
    gc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures,
	&vals);
    bgc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures,
	&vals);

    init_pixmap();
    init_signals();

    XStoreName(Dpy, wid, pname);

    xsh.flags = USSize | USPosition | PPosition | PSize;
    xsh.x = xsh.y = 0;
    xsh.width = width;
    xsh.height = height;
    XSetNormalHints(Dpy, wid, &xsh);

    XMapWindow(Dpy, wid);

    binfo = (bubble *) malloc(blimit * sizeof(bubble));
    finfo = (fish *) malloc(flimit * sizeof(fish));
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Create a new bubble.  Placement along the x axis is random, as is the size of
the bubble.  Increment value is determined by speed.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
new_bubble(b0)
    bubble     *b0;
{
    register int s;
    register bubble *b = b0;

    b->x = width * (rand() / RAND_F_MAX);
    if (Init_B)
	b->y = (height / 16) * (rand() / RAND_I_1_16 + 1) - 1;
    else
	b->y = height - 1;
    b->s = s = 1.0 + rand() / RAND_F_1_8;
    if ((b->i = smooth * height / (float) binc[s]) == 0)
	b->i = 1;
    putbubble(b, s, bcolor);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Erase old bubbles, move and draw new bubbles.  Random left-right factor
can move bubble one size-unit in either direction.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
step_bubbles()
{
    register int i,
                j,
                s;
    register bubble *b;

    for (i = 0; i < blimit; i++) {
	b = &binfo[i];
	s = b->s;
	/* clear */
	if (b->y > 0)
	    putbubble(b, s, cmap[0]);
	if ((b->y -= b->i) > 0) {
	    j = rand();
	    if (j < RAND_I_1_4)
		b->x -= s;
	    else if (j > RAND_I_3_4)
		b->x += s;
	    putbubble(b, s, bcolor);
	} else {
	    if (rand() < RAND_I_1_4)
		new_bubble(b);
	}
    }
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Fish collision detection.  The specified fish is checked against all other
fish for overlap.  The xt parameter specifies the x axis tolerance for overlap.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int 
collide_fish(f0, xt)
    fish       *f0;
    int         xt;
{
    int         i,
                j;
    register fish *f = f0;

    for (i = 0; i < flimit; i++) {
	if (&finfo[i] != f) {
	    j = finfo[i].y - f->y;
	    if ((j > -rheight) && (j < rheight)) {
		j = finfo[i].x - f->x;
		if ((j > -xt) && (j < xt))
		    return (1);
	    }
	}
    }
    return (0);
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Create a new fish.   Placement along the y axis is random, as is the side
from which the fish appears.  Direction is determined from side.  Increment
is also random.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
new_fish(f0)
    fish       *f0;
{
    int         i,
                collide;
    fish       *f = f0;

    for (i = 0, collide = 1; (i < 16) && (collide); i++) {
	f->y = (height - rheight) * (rand() / RAND_F_MAX);
	if ((f->i = smooth * width / (8.0 * (1.0 + rand() / RAND_F_1_8))) == 0)
	    f->i = 1;
	if (rand() < RAND_I_1_2) {
	    f->d = 1;
	    f->x = width;
	} else {
	    f->d = 2;
	    f->x = -rwidth;
	}

	collide = collide_fish(f, 2 * rwidth);
    }

    if (!collide)
	putfish(f);
    else
	f->d = 0;
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Move all the fish.  Clearing old fish is accomplished by masking only the
exposed areas of the old fish.  Random up-down factor can move fish 1/4 a
fish height in either direction, if no collisions are caused.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
move_fish()
{
    register int i,
                j,
                x,
                y,
                ofx,
                ofy,
                done;
    register fish *f;

    for (i = 0; i < flimit; i++) {
	f = &finfo[i];
	if (f->d) {
	    ofx = f->x;
	    ofy = f->y;

	    if (f->d == 1) {
		done = ((f->x -= f->i) < -rwidth);
		x = f->x + rwidth;
	    } else if (f->d == 2) {
		done = ((f->x += f->i) > width);
		x = f->x - f->i;
	    }
	    if (!collide_fish(f, rwidth)) {
		if (!done) {
		    j = rand();
		    if (j < RAND_I_1_4)
			y = f->i / 4;
		    else if (j > RAND_I_3_4)
			y = f->i / -4;
		    else
			y = 0;
		    if (y) {
			f->y += y;
			if (collide_fish(f, rwidth)) {
			    f->y -= y;
			    y = 0;
			} else {
			    if (y > 0) {
				j = f->y - y;
			    } else {
				j = f->y + rheight;
				y *= -1;
			    }
			}
		    }
		    putfish(f);
		    XClearArea(Dpy, wid, x, ofy, f->i, rheight, 0);
		    if (y)
			XClearArea(Dpy, wid, ofx, j, rwidth, y, 0);
		} else {
		    XClearArea(Dpy, wid, x, f->y, f->i, rheight, 0);
		    new_fish(f);
		}
	    } else {
		if ((f->d = 3 - f->d) == 1) {
		    f->x = f->x - 2 * f->i;
		    x = f->x + rwidth;
		} else {
		    f->x = f->x + 2 * f->i;
		    x = f->x - f->i;
		}
		putfish(f);
		XClearArea(Dpy, wid, x, f->y, f->i, rheight, 0);
	    }
	} else {
	    new_fish(f);
	}
    }
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Higher-resolution sleep
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
high_res_sleep(seconds)
    double      seconds;
{
    int         fds = 0;
    struct timeval timeout;

    timeout.tv_sec = seconds;
    timeout.tv_usec = (seconds - timeout.tv_sec) * 1000000.0;
    select(0, &fds, &fds, &fds, &timeout);
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 
main(argc, argv)
    int         argc;
    char      **argv;
{
    int         i;
    XEvent      ev;

    if ((Dpy = XOpenDisplay("")) == 0)
	msgdie("XOpenDisplay failed");
    screen = DefaultScreen(Dpy);
    if (DisplayPlanes(Dpy,screen) < 4) mono = 1;
    else mono = 0;

    white = WhitePixel(Dpy, screen);
    black = BlackPixel(Dpy, screen);
    parse(argc, argv);
    initialize();

    srand((unsigned) getpid());

    Init_B = 1;
    for (i = 0; i < blimit; i++)
	new_bubble(&binfo[i]);
    for (i = 0; i < flimit; i++)
	new_fish(&finfo[i]);
    if (pmode)
	XLowerWindow(Dpy, wid);
    else
	XRaiseWindow(Dpy, wid);
    XFlush(Dpy);

    Init_B = 0;

    for (;;) {
	if (XPending(Dpy))
	    XNextEvent(Dpy, &ev);

	high_res_sleep(rate);

	move_fish();

	step_bubbles();

	if (pmode)
	    XLowerWindow(Dpy, wid);
	else
	    XRaiseWindow(Dpy, wid);
    }
}

@//E*O*F xfish.c//
chmod u=r,g=r,o=r xfish.c
 
exit 0