gids.src

        Copyright (c) Kapteyn Laboratorium Groningen 2010
        All Rights Reserved.

Name:         gids.src
Creator:      vogelaar
Host:         albirumi
Date:         May 31, 2010
Contents:     gids.doc gids.make gids.h background.h heat.h
              isophot.h mousse.h rainbow.h random.h rgb.h
              smooth.h staircase.h color.c coord.c cursor.c
              data.c display.c etcetera.c gdi.c help.c
              input.c main.c menu.c misc.c recording.c
              region.c scale.c server.c slice.c wedge.c
              zoom.c

#>            gids.doc

Document:     GIDS

Purpose:      Description of the Groningen Image Display Server.

Category:     DISPLAY

File:         gids.src

Author:       K.G. Begeman

Description:

(0)           HELP

              GIDS is the Groningen Image Display Server. It will display
              two dimensional images which have to be loaded into GIDS by a
              special program (i.e. the GIPSY program VIEW).

              MOUSE BUTTONS:
              Here we assume that button1 is the left-most mouse button,
              button2 the middle mouse button and button3 the right-most
              mouse button.

              To remove the HELP window, press HELP again with button1 or
              button3 or press a mouse button in the help window.

              DISPLAY WINDOW:
              In the display window the images are shown. At startup the
              display window is the right-most window with a size of 512 x 512.
              It is possible to resize this window. The minimum size is
              128 x 128, the maximum size depends on the size of the screen.
              Each resizing of the display window will remove all previous
              recordings.

              WEDGE WINDOW:
              To the left of the display window the wedge window is placed.
              This window displays the current color lookup table.

              CALIBRATION WINDOW:
              To the left of the wedge window the calibration window is placed.
              Here the data values as a function of current color are
              displayed graphically.

              INFO WINDOWS:
              GIDS has 7 info windows which are placed in the upper-left
              window of GIDS (white on black). From top to bottom, the first
              two display info related to the image currently in the display
              window. This information depends on what the program which loaded
              the image into GIDS found necessary to show the user.
              The third window displays information about the recordings
              (REC= MR, NR, CR), where MR is the maximum number of recordings
              the server can handle, NR the number of images recorded and
              CR the current record number in the display window. Record 0 is
              special since here always the last image loaded into GIDS is
              stored. It is only possible to (de)zoom this image. Pressing
              the ETCETERA menu and then the RECORDING menu will show a
              list of recording options.
              The fourth window displays information about the graphics planes
              (MASK=  M ON=  N), where M is the current mask of graphics planes
              on which the graphics operation is valid and N the mask for the
              planes which are displayed. GIDS has 4 graphics planes, which are
              numbered 1, 2, 4 and 8. If more than one graphics plane is wanted,
              simply add the numbers. Pressing the ETCETERA menu and then the
              REGION menu will give a list of graphics plane operations.
              The fifth window displays the data value at the position of the
              cursor in the display window (VAL=   N).
              The sixth window will display the grids at the position of the
              cursor in the display window (POS=   X,   Y).
              The seventh window is an input window which displays the text
              entered via the keyboard. Some menu actions need the text in
              this window.

              MENU WINDOWS:
              Below the info windows menu windows are placed.
              Moving the pointer to a menu window will 'highlight' it, clicking
              mouse button1 or button3 will activate it. Clicking button2
              will give help on the menu item.

              CUSTOMIZATION OF GIDS:
              GIDS allows the user to specify some defaults in the .Xdefaults
              or .Xresources file. The parameters which can be set are the
              following:

              gids.calibration_font:     font for calibration window.
              gids.help_file:            path to help file.
              gids.help_font:            font for help window.
              gids.info_font:            font for info windows.
              gids.menu_font:            font for menu windows.
              gids.display_height:       default height of display window.
              gids.display_width:        default width of display window.
              gids.xposition:            x position left border of window.
              gids.yposition:            y position upper border of window.
              gids.colors:               number of colors to use. The minimum
                                         is 16, the maximum 200.
              gids.mincolors:            at least this number of colors will
                                         be allocted. The minimum is 16, the
                                         maximum is 200.
              gids.start_lut:            color lookup table at program start
                                         (use name of LUT as from color menu).
              gids.scaling:              color transfer funtion as program
                                         start (use name of scaling funtion
                                         as from scale menu).
              gids.inverse_scaling:      True for negative slope of color
                                         transfer function.
              gids.autoraise:            Raise window when new image or plot
                                         is arriving (default False).

(1)           ZOOM

              Pressing ZOOM will display record number zero, enter zoom mode
              and activate the zoom-menu.

              Mouse Button Control in display window:
              Button1     zoom in the image at the current position.
              Button2     re-centre the image at the current position.
              Button3     zoom out the image at the current position.

              Zooming can only affect the image which has been loaded into
              GIDS most recently. This image is always recorded in record 0.

(1.0)         ZOOM RESET

              Reset the image (i.e. no zoom factors).

(1.1)         ZOOM IN

              Zooms in the image by a factor 2.

(1.2)         ZOOM OUT

              Zooms out the image by a factor 2.

(1.3)         ZOOM IN-X

              Zooms in the image along the X axis by a factor 2.

(1.4)         ZOOM OUT-X

              Zooms out the image along the X axis by a factor 2.

(1.5)         ZOOM IN-Y

              Zooms in the image along the Y axis by a factor 2.

(1.6)         ZOOM OUT-Y

              Zooms out the image along the Y axis by a factor 2.

(1.7)         ZOOM RETURN

              Returns to main menu.

(2)           COLOR

              Pressing COLOR will enter color mode and activate the color-menu.

              Mouse Button Control in display window:
              Pressing any button and moving it in the display window will
              modify the color transfer function. Moving in the X direction
              will modify the slope of the transfer function (slope is zero at
              the right-most cursor position). Moving in the Y direction will
              modify the offset of the transfer function (largest offset at
              the upper-most cursor position).

              Pressing button3 will activate the monochrome LUT.
              Pressing button1 will change back to the original LUT active
              before pressing button3.
              Pressing button 2 will not change the LUT.

              The color-menu will allow the user to choose a color lookup table
              (LUT).

              NOTE: Color mode can always be activated by pressing the
              control key <Ctrl> on your keyboard and then the wanted
              mouse button.

(2.0)         COLOR RESET

              Resets the color transfer function to its initial shape (i.e.
              slope one and zero offset).

(2.1)         COLOR MONO

              Selects the monochrome LUT.

(2.2)         COLOR RAINBOW

              Selects the rainbow LUT.

(2.3)         COLOR RONEKERS

              Selects the LUT developped by Ron Ekers on the pdp 11/70.

(2.4)         COLOR STAIRCASE

              Selects the staircase LUT.

(2.5)         COLOR USER

              Selects the LUT which has been loaded by the user. A special
              program is needed for this (i.e. GIPSY program colour).

(2.6)         COLOR OTHER

              Gives another set of LUTs to choose from.

(2.6.0)       COLOR OTHER BACKGROUND

              Selects the background LUT.

(2.6.1)       COLOR OTHER HEAT

              Selects the heat LUT.

(2.6.2)       COLOR OTHER ISOPHOT

              Selects the isophot LUT.

(2.6.3)       COLOR OTHER MOUSSE

              Selects the mousse LUT.

(2.6.4)       COLOR OTHER RANDOM

              Selects the random LUT, not at random.

(2.6.5)       COLOR OTHER RGB

              Selects the red-green-and-blue LUT.

(2.6.6)       COLOR OTHER SMOOTH

              Selects the smooth LUT.

(2.6.7)       COLOR OTHER RETURN

              Goes up one menu.

(2.7)         COLOR RETURN

              Returns to main menu, exits color mode.

(3)           SCALE

              Pressing SCALE will enter color mode and activate the scale-menu.

              The scale-menu will allow the user to choose a particular color
              transfer function.

(3.0)         SCALE INVERSE

              Pressing INVERSE will make the slope of the transfer function
              negative.

(3.1)         SCALE LINEAR

              Pressing LINEAR will reset the color transfer function to its
              original shape (i.e. linear).

(3.2)         SCALE LOG

              Pressing LOG will make the color transfer function logarithmic
              (i.e. more color resolution at the lower end).

(3.3)         SCALE EXP

              Pressing EXP will make the color transfer function exponential
              (i.e. more color resolution at the upper end).

(3.4)         SCALE SQRT

              Pressing SQRT will make the color transfer function square root.

(3.5)         SCALE SQUARE

              Pressing SQRT will make the color transfer function square.

(3.6)         SCALE BLANK

              Entering 3 numbers between 0.0 and 1.0 will set resp. the
              Red, Green and Blue intensity for the BLANK data values.

(3.7)         SCALE RETURN

              Returns to main menu, exits color mode.

(4)           WEDGE

              Pressing WEDGE will enter wedge mode combined with color mode
              and activate the wedge menu.

              Mouse Button Control in wedge window:
              Pressing any button and moving it in the wedge window will
              change the color of the correspondig data values to the color
              selected with the wedge menu.

(4.0)         WEDGE RESET

              Pressing RESET will remove all wedge colors selected by the
              user.

(4.1)         WEDGE RED

              Pressing RED will select a red wedge color.

(4.2)         WEDGE GREEN

              Pressing GREEN will select a green wedge color.

(4.3)         WEDGE BLUE

              Pressing BLUE will select a blue wedge color.

(4.4)         WEDGE YELLOW

              Pressing YELLOW will select a yellow wedge color.

(4.5)         WEDGE PURPLE

              Pressing PURPLE will select a purple wedge color.

(4.6)         WEDGE WHITE

              Pressing WHITE will select a white wedge color.

(4.7)         WEDGE RETURN

              Returns to main menu, exits wedge mode.

(5)           CURSOR

              Pressing CURSOR will enable cursor mode and enter the curser
              menu. In cursor mode the user can send grid positions or the
              lower-left and upper-right grids of a box to an accepting
              program (usually hermes) or window.

              The cursor menu allows you to select the method of transfer
              of the cursor positions. You can choose between: the selection
              method, the sendevent method or the socket method. The socket
              method is default and is used with GIPSY (hermes).

              Mouse Button Control in display window.
              Pressing button1 in the display window will send the
              corresponding grid position to hermes.
              Pressing button2 and moving the cursor allows the user to draw
              a box on the display window. Pressing button2 again will allow
              the user to modify this box. Pressing button3 inside the box will
              send the box grids to hermes and remove the box, pressing
              button3 outside the box will only remove it.

(5.0)         CURSOR SELECTION

              The cursor positions are put as text in a selection, allowing
              other programs to request for the selection, i.e. simply go to
              the xterm with the cursor and press the middle mouse button to
              get the text into your program.

(5.1)         CURSOR SENDEVENT

              The cursor positions are sent as KeyPress events to a window
              which the user can select with the cursor. Note that the
              chosen  window must allow sendevents (for xterm, press
              <CTRL> together with the left mouse button).

(5.2)         CURSOR SOCKET

              Send the cursor positions as text to a socket. This is the
              default.

(5.3)         CURSOR APPEND-CR

              Append or don't append a CR (carriage return) to the string
              with positions to be sent. Default is don't append.

(5.4)         CURSOR RETURN

              Return to top menu and stay in CURSOR mode.

(6)           ETCETERA

              Pressing ETCETERA will activate the etcetera menu, where some
              extra options are made available, like manipulating recordings and
              graphics planes. Also the quit and resize button are programmed
              here.

(6.0)         ETCETERA QUIT

              Pressing QUIT will allow the user to quit via the quit menu.

(6.0.0)       ETCETERA QUIT NO

              Don't quit and go back to etcetera menu.

(6.0.1)       ETCETERA QUIT YES

              Gids is stopped graciously. Always exit via this menu item.

(6.1)         ETCETERA GRAPHICS

              Pressing GRAPHICS will open an extra window for plotting.
              Without the extra plot window plot output will appear in the
              display window.
              Pressing GRAPHICS again will remove the extra plot window
              and any plot output will again be redirected to the display
              window.

              The default plot window size is 512 x 512. The user can specify
              the size by typing the wanted X size and Y size (those numbers
              should appear in the lower info window) and then pressing
              GRAPHICS.

(6.2)         ETCETERA RECORDING

              Pressing RECORDING will activate the recording menu, where
              the user can manipulate the recorded images.

              The third info window displays information about the recordings
              (REC= MR, NR, CR), where MR is the maximum number of recordings
              the server can handle, NR the number of images recorded and
              CR the current record number in the display window. Record 0 is
              special since here always the last image loaded into GIDS is
              stored. It is only possible to (de)zoom this image.

(6.2.0)       ETCETERA RECORDING RECORD

              Typing the wanted record number and pressing RECORD will
              record the image currently in the display window.

(6.2.1)       ETCETERA RECORDING VIEW

              Pressing VIEW will enter view mode which will allow the user to
              manually loop through the recorded images.

              Mouse Button Control in display window:
              Pressing button1 in the display window will show the previous
              recording, pressing button3 will display the next recording.

              When pressing VIEW, the default action is to show the current
              record number. Any other recording can be viewed by typing its
              record number and then pressing VIEW.

(6.2.2)       ETCETERA RECORDING BLINK

              This option will allow the user to blink two images.

              Typing one or two record numbers and pressing BLINK will
              enter blink mode. If only one record number was typed, record 0
              will be used for the first recording and the record number
              entered for the second.

              Mouse Button Control in display window:
              Pressing any button will set the time interval between blinks.
              Blink frequency increases to the left.

(6.2.3)       ETCETERA RECORDING LOOP

              This option will allow the user to make a movie of
              the recorded images.

              Typing the wanted record numbers and pressing LOOP will
              enter loop mode.

              Mouse Button Control in display window:
              Button1: Loop backward.
              Button2: set the loop speed. Speed increases to the left.
              Button3: Loop forward.

              NOTE: Some programs already define the loop for the user
              (i.e. the GIPSY program VIEW with RECORD=Y). The user
              then only needs to press LOOP and does not have to specify
              the record numbers.

(6.2.4)       ETCETERA RECORDING SPLIT

              This option will allow the user to view two images in split
              screen.

              Typing one or two record numbers and pressing SPLIT will
              enter split screen mode. In split screen mode gids displays
              in different parts of the display window the two recordings
              entered by the user. If only one record number was typed,
              record zero will be used for the first recording and the
              record number entered for the second.

              Mouse Button Control in display window:
              Button1 will display to the left of the cursor the first
              recording entered by the user and to the right the second.
              Button2 will display above the cursor the second recording
              entered by the user and below the cursor the first.
              Button3 will display in the right-upper part above the cursor
              the second recording the user entered.

(6.2.5)       ETCETERA RECORDING REMOVE

              Typing one or more record numbers and pressing REMOVE will
              remove the specified recordings.

(6.2.6)       ETCETERA RECORDING RETURN

              Returns to etcetera menu.

(6.3)         ETCETERA REGION

              Pressing REGION will display record number zero and activate
              the region menu.

              This option is only of use in combination with a special
              program which can do something useful with the graphics data
              (i.e. GIPSY program BLOT for masking data).

              The fourth info window displays information about the graphics
              planes (MASK=   M ON=  N), where M is the current mask of
              graphics planes on which the selected operation (i.e. DEFINE)
              is valid and N the mask for the planes which are displayed.
              GIDS has four graphics planes which are numbered 1, 2, 4 and 8.
              If the user wants more than one graphics plane simply add the
              numbers.

              Graphics operations only work on the last image read into GIDS.

(6.3.0)       ETCETERA REGION DEFINE

              Pressing DEFINE will allow the user to start defining a region
              on top of record zero. The graphics planes which will be modified
              are shown in the fourth info window (MASK=).

              Mouse Button Control in display window:
              Pressing Button1 for the first time will start the region
              (a polygon) on that position. The following clicks on Button1
              will draw the outer boundaries of the polygon.
              Pressing Button2 will remove the last drawn boundaries.
              Pressing Button3 will close and fill the polygon.

(6.3.1)       ETCETERA REGION UNDEFINE

              Pressing UNDEFINE will alow the user to start defining a region
              which is to be removed from a previous defined region. The
              graphics planes which will be modified are shown in the fourth
              info window (MASK=).

              Mouse Button Control in display window:
              Pressing Button1 for the first time will start the region
              (a polygon) to be removed on that position. The following clicks
              on Button1 will draw the outer boundaries of the polygon to be
              removed.
              Pressing Button2 will remove the last drawn boundaries.
              Pressing Button3 will close and remove the polygon.

(6.3.2)       ETCETERA REGION ON

              Typing a new ON mask (displayed in the fourth info window)
              will display the graphics data in the planes which match
              the new ON mask.

(6.3.3)       ETCETERA REGION CLEAR

              Pressing CLEAR will clear the graphics planes which match
              the MASK shown in the fourth info window.

              The user can modify this mask by typing the wanted mask and
              pressing CLEAR.

(6.3.4)       ETCETERA REGION READY

              Press READY when finished with (un)defining regions. This
              informs the program which is interested in the graphics plane
              data to read it.

(6.3.5)       ETCETERA REGION BLOTS

              Pressing BLOTS activates BLOT mode and enters the BLOTS submenu
              which lets you choose between a rectangular and an ellipsoidal
              blot area.
              In BLOT mode all pixels overlayed by the cursor shape are
              (un)defined when any mouse button is pressed. You can change
              the shape of the cursor in the following way:
              Down Arrow           decrease height of cursor
              Up Arrow             increase height of cursor
              Left Arrow           decrease width of cursor
              Right Arrow          increase width of cursor


(6.3.5.0)     ETCETERA REGION BLOTS ELLIPSE

              Creates an ellipsoidal cursor.

(6.3.5.1)     ETCETERA REGION BLOTS RECTANGLE

              Creates a rectangular cursor.

(6.3.5.2)     ETCETERA REGION BLOTS RETURN

              Returns to region menu, disables BLOT mode.

(6.3.6)       ETCETERA REGION RETURN

              Returns to etcetera menu.

(6.4)         ETCETERA RESIZE

              Typing the wanted width and height in pixels of the display
              window and pressing RESIZE will resize the display window.

              Note that all previous recordings will be lost!

(6.5)         ETCETERA SLICE

              Pressing SLICE will enter slice mode and activate the
              slice menu.

              The slice menu allows the user to display cuts along a principal
              axis through all recordings. The xslice window (created with
              the X-SLICE option) displays an X-cut through all selected
              recordings. The yslice window (created with the Y-SLICE option)
              displays a Y-cut through all selected recordings.

              Mouse Button Control in display window:
              Pressing any button will show in the xslice window (the window
              below the display window) an X-cut through all selected
              recordings at the present x position, and in the yslice window
              (the window to the right of the display window) a Y-cut through
              all selected recordings at the present y position.

              Mouse Button Control in xslice window:
              Pressing any button will show in the display window the
              corresponding recorded image and in the yslice window the
              corresponding Y-cut.

              Mouse Button Control in yslice window:
              Pressing any button will show in the display window the
              corresponding recorded image and in the xslice window the
              corresponding X-cut.

              Note: Pressing button2 in any of the above windows will
              display a cursor to indicate the cross-sections. Any other
              button will remove the cursor.

(6.5.0)       ETCETERA SLICE X-SLICE

              Entering the wanted recorded images and then pressing X-SLICE
              will create the xslice window below the display window. The
              xslice window displays an X-cut through the selected recordings
              at the position of the cursor in the display window when
              pressing a mouse button.

              Pressing X-SLICE with no recordings selected will remove the
              xslice window.

(6.5.1)       ETCETERA SLICE Y-SLICE

              Entering the wanted recorded images and then pressing Y-SLICE
              will create the yslice window to the right of the display
              window. The yslice window displays a Y-cut through the selected
              recordings at the position of the cursor in the display window
              when pressing a mouse button.

              Pressing Y-SLICE with no recordings selected will remove the
              yslice window.

(6.5.2)       ETCETERA SLICE ZOOM-X

              Pressing ZOOM-X will double every X-cut in the xslice window.

(6.5.3)       ETCETERA SLICE ZOOM-Y

              Pressing ZOOM-Y will double every Y-cut in the yslice window.

(6.5.4)       ETCETERA SLICE DEZOOM-X

              Pressing DEZOOM-X will remove every second X-cut in the xslice
              window.

(6.5.5)       ETCETERA SLICE DEZOOM-Y

              Pressing DEZOOM-Y will remove every second Y-cut in the yslice
              window.

(6.5.6)       ETCETERA SLICE EXTRA

              Pressing EXTRA will enter a menu with extra slice options.

(6.5.6.0)     ETCETERA SLICE EXTRA COORDS

              Pressing COORDS will toggle the "coordinate send mode".
              This mode will send the text in the sixth and second info window
              via the method selected in the cursor menu. If the second info
              window is empty, it will send the record number.

(6.5.6.1)     ETCETERA SLICE EXTRA PROFILE

              Not yet implemented.

(6.5.6.2)     ETCETERA SLICE EXTRA RETURN

              Returns to previous menu.

(6.5.7)       ETCETERA SLICE RETURN

              Returns to etcetera menu and leaves slice mode.

(6.6)         ETCETERA RETURN

              Returns to main menu.

Updates:      Jul 17, 1991: KGB, Document created.
              Aug 18, 1993: KGB, Document improved.
              Jan 26, 1995: KGB, Cursor sub menu added.
              Aug  7, 1995: KGB, Blots sub menu added.
              May  1, 2007: JPT, Conditional code for Apple Mac included.
              May 31, 2010: VOG, Adapted to support DirectColor (see comments
                                 in code that start with VOG2010:)
#<

#>            gids.make
#
# Makefile to build Gipsy Image Display Server (Jan  3, 1995)
# by K.G. Begeman
#
SHELL = /bin/sh

.SUFFIXES: .c .o

DOCUMENTS = gids.doc

INCLUDES = gids.h background.h heat.h isophot.h mousse.h rainbow.h random.h \
           rgb.h smooth.h staircase.h

SOURCES = color.c coord.c cursor.c data.c display.c etcetera.c gdi.c help.c \
          input.c main.c menu.c misc.c recording.c region.c scale.c server.c \
          slice.c wedge.c zoom.c

OBJECTS = color.o coord.o cursor.o data.o display.o etcetera.o gdi.o help.o \
          input.o main.o menu.o misc.o recording.o region.o scale.o server.o \
          slice.o wedge.o zoom.o

default:: gids

pack::
	$${gip_sys}/pack.csh gids.src $(DOCUMENTS) gids.make $(INCLUDES) $(SOURCES)

clean::
	rm -f gids $(OBJECTS)

.c.o:
	@echo "$(CC_COMP) -c $(CC_OPTS) $(X11_OPTS) $<"
	@$(CC_COMP) -c $(CC_OPTS) $(X11_OPTS) $<

gids:   $(INCLUDES) $(OBJECTS)
	@echo "$(CC_COMP) -o gids $(OBJECTS) $(X11_LIBS) $(CC_LIBS)"
	@$(CC_COMP) -o gids $(OBJECTS) $(X11_LIBS) $(CC_LIBS)

#<

#>            gids.h
/* gids.h

*/


/*
 * includes:
 */

#include	"ctype.h"			/* <ctype.h> */
#include	"errno.h"			/* <errno.h> */
#include	"limits.h"			/* <limits.h> */
#include	"math.h"			/* <math.h> */
#include	"stddef.h"			/* <stddef.h> */
#include	"stdlib.h"			/* <stdlib.h> */
#include	"stdio.h"			/* <stdio.h> */
#include	"string.h"			/* <string.h> */
#include	"time.h"			/* <time.h> */
#include	"gdisysdef.h"			/* gdi definitions */

#define	fcntl		FCNTL			/* fooling around */
#define	fork		FORK			/* fooling around */
#define	getpid		GETPID			/* fooling around */
#define	gettimeofday	GETTIMEOFDAY		/* fooling around */

#include	<sys/types.h>
#include	<sys/file.h>
#include	<sys/stat.h>

#include	<fcntl.h>
#include	<netdb.h>
#include	<netinet/in.h>
#include	<signal.h>
#if	defined(__aix__)
#include	<sys/select.h>
#endif
#include	<sys/socket.h>
#include	<sys/time.h>
#include	<sys/un.h>

#ifdef	__mips__			/* for decstations, we have to ... */
#ifdef	__STDC__			/* undefine __STDC__ because the ... */
#undef	__STDC__			/* local include file are not ... */
#endif					/* setup in a nice manner */
#endif

#ifdef	__sun__				/* for sun work stations, we have ... */
#ifdef	__sysv__  			/* check whether its Solaris, ... */
#ifndef	att				/* and if so, we have to define ... */
#define	att				/* att (if not already defined) */
#endif
#endif
#endif

#include	<X11/X.h>
#include	<X11/Xlib.h>
#include	<X11/Xproto.h>
#include	<X11/Xutil.h>
#include	<X11/Xatom.h>
#include	<X11/cursorfont.h>
#include	<X11/keysym.h>

/*
 * Here we do the unscrambling again. Shit.
 */

#undef	fcntl					/* unscramble */
#undef	fork					/* unscramble */
#undef	getpid					/* unscramble */
#undef	gettimeofday				/* unscramble */

#if	!defined(ntohs)	& !defined(__alpha__) & !defined(__linux__) 
extern	u_short	ntohs( );			/* declare it */
#endif						/* not ntohs */

#if	!defined(htons)	& !defined(__alpha__) & !defined(__linux__)
extern	u_short	htons( );			/* declare it */
#endif						/* not htons */

#ifndef	fileno
#if	defined(__hp9000s300__)
#if	OS_MAJOR_VERSION < 9
#define	fileno(p)	((p)->__file)
#else
extern	int	fileno(FILE *);
#endif
#elif	defined(__hp9000s700__)
extern	int	fileno(FILE *);
#elif	defined(__linux__)
#elif	defined(__APPLE__)
#else
#define	fileno(p)	((p)->_file)
#endif
#endif


/*
 * defines:
 */

#define	WINDOW_PGPLOT		1		/* extra pgplot window */
#define	WINDOW_XSLICE		2		/* extra X slice window */
#define	WINDOW_YSLICE		4		/* extra Y slice window */
#define	WINDOW_HELP		8		/* extra Help window */

#define	BLINK_ACTION		1		/* blink action */
#define	COLOR_ACTION		2		/* lut change */
#define	DRAW_ACTION		4		/* drawing by user */
#define	NONE_ACTION		0		/* no action */
#define	QUIT_ACTION		8		/* quit server */
#define	SPLIT_ACTION		16		/* split screen */
#define	VIEW_ACTION		32		/* page through movie */
#define	WEDGE_ACTION		66		/* wedge movement, lut change */
#define	ZOOM_ACTION		128		/* pan & zoom */
#define	CURSOR_ACTION		256		/* cursor coordinates */
#define	SLICE_ACTION		512		/* slice action */
#define	BLOT_ACTION		1024		/* shape_action */

#define	BLUE_WEDGE		1		/* blue wedge code */
#define	GREEN_WEDGE		2		/* green wedge code */
#define	NO_WEDGE		0		/* no wedge */
#define	PURPLE_WEDGE		4		/* purple wedge code */
#define	RED_WEDGE		8		/* red wedge code */
#define	WHITE_WEDGE		16		/* white wedge code */
#define	YELLOW_WEDGE		32		/* yellow wedge code */

#define	LINEAR_SCALE		0		/* linear scaling */
#define	LOG_SCALE		1		/* logarithmic scaling */
#define	EXP_SCALE		2		/* exponential scaling */
#define	SQRT_SCALE		3		/* square root scaling */
#define	SQUARE_SCALE		4		/* square scaling */

#define	MAXARG			20		/* max. # of arguments */
#define	MAXCLIENTS		8		/* max. # of clients */
#define	MAXCOLORS		256		/* max. # of colors */
#define	MAXGCOLORS		(1<<MAXPLANES)	/* 2**MAXPLANES */
#define	MAXGTLEN		8		/* length of grid text */
#define	MAXHELPLINES		25		/* max. number of help lines */
#define	MAXIDTEXTLEN		64		/* max. length of id text */
#define	MAXINFO			7		/* # of info windows */
#define	MAXMENUDEPTH		5		/* max. depth of menus */
#define	MAXMENUS		8		/* max. number of buttons */
#define	MAXMENUTEXTLEN		10		/* max. length of menu text */
#define	MAXPCOLORS		16		/* plot colors */
#define	MAXPLANES		4		/* max. number of graphics planes */
#define	MAXRECORD		1024		/* max. number of records */
#define	MAXSCALE		5		/* max. number of scalings */
#define	MAXSEQUENCE		1024		/* max. sequence for movie */
#define	MAXSTRING		80		/* max. length of strings */
#define	MAXZOOMFACTOR		20		/* max. zoom factor */

#define	MININFOWIDTH		20		/* min. # of characters */
#define	MINMENUWIDTH		10		/* min. # of characters */
#define	MINCALIBWIDTH		10		/* min. # of characters */

/* VOG2010: Changed MAX_D_COLORS from 200 to 240 */
#define	MAX_D_COLORS		240	/* max. # of colors for image */
#define	MIN_D_COLORS		16		/* min. # of colors for image */

#define	DATA_CHECK( r )		\
if (user.idata == NULL) { 	\
   XBell( winfo.id, 100 ); 	\
   return( r ); 		\
}

#define	GIDS_DEBUG( text )	\
{				\
   FILE	*e;			\
   char n[80];			\
   sprintf( n, "/tmp/gids%d.debug", winfo.pid ); \
   e = fopen( n, "a" );		\
   if ( e != NULL ) {		\
      fprintf( e, "%s (%d) %s\n", __FILE__, __LINE__, text ); \
      fclose( e );		\
   }				\
}


/*
 * typedefs:
 */

typedef	struct {
   int		menu;				/* menu attached */
   int		open;				/* open or closed */
   int		socket;				/* socket number */
   int		swap;				/* byte swap needed ? */
   int		ftype;				/* client floating type */
   int		grc;				/* graphics read counter */
   int		gwc;				/* graphics write counter */
   int		irc;				/* image read counter */
   int		iwc;				/* image write counter */
   int		wstate;				/* wait state */
   time_t	time2;				/* time since last command */
} Client_struct;

typedef	struct color_struct {
   float	red;
   float	green;
   float	blue;
} Color_struct;

typedef struct menu_struct {			/* the menu structure */
   char			text[MAXMENUTEXTLEN];
   int			depth;
   int			level;
   int			ret;
   int			textlen;
   int			xpos;
   int			ypos;
   int			(*f)(int);
   struct menu_struct	*previous;
   struct menu_struct	*next;
} Menu_struct;

typedef struct {
   char	text[MAXGTLEN];
} Gtext_struct;

typedef struct {
   Gtext_struct	*xgt;
   Gtext_struct	*ygt;
   char		text1[MAXIDTEXTLEN+1];
   char		text2[MAXIDTEXTLEN+1];
   float	bscale;
   float	b_zero;
   int		mask;
   int		*x_grid;
   int		x_min;
   int		x_max;
   int		*y_grid;
   int		y_min;
   int		y_max;
   Pixmap	pixmap;
} Record_struct;

typedef struct {
   int	s;
   int	l;
} Region_struct;

typedef	struct {				/* the data structure */
   Color_struct		colors[MAXCOLORS];
   Gtext_struct		*xgt;
   Gtext_struct		*ygt;
   Region_struct	*xregion;
   Region_struct	*yregion;
   char			set[MAXSETNAMELEN];
   char			text1[MAXIDTEXTLEN+1];
   char			text2[MAXIDTEXTLEN+1];
   float		bscale;
   float		b_zero;
   int			images;
   int			n_count;
   int			n_data;
   int			x_max;
   int			x_min;
   int			x_size;
   int			y_max;
   int			y_min;
   int			y_size;
   int			subset;
   unsigned char	*idata;
   unsigned char	*imask;
   unsigned char	mask1;
   unsigned char	mask2;
} Data_struct;

typedef	struct {				/* window info structure */
   Colormap		colormap;		/* collor map */
   Color_struct		Blue;			/* blue color */
   Color_struct		Green;			/* green color */
   Color_struct		Purple;			/* purple color */
   Color_struct		Red;			/* red color */
   Color_struct		White;			/* white color */
   Color_struct		Yellow;			/* yellow color */
   Color_struct		gcolors[MAXPLANES];	/* colors for graphics planes */
   Color_struct		pcolors[MAXPCOLORS];	/* colors for plotting */
   Display		*id;			/* display id */
   GC			gcb;			/* boxing lines */
   GC			gcc;			/* for calibration */
   GC			gcg[MAXGCOLORS];	/* plotting in graphics planes */
   GC			gcm;			/* for menu */
   GC			gcmreverse;		/* negative */
   GC			gcp[MAXPCOLORS];	/* plotting context */
   GC			gci;			/* for info */
   GC			gch;			/* for help */
   Pixmap		ipixmap;		/* the image pixmap */
   Pixmap		wpixmap;		/* the wedge pixmap */
   Pixmap		Save;			/* Saved pixmap */
   int			Saved;			/* pixmap saved ? */
   Record_struct	record[MAXRECORD];	/* recordings */
   Visual		*visual;		/* default visual */
   Window		calib;			/* calibration wedge */
   Window		display;		/* window for display */
   Window		info[MAXINFO];		/* info windows */
   Window		menus[MAXMENUS];	/* windows for menus */
   Window		root;			/* root window */
   Window		xslice;			/* window for X slice */
   Window		yslice;			/* window for Y slice */
   Window		top;			/* main window */
   Window		wedge;			/* window for calibration wedge */
   Window		pgplot;			/* window for pgplot */
   Window		help;			/* window for help text */
   char			netaddr[MAXSTRING];	/* inet address */
   char			hostname[MAXSTRING];	/* name of host */
   char			con_string[MAXSTRING];	/* connection string */
   char			text[MAXINFO][MAXIDTEXTLEN+1];
   int			autoraise;		/* autoraise windows */
   int			i_nchr;			/* # of characters */
   int			i_xpos;			/* text start */
   int			i_ypos;			/* text baseline */
   int			windows;		/* masks extra windows */
   int			nxslice;		/* # of xslices */
   int			xslices[MAXRECORD];	/* xslice id's */
   int			last_y;			/* last y of x slice */
   int			nyslice;		/* # of yslices */
   int			yslices[MAXRECORD];	/* yslice id's */
   int			last_x;			/* last x of y slice */
   int			pgw;			/* width of plot window */
   int			pgh;			/* height of plot window */
   XColor		modify[MAXCOLORS];	/* modified colors */
   XColor		table[MAXCOLORS];	/* color table */
   XFontStruct		*hfont;			/* help font */
   XFontStruct		*ifont;			/* info font */
   XFontStruct		*mfont;			/* menu font */
   XFontStruct		*cfont;			/* wedge font */
   XImage		*iimage;		/* the image image */
   XImage		*wimage;		/* the wedge image */
   float		inverse;		/* negative slope */
   float		slope;			/* slope of transfer function */
   float		shift;			/* shift of transfer function */
   int			e_code;			/* last X error */
   int			r_code;			/* routine which reported error */
   int                  clients;		/* number of clients */
   int			blank;			/* pixels for blank value */
   int			class;			/* class of display */
   int			currec;			/* current recording */
   int			depth;			/* depth of display */
   int			cheight;		/* height of calibration wedge */
   int			cwidth;			/* width of calibration wedge */
   int			dheight;		/* height of display window */
   int			dwidth;			/* width of display window */
   int			hheight;		/* height help window */
   int			hwidth;			/* width help window */
   int			height;			/* height of display */
   int			heightMM;		/* height of display in MM */
   int			iheight;		/* height of info window */
   int			iwidth;			/* width of info window */
   int			maxcolor;		/* maximum color value */
   int			mcolors;		/* all colors in use */
   int			memory;			/* display memory in kbytes */
   int			mheight;		/* height of menu window */
   int			mincolor;		/* minimum color value */
   int			mrecord;		/* maximum number of recordings */
   int			mwidth;			/* width of menu window */
   int			ncolors;		/* maximum number of colors */
   int			nrecord;		/* # of recordings */
   int			nsequence;		/* number of sequential recordings */
   /* VOG2010: add padding parameter for XCreateWindow */
   int                  pad;
   /* VOG2010: add bytes per pixel attribute */
   int                  bytespp;
   /* VOG2010: add byte order attribute. The bytes per pixel */
   /* and byte order information is needed in function       */
   /* pixel2chars() in misc.c.                               */
   int                  byte_order;
   int			planes;			/* number of planes */
   int			screen;			/* screen number */
   int			sequence[MAXSEQUENCE];	/* playback sequence */
   int			theight;		/* height of main window */
   int			twidth;			/* width of main window */
   int			wedge_code[MAXCOLORS];	/* wedge color code */
   int			wheight;		/* height of wedge window */
   int			width;			/* width of screen */
   int			widthMM;		/* width of screen in MM */
   int			wwidth;			/* width of wedge window */
   int			*x_grid;		/* x grids */
   int			x_zoomc;
   int			x_zoomf;		/* x zoom factor */
   int			*y_grid;		/* y grids */
   int			y_zoomc;
   int			y_zoomf;		/* y zoom factor */
   int			scaling;		/* scaling */
   int			pid;			/* the pid */
   unsigned long	gcells[MAXGCOLORS];	/* graphics cell values */
   unsigned long	pcells[MAXPCOLORS];	/* plot cell values */
   unsigned char	scale[MAXSCALE][MAXCOLORS];	/* color scale table */
   unsigned char	*wdata;			/* wedge data */
   unsigned char	*idata;		        /* image data */
   unsigned long	black;			/* this is black */
   unsigned long	white;			/* this is white */
} Display_struct;

extern	int	color_background( );		/* color.c */
extern	int	color_heat( );			/* color.c */
extern	int	color_init( );			/* color.c */
extern	int	color_isophot( );		/* color.c */
extern	int	color_modify( );		/* color.c */
extern	int	color_modify_graphics( );	/* color.c */
extern	int	color_mono( );			/* color.c */
extern	int	color_mousse( );		/* color.c */
extern	int	color_rainbow( );		/* color.c */
extern	int	color_random( );		/* color.c */
extern	int	color_reset( );			/* color.c */
extern	int	color_rgb( );			/* color.c */
extern	int	color_ronekers( );		/* color.c */
extern	int	color_setlut( );		/* color.c */
extern	int	color_smooth( );		/* color.c */
extern	int	color_staircase( );		/* color.c */
extern	int	color_transfer( );		/* color.c */
extern	int	color_user( );			/* color.c */
extern	int	coord_init( );			/* coord.c */
#if	!defined(NO_GIPSY)
extern	int	coord_from_fits( );		/* coord.c */
#endif
extern	int	data_init( );			/* data.c */
extern	int	cursor_appendcr( );		/* cursor.c */
extern	int	cursor_box( );			/* cursor.c */
extern	int	cursor_do( );			/* cursor.c */
extern	int	cursor_init( );			/* cursor.c */
extern	int	cursor_reset( );		/* cursor.c */
extern	int	cursor_select( );		/* cursor.c */
extern	int	cursor_selection_clear( );	/* cursor.c */
extern	int	cursor_selection_request( );	/* cursor.c */
extern	int	cursor_sendev( );	  	/* cursor.c */
extern	int	cursor_send_text( );		/* cursor.c */
extern	int	cursor_socket( );		/* cursor.c */
extern	int	data_position( );		/* data.c */
extern	int	data_text( );			/* data.c */
extern	int	display_close( );		/* display.c */
extern	int	display_command( );		/* display.c */
extern	int	display_help( );		/* display.c */
extern	int	display_xslice( );		/* display.c */
extern	int	display_yslice( );		/* display.c */
extern	int	display_do( );			/* display.c */
extern	int	display_open( );		/* display.c */
extern	int	display_pgplot( );		/* display.c */
extern	int	display_resize( );		/* display.c */
extern	int	gdi_blankcol( );		/* gdi.c */
extern	int	gdi_cinfo( );			/* gdi.c */
extern	int	gdi_close( );			/* gdi.c */
extern	int	gdi_colget( );			/* gdi.c */
extern	int	gdi_colput( );			/* gdi.c */
extern	int	gdi_defimg( );			/* gdi.c */
extern	int	gdi_frame( );			/* gdi.c */
extern	int	gdi_gdsid( );			/* gdi.c */
extern	int	gdi_getlut( );			/* gdi.c */
extern	int	gdi_ginfo( );			/* gdi.c */
extern	int	gdi_grclear( );			/* gdi.c */
extern	int	gdi_grcol( );			/* gdi.c */
extern	int	gdi_groff( );			/* gdi.c */
extern	int	gdi_gron( );			/* gdi.c */
extern	int	gdi_grread( );			/* gdi.c */
extern	int	gdi_grregion( );		/* gdi.c */
extern	int	gdi_grwrite( );			/* gdi.c */
extern	int	gdi_idlen( );			/* gdi.c */
extern	int	gdi_iinfo( );			/* gdi.c */
extern	int	gdi_iinfo2( );			/* gdi.c */
extern	int	gdi_immid( );			/* gdi.c */
extern	int	gdi_imsid( );			/* gdi.c */
extern	int	gdi_imwrite( );			/* gdi.c */
#if	!defined(NO_GIPSY)
extern	int	gdi_mhead( );			/* gdi.c */
#endif
extern	int	gdi_open( );			/* gdi.c */
extern	int	gdi_pgplot( );			/* gdi.c */
extern	int	gdi_record( );			/* gdi.c */
extern	int	gdi_remove( );			/* gdi.c */
extern	int	gdi_reset( );			/* gdi.c */
extern	int	gdi_restore( );			/* gdi.c */
extern	int	gdi_rinfo( );			/* gdi.c */
extern	int	gdi_rmask( );			/* gdi.c */
extern	int	gdi_save( );			/* gdi.c */
extern	int	gdi_sequence( );		/* gdi.c */
extern	int	gdi_setxgrid( );		/* gdi.c */
extern	int	gdi_setygrid( );		/* gdi.c */
extern	int	gdi_update( );			/* gdi.c */
extern	int	help_continue( );		/* help.c */
extern	int	help_help( );			/* help.c */
extern	int	help_init( );			/* help.c */
extern	int	help_do_help( );		/* help.c */
extern	int	help_show( );			/* help.c */
extern	int	input_putchar( );		/* input.c */
extern	int	input_read_float( );		/* input.c */
extern	int	input_read_int( );		/* input.c */
extern	int	input_show( );			/* input.c */
extern	int	menu_draw( );			/* menu.c */
extern	int	menu_enter( );			/* menu.c */
extern	int	menu_init( );			/* menu.c */
extern	int	menu_leave( );			/* menu.c */
extern	int	menu_next( );			/* menu.c */
extern	int	menu_null( );			/* menu.c */
extern	int	menu_previous( );		/* menu.c */
extern	void	misc_broken_pipe( );		/* misc.c */
extern	int	misc_cmd_swap( );		/* misc.c */
extern	int	misc_error_handler1( );		/* misc.c */
extern	int	misc_error_handler2( );		/* misc.c */
extern	int	misc_flush( );			/* misc.c */
extern	int	misc_graphics( );		/* misc.c */
extern	int	misc_info( );			/* misc.c */
extern	int	misc_mask( );			/* misc.c */
extern	int	misc_max( );			/* misc.c */
extern	int	misc_message( );		/* misc.c */
extern	int	misc_min( );			/* misc.c */
extern	int	misc_nint( );			/* misc.c */
extern	int	misc_readval( );		/* misc.c */
extern	int	misc_receive( );		/* misc.c */
extern	int	misc_recordings( );		/* misc.c */
extern	int	misc_resize( );			/* misc.c */
extern	int	misc_send( );			/* misc.c */
extern	int	misc_setgridtext( );		/* misc.c */
extern	int	misc_settimer( );		/* misc.c */
extern	int	misc_show( );			/* misc.c */
extern	int	misc_sl( );			/* misc.c */
extern	int	misc_ss( );			/* misc.c */
extern  void    misc_pixel2char( );             /* misc.c */
extern	int	recording_blink( );		/* recording.c */
extern	int	recording_button( );		/* recording.c */
extern	int	recording_clear( );		/* recording.c */
extern	int	recording_delete( );		/* recording.c */
extern	int	recording_do_blink( );		/* recording.c */
extern	int	recording_do_loop( );		/* recording.c */
extern	int	recording_do_record( );		/* recording.c */
extern	int	recording_do_split( );		/* recording.c */
extern	int	recording_do_view( );		/* recording.c */
extern	int	recording_loop( );		/* recording.c */
extern	int	recording_record( );		/* recording.c */
extern	int	recording_remove( );		/* recording.c */
extern	int	recording_restore( );		/* recording.c */
extern	int	recording_save( );		/* recording.c */
extern	int	recording_show( );		/* recording.c */
extern	int	recording_split( );		/* recording.c */
extern	int	recording_view( );		/* recording.c */
extern	int	region_blot( );			/* region.c */
extern	int	region_blot_change( );		/* region.c */
extern	int	region_blot_e( );		/* region.c */
extern	int	region_blot_menu( );		/* region.c */
extern	int	region_blot_r( );		/* region.c */
extern	int	region_blot_reset( );		/* region.c */
extern	int	region_clear( );		/* region.c */
extern	int	region_do_define( );		/* region.c */
extern	int	region_define( );		/* region.c */
extern	int	region_next( );			/* region.c */
extern	int	region_on( );			/* region.c */
extern	int	region_ready( );		/* region.c */
extern	int	region_redraw( );		/* region.c */
extern	int	region_undefine( );		/* region.c */
extern	int	scale_blank( );			/* scale.c */
extern	int	scale_exp( );			/* scale.c */
extern	int	scale_init( );			/* scale.c */
extern	int	scale_inverse( );		/* scale.c */
extern	int	scale_linear( );		/* scale.c */
extern	int	scale_log( );			/* scale.c */
extern	int	scale_square( );		/* scale.c */
extern	int	scale_sqrt( );			/* scale.c */
extern	int	server_close( );		/* server.c */
extern	int	server_do( );			/* server.c */
extern	int	server_main_loop( );		/* server.c */
extern	int	server_open( );			/* server.c */
extern	int	server_timer_delay( float );	/* server.c */
extern	int	server_timer_function( int (*f)(void) );	/* server.c */
extern	int	slice_X( );			/* slice.c */
extern	int	slice_X_dezoom( );		/* slice.c */
extern	int	slice_X_zoom( );		/* slice.c */
extern	int	slice_Y( );			/* slice.c */
extern	int	slice_Y_dezoom( );		/* slice.c */
extern	int	slice_Y_zoom( );		/* slice.c */
extern	int	slice_coords( );		/* slice.c */
extern	int	slice_cursor( );		/* slice.c */
extern	int	slice_do_slice( );		/* slice.c */
extern	int	slice_profile( );		/* slice.c */
extern	int	wedge_blue( );			/* wedge.c */
extern	int	wedge_change( );		/* wedge.c */
extern	int	wedge_draw( );   		/* wedge.c */
extern	int	wedge_green( );			/* wedge.c */
extern	int	wedge_init( );			/* wedge.c */
extern	int	wedge_modify( );		/* wedge.c */
extern	int	wedge_position( );		/* wedge.c */
extern	int	wedge_purple( );		/* wedge.c */
extern	int	wedge_red( );			/* wedge.c */
extern	int	wedge_reset( );			/* wedge.c */
extern	int	wedge_white( );			/* wedge.c */
extern	int	wedge_yellow( );		/* wedge.c */
extern	int	zoom_in( );			/* zoom.c */
extern	int	zoom_in_x( );			/* zoom.c */
extern	int	zoom_in_y( );			/* zoom.c */
extern	int	zoom_modify( );			/* zoom.c */
extern	int	zoom_next( );			/* zoom.c */
extern	int	zoom_out( );			/* zoom.c */
extern	int	zoom_out_x( );			/* zoom.c */
extern	int	zoom_out_y( );			/* zoom.c */
extern	int	zoom_reset( );			/* zoom.c */
extern	int	zoom_xy( );			/* zoom.c */

extern	Data_struct	user;			/* data structure */
extern	Display_struct	winfo;			/* all window information */
extern	Menu_struct	*menu;			/* the buttons */
extern	Client_struct	clients[MAXCLIENTS];	/* for clients */

extern	char	*myargv[MAXARG];		/* program arguments */
extern	int	myargc;				/* number of arguments */
#<

#>            background.h
/* background.h

*/

static	Color_struct	background[] = {
   { 0.00000, 0.00000, 0.00000 },
   { 0.01587, 0.01587, 0.01587 },
   { 0.03174, 0.03174, 0.03174 },
   { 0.04761, 0.04761, 0.04761 },
   { 0.06348, 0.06348, 0.06348 },
   { 0.07935, 0.07935, 0.07935 },
   { 0.09522, 0.09522, 0.09522 },
   { 0.11109, 0.11109, 0.11109 },
   { 0.12696, 0.12696, 0.12696 },
   { 0.14283, 0.14283, 0.14283 },
   { 0.15870, 0.15870, 0.15870 },
   { 0.17457, 0.17457, 0.17457 },
   { 0.19044, 0.19044, 0.19044 },
   { 0.20631, 0.20631, 0.20631 },
   { 0.22218, 0.22218, 0.22218 },
   { 0.23805, 0.23805, 0.23805 },
   { 0.25392, 0.25392, 0.25392 },
   { 0.26979, 0.26979, 0.26979 },
   { 0.28566, 0.28566, 0.28566 },
   { 0.30153, 0.30153, 0.30153 },
   { 0.31740, 0.31740, 0.31740 },
   { 0.33327, 0.33327, 0.33327 },
   { 0.34914, 0.34914, 0.34914 },
   { 0.36501, 0.36501, 0.36501 },
   { 0.38088, 0.38088, 0.38088 },
   { 0.39675, 0.39675, 0.39675 },
   { 0.41262, 0.41262, 0.41262 },
   { 0.42849, 0.42849, 0.42849 },
   { 0.44436, 0.44436, 0.44436 },
   { 0.46023, 0.46023, 0.46023 },
   { 0.47610, 0.47610, 0.47610 },
   { 0.49197, 0.49197, 0.49197 },
   { 0.50784, 0.50784, 0.50784 },
   { 0.52371, 0.52371, 0.52371 },
   { 0.53958, 0.53958, 0.53958 },
   { 0.55545, 0.55545, 0.55545 },
   { 0.57132, 0.57132, 0.57132 },
   { 0.58719, 0.58719, 0.58719 },
   { 0.60306, 0.60306, 0.60306 },
   { 0.61893, 0.61893, 0.61893 },
   { 0.63480, 0.63480, 0.63480 },
   { 0.65067, 0.65067, 0.65067 },
   { 0.66654, 0.66654, 0.66654 },
   { 0.68241, 0.68241, 0.68241 },
   { 0.69828, 0.69828, 0.69828 },
   { 0.71415, 0.71415, 0.71415 },
   { 0.73002, 0.73002, 0.73002 },
   { 0.74589, 0.74589, 0.74589 },
   { 0.76176, 0.76176, 0.76176 },
   { 0.77763, 0.77763, 0.77763 },
   { 0.79350, 0.79350, 0.79350 },
   { 0.80937, 0.80937, 0.80937 },
   { 0.82524, 0.82524, 0.82524 },
   { 0.84111, 0.84111, 0.84111 },
   { 0.85698, 0.85698, 0.85698 },
   { 0.87285, 0.87285, 0.87285 },
   { 0.88872, 0.88872, 0.88872 },
   { 0.90459, 0.90459, 0.90459 },
   { 0.92046, 0.92046, 0.92046 },
   { 0.93633, 0.93633, 0.93633 },
   { 0.95220, 0.95220, 0.95220 },
   { 0.96807, 0.96807, 0.96807 },
   { 0.98394, 0.98394, 0.98394 },
   { 0.99981, 0.99981, 0.99981 },
   { 0.00000, 0.00000, 0.99981 },
   { 0.00000, 0.01587, 0.98394 },
   { 0.00000, 0.03174, 0.96807 },
   { 0.00000, 0.04761, 0.95220 },
   { 0.00000, 0.06348, 0.93633 },
   { 0.00000, 0.07935, 0.92046 },
   { 0.00000, 0.09522, 0.90459 },
   { 0.00000, 0.11109, 0.88872 },
   { 0.00000, 0.12696, 0.87285 },
   { 0.00000, 0.14283, 0.85698 },
   { 0.00000, 0.15870, 0.84111 },
   { 0.00000, 0.17457, 0.82524 },
   { 0.00000, 0.19044, 0.80937 },
   { 0.00000, 0.20631, 0.79350 },
   { 0.00000, 0.22218, 0.77763 },
   { 0.00000, 0.23805, 0.76176 },
   { 0.00000, 0.25392, 0.74589 },
   { 0.00000, 0.26979, 0.73002 },
   { 0.00000, 0.28566, 0.71415 },
   { 0.00000, 0.30153, 0.69828 },
   { 0.00000, 0.31740, 0.68241 },
   { 0.00000, 0.33327, 0.66654 },
   { 0.00000, 0.34914, 0.65067 },
   { 0.00000, 0.36501, 0.63480 },
   { 0.00000, 0.38088, 0.61893 },
   { 0.00000, 0.39675, 0.60306 },
   { 0.00000, 0.41262, 0.58719 },
   { 0.00000, 0.42849, 0.57132 },
   { 0.00000, 0.44436, 0.55545 },
   { 0.00000, 0.46023, 0.53958 },
   { 0.00000, 0.47610, 0.52371 },
   { 0.00000, 0.49197, 0.50784 },
   { 0.00000, 0.50784, 0.49197 },
   { 0.00000, 0.52371, 0.47610 },
   { 0.00000, 0.53958, 0.46023 },
   { 0.00000, 0.55545, 0.44436 },
   { 0.00000, 0.57132, 0.42849 },
   { 0.00000, 0.58719, 0.41262 },
   { 0.00000, 0.60306, 0.39675 },
   { 0.00000, 0.61893, 0.38088 },
   { 0.00000, 0.63480, 0.36501 },
   { 0.00000, 0.65067, 0.34914 },
   { 0.00000, 0.66654, 0.33327 },
   { 0.00000, 0.68241, 0.31740 },
   { 0.00000, 0.69828, 0.30153 },
   { 0.00000, 0.71415, 0.28566 },
   { 0.00000, 0.73002, 0.26979 },
   { 0.00000, 0.74589, 0.25392 },
   { 0.00000, 0.76176, 0.23805 },
   { 0.00000, 0.77763, 0.22218 },
   { 0.00000, 0.79350, 0.20631 },
   { 0.00000, 0.80937, 0.19044 },
   { 0.00000, 0.82524, 0.17457 },
   { 0.00000, 0.84111, 0.15870 },
   { 0.00000, 0.85698, 0.14283 },
   { 0.00000, 0.87285, 0.12696 },
   { 0.00000, 0.88872, 0.11109 },
   { 0.00000, 0.90459, 0.09522 },
   { 0.00000, 0.92046, 0.07935 },
   { 0.00000, 0.93633, 0.06348 },
   { 0.00000, 0.95220, 0.04761 },
   { 0.00000, 0.96807, 0.03174 },
   { 0.00000, 0.98394, 0.01587 },
   { 0.00000, 0.99981, 0.00000 },
   { 0.00000, 1.00000, 0.00000 },
   { 0.01587, 1.00000, 0.00000 },
   { 0.03174, 1.00000, 0.00000 },
   { 0.04761, 1.00000, 0.00000 },
   { 0.06348, 1.00000, 0.00000 },
   { 0.07935, 1.00000, 0.00000 },
   { 0.09522, 1.00000, 0.00000 },
   { 0.11109, 1.00000, 0.00000 },
   { 0.12696, 1.00000, 0.00000 },
   { 0.14283, 1.00000, 0.00000 },
   { 0.15870, 1.00000, 0.00000 },
   { 0.17457, 1.00000, 0.00000 },
   { 0.19044, 1.00000, 0.00000 },
   { 0.20631, 1.00000, 0.00000 },
   { 0.22218, 1.00000, 0.00000 },
   { 0.23805, 1.00000, 0.00000 },
   { 0.25392, 1.00000, 0.00000 },
   { 0.26979, 1.00000, 0.00000 },
   { 0.28566, 1.00000, 0.00000 },
   { 0.30153, 1.00000, 0.00000 },
   { 0.31740, 1.00000, 0.00000 },
   { 0.33327, 1.00000, 0.00000 },
   { 0.34914, 1.00000, 0.00000 },
   { 0.36501, 1.00000, 0.00000 },
   { 0.38088, 1.00000, 0.00000 },
   { 0.39675, 1.00000, 0.00000 },
   { 0.41262, 1.00000, 0.00000 },
   { 0.42849, 1.00000, 0.00000 },
   { 0.44436, 1.00000, 0.00000 },
   { 0.46023, 1.00000, 0.00000 },
   { 0.47610, 1.00000, 0.00000 },
   { 0.49197, 1.00000, 0.00000 },
   { 0.50784, 1.00000, 0.00000 },
   { 0.52371, 1.00000, 0.00000 },
   { 0.53958, 1.00000, 0.00000 },
   { 0.55545, 1.00000, 0.00000 },
   { 0.57132, 1.00000, 0.00000 },
   { 0.58719, 1.00000, 0.00000 },
   { 0.60306, 1.00000, 0.00000 },
   { 0.61893, 1.00000, 0.00000 },
   { 0.63480, 1.00000, 0.00000 },
   { 0.65067, 1.00000, 0.00000 },
   { 0.66654, 1.00000, 0.00000 },
   { 0.68241, 1.00000, 0.00000 },
   { 0.69828, 1.00000, 0.00000 },
   { 0.71415, 1.00000, 0.00000 },
   { 0.73002, 1.00000, 0.00000 },
   { 0.74589, 1.00000, 0.00000 },
   { 0.76176, 1.00000, 0.00000 },
   { 0.77763, 1.00000, 0.00000 },
   { 0.79350, 1.00000, 0.00000 },
   { 0.80937, 1.00000, 0.00000 },
   { 0.82524, 1.00000, 0.00000 },
   { 0.84111, 1.00000, 0.00000 },
   { 0.85698, 1.00000, 0.00000 },
   { 0.87285, 1.00000, 0.00000 },
   { 0.88872, 1.00000, 0.00000 },
   { 0.90459, 1.00000, 0.00000 },
   { 0.92046, 1.00000, 0.00000 },
   { 0.93633, 1.00000, 0.00000 },
   { 0.95220, 1.00000, 0.00000 },
   { 0.96807, 1.00000, 0.00000 },
   { 0.98394, 1.00000, 0.00000 },
   { 0.99981, 1.00000, 0.00000 },
   { 1.00000, 0.99981, 0.00000 },
   { 1.00000, 0.98394, 0.00000 },
   { 1.00000, 0.96807, 0.00000 },
   { 1.00000, 0.95220, 0.00000 },
   { 1.00000, 0.93633, 0.00000 },
   { 1.00000, 0.92046, 0.00000 },
   { 1.00000, 0.90459, 0.00000 },
   { 1.00000, 0.88872, 0.00000 },
   { 1.00000, 0.87285, 0.00000 },
   { 1.00000, 0.85698, 0.00000 },
   { 1.00000, 0.84111, 0.00000 },
   { 1.00000, 0.82524, 0.00000 },
   { 1.00000, 0.80937, 0.00000 },
   { 1.00000, 0.79350, 0.00000 },
   { 1.00000, 0.77763, 0.00000 },
   { 1.00000, 0.76176, 0.00000 },
   { 1.00000, 0.74589, 0.00000 },
   { 1.00000, 0.73002, 0.00000 },
   { 1.00000, 0.71415, 0.00000 },
   { 1.00000, 0.69828, 0.00000 },
   { 1.00000, 0.68241, 0.00000 },
   { 1.00000, 0.66654, 0.00000 },
   { 1.00000, 0.65067, 0.00000 },
   { 1.00000, 0.63480, 0.00000 },
   { 1.00000, 0.61893, 0.00000 },
   { 1.00000, 0.60306, 0.00000 },
   { 1.00000, 0.58719, 0.00000 },
   { 1.00000, 0.57132, 0.00000 },
   { 1.00000, 0.55545, 0.00000 },
   { 1.00000, 0.53958, 0.00000 },
   { 1.00000, 0.52371, 0.00000 },
   { 1.00000, 0.50784, 0.00000 },
   { 1.00000, 0.49197, 0.00000 },
   { 1.00000, 0.47610, 0.00000 },
   { 1.00000, 0.46023, 0.00000 },
   { 1.00000, 0.44436, 0.00000 },
   { 1.00000, 0.42849, 0.00000 },
   { 1.00000, 0.41262, 0.00000 },
   { 1.00000, 0.39675, 0.00000 },
   { 1.00000, 0.38088, 0.00000 },
   { 1.00000, 0.36501, 0.00000 },
   { 1.00000, 0.34914, 0.00000 },
   { 1.00000, 0.33327, 0.00000 },
   { 1.00000, 0.31740, 0.00000 },
   { 1.00000, 0.30153, 0.00000 },
   { 1.00000, 0.28566, 0.00000 },
   { 1.00000, 0.26979, 0.00000 },
   { 1.00000, 0.25392, 0.00000 },
   { 1.00000, 0.23805, 0.00000 },
   { 1.00000, 0.22218, 0.00000 },
   { 1.00000, 0.20631, 0.00000 },
   { 1.00000, 0.19044, 0.00000 },
   { 1.00000, 0.17457, 0.00000 },
   { 1.00000, 0.15870, 0.00000 },
   { 1.00000, 0.14283, 0.00000 },
   { 1.00000, 0.12696, 0.00000 },
   { 1.00000, 0.11109, 0.00000 },
   { 1.00000, 0.09522, 0.00000 },
   { 1.00000, 0.07935, 0.00000 },
   { 1.00000, 0.06348, 0.00000 },
   { 1.00000, 0.04761, 0.00000 },
   { 1.00000, 0.03174, 0.00000 },
   { 1.00000, 0.01587, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
};
#<

#>            heat.h
/* heat.h

*/

static	Color_struct	heat[] = {
   { 0.00000, 0.00000, 0.00000 },
   { 0.01176, 0.00392, 0.00000 },
   { 0.02353, 0.00784, 0.00000 },
   { 0.03529, 0.01176, 0.00000 },
   { 0.04706, 0.01569, 0.00000 },
   { 0.05882, 0.01961, 0.00000 },
   { 0.07059, 0.02353, 0.00000 },
   { 0.08235, 0.02745, 0.00000 },
   { 0.09412, 0.03137, 0.00000 },
   { 0.10588, 0.03529, 0.00000 },
   { 0.11765, 0.03922, 0.00000 },
   { 0.12941, 0.04314, 0.00000 },
   { 0.14118, 0.04706, 0.00000 },
   { 0.15294, 0.05098, 0.00000 },
   { 0.16471, 0.05490, 0.00000 },
   { 0.17647, 0.05882, 0.00000 },
   { 0.18824, 0.06275, 0.00000 },
   { 0.20000, 0.06667, 0.00000 },
   { 0.21176, 0.07059, 0.00000 },
   { 0.22353, 0.07451, 0.00000 },
   { 0.23529, 0.07843, 0.00000 },
   { 0.24706, 0.08235, 0.00000 },
   { 0.25882, 0.08627, 0.00000 },
   { 0.27059, 0.09020, 0.00000 },
   { 0.28235, 0.09412, 0.00000 },
   { 0.29412, 0.09804, 0.00000 },
   { 0.30588, 0.10196, 0.00000 },
   { 0.31765, 0.10588, 0.00000 },
   { 0.32941, 0.10980, 0.00000 },
   { 0.34118, 0.11373, 0.00000 },
   { 0.35294, 0.11765, 0.00000 },
   { 0.36471, 0.12157, 0.00000 },
   { 0.37647, 0.12549, 0.00000 },
   { 0.38824, 0.12941, 0.00000 },
   { 0.40000, 0.13333, 0.00000 },
   { 0.41176, 0.13725, 0.00000 },
   { 0.42353, 0.14118, 0.00000 },
   { 0.43529, 0.14510, 0.00000 },
   { 0.44706, 0.14902, 0.00000 },
   { 0.45882, 0.15294, 0.00000 },
   { 0.47059, 0.15686, 0.00000 },
   { 0.48235, 0.16078, 0.00000 },
   { 0.49412, 0.16471, 0.00000 },
   { 0.50588, 0.16863, 0.00000 },
   { 0.51765, 0.17255, 0.00000 },
   { 0.52941, 0.17647, 0.00000 },
   { 0.54118, 0.18039, 0.00000 },
   { 0.55294, 0.18431, 0.00000 },
   { 0.56471, 0.18824, 0.00000 },
   { 0.57647, 0.19216, 0.00000 },
   { 0.58824, 0.19608, 0.00000 },
   { 0.60000, 0.20000, 0.00000 },
   { 0.61176, 0.20392, 0.00000 },
   { 0.62353, 0.20784, 0.00000 },
   { 0.63529, 0.21176, 0.00000 },
   { 0.64706, 0.21569, 0.00000 },
   { 0.65882, 0.21961, 0.00000 },
   { 0.67059, 0.22353, 0.00000 },
   { 0.68235, 0.22745, 0.00000 },
   { 0.69412, 0.23137, 0.00000 },
   { 0.70588, 0.23529, 0.00000 },
   { 0.71765, 0.23922, 0.00000 },
   { 0.72941, 0.24314, 0.00000 },
   { 0.74118, 0.24706, 0.00000 },
   { 0.75294, 0.25098, 0.00000 },
   { 0.76471, 0.25490, 0.00000 },
   { 0.77647, 0.25882, 0.00000 },
   { 0.78824, 0.26275, 0.00000 },
   { 0.80000, 0.26667, 0.00000 },
   { 0.81176, 0.27059, 0.00000 },
   { 0.82353, 0.27451, 0.00000 },
   { 0.83529, 0.27843, 0.00000 },
   { 0.84706, 0.28235, 0.00000 },
   { 0.85882, 0.28627, 0.00000 },
   { 0.87059, 0.29020, 0.00000 },
   { 0.88235, 0.29412, 0.00000 },
   { 0.89412, 0.29804, 0.00000 },
   { 0.90588, 0.30196, 0.00000 },
   { 0.91765, 0.30588, 0.00000 },
   { 0.92941, 0.30980, 0.00000 },
   { 0.94118, 0.31373, 0.00000 },
   { 0.95294, 0.31765, 0.00000 },
   { 0.96471, 0.32157, 0.00000 },
   { 0.97647, 0.32549, 0.00000 },
   { 0.98824, 0.32941, 0.00000 },
   { 1.00000, 0.33333, 0.00000 },
   { 1.00000, 0.33725, 0.00000 },
   { 1.00000, 0.34118, 0.00000 },
   { 1.00000, 0.34510, 0.00000 },
   { 1.00000, 0.34902, 0.00000 },
   { 1.00000, 0.35294, 0.00000 },
   { 1.00000, 0.35686, 0.00000 },
   { 1.00000, 0.36078, 0.00000 },
   { 1.00000, 0.36471, 0.00000 },
   { 1.00000, 0.36863, 0.00000 },
   { 1.00000, 0.37255, 0.00000 },
   { 1.00000, 0.37647, 0.00000 },
   { 1.00000, 0.38039, 0.00000 },
   { 1.00000, 0.38431, 0.00000 },
   { 1.00000, 0.38824, 0.00000 },
   { 1.00000, 0.39216, 0.00000 },
   { 1.00000, 0.39608, 0.00000 },
   { 1.00000, 0.40000, 0.00000 },
   { 1.00000, 0.40392, 0.00000 },
   { 1.00000, 0.40784, 0.00000 },
   { 1.00000, 0.41176, 0.00000 },
   { 1.00000, 0.41569, 0.00000 },
   { 1.00000, 0.41961, 0.00000 },
   { 1.00000, 0.42353, 0.00000 },
   { 1.00000, 0.42745, 0.00000 },
   { 1.00000, 0.43137, 0.00000 },
   { 1.00000, 0.43529, 0.00000 },
   { 1.00000, 0.43922, 0.00000 },
   { 1.00000, 0.44314, 0.00000 },
   { 1.00000, 0.44706, 0.00000 },
   { 1.00000, 0.45098, 0.00000 },
   { 1.00000, 0.45490, 0.00000 },
   { 1.00000, 0.45882, 0.00000 },
   { 1.00000, 0.46275, 0.00000 },
   { 1.00000, 0.46667, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47451, 0.00000 },
   { 1.00000, 0.47843, 0.00000 },
   { 1.00000, 0.48235, 0.00000 },
   { 1.00000, 0.48627, 0.00000 },
   { 1.00000, 0.49020, 0.00000 },
   { 1.00000, 0.49412, 0.00000 },
   { 1.00000, 0.49804, 0.00000 },
   { 1.00000, 0.50196, 0.00000 },
   { 1.00000, 0.50588, 0.00000 },
   { 1.00000, 0.50980, 0.00000 },
   { 1.00000, 0.51373, 0.00000 },
   { 1.00000, 0.51765, 0.00000 },
   { 1.00000, 0.52157, 0.00000 },
   { 1.00000, 0.52549, 0.00000 },
   { 1.00000, 0.52941, 0.00000 },
   { 1.00000, 0.53333, 0.00000 },
   { 1.00000, 0.53725, 0.00000 },
   { 1.00000, 0.54118, 0.00000 },
   { 1.00000, 0.54510, 0.00000 },
   { 1.00000, 0.54902, 0.00000 },
   { 1.00000, 0.55294, 0.00000 },
   { 1.00000, 0.55686, 0.00000 },
   { 1.00000, 0.56078, 0.00000 },
   { 1.00000, 0.56471, 0.00000 },
   { 1.00000, 0.56863, 0.00000 },
   { 1.00000, 0.57255, 0.00000 },
   { 1.00000, 0.57647, 0.00000 },
   { 1.00000, 0.58039, 0.00000 },
   { 1.00000, 0.58431, 0.00000 },
   { 1.00000, 0.58824, 0.00000 },
   { 1.00000, 0.59216, 0.00000 },
   { 1.00000, 0.59608, 0.00000 },
   { 1.00000, 0.60000, 0.00000 },
   { 1.00000, 0.60392, 0.00000 },
   { 1.00000, 0.60784, 0.00000 },
   { 1.00000, 0.61176, 0.00000 },
   { 1.00000, 0.61569, 0.00000 },
   { 1.00000, 0.61961, 0.00000 },
   { 1.00000, 0.62353, 0.00000 },
   { 1.00000, 0.62745, 0.00000 },
   { 1.00000, 0.63137, 0.00000 },
   { 1.00000, 0.63529, 0.00000 },
   { 1.00000, 0.63922, 0.00000 },
   { 1.00000, 0.64314, 0.00000 },
   { 1.00000, 0.64706, 0.00000 },
   { 1.00000, 0.65098, 0.01176 },
   { 1.00000, 0.65490, 0.02353 },
   { 1.00000, 0.65882, 0.03529 },
   { 1.00000, 0.66275, 0.04706 },
   { 1.00000, 0.66667, 0.05882 },
   { 1.00000, 0.67059, 0.07059 },
   { 1.00000, 0.67451, 0.08235 },
   { 1.00000, 0.67843, 0.09412 },
   { 1.00000, 0.68235, 0.10588 },
   { 1.00000, 0.68627, 0.11765 },
   { 1.00000, 0.69020, 0.12941 },
   { 1.00000, 0.69412, 0.14118 },
   { 1.00000, 0.69804, 0.15294 },
   { 1.00000, 0.70196, 0.16471 },
   { 1.00000, 0.70588, 0.17647 },
   { 1.00000, 0.70980, 0.18824 },
   { 1.00000, 0.71373, 0.20000 },
   { 1.00000, 0.71765, 0.21176 },
   { 1.00000, 0.72157, 0.22353 },
   { 1.00000, 0.72549, 0.23529 },
   { 1.00000, 0.72941, 0.24706 },
   { 1.00000, 0.73333, 0.25882 },
   { 1.00000, 0.73725, 0.27059 },
   { 1.00000, 0.74118, 0.28235 },
   { 1.00000, 0.74510, 0.29412 },
   { 1.00000, 0.74902, 0.30588 },
   { 1.00000, 0.75294, 0.31765 },
   { 1.00000, 0.75686, 0.32941 },
   { 1.00000, 0.76078, 0.34118 },
   { 1.00000, 0.76471, 0.35294 },
   { 1.00000, 0.76863, 0.36471 },
   { 1.00000, 0.77255, 0.37647 },
   { 1.00000, 0.77647, 0.38824 },
   { 1.00000, 0.78039, 0.40000 },
   { 1.00000, 0.78431, 0.41176 },
   { 1.00000, 0.78824, 0.42353 },
   { 1.00000, 0.79216, 0.43529 },
   { 1.00000, 0.79608, 0.44706 },
   { 1.00000, 0.80000, 0.45882 },
   { 1.00000, 0.80392, 0.47059 },
   { 1.00000, 0.80784, 0.48235 },
   { 1.00000, 0.81176, 0.49412 },
   { 1.00000, 0.81569, 0.50588 },
   { 1.00000, 0.81961, 0.51765 },
   { 1.00000, 0.82353, 0.52941 },
   { 1.00000, 0.82745, 0.54118 },
   { 1.00000, 0.83137, 0.55294 },
   { 1.00000, 0.83529, 0.56471 },
   { 1.00000, 0.83922, 0.57647 },
   { 1.00000, 0.84314, 0.58824 },
   { 1.00000, 0.84706, 0.60000 },
   { 1.00000, 0.85098, 0.61176 },
   { 1.00000, 0.85490, 0.62353 },
   { 1.00000, 0.85882, 0.63529 },
   { 1.00000, 0.86275, 0.64706 },
   { 1.00000, 0.86667, 0.65882 },
   { 1.00000, 0.87059, 0.67059 },
   { 1.00000, 0.87451, 0.68235 },
   { 1.00000, 0.87843, 0.69412 },
   { 1.00000, 0.88235, 0.70588 },
   { 1.00000, 0.88627, 0.71765 },
   { 1.00000, 0.89020, 0.72941 },
   { 1.00000, 0.89412, 0.74118 },
   { 1.00000, 0.89804, 0.75294 },
   { 1.00000, 0.90196, 0.76471 },
   { 1.00000, 0.90588, 0.77647 },
   { 1.00000, 0.90980, 0.78824 },
   { 1.00000, 0.91373, 0.80000 },
   { 1.00000, 0.91765, 0.81176 },
   { 1.00000, 0.92157, 0.82353 },
   { 1.00000, 0.92549, 0.83529 },
   { 1.00000, 0.92941, 0.84706 },
   { 1.00000, 0.93333, 0.85882 },
   { 1.00000, 0.93725, 0.87059 },
   { 1.00000, 0.94118, 0.88235 },
   { 1.00000, 0.94510, 0.89412 },
   { 1.00000, 0.94902, 0.90588 },
   { 1.00000, 0.95294, 0.91765 },
   { 1.00000, 0.95686, 0.92941 },
   { 1.00000, 0.96078, 0.94118 },
   { 1.00000, 0.96471, 0.95294 },
   { 1.00000, 0.96863, 0.96471 },
   { 1.00000, 0.97255, 0.97647 },
   { 1.00000, 0.97647, 0.98824 },
   { 1.00000, 0.98039, 1.00000 },
   { 1.00000, 0.98431, 1.00000 },
   { 1.00000, 0.98824, 1.00000 },
   { 1.00000, 0.99216, 1.00000 },
   { 1.00000, 0.99608, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
};
#<

#>            isophot.h
/* isophot.h

*/

static	Color_struct	isophot[] = {
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.03922 },
   { 0.00000, 0.00000, 0.07843 },
   { 0.00000, 0.00000, 0.11765 },
   { 0.00000, 0.00000, 0.15686 },
   { 0.00000, 0.00000, 0.19608 },
   { 0.00000, 0.00000, 0.23529 },
   { 0.00000, 0.00000, 0.27843 },
   { 0.00000, 0.00000, 0.31765 },
   { 0.00000, 0.00000, 0.35686 },
   { 0.00000, 0.00000, 0.39608 },
   { 0.00000, 0.00000, 0.43529 },
   { 0.00000, 0.00000, 0.47451 },
   { 0.00000, 0.00000, 0.51765 },
   { 0.00000, 0.00000, 0.55686 },
   { 0.00000, 0.00000, 0.59608 },
   { 0.00000, 0.00000, 0.63529 },
   { 0.00000, 0.00000, 0.67451 },
   { 0.00000, 0.00000, 0.71765 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 0.00000, 0.00000, 0.87843 },
   { 0.00000, 0.00000, 0.91765 },
   { 0.00000, 0.00000, 0.95686 },
   { 0.00000, 0.00000, 1.00000 },
   { 0.00000, 0.03137, 1.00000 },
   { 0.00000, 0.06275, 1.00000 },
   { 0.00000, 0.09412, 1.00000 },
   { 0.00000, 0.12549, 1.00000 },
   { 0.00000, 0.15686, 1.00000 },
   { 0.00000, 0.18824, 1.00000 },
   { 0.00000, 0.21961, 1.00000 },
   { 0.00000, 0.25490, 1.00000 },
   { 0.00000, 0.28627, 1.00000 },
   { 0.00000, 0.31765, 1.00000 },
   { 0.00000, 0.34902, 1.00000 },
   { 0.00000, 0.38039, 1.00000 },
   { 0.00000, 0.41176, 1.00000 },
   { 0.00000, 0.44314, 1.00000 },
   { 0.00000, 0.47843, 1.00000 },
   { 0.00000, 0.49804, 1.00000 },
   { 0.00000, 0.51765, 1.00000 },
   { 0.00000, 0.53725, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 0.00000, 0.61961, 1.00000 },
   { 0.00000, 0.63922, 1.00000 },
   { 0.00000, 0.65882, 1.00000 },
   { 0.00000, 0.67843, 1.00000 },
   { 0.00000, 0.70196, 1.00000 },
   { 0.00000, 0.72157, 1.00000 },
   { 0.00000, 0.74118, 1.00000 },
   { 0.00000, 0.76078, 1.00000 },
   { 0.00000, 0.78431, 1.00000 },
   { 0.00000, 0.79608, 1.00000 },
   { 0.00000, 0.81176, 1.00000 },
   { 0.00000, 0.82353, 1.00000 },
   { 0.00000, 0.83922, 1.00000 },
   { 0.00000, 0.85490, 1.00000 },
   { 0.00000, 0.86667, 1.00000 },
   { 0.00000, 0.88235, 1.00000 },
   { 0.00000, 0.89412, 1.00000 },
   { 0.00000, 0.90980, 1.00000 },
   { 0.00000, 0.92549, 1.00000 },
   { 0.00000, 0.93725, 1.00000 },
   { 0.00000, 0.95294, 1.00000 },
   { 0.00000, 0.96863, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 0.00000, 1.00000, 0.96078 },
   { 0.00000, 1.00000, 0.94118 },
   { 0.00000, 1.00000, 0.92157 },
   { 0.00000, 1.00000, 0.90196 },
   { 0.00000, 1.00000, 0.88235 },
   { 0.00000, 1.00000, 0.86275 },
   { 0.00000, 1.00000, 0.84314 },
   { 0.00000, 1.00000, 0.82353 },
   { 0.00000, 1.00000, 0.80392 },
   { 0.00000, 1.00000, 0.78431 },
   { 0.00000, 1.00000, 0.76471 },
   { 0.00000, 1.00000, 0.74510 },
   { 0.00000, 1.00000, 0.72549 },
   { 0.00000, 1.00000, 0.70588 },
   { 0.00000, 1.00000, 0.65490 },
   { 0.00000, 1.00000, 0.60784 },
   { 0.00000, 1.00000, 0.56078 },
   { 0.00000, 1.00000, 0.51373 },
   { 0.00000, 1.00000, 0.46667 },
   { 0.00000, 1.00000, 0.41961 },
   { 0.00000, 1.00000, 0.37255 },
   { 0.00000, 1.00000, 0.32549 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 0.00000, 1.00000, 0.13725 },
   { 0.00000, 1.00000, 0.09020 },
   { 0.00000, 1.00000, 0.04314 },
   { 0.00000, 1.00000, 0.00000 },
   { 0.04706, 1.00000, 0.00000 },
   { 0.09412, 1.00000, 0.00000 },
   { 0.14118, 1.00000, 0.00000 },
   { 0.18824, 1.00000, 0.00000 },
   { 0.23529, 1.00000, 0.00000 },
   { 0.28235, 1.00000, 0.00000 },
   { 0.32941, 1.00000, 0.00000 },
   { 0.37647, 1.00000, 0.00000 },
   { 0.42353, 1.00000, 0.00000 },
   { 0.47059, 1.00000, 0.00000 },
   { 0.51765, 1.00000, 0.00000 },
   { 0.56471, 1.00000, 0.00000 },
   { 0.61176, 1.00000, 0.00000 },
   { 0.65882, 1.00000, 0.00000 },
   { 0.70588, 1.00000, 0.00000 },
   { 0.72549, 1.00000, 0.00000 },
   { 0.74510, 1.00000, 0.00000 },
   { 0.76471, 1.00000, 0.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 0.84314, 1.00000, 0.00000 },
   { 0.86275, 1.00000, 0.00000 },
   { 0.88235, 1.00000, 0.00000 },
   { 0.90196, 1.00000, 0.00000 },
   { 0.92157, 1.00000, 0.00000 },
   { 0.94118, 1.00000, 0.00000 },
   { 0.96078, 1.00000, 0.00000 },
   { 0.98039, 1.00000, 0.00000 },
   { 1.00000, 1.00000, 0.00000 },
   { 0.99608, 0.98039, 0.00000 },
   { 0.99608, 0.96078, 0.00000 },
   { 0.99608, 0.94118, 0.00000 },
   { 0.99608, 0.92549, 0.00000 },
   { 0.99216, 0.90588, 0.00000 },
   { 0.99216, 0.88627, 0.00000 },
   { 0.99216, 0.87059, 0.00000 },
   { 0.99216, 0.85098, 0.00000 },
   { 0.98824, 0.83137, 0.00000 },
   { 0.98824, 0.81569, 0.00000 },
   { 0.98824, 0.79608, 0.00000 },
   { 0.98824, 0.77647, 0.00000 },
   { 0.98824, 0.76078, 0.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 0.98824, 0.69020, 0.00000 },
   { 0.98824, 0.67059, 0.00000 },
   { 0.98824, 0.65490, 0.00000 },
   { 0.98824, 0.63922, 0.00000 },
   { 0.98824, 0.61961, 0.00000 },
   { 0.99216, 0.60392, 0.00000 },
   { 0.99216, 0.58824, 0.00000 },
   { 0.99216, 0.56863, 0.00000 },
   { 0.99216, 0.55294, 0.00000 },
   { 0.99608, 0.53725, 0.00000 },
   { 0.99608, 0.51765, 0.00000 },
   { 0.99608, 0.50196, 0.00000 },
   { 0.99608, 0.48627, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.43529, 0.00000 },
   { 1.00000, 0.40392, 0.00000 },
   { 1.00000, 0.37255, 0.00000 },
   { 1.00000, 0.34118, 0.00000 },
   { 1.00000, 0.30980, 0.00000 },
   { 1.00000, 0.27843, 0.00000 },
   { 1.00000, 0.24706, 0.00000 },
   { 1.00000, 0.21569, 0.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 0.09020, 0.00000 },
   { 1.00000, 0.05882, 0.00000 },
   { 1.00000, 0.02745, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.04706 },
   { 1.00000, 0.00000, 0.09412 },
   { 1.00000, 0.00000, 0.14118 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 0.00000, 0.32941 },
   { 1.00000, 0.00000, 0.37647 },
   { 1.00000, 0.00000, 0.42353 },
   { 1.00000, 0.00000, 0.47059 },
   { 1.00000, 0.00000, 0.51765 },
   { 1.00000, 0.00000, 0.56471 },
   { 1.00000, 0.00000, 0.61176 },
   { 1.00000, 0.00000, 0.65882 },
   { 1.00000, 0.00000, 0.70588 },
   { 1.00000, 0.00000, 0.72549 },
   { 1.00000, 0.00000, 0.74902 },
   { 1.00000, 0.00000, 0.77255 },
   { 1.00000, 0.00000, 0.79608 },
   { 1.00000, 0.00000, 0.81569 },
   { 1.00000, 0.00000, 0.83922 },
   { 1.00000, 0.00000, 0.86275 },
   { 1.00000, 0.00000, 0.88627 },
   { 1.00000, 0.00000, 0.90588 },
   { 1.00000, 0.00000, 0.92941 },
   { 1.00000, 0.00000, 0.95294 },
   { 1.00000, 0.00000, 0.97647 },
   { 1.00000, 0.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 0.14118, 1.00000 },
   { 1.00000, 0.17647, 1.00000 },
   { 1.00000, 0.21176, 1.00000 },
   { 1.00000, 0.25098, 1.00000 },
   { 1.00000, 0.28627, 1.00000 },
   { 1.00000, 0.32157, 1.00000 },
   { 1.00000, 0.36078, 1.00000 },
   { 1.00000, 0.39608, 1.00000 },
   { 1.00000, 0.43137, 1.00000 },
   { 1.00000, 0.47059, 1.00000 },
   { 1.00000, 0.48627, 1.00000 },
   { 1.00000, 0.50588, 1.00000 },
   { 1.00000, 0.52157, 1.00000 },
   { 1.00000, 0.54118, 1.00000 },
   { 1.00000, 0.56078, 1.00000 },
   { 1.00000, 0.57647, 1.00000 },
   { 1.00000, 0.59608, 1.00000 },
   { 1.00000, 0.61176, 1.00000 },
   { 1.00000, 0.63137, 1.00000 },
   { 1.00000, 0.65098, 1.00000 },
   { 1.00000, 0.66667, 1.00000 },
   { 1.00000, 0.68627, 1.00000 },
   { 1.00000, 0.70588, 1.00000 },
   { 1.00000, 0.74510, 1.00000 },
   { 1.00000, 0.78824, 1.00000 },
   { 1.00000, 0.83137, 1.00000 },
   { 1.00000, 0.87059, 1.00000 },
   { 1.00000, 0.91373, 1.00000 },
   { 1.00000, 0.95686, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
};
#<

#>            mousse.h
/* mousse.h

*/

static	Color_struct	mousse[] = {
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.13333 },
   { 0.00000, 0.00000, 0.13333 },
   { 0.00000, 0.00000, 0.13333 },
   { 0.00000, 0.00000, 0.13333 },
   { 0.00000, 0.00000, 0.13333 },
   { 0.00000, 0.00000, 0.13333 },
   { 0.00000, 0.00000, 0.13333 },
   { 0.00000, 0.00000, 0.13333 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.26667 },
   { 0.00000, 0.00000, 0.26667 },
   { 0.00000, 0.00000, 0.26667 },
   { 0.00000, 0.00000, 0.26667 },
   { 0.00000, 0.00000, 0.26667 },
   { 0.00000, 0.00000, 0.26667 },
   { 0.00000, 0.00000, 0.26667 },
   { 0.00000, 0.00000, 0.26667 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.46667 },
   { 0.00000, 0.00000, 0.46667 },
   { 0.00000, 0.00000, 0.46667 },
   { 0.00000, 0.00000, 0.46667 },
   { 0.00000, 0.00000, 0.46667 },
   { 0.00000, 0.00000, 0.46667 },
   { 0.00000, 0.00000, 0.46667 },
   { 0.00000, 0.00000, 0.46667 },
   { 0.00000, 0.00000, 0.53333 },
   { 0.00000, 0.00000, 0.53333 },
   { 0.00000, 0.00000, 0.53333 },
   { 0.00000, 0.00000, 0.53333 },
   { 0.00000, 0.00000, 0.53333 },
   { 0.00000, 0.00000, 0.53333 },
   { 0.00000, 0.00000, 0.53333 },
   { 0.00000, 0.00000, 0.53333 },
   { 0.06667, 0.00000, 0.53333 },
   { 0.06667, 0.00000, 0.53333 },
   { 0.06667, 0.00000, 0.53333 },
   { 0.06667, 0.00000, 0.53333 },
   { 0.06667, 0.00000, 0.53333 },
   { 0.06667, 0.00000, 0.53333 },
   { 0.06667, 0.00000, 0.53333 },
   { 0.06667, 0.00000, 0.53333 },
   { 0.13333, 0.00000, 0.53333 },
   { 0.13333, 0.00000, 0.53333 },
   { 0.13333, 0.00000, 0.53333 },
   { 0.13333, 0.00000, 0.53333 },
   { 0.13333, 0.00000, 0.53333 },
   { 0.13333, 0.00000, 0.53333 },
   { 0.13333, 0.00000, 0.53333 },
   { 0.13333, 0.00000, 0.53333 },
   { 0.20000, 0.00000, 0.53333 },
   { 0.20000, 0.00000, 0.53333 },
   { 0.20000, 0.00000, 0.53333 },
   { 0.20000, 0.00000, 0.53333 },
   { 0.20000, 0.00000, 0.53333 },
   { 0.20000, 0.00000, 0.53333 },
   { 0.20000, 0.00000, 0.53333 },
   { 0.20000, 0.00000, 0.53333 },
   { 0.26667, 0.00000, 0.53333 },
   { 0.26667, 0.00000, 0.53333 },
   { 0.26667, 0.00000, 0.53333 },
   { 0.26667, 0.00000, 0.53333 },
   { 0.26667, 0.00000, 0.53333 },
   { 0.26667, 0.00000, 0.53333 },
   { 0.26667, 0.00000, 0.53333 },
   { 0.26667, 0.00000, 0.53333 },
   { 0.33333, 0.00000, 0.53333 },
   { 0.33333, 0.00000, 0.53333 },
   { 0.33333, 0.00000, 0.53333 },
   { 0.33333, 0.00000, 0.53333 },
   { 0.33333, 0.00000, 0.53333 },
   { 0.33333, 0.00000, 0.53333 },
   { 0.33333, 0.00000, 0.53333 },
   { 0.33333, 0.00000, 0.53333 },
   { 0.40000, 0.00000, 0.53333 },
   { 0.40000, 0.00000, 0.53333 },
   { 0.40000, 0.00000, 0.53333 },
   { 0.40000, 0.00000, 0.53333 },
   { 0.40000, 0.00000, 0.53333 },
   { 0.40000, 0.00000, 0.53333 },
   { 0.40000, 0.00000, 0.53333 },
   { 0.40000, 0.00000, 0.53333 },
   { 0.46667, 0.00000, 0.53333 },
   { 0.46667, 0.00000, 0.53333 },
   { 0.46667, 0.00000, 0.53333 },
   { 0.46667, 0.00000, 0.53333 },
   { 0.46667, 0.00000, 0.53333 },
   { 0.46667, 0.00000, 0.53333 },
   { 0.46667, 0.00000, 0.53333 },
   { 0.46667, 0.00000, 0.53333 },
   { 0.53333, 0.00000, 0.53333 },
   { 0.53333, 0.00000, 0.53333 },
   { 0.53333, 0.00000, 0.53333 },
   { 0.53333, 0.00000, 0.53333 },
   { 0.53333, 0.00000, 0.46667 },
   { 0.53333, 0.00000, 0.46667 },
   { 0.53333, 0.00000, 0.46667 },
   { 0.53333, 0.00000, 0.46667 },
   { 0.60000, 0.00000, 0.40000 },
   { 0.60000, 0.00000, 0.40000 },
   { 0.60000, 0.00000, 0.40000 },
   { 0.60000, 0.00000, 0.40000 },
   { 0.60000, 0.00000, 0.33333 },
   { 0.60000, 0.00000, 0.33333 },
   { 0.60000, 0.00000, 0.33333 },
   { 0.60000, 0.00000, 0.33333 },
   { 0.66667, 0.00000, 0.26667 },
   { 0.66667, 0.00000, 0.26667 },
   { 0.66667, 0.00000, 0.26667 },
   { 0.66667, 0.00000, 0.26667 },
   { 0.66667, 0.00000, 0.20000 },
   { 0.66667, 0.00000, 0.20000 },
   { 0.66667, 0.00000, 0.20000 },
   { 0.66667, 0.00000, 0.20000 },
   { 0.73333, 0.00000, 0.13333 },
   { 0.73333, 0.00000, 0.13333 },
   { 0.73333, 0.00000, 0.13333 },
   { 0.73333, 0.00000, 0.13333 },
   { 0.73333, 0.00000, 0.06667 },
   { 0.73333, 0.00000, 0.06667 },
   { 0.73333, 0.00000, 0.06667 },
   { 0.73333, 0.00000, 0.06667 },
   { 0.80000, 0.00000, 0.00000 },
   { 0.80000, 0.00000, 0.00000 },
   { 0.80000, 0.00000, 0.00000 },
   { 0.80000, 0.00000, 0.00000 },
   { 0.80000, 0.00000, 0.00000 },
   { 0.80000, 0.00000, 0.00000 },
   { 0.80000, 0.00000, 0.00000 },
   { 0.80000, 0.00000, 0.00000 },
   { 0.86667, 0.00000, 0.00000 },
   { 0.86667, 0.00000, 0.00000 },
   { 0.86667, 0.00000, 0.00000 },
   { 0.86667, 0.00000, 0.00000 },
   { 0.86667, 0.00000, 0.00000 },
   { 0.86667, 0.00000, 0.00000 },
   { 0.86667, 0.00000, 0.00000 },
   { 0.86667, 0.00000, 0.00000 },
   { 0.93333, 0.00000, 0.00000 },
   { 0.93333, 0.00000, 0.00000 },
   { 0.93333, 0.00000, 0.00000 },
   { 0.93333, 0.00000, 0.00000 },
   { 0.93333, 0.00000, 0.00000 },
   { 0.93333, 0.00000, 0.00000 },
   { 0.93333, 0.00000, 0.00000 },
   { 0.93333, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.06667, 0.00000 },
   { 1.00000, 0.06667, 0.00000 },
   { 1.00000, 0.13333, 0.00000 },
   { 1.00000, 0.13333, 0.00000 },
   { 1.00000, 0.20000, 0.00000 },
   { 1.00000, 0.20000, 0.00000 },
   { 1.00000, 0.26667, 0.00000 },
   { 1.00000, 0.26667, 0.00000 },
   { 1.00000, 0.33333, 0.00000 },
   { 1.00000, 0.33333, 0.00000 },
   { 1.00000, 0.40000, 0.00000 },
   { 1.00000, 0.40000, 0.00000 },
   { 1.00000, 0.46667, 0.00000 },
   { 1.00000, 0.46667, 0.00000 },
   { 1.00000, 0.53333, 0.00000 },
   { 1.00000, 0.53333, 0.00000 },
   { 1.00000, 0.60000, 0.00000 },
   { 1.00000, 0.60000, 0.00000 },
   { 1.00000, 0.66667, 0.00000 },
   { 1.00000, 0.66667, 0.00000 },
   { 1.00000, 0.73333, 0.00000 },
   { 1.00000, 0.73333, 0.00000 },
   { 1.00000, 0.80000, 0.00000 },
   { 1.00000, 0.80000, 0.00000 },
   { 1.00000, 0.86667, 0.00000 },
   { 1.00000, 0.86667, 0.00000 },
   { 1.00000, 0.93333, 0.00000 },
   { 1.00000, 0.93333, 0.00000 },
   { 1.00000, 1.00000, 0.00000 },
   { 1.00000, 1.00000, 0.00000 },
   { 1.00000, 1.00000, 0.00000 },
   { 1.00000, 1.00000, 0.00000 },
   { 1.00000, 1.00000, 0.06667 },
   { 1.00000, 1.00000, 0.06667 },
   { 1.00000, 1.00000, 0.13333 },
   { 1.00000, 1.00000, 0.13333 },
   { 1.00000, 1.00000, 0.20000 },
   { 1.00000, 1.00000, 0.20000 },
   { 1.00000, 1.00000, 0.26667 },
   { 1.00000, 1.00000, 0.26667 },
   { 1.00000, 1.00000, 0.33333 },
   { 1.00000, 1.00000, 0.33333 },
   { 1.00000, 1.00000, 0.40000 },
   { 1.00000, 1.00000, 0.40000 },
   { 1.00000, 1.00000, 0.46667 },
   { 1.00000, 1.00000, 0.46667 },
   { 1.00000, 1.00000, 0.53333 },
   { 1.00000, 1.00000, 0.53333 },
   { 1.00000, 1.00000, 0.60000 },
   { 1.00000, 1.00000, 0.60000 },
   { 1.00000, 1.00000, 0.66667 },
   { 1.00000, 1.00000, 0.66667 },
   { 1.00000, 1.00000, 0.73333 },
   { 1.00000, 1.00000, 0.73333 },
   { 1.00000, 1.00000, 0.80000 },
   { 1.00000, 1.00000, 0.80000 },
   { 1.00000, 1.00000, 0.86667 },
   { 1.00000, 1.00000, 1.00000 },
};
#<

#>            rainbow.h
/* rainbow.h

*/

static	Color_struct	rainbow[] = {
   { 0.00000, 0.00000, 0.01176 },
   { 0.00000, 0.00000, 0.02745 },
   { 0.00000, 0.00000, 0.04314 },
   { 0.00000, 0.00000, 0.05882 },
   { 0.00000, 0.00000, 0.07451 },
   { 0.00000, 0.00000, 0.09020 },
   { 0.00000, 0.00000, 0.10588 },
   { 0.00000, 0.00000, 0.12157 },
   { 0.00000, 0.00000, 0.13725 },
   { 0.00000, 0.00000, 0.15294 },
   { 0.00000, 0.00000, 0.16863 },
   { 0.00000, 0.00000, 0.18431 },
   { 0.00000, 0.00000, 0.20000 },
   { 0.00000, 0.00000, 0.21176 },
   { 0.00000, 0.00000, 0.22745 },
   { 0.00000, 0.00000, 0.24314 },
   { 0.00000, 0.00000, 0.25882 },
   { 0.00000, 0.00000, 0.27451 },
   { 0.00000, 0.00000, 0.29020 },
   { 0.00000, 0.00000, 0.30588 },
   { 0.00000, 0.00000, 0.32157 },
   { 0.00000, 0.00000, 0.33725 },
   { 0.00000, 0.00000, 0.35294 },
   { 0.00000, 0.00000, 0.36863 },
   { 0.00000, 0.00000, 0.38431 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.41176 },
   { 0.00000, 0.00000, 0.42745 },
   { 0.00000, 0.00000, 0.44314 },
   { 0.00000, 0.00000, 0.45882 },
   { 0.00000, 0.00000, 0.47451 },
   { 0.00000, 0.00000, 0.49020 },
   { 0.00000, 0.00000, 0.50588 },
   { 0.00000, 0.00000, 0.52157 },
   { 0.00000, 0.00000, 0.53725 },
   { 0.00000, 0.00000, 0.55294 },
   { 0.00000, 0.00000, 0.56863 },
   { 0.00000, 0.00000, 0.58431 },
   { 0.00000, 0.00000, 0.60000 },
   { 0.00000, 0.00000, 0.61176 },
   { 0.00000, 0.00000, 0.62745 },
   { 0.00000, 0.00000, 0.64314 },
   { 0.00000, 0.00000, 0.65882 },
   { 0.00000, 0.00000, 0.67451 },
   { 0.00000, 0.00000, 0.69020 },
   { 0.00000, 0.00000, 0.70588 },
   { 0.00000, 0.00000, 0.72157 },
   { 0.00000, 0.00000, 0.73725 },
   { 0.00000, 0.00000, 0.75294 },
   { 0.00000, 0.00000, 0.76863 },
   { 0.00000, 0.00000, 0.78431 },
   { 0.00000, 0.00000, 0.80000 },
   { 0.00000, 0.00000, 0.81176 },
   { 0.00000, 0.00000, 0.82745 },
   { 0.00000, 0.00000, 0.84314 },
   { 0.00000, 0.00000, 0.85882 },
   { 0.00000, 0.00000, 0.87451 },
   { 0.00000, 0.00000, 0.89020 },
   { 0.00000, 0.00000, 0.90588 },
   { 0.00000, 0.00000, 0.92157 },
   { 0.00000, 0.00000, 0.93725 },
   { 0.00000, 0.00000, 0.95294 },
   { 0.00000, 0.00000, 0.96863 },
   { 0.00000, 0.00000, 0.98431 },
   { 0.00000, 0.00000, 1.00000 },
   { 0.00000, 0.03529, 1.00000 },
   { 0.00000, 0.07059, 1.00000 },
   { 0.00000, 0.10980, 1.00000 },
   { 0.00000, 0.14510, 1.00000 },
   { 0.00000, 0.18039, 1.00000 },
   { 0.00000, 0.21961, 1.00000 },
   { 0.00000, 0.25490, 1.00000 },
   { 0.00000, 0.29412, 1.00000 },
   { 0.00000, 0.32941, 1.00000 },
   { 0.00000, 0.36471, 1.00000 },
   { 0.00000, 0.40392, 1.00000 },
   { 0.00000, 0.43922, 1.00000 },
   { 0.00000, 0.47843, 1.00000 },
   { 0.00000, 0.50196, 1.00000 },
   { 0.00000, 0.52549, 1.00000 },
   { 0.00000, 0.54902, 1.00000 },
   { 0.00000, 0.57255, 1.00000 },
   { 0.00000, 0.59608, 1.00000 },
   { 0.00000, 0.61961, 1.00000 },
   { 0.00000, 0.64314, 1.00000 },
   { 0.00000, 0.66667, 1.00000 },
   { 0.00000, 0.69020, 1.00000 },
   { 0.00000, 0.71373, 1.00000 },
   { 0.00000, 0.73725, 1.00000 },
   { 0.00000, 0.76078, 1.00000 },
   { 0.00000, 0.78431, 1.00000 },
   { 0.00000, 0.80000, 1.00000 },
   { 0.00000, 0.81569, 1.00000 },
   { 0.00000, 0.83137, 1.00000 },
   { 0.00000, 0.84706, 1.00000 },
   { 0.00000, 0.86667, 1.00000 },
   { 0.00000, 0.88235, 1.00000 },
   { 0.00000, 0.89804, 1.00000 },
   { 0.00000, 0.91373, 1.00000 },
   { 0.00000, 0.93333, 1.00000 },
   { 0.00000, 0.94902, 1.00000 },
   { 0.00000, 0.96471, 1.00000 },
   { 0.00000, 0.98039, 1.00000 },
   { 0.00000, 1.00000, 1.00000 },
   { 0.00000, 1.00000, 0.97647 },
   { 0.00000, 1.00000, 0.95294 },
   { 0.00000, 1.00000, 0.92941 },
   { 0.00000, 1.00000, 0.90588 },
   { 0.00000, 1.00000, 0.88627 },
   { 0.00000, 1.00000, 0.86275 },
   { 0.00000, 1.00000, 0.83922 },
   { 0.00000, 1.00000, 0.81569 },
   { 0.00000, 1.00000, 0.79608 },
   { 0.00000, 1.00000, 0.77255 },
   { 0.00000, 1.00000, 0.74902 },
   { 0.00000, 1.00000, 0.72549 },
   { 0.00000, 1.00000, 0.70588 },
   { 0.00000, 1.00000, 0.65098 },
   { 0.00000, 1.00000, 0.59608 },
   { 0.00000, 1.00000, 0.54118 },
   { 0.00000, 1.00000, 0.48627 },
   { 0.00000, 1.00000, 0.43137 },
   { 0.00000, 1.00000, 0.37647 },
   { 0.00000, 1.00000, 0.32549 },
   { 0.00000, 1.00000, 0.27059 },
   { 0.00000, 1.00000, 0.21569 },
   { 0.00000, 1.00000, 0.16078 },
   { 0.00000, 1.00000, 0.10588 },
   { 0.00000, 1.00000, 0.05098 },
   { 0.00000, 1.00000, 0.00000 },
   { 0.05098, 1.00000, 0.00000 },
   { 0.10588, 1.00000, 0.00000 },
   { 0.16078, 1.00000, 0.00000 },
   { 0.21569, 1.00000, 0.00000 },
   { 0.27059, 1.00000, 0.00000 },
   { 0.32549, 1.00000, 0.00000 },
   { 0.37647, 1.00000, 0.00000 },
   { 0.43137, 1.00000, 0.00000 },
   { 0.48627, 1.00000, 0.00000 },
   { 0.54118, 1.00000, 0.00000 },
   { 0.59608, 1.00000, 0.00000 },
   { 0.65098, 1.00000, 0.00000 },
   { 0.70588, 1.00000, 0.00000 },
   { 0.72549, 1.00000, 0.00000 },
   { 0.74902, 1.00000, 0.00000 },
   { 0.77255, 1.00000, 0.00000 },
   { 0.79608, 1.00000, 0.00000 },
   { 0.81569, 1.00000, 0.00000 },
   { 0.83922, 1.00000, 0.00000 },
   { 0.86275, 1.00000, 0.00000 },
   { 0.88627, 1.00000, 0.00000 },
   { 0.90588, 1.00000, 0.00000 },
   { 0.92941, 1.00000, 0.00000 },
   { 0.95294, 1.00000, 0.00000 },
   { 0.97647, 1.00000, 0.00000 },
   { 1.00000, 1.00000, 0.00000 },
   { 0.99608, 0.97647, 0.00000 },
   { 0.99608, 0.95686, 0.00000 },
   { 0.99608, 0.93333, 0.00000 },
   { 0.99608, 0.91373, 0.00000 },
   { 0.99216, 0.89412, 0.00000 },
   { 0.99216, 0.87059, 0.00000 },
   { 0.99216, 0.85098, 0.00000 },
   { 0.99216, 0.82745, 0.00000 },
   { 0.98824, 0.80784, 0.00000 },
   { 0.98824, 0.78824, 0.00000 },
   { 0.98824, 0.76471, 0.00000 },
   { 0.98824, 0.74510, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.70588, 0.00000 },
   { 0.98824, 0.68627, 0.00000 },
   { 0.98824, 0.66667, 0.00000 },
   { 0.98824, 0.64706, 0.00000 },
   { 0.99216, 0.62745, 0.00000 },
   { 0.99216, 0.60784, 0.00000 },
   { 0.99216, 0.58824, 0.00000 },
   { 0.99216, 0.56863, 0.00000 },
   { 0.99608, 0.54902, 0.00000 },
   { 0.99608, 0.52941, 0.00000 },
   { 0.99608, 0.50980, 0.00000 },
   { 0.99608, 0.49020, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.43137, 0.00000 },
   { 1.00000, 0.39608, 0.00000 },
   { 1.00000, 0.36078, 0.00000 },
   { 1.00000, 0.32549, 0.00000 },
   { 1.00000, 0.28627, 0.00000 },
   { 1.00000, 0.25098, 0.00000 },
   { 1.00000, 0.21569, 0.00000 },
   { 1.00000, 0.18039, 0.00000 },
   { 1.00000, 0.14118, 0.00000 },
   { 1.00000, 0.10588, 0.00000 },
   { 1.00000, 0.07059, 0.00000 },
   { 1.00000, 0.03529, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.05098 },
   { 1.00000, 0.00000, 0.10588 },
   { 1.00000, 0.00000, 0.16078 },
   { 1.00000, 0.00000, 0.21569 },
   { 1.00000, 0.00000, 0.27059 },
   { 1.00000, 0.00000, 0.32549 },
   { 1.00000, 0.00000, 0.37647 },
   { 1.00000, 0.00000, 0.43137 },
   { 1.00000, 0.00000, 0.48627 },
   { 1.00000, 0.00000, 0.54118 },
   { 1.00000, 0.00000, 0.59608 },
   { 1.00000, 0.00000, 0.65098 },
   { 1.00000, 0.00000, 0.70588 },
   { 1.00000, 0.00000, 0.72549 },
   { 1.00000, 0.00000, 0.74902 },
   { 1.00000, 0.00000, 0.77255 },
   { 1.00000, 0.00000, 0.79608 },
   { 1.00000, 0.00000, 0.81569 },
   { 1.00000, 0.00000, 0.83922 },
   { 1.00000, 0.00000, 0.86275 },
   { 1.00000, 0.00000, 0.88627 },
   { 1.00000, 0.00000, 0.90588 },
   { 1.00000, 0.00000, 0.92941 },
   { 1.00000, 0.00000, 0.95294 },
   { 1.00000, 0.00000, 0.97647 },
   { 1.00000, 0.00000, 1.00000 },
   { 1.00000, 0.03529, 1.00000 },
   { 1.00000, 0.07059, 1.00000 },
   { 1.00000, 0.10588, 1.00000 },
   { 1.00000, 0.14118, 1.00000 },
   { 1.00000, 0.18039, 1.00000 },
   { 1.00000, 0.21569, 1.00000 },
   { 1.00000, 0.25098, 1.00000 },
   { 1.00000, 0.28627, 1.00000 },
   { 1.00000, 0.32549, 1.00000 },
   { 1.00000, 0.36078, 1.00000 },
   { 1.00000, 0.39608, 1.00000 },
   { 1.00000, 0.43137, 1.00000 },
   { 1.00000, 0.47059, 1.00000 },
   { 1.00000, 0.48627, 1.00000 },
   { 1.00000, 0.50588, 1.00000 },
   { 1.00000, 0.52157, 1.00000 },
   { 1.00000, 0.54118, 1.00000 },
   { 1.00000, 0.56078, 1.00000 },
   { 1.00000, 0.57647, 1.00000 },
   { 1.00000, 0.59608, 1.00000 },
   { 1.00000, 0.61176, 1.00000 },
   { 1.00000, 0.63137, 1.00000 },
   { 1.00000, 0.65098, 1.00000 },
   { 1.00000, 0.66667, 1.00000 },
   { 1.00000, 0.68627, 1.00000 },
   { 1.00000, 0.70588, 1.00000 },
   { 1.00000, 0.74510, 1.00000 },
   { 1.00000, 0.78824, 1.00000 },
   { 1.00000, 0.83137, 1.00000 },
   { 1.00000, 0.87059, 1.00000 },
   { 1.00000, 0.91373, 1.00000 },
   { 1.00000, 0.95686, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
};
#<

#>            random.h
/* random.h

*/

static	Color_struct	ranlut[] = {
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.47059, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.62745, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 0.78431, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 1.00000, 0.00392 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00392, 0.86275, 0.47059 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.78431, 0.62745 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.70588, 0.78431 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.00000, 0.62745, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.47059, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.23529, 0.00392, 1.00000 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.47059, 0.00392, 0.78431 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.62745, 0.00392, 0.62745 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.78431, 0.00392, 0.47059 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 0.90196, 0.11765, 0.23529 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.23529, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 1.00000, 0.47059, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 0.98039, 0.98039, 0.47059 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
   { 1.00000, 1.00000, 1.00000 },
};
#<

#>            rgb.h
/* rgb.h

*/

static	Color_struct	rgb[] = {
   { 0.00000, 0.00000, 0.00000 },
   { 0.01176, 0.00000, 0.00000 },
   { 0.02745, 0.00000, 0.00000 },
   { 0.04314, 0.00000, 0.00000 },
   { 0.05882, 0.00000, 0.00000 },
   { 0.07451, 0.00000, 0.00000 },
   { 0.08627, 0.00000, 0.00000 },
   { 0.10196, 0.00000, 0.00000 },
   { 0.11765, 0.00000, 0.00000 },
   { 0.13333, 0.00000, 0.00000 },
   { 0.14902, 0.00000, 0.00000 },
   { 0.16078, 0.00000, 0.00000 },
   { 0.17647, 0.00000, 0.00000 },
   { 0.19216, 0.00000, 0.00000 },
   { 0.20784, 0.00000, 0.00000 },
   { 0.22353, 0.00000, 0.00000 },
   { 0.23529, 0.00000, 0.00000 },
   { 0.25098, 0.00000, 0.00000 },
   { 0.26667, 0.00000, 0.00000 },
   { 0.28235, 0.00000, 0.00000 },
   { 0.29804, 0.00000, 0.00000 },
   { 0.30980, 0.00000, 0.00000 },
   { 0.32549, 0.00000, 0.00000 },
   { 0.34118, 0.00000, 0.00000 },
   { 0.35686, 0.00000, 0.00000 },
   { 0.37255, 0.00000, 0.00000 },
   { 0.38431, 0.00000, 0.00000 },
   { 0.40000, 0.00000, 0.00000 },
   { 0.41569, 0.00000, 0.00000 },
   { 0.43137, 0.00000, 0.00000 },
   { 0.44706, 0.00000, 0.00000 },
   { 0.45882, 0.00000, 0.00000 },
   { 0.47451, 0.00000, 0.00000 },
   { 0.49020, 0.00000, 0.00000 },
   { 0.50588, 0.00000, 0.00000 },
   { 0.52157, 0.00000, 0.00000 },
   { 0.53725, 0.00000, 0.00000 },
   { 0.54902, 0.00000, 0.00000 },
   { 0.56471, 0.00000, 0.00000 },
   { 0.58039, 0.00000, 0.00000 },
   { 0.59608, 0.00000, 0.00000 },
   { 0.61176, 0.00000, 0.00000 },
   { 0.62353, 0.00000, 0.00000 },
   { 0.63922, 0.00000, 0.00000 },
   { 0.65490, 0.00000, 0.00000 },
   { 0.67059, 0.00000, 0.00000 },
   { 0.68627, 0.00000, 0.00000 },
   { 0.69804, 0.00000, 0.00000 },
   { 0.71373, 0.00000, 0.00000 },
   { 0.72941, 0.00000, 0.00000 },
   { 0.74510, 0.00000, 0.00000 },
   { 0.76078, 0.00000, 0.00000 },
   { 0.77255, 0.00000, 0.00000 },
   { 0.78824, 0.00000, 0.00000 },
   { 0.80392, 0.00000, 0.00000 },
   { 0.81961, 0.00000, 0.00000 },
   { 0.83529, 0.00000, 0.00000 },
   { 0.84706, 0.00000, 0.00000 },
   { 0.86275, 0.00000, 0.00000 },
   { 0.87843, 0.00000, 0.00000 },
   { 0.89412, 0.00000, 0.00000 },
   { 0.90980, 0.00000, 0.00000 },
   { 0.92157, 0.00000, 0.00000 },
   { 0.93725, 0.00000, 0.00000 },
   { 0.95294, 0.00000, 0.00000 },
   { 0.96863, 0.01176, 0.00000 },
   { 0.98431, 0.02745, 0.00000 },
   { 1.00000, 0.04314, 0.00000 },
   { 0.98431, 0.05882, 0.00000 },
   { 0.96863, 0.07451, 0.00000 },
   { 0.95294, 0.09020, 0.00000 },
   { 0.93725, 0.10588, 0.00000 },
   { 0.92157, 0.12157, 0.00000 },
   { 0.90196, 0.13725, 0.00000 },
   { 0.88627, 0.15294, 0.00000 },
   { 0.87059, 0.16863, 0.00000 },
   { 0.85490, 0.18431, 0.00000 },
   { 0.83922, 0.20000, 0.00000 },
   { 0.82353, 0.21569, 0.00000 },
   { 0.80392, 0.23137, 0.00000 },
   { 0.78824, 0.24706, 0.00000 },
   { 0.77255, 0.26275, 0.00000 },
   { 0.75686, 0.27843, 0.00000 },
   { 0.74118, 0.29412, 0.00000 },
   { 0.72157, 0.30980, 0.00000 },
   { 0.70588, 0.32549, 0.00000 },
   { 0.69020, 0.34118, 0.00000 },
   { 0.67451, 0.35686, 0.00000 },
   { 0.65882, 0.37255, 0.00000 },
   { 0.64314, 0.38824, 0.00000 },
   { 0.62353, 0.40392, 0.00000 },
   { 0.60784, 0.41961, 0.00000 },
   { 0.59216, 0.43529, 0.00000 },
   { 0.57647, 0.45098, 0.00000 },
   { 0.56078, 0.46667, 0.00000 },
   { 0.54118, 0.48235, 0.00000 },
   { 0.52549, 0.49804, 0.00000 },
   { 0.50980, 0.51373, 0.00000 },
   { 0.49412, 0.52941, 0.00000 },
   { 0.47843, 0.54510, 0.00000 },
   { 0.46275, 0.56078, 0.00000 },
   { 0.44314, 0.57647, 0.00000 },
   { 0.42745, 0.59216, 0.00000 },
   { 0.41176, 0.60784, 0.00000 },
   { 0.39608, 0.62353, 0.00000 },
   { 0.38039, 0.63922, 0.00000 },
   { 0.36078, 0.65490, 0.00000 },
   { 0.34510, 0.67059, 0.00000 },
   { 0.32941, 0.68627, 0.00000 },
   { 0.31373, 0.70196, 0.00000 },
   { 0.29804, 0.71765, 0.00000 },
   { 0.28235, 0.73333, 0.00000 },
   { 0.26275, 0.74902, 0.00000 },
   { 0.24706, 0.76471, 0.00000 },
   { 0.23137, 0.78039, 0.00000 },
   { 0.21569, 0.79608, 0.00000 },
   { 0.20000, 0.81176, 0.00000 },
   { 0.18039, 0.82745, 0.00000 },
   { 0.16471, 0.84314, 0.00000 },
   { 0.14902, 0.85882, 0.00000 },
   { 0.13333, 0.87451, 0.00000 },
   { 0.11765, 0.89020, 0.00000 },
   { 0.10196, 0.90588, 0.00000 },
   { 0.08235, 0.92157, 0.00000 },
   { 0.06667, 0.93725, 0.00000 },
   { 0.05098, 0.95294, 0.00000 },
   { 0.03529, 0.96863, 0.00000 },
   { 0.01961, 0.98431, 0.01176 },
   { 0.00000, 1.00000, 0.02745 },
   { 0.00000, 0.98431, 0.04314 },
   { 0.00000, 0.96863, 0.05882 },
   { 0.00000, 0.95294, 0.07451 },
   { 0.00000, 0.93725, 0.09020 },
   { 0.00000, 0.92157, 0.10588 },
   { 0.00000, 0.90588, 0.11765 },
   { 0.00000, 0.89020, 0.13333 },
   { 0.00000, 0.87451, 0.14902 },
   { 0.00000, 0.85882, 0.16471 },
   { 0.00000, 0.84314, 0.18039 },
   { 0.00000, 0.82745, 0.19608 },
   { 0.00000, 0.81176, 0.21176 },
   { 0.00000, 0.79608, 0.22353 },
   { 0.00000, 0.78039, 0.23922 },
   { 0.00000, 0.76471, 0.25490 },
   { 0.00000, 0.74902, 0.27059 },
   { 0.00000, 0.73333, 0.28627 },
   { 0.00000, 0.71765, 0.30196 },
   { 0.00000, 0.70196, 0.31765 },
   { 0.00000, 0.68627, 0.33333 },
   { 0.00000, 0.66667, 0.34510 },
   { 0.00000, 0.65098, 0.36078 },
   { 0.00000, 0.63529, 0.37647 },
   { 0.00000, 0.61961, 0.39216 },
   { 0.00000, 0.60392, 0.40784 },
   { 0.00000, 0.58824, 0.42353 },
   { 0.00000, 0.57255, 0.43922 },
   { 0.00000, 0.55686, 0.45098 },
   { 0.00000, 0.54118, 0.46667 },
   { 0.00000, 0.52549, 0.48235 },
   { 0.00000, 0.50980, 0.49804 },
   { 0.00000, 0.49412, 0.51373 },
   { 0.00000, 0.47843, 0.52941 },
   { 0.00000, 0.46275, 0.54510 },
   { 0.00000, 0.44706, 0.55686 },
   { 0.00000, 0.43137, 0.57255 },
   { 0.00000, 0.41569, 0.58824 },
   { 0.00000, 0.40000, 0.60392 },
   { 0.00000, 0.38431, 0.61961 },
   { 0.00000, 0.36863, 0.63529 },
   { 0.00000, 0.35294, 0.65098 },
   { 0.00000, 0.33333, 0.66667 },
   { 0.00000, 0.31765, 0.67843 },
   { 0.00000, 0.30196, 0.69412 },
   { 0.00000, 0.28627, 0.70980 },
   { 0.00000, 0.27059, 0.72549 },
   { 0.00000, 0.25490, 0.74118 },
   { 0.00000, 0.23922, 0.75686 },
   { 0.00000, 0.22353, 0.77255 },
   { 0.00000, 0.20784, 0.78431 },
   { 0.00000, 0.19216, 0.80000 },
   { 0.00000, 0.17647, 0.81569 },
   { 0.00000, 0.16078, 0.83137 },
   { 0.00000, 0.14510, 0.84706 },
   { 0.00000, 0.12941, 0.86275 },
   { 0.00000, 0.11373, 0.87843 },
   { 0.00000, 0.09804, 0.89020 },
   { 0.00000, 0.08235, 0.90588 },
   { 0.00000, 0.06667, 0.92157 },
   { 0.00000, 0.05098, 0.93725 },
   { 0.00000, 0.03529, 0.95294 },
   { 0.00000, 0.01961, 0.96863 },
   { 0.00000, 0.00000, 0.98431 },
   { 0.00000, 0.00000, 1.00000 },
   { 0.00000, 0.00000, 0.98431 },
   { 0.00000, 0.00000, 0.96863 },
   { 0.00000, 0.00000, 0.95294 },
   { 0.00000, 0.00000, 0.93725 },
   { 0.00000, 0.00000, 0.92157 },
   { 0.00000, 0.00000, 0.90588 },
   { 0.00000, 0.00000, 0.89020 },
   { 0.00000, 0.00000, 0.87451 },
   { 0.00000, 0.00000, 0.85882 },
   { 0.00000, 0.00000, 0.84314 },
   { 0.00000, 0.00000, 0.82745 },
   { 0.00000, 0.00000, 0.81176 },
   { 0.00000, 0.00000, 0.79608 },
   { 0.00000, 0.00000, 0.78039 },
   { 0.00000, 0.00000, 0.76471 },
   { 0.00000, 0.00000, 0.74902 },
   { 0.00000, 0.00000, 0.73333 },
   { 0.00000, 0.00000, 0.71765 },
   { 0.00000, 0.00000, 0.70196 },
   { 0.00000, 0.00000, 0.68627 },
   { 0.00000, 0.00000, 0.66667 },
   { 0.00000, 0.00000, 0.65098 },
   { 0.00000, 0.00000, 0.63529 },
   { 0.00000, 0.00000, 0.61961 },
   { 0.00000, 0.00000, 0.60392 },
   { 0.00000, 0.00000, 0.58824 },
   { 0.00000, 0.00000, 0.57255 },
   { 0.00000, 0.00000, 0.55686 },
   { 0.00000, 0.00000, 0.54118 },
   { 0.00000, 0.00000, 0.52549 },
   { 0.00000, 0.00000, 0.50980 },
   { 0.00000, 0.00000, 0.49412 },
   { 0.00000, 0.00000, 0.47843 },
   { 0.00000, 0.00000, 0.46275 },
   { 0.00000, 0.00000, 0.44706 },
   { 0.00000, 0.00000, 0.43137 },
   { 0.00000, 0.00000, 0.41569 },
   { 0.00000, 0.00000, 0.40000 },
   { 0.00000, 0.00000, 0.38431 },
   { 0.00000, 0.00000, 0.36863 },
   { 0.00000, 0.00000, 0.35294 },
   { 0.00000, 0.00000, 0.33333 },
   { 0.00000, 0.00000, 0.31765 },
   { 0.00000, 0.00000, 0.30196 },
   { 0.00000, 0.00000, 0.28627 },
   { 0.00000, 0.00000, 0.27059 },
   { 0.00000, 0.00000, 0.25490 },
   { 0.00000, 0.00000, 0.23922 },
   { 0.00000, 0.00000, 0.22353 },
   { 0.00000, 0.00000, 0.20784 },
   { 0.00000, 0.00000, 0.19216 },
   { 0.00000, 0.00000, 0.17647 },
   { 0.00000, 0.00000, 0.16078 },
   { 0.00000, 0.00000, 0.14510 },
   { 0.00000, 0.00000, 0.12941 },
   { 0.00000, 0.00000, 0.11373 },
   { 0.00000, 0.00000, 0.09804 },
   { 0.00000, 0.00000, 0.08235 },
   { 0.00000, 0.00000, 0.06667 },
   { 0.00000, 0.00000, 0.05098 },
   { 0.00000, 0.00000, 0.03529 },
   { 0.00000, 0.00000, 0.01961 },
   { 0.00000, 0.00000, 0.00000 },
};
#<

#>            smooth.h
/* smooth.h

*/

static	Color_struct	smooth[] = {
   { 0.00000, 0.00000, 1.00000 },
   { 0.01569, 0.00000, 0.98431 },
   { 0.03529, 0.00000, 0.96471 },
   { 0.05098, 0.00000, 0.94902 },
   { 0.06667, 0.00000, 0.93333 },
   { 0.08627, 0.00000, 0.91373 },
   { 0.10196, 0.00000, 0.89804 },
   { 0.11765, 0.00000, 0.88235 },
   { 0.13725, 0.00000, 0.86275 },
   { 0.15294, 0.00000, 0.84706 },
   { 0.16863, 0.00000, 0.83137 },
   { 0.18824, 0.00000, 0.81176 },
   { 0.20392, 0.00000, 0.79608 },
   { 0.21961, 0.00000, 0.78039 },
   { 0.23922, 0.00000, 0.76078 },
   { 0.25490, 0.00000, 0.74510 },
   { 0.27059, 0.00000, 0.72941 },
   { 0.28627, 0.00000, 0.71373 },
   { 0.30588, 0.00000, 0.69412 },
   { 0.32157, 0.00000, 0.67843 },
   { 0.33725, 0.00000, 0.66275 },
   { 0.35686, 0.00000, 0.64314 },
   { 0.37255, 0.00000, 0.62745 },
   { 0.38824, 0.00000, 0.61176 },
   { 0.40784, 0.00000, 0.59216 },
   { 0.42353, 0.00000, 0.57647 },
   { 0.43922, 0.00000, 0.56078 },
   { 0.45882, 0.00000, 0.54118 },
   { 0.47451, 0.00000, 0.52549 },
   { 0.49020, 0.00000, 0.50980 },
   { 0.50980, 0.00000, 0.49020 },
   { 0.52549, 0.00000, 0.47451 },
   { 0.54118, 0.00000, 0.45882 },
   { 0.56078, 0.00000, 0.43922 },
   { 0.57647, 0.00000, 0.42353 },
   { 0.59216, 0.00000, 0.40784 },
   { 0.61176, 0.00000, 0.38824 },
   { 0.62745, 0.00000, 0.37255 },
   { 0.64314, 0.00000, 0.35686 },
   { 0.66275, 0.00000, 0.33725 },
   { 0.67843, 0.00000, 0.32157 },
   { 0.69412, 0.00000, 0.30588 },
   { 0.71373, 0.00000, 0.28627 },
   { 0.72941, 0.00000, 0.27059 },
   { 0.74510, 0.00000, 0.25490 },
   { 0.76078, 0.00000, 0.23922 },
   { 0.78039, 0.00000, 0.21961 },
   { 0.79608, 0.00000, 0.20392 },
   { 0.81176, 0.00000, 0.18824 },
   { 0.83137, 0.00000, 0.16863 },
   { 0.84706, 0.00000, 0.15294 },
   { 0.86275, 0.00000, 0.13725 },
   { 0.88235, 0.00000, 0.11765 },
   { 0.89804, 0.00000, 0.10196 },
   { 0.91373, 0.00000, 0.08627 },
   { 0.93333, 0.00000, 0.06667 },
   { 0.94902, 0.00000, 0.05098 },
   { 0.96471, 0.00000, 0.03529 },
   { 0.98431, 0.00000, 0.01569 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.00000, 0.00000 },
   { 1.00000, 0.01176, 0.00000 },
   { 1.00000, 0.01961, 0.00000 },
   { 1.00000, 0.03137, 0.00000 },
   { 1.00000, 0.03922, 0.00000 },
   { 1.00000, 0.05098, 0.00000 },
   { 1.00000, 0.05882, 0.00000 },
   { 1.00000, 0.07059, 0.00000 },
   { 1.00000, 0.08235, 0.00000 },
   { 1.00000, 0.09020, 0.00000 },
   { 1.00000, 0.10196, 0.00000 },
   { 1.00000, 0.10980, 0.00000 },
   { 1.00000, 0.12157, 0.00000 },
   { 1.00000, 0.12941, 0.00000 },
   { 1.00000, 0.14118, 0.00000 },
   { 0.99608, 0.15294, 0.00000 },
   { 0.99608, 0.16078, 0.00000 },
   { 0.99608, 0.17255, 0.00000 },
   { 0.99608, 0.18039, 0.00000 },
   { 0.99608, 0.19216, 0.00000 },
   { 0.99608, 0.20392, 0.00000 },
   { 0.99608, 0.21176, 0.00000 },
   { 0.99608, 0.22353, 0.00000 },
   { 0.99608, 0.23137, 0.00000 },
   { 0.99608, 0.24314, 0.00000 },
   { 0.99608, 0.25098, 0.00000 },
   { 0.99608, 0.26275, 0.00000 },
   { 0.99608, 0.27451, 0.00000 },
   { 0.99608, 0.28235, 0.00000 },
   { 0.99608, 0.29412, 0.00000 },
   { 0.99608, 0.30196, 0.00000 },
   { 0.99608, 0.31373, 0.00000 },
   { 0.99608, 0.32157, 0.00000 },
   { 0.99608, 0.33333, 0.00000 },
   { 0.99608, 0.34510, 0.00000 },
   { 0.99608, 0.35294, 0.00000 },
   { 0.99608, 0.36471, 0.00000 },
   { 0.99608, 0.37255, 0.00000 },
   { 0.99608, 0.38431, 0.00000 },
   { 0.99608, 0.39216, 0.00000 },
   { 0.99608, 0.40392, 0.00000 },
   { 0.99608, 0.41569, 0.00000 },
   { 0.99608, 0.42353, 0.00000 },
   { 0.99608, 0.43529, 0.00000 },
   { 0.99608, 0.44314, 0.00000 },
   { 0.99216, 0.45490, 0.00000 },
   { 0.99216, 0.46667, 0.00000 },
   { 0.99216, 0.47451, 0.00000 },
   { 0.99216, 0.48627, 0.00000 },
   { 0.99216, 0.49412, 0.00000 },
   { 0.99216, 0.50588, 0.00000 },
   { 0.99216, 0.51373, 0.00000 },
   { 0.99216, 0.52549, 0.00000 },
   { 0.99216, 0.53725, 0.00000 },
   { 0.99216, 0.54510, 0.00000 },
   { 0.99216, 0.55686, 0.00000 },
   { 0.99216, 0.56471, 0.00000 },
   { 0.99216, 0.57647, 0.00000 },
   { 0.99216, 0.58431, 0.00000 },
   { 0.99216, 0.59608, 0.00000 },
   { 0.99216, 0.60000, 0.00000 },
   { 0.99216, 0.60784, 0.00000 },
   { 0.99216, 0.61176, 0.00000 },
   { 0.99216, 0.61569, 0.00000 },
   { 0.99216, 0.61961, 0.00000 },
   { 0.99216, 0.62745, 0.00000 },
   { 0.99216, 0.63137, 0.00000 },
   { 0.99216, 0.63529, 0.00000 },
   { 0.99216, 0.64314, 0.00000 },
   { 0.98824, 0.64706, 0.00000 },
   { 0.98824, 0.65098, 0.00000 },
   { 0.98824, 0.65882, 0.00000 },
   { 0.98824, 0.66275, 0.00000 },
   { 0.98824, 0.66667, 0.00000 },
   { 0.98824, 0.67451, 0.00000 },
   { 0.98824, 0.67843, 0.00000 },
   { 0.98824, 0.68235, 0.00000 },
   { 0.98824, 0.68627, 0.00000 },
   { 0.98824, 0.69412, 0.00000 },
   { 0.98824, 0.69804, 0.00000 },
   { 0.98824, 0.70196, 0.00000 },
   { 0.98824, 0.70980, 0.00000 },
   { 0.98824, 0.71373, 0.00000 },
   { 0.98824, 0.71765, 0.00000 },
   { 0.98824, 0.72549, 0.00000 },
   { 0.98824, 0.72941, 0.00000 },
   { 0.98824, 0.73333, 0.00000 },
   { 0.98824, 0.73725, 0.00000 },
   { 0.98824, 0.74510, 0.00000 },
   { 0.98824, 0.74902, 0.00000 },
   { 0.98431, 0.75294, 0.00000 },
   { 0.98431, 0.76078, 0.00000 },
   { 0.98431, 0.76471, 0.00000 },
   { 0.98431, 0.76863, 0.00000 },
   { 0.98431, 0.77255, 0.00000 },
   { 0.98431, 0.78039, 0.00000 },
   { 0.98431, 0.78431, 0.00000 },
   { 0.98431, 0.78824, 0.00000 },
   { 0.98431, 0.79608, 0.00000 },
   { 0.98431, 0.80000, 0.00000 },
   { 0.98431, 0.80392, 0.00000 },
   { 0.98431, 0.81176, 0.00000 },
   { 0.98431, 0.81569, 0.00000 },
   { 0.98431, 0.81961, 0.00000 },
   { 0.98431, 0.82745, 0.00000 },
   { 0.98431, 0.83137, 0.00000 },
   { 0.98431, 0.83529, 0.00000 },
   { 0.98431, 0.83922, 0.00000 },
   { 0.98431, 0.84706, 0.00000 },
   { 0.98431, 0.85098, 0.00000 },
   { 0.98039, 0.85490, 0.00000 },
   { 0.98039, 0.86275, 0.00000 },
   { 0.98039, 0.86667, 0.00000 },
   { 0.98039, 0.87059, 0.00000 },
   { 0.98039, 0.87843, 0.00000 },
   { 0.98039, 0.88235, 0.00000 },
   { 0.98039, 0.88627, 0.00000 },
   { 0.98039, 0.89020, 0.00000 },
   { 0.98039, 0.89804, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.98039, 0.90196, 0.00000 },
   { 0.96471, 0.88627, 0.00000 },
   { 0.94902, 0.87059, 0.00000 },
   { 0.92941, 0.85490, 0.00000 },
   { 0.91373, 0.83922, 0.00000 },
   { 0.89804, 0.82745, 0.00000 },
   { 0.88235, 0.81176, 0.00000 },
   { 0.86275, 0.79608, 0.00000 },
   { 0.84706, 0.78039, 0.00000 },
   { 0.83137, 0.76471, 0.00000 },
   { 0.81569, 0.74902, 0.00000 },
   { 0.79608, 0.73333, 0.00000 },
   { 0.78039, 0.71765, 0.00000 },
   { 0.76471, 0.70196, 0.00000 },
   { 0.74902, 0.68627, 0.00000 },
   { 0.72941, 0.67451, 0.00000 },
   { 0.71373, 0.65882, 0.00000 },
   { 0.69804, 0.64314, 0.00000 },
   { 0.68235, 0.62745, 0.00000 },
   { 0.66275, 0.61176, 0.00000 },
   { 0.64706, 0.59608, 0.00000 },
   { 0.63137, 0.58039, 0.00000 },
   { 0.61569, 0.56471, 0.00000 },
   { 0.60000, 0.54902, 0.00000 },
   { 0.58039, 0.53333, 0.00000 },
   { 0.56471, 0.52157, 0.00000 },
   { 0.54902, 0.50588, 0.00000 },
   { 0.53333, 0.49020, 0.00000 },
   { 0.51373, 0.47451, 0.00000 },
   { 0.49804, 0.45882, 0.00000 },
   { 0.48235, 0.44314, 0.00000 },
   { 0.46667, 0.42745, 0.00000 },
   { 0.44706, 0.41176, 0.00000 },
   { 0.43137, 0.39608, 0.00000 },
   { 0.41569, 0.38039, 0.00000 },
   { 0.40000, 0.36863, 0.00000 },
   { 0.38039, 0.35294, 0.00000 },
   { 0.36471, 0.33725, 0.00000 },
   { 0.34902, 0.32157, 0.00000 },
   { 0.33333, 0.30588, 0.00000 },
   { 0.31765, 0.29020, 0.00000 },
   { 0.29804, 0.27451, 0.00000 },
   { 0.28235, 0.25882, 0.00000 },
   { 0.26667, 0.24314, 0.00000 },
   { 0.25098, 0.22745, 0.00000 },
   { 0.23137, 0.21569, 0.00000 },
   { 0.21569, 0.20000, 0.00000 },
   { 0.20000, 0.18431, 0.00000 },
   { 0.18431, 0.16863, 0.00000 },
   { 0.16471, 0.15294, 0.00000 },
   { 0.14902, 0.13725, 0.00000 },
   { 0.13333, 0.12157, 0.00000 },
   { 0.11765, 0.10588, 0.00000 },
   { 0.09804, 0.09020, 0.00000 },
   { 0.08235, 0.07451, 0.00000 },
   { 0.06667, 0.06275, 0.00000 },
   { 0.05098, 0.04706, 0.00000 },
   { 0.03137, 0.03137, 0.00000 },
   { 0.01569, 0.01569, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
   { 0.00000, 0.00000, 0.00000 },
};
#<

#>            staircase.h
/* staircase.h

*/

static	Color_struct staircase[] = {
   { 0.00392, 0.00392, 0.31373 },
   { 0.00784, 0.00784, 0.31373 },
   { 0.01176, 0.01176, 0.31373 },
   { 0.01569, 0.01569, 0.31373 },
   { 0.01961, 0.01961, 0.31373 },
   { 0.02353, 0.02353, 0.31373 },
   { 0.02745, 0.02745, 0.31373 },
   { 0.03137, 0.03137, 0.31373 },
   { 0.03529, 0.03529, 0.31373 },
   { 0.03922, 0.03922, 0.31373 },
   { 0.04314, 0.04314, 0.31373 },
   { 0.04706, 0.04706, 0.31373 },
   { 0.05098, 0.05098, 0.31373 },
   { 0.05490, 0.05490, 0.31373 },
   { 0.05882, 0.05882, 0.31373 },
   { 0.06275, 0.06275, 0.31373 },
   { 0.06667, 0.06667, 0.47059 },
   { 0.07059, 0.07059, 0.47059 },
   { 0.07451, 0.07451, 0.47059 },
   { 0.07843, 0.07843, 0.47059 },
   { 0.08235, 0.08235, 0.47059 },
   { 0.08627, 0.08627, 0.47059 },
   { 0.09020, 0.09020, 0.47059 },
   { 0.09412, 0.09412, 0.47059 },
   { 0.09804, 0.09804, 0.47059 },
   { 0.10196, 0.10196, 0.47059 },
   { 0.10588, 0.10588, 0.47059 },
   { 0.10980, 0.10980, 0.47059 },
   { 0.11373, 0.11373, 0.47059 },
   { 0.11765, 0.11765, 0.47059 },
   { 0.12157, 0.12157, 0.47059 },
   { 0.12549, 0.12549, 0.47059 },
   { 0.12941, 0.12941, 0.62745 },
   { 0.13333, 0.13333, 0.62745 },
   { 0.13725, 0.13725, 0.62745 },
   { 0.14118, 0.14118, 0.62745 },
   { 0.14510, 0.14510, 0.62745 },
   { 0.14902, 0.14902, 0.62745 },
   { 0.15294, 0.15294, 0.62745 },
   { 0.15686, 0.15686, 0.62745 },
   { 0.16078, 0.16078, 0.62745 },
   { 0.16471, 0.16471, 0.62745 },
   { 0.16863, 0.16863, 0.62745 },
   { 0.17255, 0.17255, 0.62745 },
   { 0.17647, 0.17647, 0.62745 },
   { 0.18039, 0.18039, 0.62745 },
   { 0.18431, 0.18431, 0.62745 },
   { 0.18824, 0.18824, 0.62745 },
   { 0.19216, 0.19216, 0.78431 },
   { 0.19608, 0.19608, 0.78431 },
   { 0.20000, 0.20000, 0.78431 },
   { 0.20392, 0.20392, 0.78431 },
   { 0.20784, 0.20784, 0.78431 },
   { 0.21176, 0.21176, 0.78431 },
   { 0.21569, 0.21569, 0.78431 },
   { 0.21961, 0.21961, 0.78431 },
   { 0.22353, 0.22353, 0.78431 },
   { 0.22745, 0.22745, 0.78431 },
   { 0.23137, 0.23137, 0.78431 },
   { 0.23529, 0.23529, 0.78431 },
   { 0.23922, 0.23922, 0.78431 },
   { 0.24314, 0.24314, 0.78431 },
   { 0.24706, 0.24706, 0.78431 },
   { 0.25098, 0.25098, 0.78431 },
   { 0.25490, 0.25490, 0.94118 },
   { 0.25882, 0.25882, 0.94118 },
   { 0.26275, 0.26275, 0.94118 },
   { 0.26667, 0.26667, 0.94118 },
   { 0.27059, 0.27059, 0.94118 },
   { 0.27451, 0.27451, 0.94118 },
   { 0.27843, 0.27843, 0.94118 },
   { 0.28235, 0.28235, 0.94118 },
   { 0.28627, 0.28627, 0.94118 },
   { 0.29020, 0.29020, 0.94118 },
   { 0.29412, 0.29412, 0.94118 },
   { 0.29804, 0.29804, 0.94118 },
   { 0.30196, 0.30196, 0.94118 },
   { 0.30588, 0.30588, 0.94118 },
   { 0.30980, 0.30980, 0.94118 },
   { 0.31373, 0.31373, 0.94118 },
   { 0.31765, 0.31765, 0.95294 },
   { 0.32157, 0.32157, 0.96471 },
   { 0.32549, 0.32549, 0.97647 },
   { 0.32941, 0.32941, 0.98824 },
   { 0.33333, 0.33333, 1.00000 },
   { 0.00392, 0.31373, 0.00392 },
   { 0.00784, 0.31373, 0.00784 },
   { 0.01176, 0.31373, 0.01176 },
   { 0.01569, 0.31373, 0.01569 },
   { 0.01961, 0.31373, 0.01961 },
   { 0.02353, 0.31373, 0.02353 },
   { 0.02745, 0.31373, 0.02745 },
   { 0.03137, 0.31373, 0.03137 },
   { 0.03529, 0.31373, 0.03529 },
   { 0.03922, 0.31373, 0.03922 },
   { 0.04314, 0.31373, 0.04314 },
   { 0.04706, 0.31373, 0.04706 },
   { 0.05098, 0.31373, 0.05098 },
   { 0.05490, 0.31373, 0.05490 },
   { 0.05882, 0.31373, 0.05882 },
   { 0.06275, 0.31373, 0.06275 },
   { 0.06667, 0.47059, 0.06667 },
   { 0.07059, 0.47059, 0.07059 },
   { 0.07451, 0.47059, 0.07451 },
   { 0.07843, 0.47059, 0.07843 },
   { 0.08235, 0.47059, 0.08235 },
   { 0.08627, 0.47059, 0.08627 },
   { 0.09020, 0.47059, 0.09020 },
   { 0.09412, 0.47059, 0.09412 },
   { 0.09804, 0.47059, 0.09804 },
   { 0.10196, 0.47059, 0.10196 },
   { 0.10588, 0.47059, 0.10588 },
   { 0.10980, 0.47059, 0.10980 },
   { 0.11373, 0.47059, 0.11373 },
   { 0.11765, 0.47059, 0.11765 },
   { 0.12157, 0.47059, 0.12157 },
   { 0.12549, 0.47059, 0.12549 },
   { 0.12941, 0.62745, 0.12941 },
   { 0.13333, 0.62745, 0.13333 },
   { 0.13725, 0.62745, 0.13725 },
   { 0.14118, 0.62745, 0.14118 },
   { 0.14510, 0.62745, 0.14510 },
   { 0.14902, 0.62745, 0.14902 },
   { 0.15294, 0.62745, 0.15294 },
   { 0.15686, 0.62745, 0.15686 },
   { 0.16078, 0.62745, 0.16078 },
   { 0.16471, 0.62745, 0.16471 },
   { 0.16863, 0.62745, 0.16863 },
   { 0.17255, 0.62745, 0.17255 },
   { 0.17647, 0.62745, 0.17647 },
   { 0.18039, 0.62745, 0.18039 },
   { 0.18431, 0.62745, 0.18431 },
   { 0.18824, 0.62745, 0.18824 },
   { 0.19216, 0.78431, 0.19216 },
   { 0.19608, 0.78431, 0.19608 },
   { 0.20000, 0.78431, 0.20000 },
   { 0.20392, 0.78431, 0.20392 },
   { 0.20784, 0.78431, 0.20784 },
   { 0.21176, 0.78431, 0.21176 },
   { 0.21569, 0.78431, 0.21569 },
   { 0.21961, 0.78431, 0.21961 },
   { 0.22353, 0.78431, 0.22353 },
   { 0.22745, 0.78431, 0.22745 },
   { 0.23137, 0.78431, 0.23137 },
   { 0.23529, 0.78431, 0.23529 },
   { 0.23922, 0.78431, 0.23922 },
   { 0.24314, 0.78431, 0.24314 },
   { 0.24706, 0.78431, 0.24706 },
   { 0.25098, 0.78431, 0.25098 },
   { 0.25490, 0.94118, 0.25490 },
   { 0.25882, 0.94118, 0.25882 },
   { 0.26275, 0.94118, 0.26275 },
   { 0.26667, 0.94118, 0.26667 },
   { 0.27059, 0.94118, 0.27059 },
   { 0.27451, 0.94118, 0.27451 },
   { 0.27843, 0.94118, 0.27843 },
   { 0.28235, 0.94118, 0.28235 },
   { 0.28627, 0.94118, 0.28627 },
   { 0.29020, 0.94118, 0.29020 },
   { 0.29412, 0.94118, 0.29412 },
   { 0.29804, 0.94118, 0.29804 },
   { 0.30196, 0.94118, 0.30196 },
   { 0.30588, 0.94118, 0.30588 },
   { 0.30980, 0.94118, 0.30980 },
   { 0.31373, 0.94118, 0.31373 },
   { 0.31765, 0.95294, 0.31765 },
   { 0.32157, 0.96471, 0.32157 },
   { 0.32549, 0.97647, 0.32549 },
   { 0.32941, 0.98824, 0.32941 },
   { 0.33333, 1.00000, 0.33333 },
   { 0.31373, 0.00392, 0.00392 },
   { 0.31373, 0.00784, 0.00784 },
   { 0.31373, 0.01176, 0.01176 },
   { 0.31373, 0.01569, 0.01569 },
   { 0.31373, 0.01961, 0.01961 },
   { 0.31373, 0.02353, 0.02353 },
   { 0.31373, 0.02745, 0.02745 },
   { 0.31373, 0.03137, 0.03137 },
   { 0.31373, 0.03529, 0.03529 },
   { 0.31373, 0.03922, 0.03922 },
   { 0.31373, 0.04314, 0.04314 },
   { 0.31373, 0.04706, 0.04706 },
   { 0.31373, 0.05098, 0.05098 },
   { 0.31373, 0.05490, 0.05490 },
   { 0.31373, 0.05882, 0.05882 },
   { 0.31373, 0.06275, 0.06275 },
   { 0.47059, 0.06667, 0.06667 },
   { 0.47059, 0.07059, 0.07059 },
   { 0.47059, 0.07451, 0.07451 },
   { 0.47059, 0.07843, 0.07843 },
   { 0.47059, 0.08235, 0.08235 },
   { 0.47059, 0.08627, 0.08627 },
   { 0.47059, 0.09020, 0.09020 },
   { 0.47059, 0.09412, 0.09412 },
   { 0.47059, 0.09804, 0.09804 },
   { 0.47059, 0.10196, 0.10196 },
   { 0.47059, 0.10588, 0.10588 },
   { 0.47059, 0.10980, 0.10980 },
   { 0.47059, 0.11373, 0.11373 },
   { 0.47059, 0.11765, 0.11765 },
   { 0.47059, 0.12157, 0.12157 },
   { 0.47059, 0.12549, 0.12549 },
   { 0.62745, 0.12941, 0.12941 },
   { 0.62745, 0.13333, 0.13333 },
   { 0.62745, 0.13725, 0.13725 },
   { 0.62745, 0.14118, 0.14118 },
   { 0.62745, 0.14510, 0.14510 },
   { 0.62745, 0.14902, 0.14902 },
   { 0.62745, 0.15294, 0.15294 },
   { 0.62745, 0.15686, 0.15686 },
   { 0.62745, 0.16078, 0.16078 },
   { 0.62745, 0.16471, 0.16471 },
   { 0.62745, 0.16863, 0.16863 },
   { 0.62745, 0.17255, 0.17255 },
   { 0.62745, 0.17647, 0.17647 },
   { 0.62745, 0.18039, 0.18039 },
   { 0.62745, 0.18431, 0.18431 },
   { 0.62745, 0.18824, 0.18824 },
   { 0.78431, 0.19216, 0.19216 },
   { 0.78431, 0.19608, 0.19608 },
   { 0.78431, 0.20000, 0.20000 },
   { 0.78431, 0.20392, 0.20392 },
   { 0.78431, 0.20784, 0.20784 },
   { 0.78431, 0.21176, 0.21176 },
   { 0.78431, 0.21569, 0.21569 },
   { 0.78431, 0.21961, 0.21961 },
   { 0.78431, 0.22353, 0.22353 },
   { 0.78431, 0.22745, 0.22745 },
   { 0.78431, 0.23137, 0.23137 },
   { 0.78431, 0.23529, 0.23529 },
   { 0.78431, 0.23922, 0.23922 },
   { 0.78431, 0.24314, 0.24314 },
   { 0.78431, 0.24706, 0.24706 },
   { 0.78431, 0.25098, 0.25098 },
   { 0.94118, 0.25490, 0.25490 },
   { 0.94118, 0.25882, 0.25882 },
   { 0.94118, 0.26275, 0.26275 },
   { 0.94118, 0.26667, 0.26667 },
   { 0.94118, 0.27059, 0.27059 },
   { 0.94118, 0.27451, 0.27451 },
   { 0.94118, 0.27843, 0.27843 },
   { 0.94118, 0.28235, 0.28235 },
   { 0.94118, 0.28627, 0.28627 },
   { 0.94118, 0.29020, 0.29020 },
   { 0.94118, 0.29412, 0.29412 },
   { 0.94118, 0.29804, 0.29804 },
   { 0.94118, 0.30196, 0.30196 },
   { 0.94118, 0.30588, 0.30588 },
   { 0.94118, 0.30980, 0.30980 },
   { 0.94118, 0.31373, 0.31373 },
   { 0.94902, 0.39216, 0.39216 },
   { 0.96078, 0.52941, 0.52941 },
   { 0.97255, 0.66667, 0.66667 },
   { 0.98431, 0.80392, 0.80392 },
   { 0.99216, 0.80000, 0.80000 },
   { 1.00000, 1.00000, 1.00000 },
};
#<

#>            color.c
/* color.c

*/

#include	"gids.h"			/* GIDS symbols */
#include	"background.h"			/* background color table */
#include	"heat.h"			/* heat color table */
#include	"isophot.h"			/* isophot color table */
#include	"mousse.h"			/* mousse color table */
#include	"random.h"			/* random color table */
#include	"rainbow.h"			/* rainbow color table */
#include	"rgb.h"				/* rgb color table */
#include	"smooth.h"			/* smooth color table */
#include	"staircase.h"			/* staircase color table */

static	char	lutname[MAXSTRING];

static	int	init_color_table( Color_struct *lut )
{
   int	n;					/* loop counter */
   int	ncolors;				/* number of colors */

   ncolors = winfo.ncolors;			/* number of colors in image */
   for (n = 1; n < ncolors; n++) {
      float	y;
      float	w;
      int	k1;
      int	k2;

      y = (float) MAXCOLORS / (float) (ncolors - 2) * ( n - 1 );
      if (y < 0.0) y = 0.0;
      if (y > (MAXCOLORS - 1)) y = MAXCOLORS - 1;
      w = y - floor( y );
      k1 = (int) y;
      k2 = k1 + 1;
      if (k2 == MAXCOLORS) k2 = k1;
      winfo.table[n].red   = (float) USHRT_MAX *
         ( ( 1.0 - w ) * lut[k1].red + w * lut[k2].red );
      winfo.table[n].green = (float) USHRT_MAX *
         ( ( 1.0 - w ) * lut[k1].green + w * lut[k2].green );
      winfo.table[n].blue  = (float) USHRT_MAX *
         ( ( 1.0 - w ) * lut[k1].blue +  w * lut[k2].blue );

   }
   return( 0 );					/* return to caller */
}

static	void	init_color_table_mono( void )
{
   int	n;					/* loop counter */

   for (n = 1; n < winfo.ncolors; n++) {
      winfo.table[n].red   = USHRT_MAX / (winfo.ncolors - 2) * (n - 1);
      winfo.table[n].green = USHRT_MAX / (winfo.ncolors - 2) * (n - 1);
      winfo.table[n].blue  = USHRT_MAX / (winfo.ncolors - 2) * (n - 1);
   }
}

static	void	init_color_table_ronekers( void )
{
   int	n;					/* loop counter */

   for (n = 1; n < winfo.ncolors; n++) {
      int	k = (n / ((winfo.ncolors - 1) / 9));

      winfo.table[n].pixel = winfo.mincolor + n;
      winfo.table[n].flags = DoRed | DoGreen | DoBlue;
      switch( k ) {				/* which color */
         case 0: {				/* black */
            winfo.table[n].red   = 0.19608 * USHRT_MAX;
            winfo.table[n].green = 0.19608 * USHRT_MAX;
            winfo.table[n].blue  = 0.19608 * USHRT_MAX;
            break;
         }
         case 1: {				/* purple */
            winfo.table[n].red   = 0.47451 * USHRT_MAX;
            winfo.table[n].green = 0;
            winfo.table[n].blue  = 0.60784 * USHRT_MAX;
            break;
         }
         case 2: {				/* dark blue */
            winfo.table[n].red   = 0;
            winfo.table[n].green = 0;
            winfo.table[n].blue  = 0.78431 * USHRT_MAX;
            break;
         }
         case 3: {				/* light blue */
            winfo.table[n].red   = 0.37255 * USHRT_MAX;
            winfo.table[n].green = 0.65490 * USHRT_MAX;
            winfo.table[n].blue  = 0.92549 * USHRT_MAX;
            break;
         }
         case 4: {				/* dark green */
            winfo.table[n].red   = 0;
            winfo.table[n].green = 0.56863 * USHRT_MAX;
            winfo.table[n].blue  = 0;
            break;
         }
         case 5: {				/* light green */
            winfo.table[n].red   = 0;
            winfo.table[n].green = 0.96471 * USHRT_MAX;
            winfo.table[n].blue  = 0;
            break;
         }
         case 6: {				/* yellow */
            winfo.table[n].red   = 1.00000 * USHRT_MAX;
            winfo.table[n].green = 1.00000 * USHRT_MAX;
            winfo.table[n].blue  = 0;
            break;
         }
         case 7: {				/* orange */
            winfo.table[n].red   = 1.00000 * USHRT_MAX;
            winfo.table[n].green = 0.69412 * USHRT_MAX;
            winfo.table[n].blue  = 0;
            break;
         }
         default: {				/* red */
            winfo.table[n].red   = 1.00000 * USHRT_MAX;
            winfo.table[n].green = 0;
            winfo.table[n].blue  = 0;
            break;
         }
      }
   }
}

static	void	init_color_table_user( void )
{
   int	n;

   for (n = 0; n < winfo.ncolors; n++) {
      winfo.table[n].red   = user.colors[n].red * (float) USHRT_MAX;
      winfo.table[n].green = user.colors[n].green * (float) USHRT_MAX;
      winfo.table[n].blue  = user.colors[n].blue * (float) USHRT_MAX;
   }
}

static	void	setlut( char *ptr )
{
   if (!strcmp( ptr, "Background" )) {
      init_color_table( background );
   } else if (!strcmp( ptr, "Heat" )) {
      init_color_table( heat );
   } else if (!strcmp( ptr, "Isophot" )) {
      init_color_table( isophot );
   } else if (!strcmp( ptr, "Mousse" )) {
      init_color_table( mousse );
   } else if (!strcmp( ptr, "Random" )) {
      init_color_table( ranlut );
   } else if (!strcmp( ptr, "RGB" )) {
      init_color_table( rgb );
   } else if (!strcmp( ptr, "Smooth" )) {
      init_color_table( smooth );
   } else if (!strcmp( ptr, "Staircase" )) {
      init_color_table( staircase );
   } else if (!strcmp( ptr, "Rainbow" )) {
      init_color_table( rainbow );
   } else if (!strcmp( ptr, "Ronekers" )) {
      init_color_table_ronekers( );
   } else if (!strcmp( ptr, "User" )) {
      init_color_table_user( );
   } else if (!strcmp( ptr, "Mono" )) {
      init_color_table_mono( );
   }
   strcpy( lutname, ptr );
}


static	int set_visual(int min_size)
/* VOG2010: Function which sets the visual either to 8-bits PseudoColor  */
/* or to 24-bits DirectColor. PseudoColor is the default, but is usually */
/* not available on 24 bits displays. However it can be executed in an   */
/* 8 bits server environment (e.g. VNC). DirectColor shows colour        */
/* flashing which is annoying but cannot be avoided. A True colour       */
/* version of GIDS is not in the planning because it differs too much    */
/* from the PseudoColor and DirectColor approach and we want to prevent  */
/* too many changes in the original program.                             */
{
   XVisualInfo	*vinfo, vinfo_template;
   int		cnt, i, p = 0;
   int          min_depth;

   min_depth = 8;
   /* VOG2010: winfo.id is derived in display.c from the default display/screen. */
   /* But we want to try PseudoColor first. Then DirectColor. Abort if neither   */
   /* are available. */
   vinfo_template.screen = winfo.screen;
   vinfo_template.class  = PseudoColor;      /* VOG2010: Change default class to wanted class */
   vinfo_template.depth = min_depth;
   vinfo = XGetVisualInfo( winfo.id, VisualClassMask | VisualScreenMask | VisualDepthMask,
                           &vinfo_template, &cnt );

   /* VOG2010: If this does not succeed then try the DirectColor visual.     */
   /* We don't have a graphical interface that supports 16 bit DirectColor   */
   /* so we require 24 bits from the start. The code however supports 16     */
   /* bits also, so in fact 16 bits DirectColor can be supported by changing */
   /* variable min_depth from 24 to 16.                                      */ 
   if (vinfo == NULL) {
      min_depth = 24;
      vinfo_template.class  = DirectColor;
      vinfo_template.depth = min_depth;
   }
   vinfo = XGetVisualInfo( winfo.id, VisualClassMask | VisualScreenMask | VisualDepthMask,
                           &vinfo_template, &cnt );
   if ( cnt == 0 ) return( 1 );
   for ( p = 0, i = 1; i < cnt; i++ ) {
      if ( ( vinfo[p].depth < min_depth ) &&
         ( vinfo[p].colormap_size < min_size ) &&
         ( vinfo[i].depth >= vinfo[p].depth ) &&
         ( vinfo[i].colormap_size >= vinfo[p].colormap_size ) ) {
         p = i;
      }
   }
   /* VOG2010: Note that in display.c, the value of winfo.visual is set    */
   /* to XDefaultVisual() and it could have been changed by this function. */
   if ( vinfo[p].visual != winfo.visual ) {
      winfo.visual = vinfo[p].visual;
   }
   winfo.class = winfo.visual->class;
   winfo.pad = winfo.depth>16?32:(winfo.depth>8?16:8);
   winfo.bytespp = winfo.pad/8;
   /* VOG2010: Here we need to find the byte order. The byte order is an   */
   /* attribute of an XImage struct. So first assume an order and correct  */
   /* as soon an XImage is available (that is in display.c).               */
   winfo.byte_order = LSBFirst; 
   XFree( (caddr_t) vinfo );
   return( 1 );
}



int	color_init( )
{
   Display	*display;			/* display id */
   int		 screen;			/* screen number */
   int		 r = 0;				/* return value */
   unsigned long pixels[MAXCOLORS];


   display = winfo.id;				/* display id */
   screen  = winfo.screen;			/* screen number */
   winfo.slope = 1.0;				/* set slope */
   winfo.shift = 0.5;				/* set shift */

   /* VOG2010: GIDS is written for pseudocolor which is not commonly supported */
   /* by current graphical interfaces. To be able to use GIDS on 24 bits       */
   /* displays we made a DirectColor version available. Function set_visual()  */
   /* first test the existence of a 8-bits PseudoColor visual. If not          */
   /* available, it tests for a 24 bits DirectColor visual.                    */
   if (!set_visual(MAXCOLORS)) {
      r = -1;
      return(r);
   }
   /* VOG2010: At this stage we either have pseudo color or direct color. */
   /* Note that this differs from the original code where only a pseudo   */
   /* color test was included in the switch below. */
   /* printf("Visual class=%d. Visual depth=%d, padding=%d\n",
   winfo.class,  winfo.depth, winfo.pad); */
   
   switch( winfo.class ) {			/* class of color */
      case StaticColor: 			/* static colors */
      case StaticGray:				/* static grey */
      case TrueColor:				/* true color */
      case GrayScale:				/* grey scale */
      case PseudoColor:                         /* 8 bits pseudo color */
      case DirectColor: {			/* 24 bits direct color */
         int		g;
         int		mcolors = MAXCOLORS;    /* VOG2010: All colors */
         int		min_cols = MIN_D_COLORS;
         int		max_cols = MAX_D_COLORS; /* VOG2010: Min & Max colors for IMAGE */
         int            n;
         int		ncolors = MAXCOLORS;
         int		p;
         Status		status;
         int            pixdif;

         /* VOG2010: The original code to get a color map was:     */
         /* winfo.colormap = DefaultColormap( display, screen );   */
         /* This will not work if the visual of the root window    */
         /* differs from the required visual.                      */
         /* Then use XCreateColormap() with AllocNone. Then the    */
         /* colormap initially has no allocated entries, and       */
         /* clients can allocate them. This private colormap is    */
         /* responsible for color flashing.                        */
         if (winfo.class == PseudoColor) {
            pixdif = 1;
            winfo.colormap = DefaultColormap( display, screen );
         }
         else
         {
            if (winfo.depth == 24) {
               pixdif = 1 | (1<<8) | (1<<16);
            }
            else
            {
               pixdif = 1 | (1<<8);
            }
            winfo.colormap = XCreateColormap(display,
                                          winfo.root,
                                          winfo.visual, AllocNone);
         }
	 do {
            status = XAllocColorCells( display, winfo.colormap, False,
	             NULL, 0, pixels, mcolors );
            if (status) {
               int	minp = 0, maxp = 0;
               int	mins = 0, maxs = 0;
               int	n, nrange = 0;

               for ( n = 1; n < mcolors; n++ ) {
                  if ( ( pixels[n] - pixels[n-1] ) == pixdif) {
                     maxp = n;
                  } else {
                     if ( nrange ) {
                        if ( ( maxs - mins + 1 ) < ( maxp - minp + 1 ) ) {
                           mins = minp; maxs = maxp;
                        }
                     } else {
                        mins = minp; maxs = maxp;
                     }
                     nrange += 1;
                     minp = maxp = n;
                  }
               }
               if ( nrange ) {
                  if ( ( maxs - mins + 1 ) < ( maxp - minp + 1 ) ) {
                     mins = minp; maxs = maxp;
                  }
               } else {
                  mins = minp; maxs = maxp;
               }
               nrange += 1;
               for ( n = 0; n < mins; n++ ) {
                  XFreeColors( display, winfo.colormap, &pixels[n], 1, 0 );
               }
               for ( n = maxs + 1; n < mcolors; n++ ) {
                  XFreeColors( display, winfo.colormap, &pixels[n], 1, 0 );
               }
               for ( mcolors = 0, n = mins; n <= maxs; n++ ) {
                  pixels[mcolors++] = pixels[n];
               }
               break;
            } else {
               mcolors -= 1;
            }
         } while ( mcolors );
         {
            char	*ptr;

            ptr = XGetDefault( winfo.id, "gids", "mincolors" );
            if (ptr != NULL) {
               min_cols = atoi( ptr );

               if (min_cols < MIN_D_COLORS) min_cols = MIN_D_COLORS;
               if (min_cols > MAX_D_COLORS) min_cols = MAX_D_COLORS;
            }
            ptr = XGetDefault( winfo.id, "gids", "colors" );
            if (ptr != NULL) {
               max_cols = atoi( ptr );

               if (max_cols < min_cols) max_cols = min_cols;
               if (max_cols > MAX_D_COLORS) max_cols = MAX_D_COLORS;
               min_cols = max_cols;
            }
         }
         if (mcolors < ( min_cols + 1 + MAXGCOLORS + MAXPCOLORS )) {
            /* VOG2010: MAXGCOLORS=16, MAXPCOLORS=16 */
            Colormap	cmap;
            int		n, m;

            if (mcolors) {
               XFreeColors( display, winfo.colormap, pixels, mcolors, 0 );
            }
	         cmap = XCreateColormap( winfo.id, winfo.root, winfo.visual, AllocAll );
            mcolors = max_cols + 1 + MAXGCOLORS + MAXPCOLORS;
            for ( n = 0; n < ( MAXCOLORS - mcolors ); n++ ) {
               XColor	def_in_out;

               def_in_out.pixel = pixels[n];
               XQueryColor( display, winfo.colormap, &def_in_out );
               XStoreColor( display, cmap, &def_in_out );
            }
            winfo.colormap = cmap;
            for ( m = 0; n < MAXCOLORS; n++ ) {
               /* ORIG: pixels[m++] = n; */
               pixels[m++] = pixels[n];
            }
         }
	 if (!r) {				/* no error */
            if (mcolors > ( max_cols + 1 + MAXGCOLORS + MAXPCOLORS) ) {
               ncolors = MAX_D_COLORS + 1;
               mcolors = ncolors + MAXGCOLORS + MAXPCOLORS;
            } else {
               ncolors = mcolors - MAXGCOLORS - MAXPCOLORS;
            }
            /* VOG2010: Next follows a generalization of the setting of    */
            /* parameters used to scale image data. For the conversion     */
            /* from image data to pixmap data we need a minimum color,     */
            /* a maximum color and a value for a blank. In the original    */
            /* version, the pixels were 8-bit and range from e.g. 80 to    */
            /* 230 depending on the available colors (shared, not private) */
            /* and the number of colors needed for other purposes, like    */
            /* drawing graphics. The difference in color pixel values for  */
            /* 8 bits is 1, but this is different for other depths.        */
            /* Therefore it is better to address the pixels with an index  */
            /* which corresponds to an array element in the pixels array.  */
            /* Then the scaling is done with these indices (mincolor and   */
            /* maxcolor) and we reserve index 0 for a blank. The color of  */
            /* a blank can be changed in menu 'scale -> blank' with 3 rgb  */
            /* floating point numbers between 0 and 1.                     */ 
            winfo.mcolors  = mcolors;
            winfo.ncolors  = ncolors;
            winfo.maxcolor = ncolors-1;              /* VOG2010: ORIG pixels[ncolors-1];*/
            winfo.mincolor = 0;                      /* VOG2010: ORIG pixels[0]; */
            winfo.blank    = 0;                      /* VOG2010: ORIG pixels[0]; */
            winfo.table[0].pixel = pixels[0];
            winfo.table[0].flags = DoRed | DoGreen | DoBlue;
            winfo.table[0].red   = 0;
            winfo.table[0].green = 0;
            winfo.table[0].blue  = 0;
            winfo.modify[0] = winfo.table[0];
            {
               char	*ptr;

               ptr = XGetDefault( winfo.id, "gids", "start_lut" );
               if (ptr == NULL) {
                  ptr = "Mono";
                  /* VOG2010: Here one can change the default colormap, */
                  /* e.g. in Rainbow with: ptr = "Rainbow";             */
               }
               setlut( ptr );
            }
            for (n = 1; n < ncolors; n++) {
               winfo.table[n].pixel = pixels[n];
               winfo.table[n].flags = DoRed | DoGreen | DoBlue;
               winfo.modify[n] = winfo.table[n];
            }
            for (n = 0; n < MAXPLANES; n++) {
               winfo.gcolors[1<<n].red   = 0.5 / (float) ( MAXPLANES - 1 ) * n + 0.5;
               winfo.gcolors[1<<n].green = 0.5 / (float) ( MAXPLANES - 1 ) * ( MAXPLANES - 1 - n ) + 0.5;
               winfo.gcolors[1<<n].blue  = 0.5;
            }
            for (g = 0, n = ncolors; n < (mcolors - MAXPCOLORS); n++, g++) {
               int		c;
               Color_struct	sum;

               /* VOG2010: These are the colors for the plot graphics */
               winfo.table[n].pixel = pixels[n];
               winfo.gcells[g] = pixels[n];
               winfo.table[n].flags = DoRed | DoGreen | DoBlue;
               sum.red   = 0.0;
               sum.green = 0.0;
               sum.blue  = 0.0;
               for (c = 0; c < MAXPLANES; c++) {
                  if (g & (1<<c)) {
                     sum.red   += winfo.gcolors[1<<c].red;
                     sum.green += winfo.gcolors[1<<c].green;
                     sum.blue  += winfo.gcolors[1<<c].blue;
                  }
               }
               if (sum.red > 1.0) sum.red = 1.0;
               if (sum.green > 1.0) sum.green = 1.0;
               if (sum.blue > 1.0) sum.blue = 1.0;
               winfo.table[n].red   = USHRT_MAX * sum.red;
               winfo.table[n].green = USHRT_MAX * sum.green;
               winfo.table[n].blue  = USHRT_MAX * sum.blue;
               winfo.modify[n] = winfo.table[n];
            }
            for (n = 0; n < MAXPCOLORS; n++) {
               switch( n ) {			/* color index */
                  case 0: {			/* black (background) */
                     winfo.pcolors[n].red   = 0.00;
                     winfo.pcolors[n].green = 0.00;
                     winfo.pcolors[n].blue  = 0.00;
                     break;
                  }
                  case 1: {			/* white (default) */
                     winfo.pcolors[n].red   = 1.00;
                     winfo.pcolors[n].green = 1.00;
                     winfo.pcolors[n].blue  = 1.00;
                     break;
                  }
                  case 2: {			/* red */
                     winfo.pcolors[n].red   = 1.00;
                     winfo.pcolors[n].green = 0.00;
                     winfo.pcolors[n].blue  = 0.00;
                     break;
                  }
                  case 3: {			/* green */
                     winfo.pcolors[n].red   = 0.00;
                     winfo.pcolors[n].green = 1.00;
                     winfo.pcolors[n].blue  = 0.00;
                     break;
                  }
                  case 4: {			/* blue */
                     winfo.pcolors[n].red   = 0.00;
                     winfo.pcolors[n].green = 0.00;
                     winfo.pcolors[n].blue  = 1.00;
                     break;
                  }
                  case 5: {			/* cyan (green + blue) */
                     winfo.pcolors[n].red   = 0.00;
                     winfo.pcolors[n].green = 1.00;
                     winfo.pcolors[n].blue  = 1.00;
                     break;
                  }
                  case 6: {			/* magenta (red + blue) */
                     winfo.pcolors[n].red   = 1.00;
                     winfo.pcolors[n].green = 0.00;
                     winfo.pcolors[n].blue  = 1.00;
                     break;
                  }
                  case 7: {			/* yellow (red + green) */
                     winfo.pcolors[n].red   = 1.00;
                     winfo.pcolors[n].green = 1.00;
                     winfo.pcolors[n].blue  = 0.00;
                     break;
                  }
                  case 8: {			/* red + yellow (orange) */
                     winfo.pcolors[n].red   = 1.00;
                     winfo.pcolors[n].green = 0.50;
                     winfo.pcolors[n].blue  = 0.00;
                     break;
                  }
                  case 9: {			/* green + yellow */
                     winfo.pcolors[n].red   = 0.50;
                     winfo.pcolors[n].green = 1.00;
                     winfo.pcolors[n].blue  = 0.00;
                     break;
                  }
                  case 10: {			/* green + cyan */
                     winfo.pcolors[n].red   = 0.00;
                     winfo.pcolors[n].green = 1.00;
                     winfo.pcolors[n].blue  = 0.50;
                     break;
                  }
                  case 11: {			/* blue + cyan */
                     winfo.pcolors[n].red   = 0.00;
                     winfo.pcolors[n].green = 0.50;
                     winfo.pcolors[n].blue  = 1.00;
                     break;
                  }
                  case 12: {			/* blue + magenta */
                     winfo.pcolors[n].red   = 0.50;
                     winfo.pcolors[n].green = 0.00;
                     winfo.pcolors[n].blue  = 1.00;
                     break;
                  }
                  case 13: {			/* red + magenta */
                     winfo.pcolors[n].red   = 1.00;
                     winfo.pcolors[n].green = 0.00;
                     winfo.pcolors[n].blue  = 0.50;
                     break;
                  }
                  case 14: {			/* dark gray */
                     winfo.pcolors[n].red   = 0.33;
                     winfo.pcolors[n].green = 0.33;
                     winfo.pcolors[n].blue  = 0.33;
                     break;
                  }
                  case 15: {			/* light gray */
                     winfo.pcolors[n].red   = 0.66;
                     winfo.pcolors[n].green = 0.66;
                     winfo.pcolors[n].blue  = 0.66;
                     break;
                  }
                  default: {			/* undefined (white) */
   	             winfo.pcolors[n].red   = 1.00;
                     winfo.pcolors[n].green = 1.00;
                     winfo.pcolors[n].blue  = 1.00;
                     break;
                  }
               }
            }
            for (p = 0, n = ncolors + MAXGCOLORS; n < mcolors; n++, p++) {
               winfo.table[n].pixel = pixels[n];
               winfo.table[n].flags = DoRed | DoGreen | DoBlue;
               winfo.table[n].red   = USHRT_MAX * winfo.pcolors[p].red;
               winfo.table[n].green = USHRT_MAX * winfo.pcolors[p].green;
               winfo.table[n].blue  = USHRT_MAX * winfo.pcolors[p].blue;
               winfo.modify[n] = winfo.table[n];
               winfo.pcells[p] = pixels[n];
            }
            XStoreColors( display, winfo.colormap, winfo.table, mcolors );
            XFlush( display );
	 }
         break;
      }
      default: {				/* ? */
         r = -1;				/* don't know what to do */
         break;
      }
   }
   return( r );					/* return to caller */
}

int	color_mono( int button )
{
   setlut( "Mono" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_ronekers( int button )
{
   setlut( "Ronekers" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_rainbow( int button )
{
   setlut( "Rainbow" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_staircase( int button )
{
   setlut( "Staircase" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_user( int button )
{
   setlut( "User" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_random( int button )
{
   setlut( "Random" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_mousse( int button )
{
   setlut( "Mousse" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_isophot( int button )
{
   setlut( "Isophot" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_rgb( int button )
{
   setlut( "RGB" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_heat( int button )
{
   setlut( "Heat" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_smooth( int button )
{
   setlut( "Smooth" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_background( int button )
{
   setlut( "Background" );
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_reset( int button )
{
   winfo.inverse = 1.0;				/* reset */
   winfo.slope   = 1.0;				/* reset slope */
   winfo.shift   = 0.5;				/* reset shift */
   color_modify( );				/* modify colors */
   return( menu[button].ret );			/* return to caller */
}

int	color_transfer( int xc, int yc )
{
   double	phi;				/* angle */

   if (xc < 0) return( -1 );
   if (xc > (winfo.dwidth - 1)) return( -2 );
   if (yc < 0) return( -3 );
   if (yc > (winfo.dheight - 1)) return( -4 );
   yc = winfo.dheight - 1 - yc;
   phi = 1.57 / (double) ( winfo.dwidth - 1 ) * (double) xc;
   winfo.slope = tan( phi );
   winfo.shift = (float) yc / (float) ( winfo.dheight - 1 );
   return( 0 );
}

int	color_modify( )
{
   float	x;				/* x value */
   float	y;				/* y value */
   int		m;				/* table entry */
   int		n;				/* loop counter */

   winfo.modify[0] = winfo.table[0];
   for (n = 1; n < winfo.ncolors; n++) {
      int	te = winfo.wedge_code[n];

      x = 1.0 / (float) (winfo.ncolors - 1) * ( n - 1 );
      y = ( winfo.inverse * winfo.slope ) * (x - winfo.shift ) + 0.5;
      if (y < 0.0) {
         y = 0.0;
      } else if (y > 1.0) {
         y = 1.0;
      }
      if (te == NO_WEDGE) {
         m = ( (float) (winfo.ncolors - 2) * y + 1.5 );
         m = winfo.scale[winfo.scaling][m+winfo.mincolor]-winfo.mincolor;
         winfo.modify[n].red   = winfo.table[m].red;
         winfo.modify[n].green = winfo.table[m].green;
         winfo.modify[n].blue  = winfo.table[m].blue;
      } else {
         Color_struct	color;			/* added colors */

         color.red   = 0.0;
         color.blue  = 0.0;
         color.green = 0.0;
         if (te & BLUE_WEDGE) {
            color.red   += winfo.Blue.red;
            color.green += winfo.Blue.green;
            color.blue  += winfo.Blue.blue;
         }
         if (te & GREEN_WEDGE) {
            color.red   += winfo.Green.red;
            color.green += winfo.Green.green;
            color.blue  += winfo.Green.blue;
         }
         if (te & PURPLE_WEDGE) {
            color.red   += winfo.Purple.red;
            color.green += winfo.Purple.green;
            color.blue  += winfo.Purple.blue;
         }
         if (te & RED_WEDGE) {
            color.red   += winfo.Red.red;
            color.green += winfo.Red.green;
            color.blue  += winfo.Red.blue;
         }
         if (te & WHITE_WEDGE) {
            color.red   += winfo.White.red;
            color.green += winfo.White.green;
            color.blue  += winfo.White.blue;
         }
         if (te & YELLOW_WEDGE) {
            color.red   += winfo.Yellow.red;
            color.green += winfo.Yellow.green;
            color.blue  += winfo.Yellow.blue;
         }
         if (color.red > 1.0) color.red = 1.0;
         if (color.green > 1.0) color.green = 1.0;
         if (color.blue > 1.0) color.blue = 1.0;
         winfo.modify[n].red   = color.red * (float) USHRT_MAX;
         winfo.modify[n].green = color.green * (float) USHRT_MAX;
         winfo.modify[n].blue  = color.blue * (float) USHRT_MAX;
      }
   }
   XStoreColors( winfo.id, winfo.colormap, winfo.modify , winfo.mcolors );
   return( 0 );					/* return to caller */
}

int	color_modify_graphics( void )
{
   int	n;

   for (n = 0; n < MAXGCOLORS; n++) {
      int		c;
      Color_struct	sum;

      sum.red   = 0.0;
      sum.green = 0.0;
      sum.blue  = 0.0;
      for (c = 0; c < MAXPLANES; c++) {
         if (n & (1<<c)) {
            sum.red   += winfo.gcolors[1<<c].red;
            sum.green += winfo.gcolors[1<<c].green;
            sum.blue  += winfo.gcolors[1<<c].blue;
         }
      }
      if (sum.red > 1.0) sum.red = 1.0;
      if (sum.green > 1.0) sum.green = 1.0;
      if (sum.blue > 1.0) sum.blue = 1.0;
      winfo.table[n+winfo.ncolors].red   = USHRT_MAX * sum.red;
      winfo.table[n+winfo.ncolors].green = USHRT_MAX * sum.green;
      winfo.table[n+winfo.ncolors].blue  = USHRT_MAX * sum.blue;
      winfo.modify[n+winfo.ncolors] = winfo.table[n+winfo.ncolors];
   }
   XStoreColors( winfo.id, winfo.colormap, winfo.modify, winfo.mcolors );
   XFlush( winfo.id );
   return( 0 );
}

int	color_setlut( int button )
{
   static char	old_lutname[MAXSTRING];

   switch( button ) {
      case Button1: {
         if (!strcmp( lutname, "Mono" )) {
            setlut( old_lutname );
         }
         break;
      }
      case Button3: {
         if (strcmp( lutname, "Mono" )) {
            strcpy( old_lutname, lutname );
            setlut( "Mono" );
         }
         break;
      }
      default: {
         break;
      }
   }
   return( 0 );
}
#<

#>            coord.c
/* coord.c

*/

#include	"gids.h"			/* GIDS definitions */
#if	defined(NO_GIPSY)
#include	"f2cvvdefs.h"			/* Fortran -> C definitions */
#else
#include	"gipsyc.h"			/* GIPSY symbols */
#include	"ftsd_rchar.h"			/* define ftsd_rchar_c */
#include	"ftsd_rdble.h"			/* define ftsd_rdble_c */
#include	"ftsd_rint.h"			/* define ftsd_rint_c */
#include	"ftsd_rreal.h"			/* define ftsd_rreal_c */
#endif

#define	FITSNAMELEN	8			/* length of FITS item */
#define	FITSSTRINGLEN	18			/* length of FITS string */

typedef struct {				/* axis struct */
   char		ctype[FITSSTRINGLEN];		/* primary axis name */
   char		cunit[FITSSTRINGLEN];		/* primary axis units */
   char		dtype[FITSSTRINGLEN];		/* secondary axis name */
   char		dunit[FITSSTRINGLEN];		/* secondary axis units */
   double	cdelt;				/* primary pixel separation */
   double	crpix;				/* primary reference pixel */
   double	crota;				/* primary rotation angle */
   double	crval;				/* primary reference value */
   double	ddelt;				/* secondary pixel separation */
   double	drpix;				/* secondary reference pixel */
   double	drota;				/* secondary rotation angle */
   double	drval;				/* secondary reference value */
   fint		naxis;				/* length of axis */
   fint		primary_mask;			/* primary axis mask */
   fint		secondary_mask;			/* secondary axis mask */
} Coord2_struct;				/* THE STRUCT */

typedef struct {				/* main coord struct */
   Coord2_struct	*ax;			/* axis struct */
   char			instrume[FITSSTRINGLEN];/* instrument */
   double		epoch;			/* the epoch */
   double		freq0;			/* rest frequency */
   fint			maxis;			/* real + hidden axes */
   fint			naxis;			/* real axes */
} Coord1_struct;				/* THE STRUCT */

static	Coord1_struct	coord;			/* it */

int	coord_init( void )
{
   coord.ax    = NULL;				/* null pointer */
   coord.maxis = 0;				/* no axes */
   coord.naxis = 0;				/* no axes */
   return( 0 );					/* return to caller */
}

#if	!defined(NO_GIPSY)
int	coord_from_fits( char *fits, int nbytes )
{
   fchar	ctype;				/* primary axis name */
   fchar	cunit;				/* primary axis units */
   fchar	dtype;				/* secondary axis name */
   fchar	dunit;				/* secondary axis units */
   fchar	instrume;			/* the instrument */
   fchar	tape;				/* the fits header */
   fint		nrec;				/* FITS record */
   float	bscale;				/* scaling factor */
   float	b_zero;				/* offset */
   int		n;				/* loop counter */
   int		nd;				/* descriptor masker */
   int		ndata = 1;			/* number of pixels */

   if (coord.naxis) {				/* already info present */
      free( coord.ax );				/* release info */
      coord.ax    = NULL;			/* null pointer */
      coord.maxis = 0;				/* no axes */
      coord.naxis = 0;				/* no axes */
   }
   tape.a = fits;				/* assign pointer */
   tape.l = nbytes;				/* length of character */
   ctype.l = FITSSTRINGLEN;			/* set the length */
   cunit.l = FITSSTRINGLEN;			/* set the length */
   dtype.l = FITSSTRINGLEN;			/* set the length */
   dunit.l = FITSSTRINGLEN;			/* set the length */
   instrume.l = FITSSTRINGLEN;			/* the length */
   nrec = ftsd_rreal_c( tape, tofchar( "BSCALE" ), &bscale );
   if (nrec < 0) bscale = 1.0;			/* default */
   nrec = ftsd_rreal_c( tape, tofchar( "BZERO" ), &b_zero );
   if (nrec < 0) b_zero = 0.0;			/* default */
   nrec = ftsd_rdble_c( tape, tofchar( "EPOCH" ), &coord.epoch );
   if (nrec < 0) coord.epoch = 0.0;		/* no epoch */
   nrec = ftsd_rdble_c( tape, tofchar( "FREQ0" ), &coord.freq0 );
   if (nrec < 0) coord.freq0 = 0.0;		/* no rest frequency */
   instrume.a = coord.instrume;			/* the address */
   nrec = ftsd_rchar_c( tape, tofchar( "INSTRUME" ), instrume );
   nrec = ftsd_rint_c( tape, tofchar( "NAXIS" ), &coord.naxis );
   if (nrec < 0) return( -9 );			/* error */
   for (nd = 1, n = 0; nd; n++) {		/* loop to load axis info */
      char	descr[FITSNAMELEN+1];		/* FITS descriptor */

      coord.ax = realloc( coord.ax, sizeof( Coord2_struct ) * ( n + 1 ) );
      if (coord.ax == NULL) return( -10 );	/* allocation error */
      coord.ax[n].primary_mask = 0;		/* reset */
      coord.ax[n].secondary_mask = 0;		/* reset */
      ctype.a = coord.ax[n].ctype;		/* set the address */
      cunit.a = coord.ax[n].cunit;		/* set the address */
      dtype.a = coord.ax[n].dtype;		/* set the address */
      dunit.a = coord.ax[n].dunit;		/* set the address */
      sprintf( descr, "CDELT%d", n + 1 );	/* CDELT% */
      nrec = ftsd_rdble_c( tape, tofchar( descr ), &coord.ax[n].cdelt );
      if (nrec >= 0) coord.ax[n].primary_mask |= 1;
      sprintf( descr, "CROTA%d", n + 1 );	/* CROTA% */
      nrec = ftsd_rdble_c( tape, tofchar( descr ), &coord.ax[n].crota );
      if (nrec >= 0) coord.ax[n].primary_mask |= 2;
      sprintf( descr, "CRPIX%d", n + 1 );	/* CRPIX% */
      nrec = ftsd_rdble_c( tape, tofchar( descr ), &coord.ax[n].crpix );
      if (nrec >= 0) coord.ax[n].primary_mask |= 4;
      sprintf( descr, "CRVAL%d", n + 1 );	/* CRVAL% */
      nrec = ftsd_rdble_c( tape, tofchar( descr ), &coord.ax[n].crval );
      if (nrec >= 0) coord.ax[n].primary_mask |= 8;
      sprintf( descr, "CTYPE%d", n + 1 );	/* CTYPE% */
      nrec = ftsd_rchar_c( tape, tofchar( descr ), ctype );
      if (nrec >= 0) coord.ax[n].primary_mask |= 16;
      sprintf( descr, "CUNIT%d", n + 1 );	/* CUNIT% */
      nrec = ftsd_rchar_c( tape, tofchar( descr ), cunit );
      if (nrec >= 0) coord.ax[n].primary_mask |= 32;
      sprintf( descr, "DDELT%d", n + 1 );	/* DDELT% */
      nrec = ftsd_rdble_c( tape, tofchar( descr ), &coord.ax[n].ddelt );
      if (nrec >= 0) coord.ax[n].secondary_mask |= 1;
      sprintf( descr, "DROTA%d", n + 1 );	/* DROTA% */
      nrec = ftsd_rdble_c( tape, tofchar( descr ), &coord.ax[n].drota );
      if (nrec >= 0) coord.ax[n].secondary_mask |= 2;
      sprintf( descr, "DRPIX%d", n + 1 );	/* DRPIX% */
      nrec = ftsd_rdble_c( tape, tofchar( descr ), &coord.ax[n].drpix );
      if (nrec >= 0) coord.ax[n].secondary_mask |= 4;
      sprintf( descr, "DRVAL%d", n + 1 );	/* DRVAL% */
      nrec = ftsd_rdble_c( tape, tofchar( descr ), &coord.ax[n].drval );
      if (nrec >= 0) coord.ax[n].secondary_mask |= 8;
      sprintf( descr, "DTYPE%d", n + 1 );	/* DTYPE% */
      nrec = ftsd_rchar_c( tape, tofchar( descr ), dtype );
      if (nrec >= 0) coord.ax[n].secondary_mask |= 16;
      sprintf( descr, "DUNIT%d", n + 1 );	/* DUNIT% */
      nrec = ftsd_rchar_c( tape, tofchar( descr ), dunit );
      if (nrec >= 0) coord.ax[n].secondary_mask |= 32;
      sprintf( descr, "NAXIS%d", n + 1 );	/* NAXIS% */
      nrec = ftsd_rint_c( tape, tofchar( descr ), &coord.ax[n].naxis );
      if ((nrec < 0) && (n >= coord.naxis)) {	/* fatal error */
         free( coord.ax );			/* deallocate */
         coord.ax    = NULL;			/* null pointer */
         coord.maxis = 0;			/* no axes */
         coord.naxis = 0;			/* no axes */
         return( -9 );				/* error code */
      } else if (n < coord.naxis) {		/* real axes */
         ndata *= coord.ax[n].naxis;		/* multiply */
      }
      nd = coord.ax[n].primary_mask | coord.ax[n].secondary_mask;
   }
   coord.maxis = n - 1;				/* total number of axis */
   return( 0 );					/* return to caller */
}
#endif
#<

#>            cursor.c
/* cursor.c

*/

#include	"gids.h"
#include	"xscanf.h"

#define	SOCKET_MODE	1
#define	SELECTION_MODE	2
#define	SENDEVENT_MODE	3

static	int	Mode = SOCKET_MODE;
static	int	CR = 0;

static	Window	SW = None;
static	char	*alt_keyboard = NULL;
static	char	cursor_string[2*MAXIDTEXTLEN+1];
static	int	cursor_string_len = 0;
static	int	npos = 0;
static	int	xpos[2];
static	int	ypos[2];
static	int	xmod = 0;
static	int	ymod = 0;
static	int	old_h = 0, old_w = 0, old_x, old_y;


static KeyCode		keycode[128];
static unsigned int	state[128];

static	void	MakeKeys( void )
{
   XKeyEvent	E;
   int		n;
   char		b[128], nb;

   for ( n = 0; n < 128; n++ ) {
      KeySym	keysym, ks;
      int 	ch = n;

      state[n] = 0;
      if ( ch >= ' ' && ch <= '~' ) {
         keysym = XK_space + ch  - ' ';
         E.keycode = keycode[n] = XKeysymToKeycode( winfo.id, keysym );
         E.display = winfo.id;
         E.state = state[n];
         nb = XLookupString( &E, b, sizeof( b ), &ks, NULL );
         if ( nb != 1 || b[0] != ch ) {
            state[n] = E.state = ShiftMask;
            nb = XLookupString( &E, b, sizeof( b ), &ks, NULL );
         }
         if ( keysym != ks ) {
            state[n] = 0; keycode[n] = 0;
         }
      } else {
         switch( ch ) {
            case '\n': keysym = XK_Return; break;
            case 0x08: keysym = XK_BackSpace; break;
            case 0x09: keysym = XK_Tab; break;
#if	'\n' != 0x0a
            case 0x0a: keysym = XK_Linefeed; break;
#endif
            case 0x0b: keysym = XK_Clear; break;
            case 0x0d: keysym = XK_Return; break;
            case 0x13: keysym = XK_Pause; break;
            case 0x1b: keysym = XK_Escape; break;
            case 0x7f: keysym = XK_Delete; break;
            default: keysym = NoSymbol; break;
         }
         keycode[n] = XKeysymToKeycode( winfo.id, keysym );
         if ( keycode[n] ) {
            E.keycode = keycode[n];
            E.display = winfo.id;
            E.state = state[n];
            nb = XLookupString( &E, b, sizeof( b ), &ks, NULL );
            if ( nb != 1 || b[0] != ch ) {
               state[n] = E.state = ShiftMask;
               nb = XLookupString( &E, b, sizeof( b ), &ks, NULL );
            }
            if ( keysym != ks ) {
               state[n] = 0; keycode[n] = 0;
            }
         }
      }
   }
}

int	cursor_selection_clear( XEvent *E )
{
   if ( E->xselectionclear.selection == XA_PRIMARY ) {
      if ( XGetSelectionOwner( winfo.id, XA_PRIMARY ) != winfo.top ) {
         cursor_string_len = 0;
      }
   }
   return( 0 );
}

int	cursor_selection_request( XEvent *E )
{
   XSelectionEvent	S;

   S.type      = SelectionNotify;
   S.requestor = E->xselectionrequest.requestor;
   S.selection = E->xselectionrequest.selection;
   S.target    = E->xselectionrequest.target;
   S.time      = E->xselectionrequest.time;
   if ( ( E->xselectionrequest.selection != XA_PRIMARY ) ||
      ( E->xselectionrequest.target != XA_STRING ) ||
      ( E->xselectionrequest.property == None ) ||
      ( cursor_string_len == 0 ) ) {
      S.property = None;
   } else {
      S.property = E->xselectionrequest.property;
      XChangeProperty( winfo.id, S.requestor, S.property, S.target, 8,
         PropModeReplace, (unsigned char *) cursor_string, cursor_string_len );
   }
   XSendEvent( winfo.id, S.requestor, False, 0, (XEvent *)&S );
   return( 0 );
}

static	int	send_to_socket( void )
{
   FILE		*f;
   char		hostname[32];
   char		sockname[FILENAME_MAX+1];
   int		sock;
   int		portnumber;
   int		r = 0;

   if (alt_keyboard == NULL) return( 1 );
   if (!npos) return( 0 );
   if (!cursor_string_len) return( 0 );
   f = fopen( alt_keyboard, "r" );
   if (f == NULL) return( 1 );
   if (xscanf( f, "%s %s %d", hostname, sockname, &portnumber ) != 3) {
      r = 1;
   } else {
      int			close( );
      int			connect( );
      int			socket( );
      short			port;
      struct hostent		*hp;
      struct hostent		*gethostbyname( );
      struct sockaddr_in	keyboard;

      hp = gethostbyname( hostname );
      sock = socket( AF_INET, SOCK_STREAM, 0 );
      memmove( (char *)&keyboard.sin_addr, (char *)hp->h_addr, hp->h_length );
      port = portnumber;
      keyboard.sin_family = AF_INET;
      keyboard.sin_port = htons( port );
      if (!connect( sock, (struct sockaddr *)&keyboard, sizeof( keyboard ) )) {
         r = misc_send( sock, cursor_string, cursor_string_len + 1 );
         close( sock );
      } else {
         r = 1;
      }
   }
   fclose( f );
   return( 0 );
}

static	int	send_to_selection( void )
{
   if (!cursor_string_len) return( 0 );
   XSetSelectionOwner( winfo.id, XA_PRIMARY, winfo.top, CurrentTime );
   if ( XGetSelectionOwner( winfo.id, XA_PRIMARY ) != winfo.top ) {
      return( 1 );
   } else {
      return( 0 );
   }
}

static	Window	Lookup_Window( Window w )
{
   Window	R = None, r, p, *c[1];
   char		*window_name[1];
   unsigned int	n, nc;

   XFetchName( winfo.id, w, window_name );
   if ( window_name[0] != NULL ) {
      XFree( (caddr_t) window_name[0] );
      return( w );
   }
   XQueryTree( winfo.id, w, &r, &p, c, &nc );
   for ( n = 0; n < nc && R == None; n++ ) {
      R = Lookup_Window( c[0][n] );
   }
   if ( nc ) XFree( (caddr_t) c[0] );
   return( R );
}

static	Window	Select_Window( void )
{
   Cursor	cursor;
   Window	target = None;
   XEvent	event;
   int		buttons = 0;
   int		status;

   cursor = XCreateFontCursor( winfo.id, XC_crosshair );
   status = XGrabPointer( winfo.id, winfo.root, False,
      ButtonPressMask | ButtonReleaseMask, GrabModeSync, GrabModeAsync,
      winfo.root, cursor, CurrentTime );
   if ( status != GrabSuccess ) return( target );
   while ( ( target == None ) || ( target == winfo.root ) || ( buttons != 0 ) ) {
      XAllowEvents( winfo.id, SyncPointer, CurrentTime );
      XWindowEvent( winfo.id, winfo.root, ButtonPressMask | ButtonReleaseMask,
         &event );
      switch( event.type ) {
         case ButtonPress: {
            if ( ( target == None ) || ( target == winfo.root ) ) {
               target = event.xbutton.subwindow;
            }
            buttons++;
            break;
         }
         case ButtonRelease: {
            if ( buttons > 0 ) buttons--;
            break;
         }
      }
   }
   XUngrabPointer( winfo.id, CurrentTime );
   return( Lookup_Window( target ) );
}

static	int	send_to_sendevent( void )
{
   int		n;

   if (!cursor_string_len) return( 0 );
   if ( SW == None ) SW = Select_Window( );
   if ( SW == None ) return( 1 );
   for ( n = 0; n < cursor_string_len; n++ ) {
      XKeyEvent	K;

      K.type        = KeyPress;
      K.keycode     = keycode[0xff&cursor_string[n]];
      K.state       = state[0xff&cursor_string[n]];
      K.window      = SW;
      K.root        = winfo.root;
      K.subwindow   = None;
      K.same_screen = True;
      XSendEvent( winfo.id, SW, True, 0, (XEvent *)&K );
      XFlush( winfo.id );
   }
   return( 0 );
}

static	int	send_away( void )
{
   int	r = 0;

   switch( Mode ) {
      case SOCKET_MODE: {
         r = send_to_socket( );
         break;
      }
      case SELECTION_MODE: {
         r = send_to_selection( );
         break;
      }
      case SENDEVENT_MODE: {
         r = send_to_sendevent( );
         break;
      }
   }
   return( r );
}

static	int	put_out( )
{
   if (npos == 1) {
      cursor_string_len = sprintf( cursor_string, " %d %d\n",
         winfo.record[winfo.currec].x_grid[xpos[0]],
         winfo.record[winfo.currec].y_grid[ypos[0]] );
   } else {
      cursor_string_len = sprintf( cursor_string, " %d %d %d %d\n",
         winfo.record[winfo.currec].x_grid[xpos[0]],
         winfo.record[winfo.currec].y_grid[ypos[0]],
         winfo.record[winfo.currec].x_grid[xpos[1]],
         winfo.record[winfo.currec].y_grid[ypos[1]] );
   }
   if (!CR && ( cursor_string_len > 0 ) ) {
      cursor_string[--cursor_string_len] = 0;
   }
   return( send_away( ) );
}

int	cursor_appendcr( int button )
{
   CR = !CR;
   return( menu[button].ret );
}

int	cursor_socket( int button )
{
   Mode = SOCKET_MODE;
   if ( alt_keyboard == NULL ) XBell( winfo.id, 100 );
   return( menu[button].ret );
}

int	cursor_select( int button )
{
   Mode = SELECTION_MODE;
   return( menu[button].ret );
}

int	cursor_sendev( int button )
{
   Mode = SENDEVENT_MODE;
   SW = Select_Window( );
   return( menu[button].ret );
}

int	cursor_init( char *key_board )
{
   alt_keyboard = key_board;
   MakeKeys( );
   return( 0 );
}

int	cursor_box( int x, int y )
{
   int	valid = 0;

   DATA_CHECK( 0 );
   if (x < 0) {
      valid = 0;
   } else if (y < 0) {
      valid = 0;
   } else if (x >= winfo.dwidth) {
      valid = 0;
   } else if (y >= winfo.dheight) {
      valid = 0;
   } else {
      valid = 1;
   }
   if (valid) {
      int	h, w;

      xpos[xmod] = x;
      ypos[ymod] = y;
      h = ypos[1] - ypos[0] + 1;
      w = xpos[1] - xpos[0] + 1;
      if (h < 0) { y = ypos[1]; h = -h; } else { y = ypos[0]; }
      if (w < 0) { x = xpos[1]; w = -w; } else { x = xpos[0]; }
      if (old_h) {
         XDrawRectangle( winfo.id, winfo.display, winfo.gcb, old_x, old_y, old_w, old_h );
      }
      old_h = h; old_w = w; old_x = x; old_y = y;
      XDrawRectangle( winfo.id, winfo.display, winfo.gcb, x, y, w, h );
   }
   return( 0 );
}

int	cursor_do( int x, int y, int button )
{
   int	r = 0;
   int	valid = 0;

   DATA_CHECK( 0 );
   if (x < 0) {
      valid = 0;
   } else if (y < 0) {
      valid = 0;
   } else if (x >= winfo.dwidth) {
      valid = 0;
   } else if (y >= winfo.dheight) {
      valid = 0;
   } else {
      valid = 1;
   }
   switch( button ) {
      case Button1: {
         if (valid) {
            if (npos == 2) {
               if (old_h) {
                  XDrawRectangle( winfo.id, winfo.display, winfo.gcb, old_x, old_y, old_w, old_h );
                  old_h = 0;
               }
            }
            npos = 1;
            xpos[0] = x;
            ypos[0] = y;
            put_out( );
         }
         break;
      }
      case Button2: {
         int	h, w;

         if (valid) {
            r = 1;
            if (npos == 2) {
               if (abs(xpos[0]-x) < abs(xpos[1]-x)) {
                  xmod = 0;
               } else {
                  xmod = 1;
               }
               if (abs(ypos[0]-y) < abs(ypos[1]-y)) {
                  ymod = 0;
               } else {
                  ymod = 1;
               }
               xpos[xmod] = x;
               ypos[ymod] = y;
            } else {
               xpos[1] = xpos[0] = x;
               ypos[1] = ypos[0] = y;
               xmod = 1;
               ymod = 1;
               npos = 2;
            }
            h = ypos[1] - ypos[0] + 1;
            w = xpos[1] - xpos[0] + 1;
            if (h < 0) { y = ypos[1]; h = -h; } else { y = ypos[0]; }
            if (w < 0) { x = xpos[1]; w = -w; } else { x = xpos[0]; }
            if (old_h) {
               XDrawRectangle( winfo.id, winfo.display, winfo.gcb, old_x, old_y, old_w, old_h );
            }
            old_h = h; old_w = w; old_x = x; old_y = y;
            XDrawRectangle( winfo.id, winfo.display, winfo.gcb, x, y, w, h );
         }
         break;
      }
      case Button3: {
         if (npos == 2) {
            if (xpos[0] > xpos[1]) {
               int	xsav = xpos[0];

               xpos[0] = xpos[1];
               xpos[1] = xsav;
            }
            if (ypos[0] < ypos[1]) {
               int	ysav = ypos[0];

               ypos[0] = ypos[1];
               ypos[1] = ysav;
            }
            if (xpos[0] <= x && x <= xpos[1] && ypos[1] <= y && y <= ypos[0]) {
               put_out( );
            }
            if (old_h) {
               XDrawRectangle( winfo.id, winfo.display, winfo.gcb, old_x, old_y, old_w, old_h );
               old_h = 0;
            }
         }
         npos = 0;
         break;
      }
      default: {
         break;
      }
   }
   return( r );
}

int	cursor_reset( int action )
{
   if (!(action & CURSOR_ACTION)) {
      if (old_h) {
         XDrawRectangle( winfo.id, winfo.display, winfo.gcb, old_x, old_y, old_w, old_h );
         old_h = 0;
      }
   }
   return( 0 );
}

int	cursor_send_text( char *string )
{
   strcpy( cursor_string, string );
   cursor_string_len = strlen( string );
   if ( cursor_string_len ) {
      if ( CR && ( cursor_string[cursor_string_len-1] != '\n' ) ) {
         cursor_string[cursor_string_len++] = '\n';
         cursor_string[cursor_string_len] = 0;
      }
   }
   return( send_away( ) );
}
#<

#>            data.c
/* data.c

*/

#include	"gids.h"			/* definitions and symbols */

Data_struct	user;				/* here it is */

int	data_init( void )
{
   int	n;					/* counter */

   user.bscale  = 1.0;				/* reset */
   user.b_zero   = 0.0;				/* reset */
   user.xregion = NULL;
   user.xgt     = NULL;
   user.ygt     = NULL;
   user.yregion = NULL;
   user.idata   = NULL;				/* reset */
   user.imask   = NULL;
   user.n_data  = 0;
   user.mask1   = 0;				/* no plane defined */
   user.mask2   = 0;				/* no planes shown */
   user.images  = 0;
   for (n = 0; n < winfo.ncolors; n++) {
      user.colors[n].red   = 0.0;
      user.colors[n].green = 0.0;
      user.colors[n].blue  = 0.0;
   }
   for (n = 0; n < MAXIDTEXTLEN; n++) {
      user.text1[n] = user.text2[n] = 0;
   }
   return( 0 );					/* return to caller */
}

int	data_text( void )
{
   int	rec = winfo.currec;

   if (winfo.record[rec].mask) {
      strcpy( winfo.text[0], winfo.record[rec].text1 );
      strcpy( winfo.text[1], winfo.record[rec].text2 );
   } else {
      winfo.text[0][0] = 0;
      winfo.text[1][0] = 0;
   }
   misc_info( 0 );
   return( 0 );
}

int	data_position( int window_id, int d_x, int d_y )
{
   Window		window;
   double		u_v;
   int			rec = 0;
   int			u_x = 0;
   int			u_y = 0;
   int			valid = 1;
   int			h, w;
   int			w_x = d_x;
   int			w_y = d_y;
   unsigned char	d_v;

   switch( window_id ) {
      case 0: {
         window = winfo.display;
         h = winfo.dheight;
         w = winfo.dwidth;
         break;
      }
      case 1: {
         window = winfo.xslice;
         h = winfo.nxslice;
         w = winfo.dwidth;
         break;
      }
      case 2: {
         window = winfo.yslice;
         h = winfo.dheight;
         w = winfo.nyslice;
         break;
      }
      default: {
         return( 0 );
         break;
      }
   }
   if (user.idata == NULL) {
      valid = 0;
   } else if (d_x < 0) {			/* x out of range */
      valid = 0;
   } else if (d_y < 0) {			/* y out of range */
      valid = 0;
   } else if (d_x >= w) {			/* x out of range */
      valid = 0;
   } else if (d_y >= h) {			/* y out of range */
      valid = 0;
   } else {
      switch( window_id ) {
         case 0: {
            rec = winfo.currec;
            break;
         }
         case 1: {
            rec = winfo.xslices[d_y];
            break;
         }
         case 2: {
            rec = winfo.yslices[d_x];
            break;
         }
         default: {
            return( 0 );
            break;
         }
      }
      if (rec >= 0 && rec <= winfo.mrecord && winfo.record[rec].mask) {
         switch( window_id ) {
            case 0: {
               u_x = winfo.record[rec].x_grid[d_x];
               u_y = winfo.record[rec].y_grid[d_y];
               break;
            }
            case 1: {
               u_x = winfo.record[rec].x_grid[d_x];
               u_y = winfo.record[rec].y_grid[winfo.last_y];
               w_y = winfo.last_y;
               break;
            }
            case 2: {
               u_x = winfo.record[rec].x_grid[winfo.last_x];
               u_y = winfo.record[rec].y_grid[d_y];
               w_x = winfo.last_x;
               break;
            }
            default: {
               break;
            }
         }
         if (u_x < winfo.record[rec].x_min || u_x > winfo.record[rec].x_max ||
            u_y < winfo.record[rec].y_min || u_y > winfo.record[rec].y_max) {
            valid = 0;
         }
      } else {
         valid = 0;
      }
   }
   if (!valid) {
      if (window_id) {
         winfo.text[0][0] = 0;
         winfo.text[1][0] = 0;
      }
      sprintf( winfo.text[4], "VALUE=" );
      sprintf( winfo.text[5], "POS=" );
   } else {
      strcpy( winfo.text[0], winfo.record[rec].text1 );
      strcpy( winfo.text[1], winfo.record[rec].text2 );
      d_v = misc_readval( window_id, d_x, d_y );
      if (d_v == winfo.blank) {
         sprintf( winfo.text[4], "VALUE=      BLANK" );
      } else {
         u_v = winfo.record[rec].bscale * d_v + winfo.record[rec].b_zero;
         sprintf( winfo.text[4], "VALUE= % 10.2E", u_v);
      }
      if ((winfo.record[rec].xgt == NULL) && (winfo.record[rec].ygt == NULL)) {
         sprintf( winfo.text[5], "POS=%7d,%7d", u_x, u_y );
      } else if (winfo.record[rec].ygt == NULL) {
         sprintf( winfo.text[5], "POS=%s,%7d", winfo.record[rec].xgt[w_x].text,
            u_y );
      } else if (winfo.record[rec].xgt == NULL) {
         sprintf( winfo.text[5], "POS=%7d,%s", u_x,
            winfo.record[rec].ygt[w_y].text );
      } else {
         sprintf( winfo.text[5], "POS=%s,%s", winfo.record[rec].xgt[w_x].text,
            winfo.record[rec].ygt[w_y].text );
      }
   }
   misc_info( 0 );
   return( 0 );					/* return to caller */
}
#<

#>            display.c
/* display.c

*/

#include	"gids.h"			/* GIDS symbols */

#define	CALIB_WINDOW	1			/* calibration window */
#define	DISPLAY_WINDOW	2			/* display window */
#define	MENU_WINDOW	3			/* button window */
#define	OTHER_WINDOW	4			/* other window */
#define	TOP_WINDOW	5			/* main window */
#define	WEDGE_WINDOW	6			/* wedge window */
#define	XSLICE_WINDOW	7			/* X slice window */
#define	YSLICE_WINDOW	8			/* Y slice window */
#define	HELP_WINDOW	9			/* Help window */
#define	PGPLOT_WINDOW	10			/* Plot window */

#define	MIN_HEIGHT	128			/* minimum size display window */
#define MIN_WIDTH	128			/* maximum size display window */

#define	DISPLAY_HEIGHT  512			/* height display window */
#define	DISPLAY_WIDTH	512			/* width display window */
#define	WEDGE_WIDTH	25			/* width wedge window */

Display_struct		winfo;			/* Declared here */
static	int		event_mask;		/* mask for event types */
static	int		min_width;		/* minimum width */
static	int		min_height;		/* minimum height */

extern void pixel2chars( );

static	char	*cfonts[] = {
   "-misc-fixed-medium-r-normal--14-*",
   "-adobe-courier-medium-r-normal--14-*",
   "-misc-fixed-medium-r-semicondensed--12-*",
   "-misc-fixed-medium-r-*-*-12-*",
   "*-*-bold-r-normal-*-12-*",
   "fixed",
   "6x13",
   "6x12",
};

static	char	*hfonts[] = {
   "-misc-fixed-bold-r-normal--15-*",
   "-schumacher-clean-bold-r-normal--15-*",
   "-misc-fixed-medium-r-semicondensed--14-*",
   "-misc-fixed-medium-r-*-*-14-*",
   "-adobe-courier-medium-r-normal--14-*",
   "-misc-fixed-medium-r-semicondensed--13-*",
   "*-*-bold-r-normal-*-15-*",
   "fixed",
   "6x13",
   "6x12",
};

static	char	*ifonts[] = {
   "-misc-fixed-medium-r-semicondensed--13-*",
   "-misc-fixed-medium-r-*-*-10-*",
   "*-*-bold-r-normal-*-10-*",
   "*-misc-fixed-medium-r-normal-*-10-*",
   "*-*-demi-r-normal-*-10-*",
   "fixed",
   "6x13",
   "6x12",
};

static	char	*mfonts[] = {
   "-linotype-helvetica-bold-r-normal-sans-14-*",
   "-adobe-helvetica-bold-r-normal--14-*",
   "-misc-fixed-bold-r-normal--15-*"
   "-misc-fixed-medium-r-normal--18-*",
   "-adobe-helvetica-bold-r-normal--18-*",
   "-misc-fixed-*-r-*-*-15-*",
   "6x20",
   "fixed",
   "6x13",
   "6x12",
};


int	display_command( void )
{
   myargv[myargc++] = "-connection";
   myargv[myargc++] = winfo.con_string;
   XSetCommand( winfo.id, winfo.top, myargv, myargc );
   return( 0 );
}

static	void	check_for_GIDS( Window w, char *Gids_WN )
{
   Window	r, p, *c[1];
   char		*window_name[1];
   unsigned int	nc, n;

   XFetchName( winfo.id, w, window_name );
   if ((window_name[0] != NULL ) && !strcmp( window_name[0], Gids_WN )) {
      Atom		actual_type;
      int		actual_format;
      unsigned long	nitems, bytes_after;
      unsigned char	*prop[1];

      if (XGetWindowProperty( winfo.id, w, XA_WM_COMMAND, 0, 400,
         False, AnyPropertyType, &actual_type, &actual_format, &nitems,
         &bytes_after, prop ) == Success) {
         if (nitems && (actual_type == XA_STRING)) {
            char	*ptr = (char *) prop[0];
            int		next = 0;

            while (nitems > 0) {
               int	l = strlen( ptr );

               if (next && l) {
                  strcpy( winfo.con_string, ptr );
                  next = 0;
               }
               if (!strcmp( ptr, "-connection" )) next = 1;
               l++;
               nitems -= l;
               ptr += l;
            }
         }
         if (prop[0] != NULL) XFree( (caddr_t) prop[0] );
      }
   }
   if (window_name[0] != NULL) XFree( (caddr_t) window_name[0] );
   XQueryTree( winfo.id, w, &r, &p, c, &nc );
   for ( n = 0; n < nc && !winfo.con_string[0]; n++ ) {
      check_for_GIDS( c[0][n], Gids_WN );
   }
   if (nc) XFree( (caddr_t) c[0] );
}

int	display_open( char *display_name, char *window_name )
{
   char			*ptr;
   int			getpid( );		/* gets pid */
   int			n;			/* loop counter */
   int			x;			/* x loop counter */
   int			y;			/* y loop counter */
   XGCValues	 	values;
   XSetWindowAttributes	attributes;		/* window attributes */
   XSizeHints		sizehints;		/* Sizehints */

   winfo.clients       = 0;			/* no clients yet */
   winfo.con_string[0] = 0;			/* no connections yet */
   winfo.pid           = getpid( );		/* the pid */
   winfo.Saved         = 0;			/* no pixmap saved yet */
   winfo.id      = XOpenDisplay( display_name );/* open display */
   
   if (winfo.id == NULL) {			/* error */
      return( GDIE_S_NOOPEN );			/* display open error */
   }
   XSetErrorHandler( misc_error_handler1 );	/* our own error handler */
   XSetIOErrorHandler( misc_error_handler2 );	/* for fatal errors */
   winfo.autoraise = 0;				/* default */
   ptr = XGetDefault( winfo.id, "gids", "autoraise" );
   if (ptr != NULL && !strcmp( ptr, "True" )) {
      winfo.autoraise = 1;
   }
   winfo.windows = 0;				/* no extra graphics window */
   winfo.screen  = DefaultScreen( winfo.id );	/* get screen number */
   winfo.currec  = 0;				/* first record */
   winfo.scaling = LINEAR_SCALE;		/* linear scaling */
   winfo.root    = RootWindow( winfo.id, winfo.screen );
   check_for_GIDS( winfo.root, window_name );	/* GIDS alreay active ? */
   if (winfo.con_string[0]) return( GDIE_SUCCESS );
   ptr = XGetDefault( winfo.id, "gids", "help_file" );
   help_init( ptr );
   ptr = XGetDefault( winfo.id, "gids", "calibration_font" );
   if (ptr != NULL) {
      winfo.cfont = XLoadQueryFont( winfo.id, ptr );
   } else {
      winfo.cfont = NULL;
   }
   n = 0;
   while ( (winfo.cfont == NULL) && (n < (sizeof(cfonts)/sizeof(char *)))) {
      winfo.cfont = XLoadQueryFont( winfo.id, cfonts[n++] );
   }
   if (winfo.cfont == NULL ) {			/* no fonts */
      display_close( display_name );
      return( GDIE_S_NOCFONT );
   }
   ptr = XGetDefault( winfo.id, "gids", "menu_font" );
   if (ptr != NULL) {
      winfo.mfont = XLoadQueryFont( winfo.id, ptr );
   } else {
      winfo.mfont = NULL;
   }
   n = 0;
   while ( (winfo.mfont == NULL) && (n < (sizeof(mfonts)/sizeof(char *)))) {
      winfo.mfont = XLoadQueryFont( winfo.id, mfonts[n++] );
   }
   if (winfo.mfont == NULL ) {			/* no fonts */
      display_close( display_name );
      return( GDIE_S_NOMFONT );
   }
   ptr = XGetDefault( winfo.id, "gids", "info_font" );
   if (ptr != NULL) {
      winfo.ifont = XLoadQueryFont( winfo.id, ptr );
   } else {
      winfo.ifont = NULL;
   }
   n = 0;
   while ( (winfo.ifont == NULL) && (n < (sizeof(ifonts)/sizeof(char *)))) {
      winfo.ifont = XLoadQueryFont( winfo.id, ifonts[n] );
      n++;
   }
   if (winfo.ifont == NULL ) {			/* no fonts */
      winfo.ifont = winfo.cfont;
   }
   ptr = XGetDefault( winfo.id, "gids", "help_font" );
   if (ptr != NULL) {
      winfo.hfont = XLoadQueryFont( winfo.id, ptr );
   } else {
      winfo.hfont = NULL;
   }
   n = 0;
   while ( (winfo.hfont == NULL) && (n < (sizeof(hfonts)/sizeof(char *)))) {
      winfo.hfont = XLoadQueryFont( winfo.id, hfonts[n] );
      n++;
   }
   if (winfo.hfont == NULL ) {			/* no fonts */
      winfo.hfont = winfo.ifont;
   }


   /* VOG2010: The definitions of black and white pixels in the next lines */
   /* in the original code are not valid for a private colormap. We define */
   /* them later in this code after the color setup.                       */
   /*winfo.white = WhitePixel( winfo.id, winfo.screen );*/
   /*winfo.black = BlackPixel( winfo.id, winfo.screen );*/
   winfo.visual  = XDefaultVisual( winfo.id, winfo.screen );
   winfo.class   = winfo.visual->class;
   winfo.planes  = DisplayPlanes( winfo.id, winfo.screen );
   winfo.depth   = DefaultDepth( winfo.id, winfo.screen );
   winfo.width   = DisplayWidth( winfo.id, winfo.screen );
   winfo.widthMM = DisplayWidthMM( winfo.id, winfo.screen );
   winfo.height  = DisplayHeight( winfo.id, winfo.screen );
   winfo.heightMM= DisplayHeightMM( winfo.id, winfo.screen );
   winfo.nxslice = 0;				/* no x slices yet */
   winfo.nyslice = 0;				/* no y slices yet */
   winfo.windows = 0;				/* no extra windows */
   ptr = XGetDefault( winfo.id, "gids","display_height" );
   if (ptr == NULL) {
      winfo.dheight = DISPLAY_HEIGHT;		/* height of display window */
   } else {
      winfo.dheight = atoi( ptr );
   }
   if (winfo.dheight < MIN_HEIGHT) winfo.dheight = MIN_HEIGHT;
   ptr = XGetDefault( winfo.id, "gids","display_width");
   if (ptr == NULL ) {
      winfo.dwidth  = DISPLAY_WIDTH;		/* width of display window */
   } else {
      winfo.dwidth  = atoi( ptr );
   }
   if (winfo.dwidth < MIN_WIDTH) winfo.dwidth = MIN_WIDTH;
   {
      int	ch;

      winfo.iwidth = ( MININFOWIDTH + 1 ) * ( winfo.ifont->max_bounds.rbearing
         - winfo.ifont->min_bounds.lbearing );
      ch = winfo.ifont->ascent + winfo.ifont->descent;
      winfo.iheight = ch + ch / 2;
   }
   {
      char	text[MINMENUWIDTH+1];
      int	ch;
      int	n;

      for ( n = 0; n < sizeof(text); text[n++] = 'w' );
      winfo.mwidth = XTextWidth( winfo.mfont, text, n );
      ch = winfo.mfont->ascent + winfo.mfont->descent;
      winfo.mheight = ch + ch;
   }
   if (winfo.iwidth > winfo.mwidth) {
      winfo.mwidth = winfo.iwidth;
   } else {
      winfo.iwidth = winfo.mwidth;
   }
   {
      char	text[MAXIDTEXTLEN+1];
      int	ch;
      int	n;
      int	nc = MAXIDTEXTLEN;

      ch = winfo.ifont->ascent + winfo.ifont->descent;
      for ( n = 0; n < nc; text[n++] = 'e' );
      while ( XTextWidth( winfo.ifont, text, nc ) >= ( winfo.iwidth - 2) ) nc--;
      winfo.i_nchr = nc;
      winfo.i_xpos = ( winfo.iwidth - XTextWidth( winfo.ifont, text, nc ) ) / 2;
      winfo.i_ypos = ( winfo.iheight + winfo.ifont->ascent -
         winfo.ifont->descent ) / 2;
   }
   winfo.wwidth  = WEDGE_WIDTH;			/* width of wedge window */
   {
      char	text[MINCALIBWIDTH+1];

      sprintf( text, "%*.2E", MINCALIBWIDTH, 1.0 );
      winfo.cwidth = XTextWidth( winfo.cfont, text, MINCALIBWIDTH ) + 10;
   }
   winfo.mrecord = ( winfo.memory * 1024 ) / ( winfo.dwidth * winfo.dheight ) - 1;
   if (winfo.mrecord < 0) winfo.mrecord = 0;	/* just in case */
   if (winfo.mrecord >= MAXRECORD) winfo.mrecord = MAXRECORD - 1;
   winfo.nrecord = 0;				/* recordings counter */
   winfo.nsequence = 0;
   for (n = 0; n <= winfo.mrecord; n++) {
      winfo.record[n].mask = 0;
      winfo.record[n].xgt  = NULL;
      winfo.record[n].ygt  = NULL;
   }
   {						/* find size of help window */
      char	text[76];
      int	n;

      for (n = 0; n < sizeof( text ); n++) text[n] = 'e';
      winfo.hwidth = XTextWidth( winfo.hfont, text, n );
      winfo.hheight = ( MAXHELPLINES + 1 ) *
         ( winfo.hfont->ascent + winfo.hfont->descent ) + 5;
   }
   /*
    * find size of top window.
    */
   {
      int	h, w;

      h = MAXINFO * winfo.iheight + MAXMENUS * winfo.mheight +
         3 * (MAXINFO + MAXMENUS) + 1;
      min_height = h;
      if ((winfo.dheight + 4 ) > min_height) {
         winfo.wheight = winfo.dheight;		/* height of wedge window */
         winfo.cheight = winfo.dheight;		/* height calibration wedge */
      } else {
         winfo.wheight = min_height - 4;
         winfo.cheight = min_height - 4;
      }
      if (min_height < (MIN_HEIGHT + 4)) min_height = MIN_HEIGHT + 4;
      if ( ( winfo.wheight + 4 ) > h ) h = winfo.wheight + 4;
      if ( ( winfo.cheight + 4 ) > h ) h = winfo.cheight + 4;
      if ( ( winfo.dheight + 4 ) > h ) h = winfo.dheight + 4;
      winfo.theight = h;
      w = winfo.iwidth;
      if ( w < winfo.mwidth ) w = winfo.mwidth;
      min_width = w + winfo.wwidth + winfo.cwidth + MIN_WIDTH + 13;
      w = w + winfo.wwidth + winfo.cwidth + winfo.dwidth + 13;
      winfo.twidth = w;
   }
   winfo.record[0].x_grid = calloc( sizeof( int ), winfo.dwidth );
   for (n = 0; n < winfo.dwidth; n++) {
      winfo.record[0].x_grid[n] = n;
   }
   winfo.x_zoomc = 0;
   winfo.x_zoomf = 0;
   winfo.record[0].y_grid = calloc( sizeof( int ), winfo.dheight );
   for (n = 0; n < winfo.dheight; n++) {
      winfo.record[0].y_grid[n] = winfo.dheight - 1 - n;
   }
   winfo.y_zoomc = 0;
   winfo.y_zoomf = 0;
   if (color_init( )) {				/* initialize the colors */
      display_close( display_name );		/* close display */
      return( GDIE_S_NOCOLOR );			/* return code */
   }
   /* VOG2010: Now we have explicit settings for black and white pixels  */
   /* Use the indices for black and white pixels in the user.idata array */
   /* because these contain client bytes with one byte per pixel.        */
   winfo.black   = winfo.table[winfo.ncolors+MAXGCOLORS].pixel;
   winfo.white   = winfo.table[winfo.ncolors+MAXGCOLORS+1].pixel;
   values.line_width = 1;
   values.cap_style  = CapRound;
   values.join_style = JoinRound;

   values.foreground = winfo.white;
   values.font       = winfo.cfont->fid;
   winfo.gcc         = XCreateGC( winfo.id, winfo.root, GCForeground |
      GCFont | GCLineWidth | GCJoinStyle | GCCapStyle, &values );
   values.foreground = winfo.black;
   values.font       = winfo.mfont->fid;
   winfo.gcm         = XCreateGC( winfo.id, winfo.root, GCForeground |
      GCFont | GCLineWidth | GCJoinStyle | GCCapStyle, &values );
   values.foreground = winfo.white;
   winfo.gcmreverse  = XCreateGC( winfo.id, winfo.root, GCForeground |
      GCFont | GCLineWidth | GCJoinStyle | GCCapStyle, &values );
   values.font       = winfo.hfont->fid;
   values.foreground = winfo.black;
   winfo.gch         = XCreateGC( winfo.id, winfo.root, GCForeground |
      GCFont | GCLineWidth | GCJoinStyle | GCCapStyle, &values );
   values.font       = winfo.ifont->fid;
   values.foreground = winfo.white;
   winfo.gci         = XCreateGC( winfo.id, winfo.root, GCForeground |
      GCFont | GCLineWidth | GCJoinStyle | GCCapStyle, &values );
   values.foreground = 255;
   values.function   = GXxor;
   winfo.gcb         = XCreateGC( winfo.id, winfo.root, GCForeground |
      GCFont | GCFunction | GCLineWidth | GCJoinStyle | GCCapStyle, &values );
   if (menu_init( )) {				/* initialize the menu */
      display_close( display_name );		/* close display */
      return( GDIE_S_NOMENU );			/* return code */
   }
   if (scale_init( )) {				/* initialize scaling */
      display_close( display_name );		/* close display */
      return( GDIE_S_NOSCALE );			/* return code */
   }
   if (wedge_init( )) {				/* initialize wedge colors */
      display_close( display_name );		/* close display */
      return( GDIE_S_NOWEDGE );			/* return code */
   }
   if (data_init( )) {				/* initialize data part */
      display_close( display_name );		/* close display */
      return( GDIE_S_NODATA );			/* return code */
   }
   if (coord_init( )) {				/* initialize coordinate part */
      display_close( display_name );		/* close display */
      return( GDIE_S_NOCOORD );			/* return code */
   }
   for (n = 0; n < MAXGCOLORS; n++) {
      values.foreground = winfo.gcells[n];
      values.line_width = 1;
      if (n) {
         values.function = GXcopy;
      } else {
         values.function = GXnoop;
      }
      winfo.gcg[n] = XCreateGC( winfo.id, winfo.root, GCForeground | GCFunction |
         GCLineWidth, &values );
   }
   /*
    * attributes for main window
    */
   attributes.colormap         = winfo.colormap;
   attributes.cursor           = XCreateFontCursor( winfo.id, XC_crosshair );
   attributes.background_pixel = winfo.white;
						/* create main window */
   winfo.top = XCreateWindow( winfo.id, winfo.root, 0, 0, winfo.twidth,
      winfo.theight, 1, winfo.depth, InputOutput, winfo.visual,
      CWCursor | CWBackPixel | CWColormap, &attributes );
						/* set properties of window */
   XStoreName( winfo.id, winfo.top, window_name );
   sizehints.height     = winfo.theight;
   sizehints.width      = winfo.twidth;
   sizehints.min_height = winfo.theight - winfo.dheight;
   sizehints.min_width  = winfo.twidth - winfo.dwidth;
   sizehints.height_inc = 1;
   sizehints.width_inc  = 1;
   sizehints.flags      = PSize | PMinSize | PResizeInc;
   /*
    * Find out if user has specified a position for the window.
    */
   {
      char	*x, *y;

      x = XGetDefault( winfo.id, "gids", "xposition" );
      y = XGetDefault( winfo.id, "gids", "yposition" );
      if ( ( x != NULL ) && ( y != NULL ) ) {
         sizehints.x = atoi( x );
         sizehints.y = atoi( y );
         if ( sizehints.x < 0 ) sizehints.x += ( winfo.width - winfo.twidth );
         if ( sizehints.y < 0 ) sizehints.y += ( winfo.height - winfo.theight );
         sizehints.flags |= USPosition;
         XMoveWindow( winfo.id, winfo.top, sizehints.x, sizehints.y );
      }
   }
   XSetNormalHints( winfo.id, winfo.top, &sizehints );
   /*
    * attributes for info windows
    */
   attributes.backing_store    = Always;
   attributes.backing_planes   = 0xff;
   attributes.border_pixel     = winfo.black;
   attributes.background_pixel = winfo.black;
   for ( n = 0; n < MAXINFO; n++ ) {
      int	yoff;

      yoff = 1 + n * ( winfo.iheight + 3 );
      winfo.info[n] = XCreateWindow( winfo.id, winfo.top, 1, yoff, winfo.iwidth,
         winfo.iheight, 1, winfo.depth, InputOutput, winfo.visual,
         CWBackingStore | CWBackingPlanes | CWBorderPixel | CWBackPixel,
         &attributes );
      winfo.text[n][0] = 0;
   }
   /*
    * attributes for menu windows
    */
   attributes.backing_store    = Always;
   attributes.backing_planes   = 0xff;
   attributes.background_pixel = winfo.white;
   attributes.border_pixel     = winfo.black;
   attributes.cursor           = XCreateFontCursor( winfo.id, XC_hand2 );
   for (n = 0; n < MAXMENUS; n++) {		/* create menu */
      int	yoff;

      yoff = 1 + MAXINFO * ( winfo.iheight + 3 ) + n * ( winfo.mheight + 3 );
      winfo.menus[n] = XCreateWindow( winfo.id, winfo.top, 1, yoff,
         winfo.mwidth, winfo.mheight, 1, winfo.depth, InputOutput, winfo.visual,
         CWBackingStore | CWBackingPlanes | CWBorderPixel | CWCursor |
         CWBackPixel, &attributes );
   }
   /*
    * attributes for calibration wedge.
    */
   attributes.backing_store    = Always;
   attributes.backing_planes   = 0xff;
   attributes.border_pixel     = winfo.black;
   attributes.background_pixel = winfo.black;
   attributes.cursor           = XCreateFontCursor( winfo.id, XC_crosshair );
   winfo.calib = XCreateWindow( winfo.id, winfo.top,
      winfo.mwidth + 4, 1, winfo.cwidth, winfo.cheight, 1 ,
      winfo.depth, InputOutput, winfo.visual, CWBackingStore |
      CWBackingPlanes | CWCursor | CWBackPixel | CWBorderPixel, &attributes );
   /*
    * attributes for wedge window
    */
   attributes.backing_store    = Always;
   attributes.backing_planes   = 0xff;
   attributes.background_pixel = winfo.white;
   attributes.border_pixel     = winfo.black;
   attributes.cursor           = XCreateFontCursor( winfo.id, XC_double_arrow );
						/* create wedge window */
   winfo.wedge = XCreateWindow( winfo.id, winfo.top,
      winfo.mwidth + winfo.cwidth + 7, 1, winfo.wwidth, winfo.wheight, 1,
      winfo.depth, InputOutput, winfo.visual, CWBackingStore |
      CWBackingPlanes | CWCursor | CWBackPixel | CWBorderPixel, &attributes );
   /*
    * attributes for display window
    */
   attributes.backing_store    = Always;
   attributes.backing_planes   = 0xff;
   attributes.background_pixel = winfo.black;
   attributes.border_pixel     = winfo.black;
   attributes.cursor           = XCreateFontCursor( winfo.id, XC_circle );
						/* create display window */
   winfo.display = XCreateWindow( winfo.id, winfo.top,
      winfo.mwidth + winfo.wwidth + winfo.cwidth + 10, 1, winfo.dwidth,
      winfo.dheight, 1, winfo.depth, InputOutput, winfo.visual,
      CWBackingStore | CWBackingPlanes | CWCursor | CWBackPixel |
      CWBorderPixel, &attributes );
   winfo.pgplot  = winfo.display;
   winfo.pgh     = winfo.dheight;
   winfo.pgw     = winfo.dwidth;

   /* VOG2010: For DirecColor the number of bytes in a pixel is   */
   /* 1, 2 or 4. The original code only allocated space for 1     */
   /* unsigned character which only works for 8-bits PseudoColor. */
   winfo.wdata = calloc( sizeof(unsigned char), winfo.wwidth * winfo.wheight*(winfo.pad/8) );

   /* VOG2010: In the original code the padding parameter was set to */
   /* the value of CHAR_BIT, but is now replaced by winfo.pad to     */
   /* support DirectColor pixels also.                               */
   
   winfo.wimage = XCreateImage( winfo.id, winfo.visual, winfo.depth, ZPixmap,
                                0, NULL, /*(char *) winfo.wdata,*/
                                winfo.wwidth, winfo.wheight, winfo.pad, 0 );
   /* VOG2010: The data was set to NULL and is now filled and assigned. */
   /* We needed to create n image first to get the byte order which is  */
   /* required in the pixel2chars() function.                           */
   winfo.byte_order = winfo.wimage->byte_order;
   /* VOG2010: Scale indices between all available image colors */
   for (n = 0, y = winfo.wheight; y-- > 0;) {
      unsigned char ch;

      ch = (float) (winfo.maxcolor - winfo.mincolor - 1) /
         (float) (winfo.wheight - 1) * (float) y + winfo.mincolor + 1;

      for (x = 0; x < winfo.wwidth; x++) {
         /* VOG2010: The original code only needed to assign the   */
         /* pixel value to the wedge data array. Now the pixels    */
         /* could be represented by more than 1 byte. The function */
         /* pixel2chars() takes care of the decomposition into     */
         /* bytes (unsigned chars) and the byte order.             */
         pixel2chars(winfo.table[ch].pixel, winfo.wdata, &n,
                     winfo.bytespp, winfo.byte_order);
      }
   }
   winfo.wimage->data = (char *) winfo.wdata;
   
   winfo.wpixmap = XCreatePixmap( winfo.id, winfo.wedge, winfo.wwidth,
      winfo.wheight, winfo.depth );
   XPutImage( winfo.id, winfo.wpixmap, winfo.gcm, winfo.wimage, 0, 0, 0, 0,
              winfo.wwidth, winfo.wheight );
   /* VOG2010: Changed allocation */
   winfo.idata = calloc( sizeof(unsigned char), winfo.dwidth * winfo.dheight*(winfo.pad/8) );
   for (n = 0, x = 0; x < winfo.dwidth; x++) {
      for (y = 0; y < winfo.dheight; y++) {
         pixel2chars(winfo.blank, winfo.idata, &n, winfo.bytespp, winfo.byte_order);
      }
   }
   /* VOG2010: Replaced CHAR_BIT by winfo.pad in XCreateImage() */
   winfo.iimage = XCreateImage( winfo.id, winfo.visual, winfo.depth, ZPixmap,
      0, (char *) winfo.idata, winfo.dwidth, winfo.dheight, winfo.pad, 0 );
   winfo.record[0].pixmap = XCreatePixmap( winfo.id, winfo.display,
      winfo.dwidth, winfo.dheight, winfo.depth );
   XPutImage( winfo.id, winfo.record[0].pixmap, winfo.gcm, winfo.iimage,
      0, 0, 0, 0, winfo.dwidth, winfo.dheight );
   winfo.record[0].mask = 1;
   XMapSubwindows( winfo.id, winfo.top );
   XMapWindow( winfo.id, winfo.top );
   XSelectInput( winfo.id, winfo.top, ButtonPressMask | ButtonReleaseMask |
      ExposureMask | VisibilityChangeMask | StructureNotifyMask |
      KeyPressMask | KeyReleaseMask );
   XSelectInput( winfo.id, winfo.wedge, ExposureMask | VisibilityChangeMask |
      PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
      ButtonMotionMask | EnterWindowMask | LeaveWindowMask );
   XSelectInput( winfo.id, winfo.calib, ExposureMask | VisibilityChangeMask );
   XSelectInput( winfo.id, winfo.display, ExposureMask | VisibilityChangeMask |
      PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
      ButtonMotionMask | EnterWindowMask | LeaveWindowMask |
      KeyPressMask | KeyReleaseMask );
   for (n = 0; n < MAXMENUS; n++) {
      XSelectInput( winfo.id, winfo.menus[n], ButtonPressMask | ExposureMask |
         VisibilityChangeMask | ButtonReleaseMask | EnterWindowMask |
         LeaveWindowMask | StructureNotifyMask | SubstructureNotifyMask );
   }
   {
      event_mask = 0;
      n = 1;
      do {
         event_mask |= n;
         n *= 2;
      } while (n < LASTEvent);
   }
   XFlush( winfo.id );
   {
      XEvent	event;

      XMaskEvent( winfo.id, ExposureMask | VisibilityChangeMask |
         StructureNotifyMask | SubstructureNotifyMask, &event );
      input_show( );
      misc_mask( );
      misc_recordings( );
      data_position( 0, -1, -1 );
      data_text( );
      menu_draw( );				/* menus */
      XCopyArea( winfo.id, winfo.wpixmap, winfo.wedge, winfo.gcm,
         0, 0, winfo.wwidth, winfo.wheight, 0, 0 );
      wedge_draw( 1 );				/* calibration wedge */
   }
   return( GDIE_SUCCESS );
}

int	display_close( char *display_name )	/* display name */
{
   if (winfo.id != NULL) {			/* display open ? */
      int	n;

      XFreeColormap( winfo.id, winfo.colormap );
      recording_clear( );
      for ( n = 0; n <= winfo.mrecord; n++ ) {
         recording_delete( n );
      }
      XCloseDisplay( winfo.id );		/* close it */
   }
   winfo.id = NULL;				/* reset */
   return( 0 );					/* return to caller */
}

int	display_do( int action )
{
   static int	button;
   static int	old_action = NONE_ACTION;
   static int	old_button = -1;
   static int	old_track_display = -1;
   static int	blink_button = 0;
   static int	slice_button = AnyButton;
   static int	split_button = 0;
   static int	track_display = 0;
   static int	track_keyboard = 0;
   static int	track_wedge = 0;
   static int	window_id;

    while (XPending( winfo.id )) {
      XEvent	event;

      XNextEvent( winfo.id, &event );
      event.type &= event_mask;
      for (button = 0; button < MAXMENUS; button++) {
         if (winfo.menus[button] == event.xany.window) break;
      }
      if (button < MAXMENUS) {
         window_id = MENU_WINDOW;
      } else if (winfo.display == event.xany.window) {
         window_id = DISPLAY_WINDOW;
      } else if (winfo.wedge == event.xany.window) {
         window_id = WEDGE_WINDOW;
      } else if (winfo.calib == event.xany.window) {
         window_id = CALIB_WINDOW;
      } else if ((winfo.windows & WINDOW_XSLICE) &&
         winfo.xslice == event.xany.window) {
         window_id = XSLICE_WINDOW;
      } else if ((winfo.windows & WINDOW_YSLICE) &&
         winfo.yslice == event.xany.window) {
         window_id = YSLICE_WINDOW;
      } else if ((winfo.windows & WINDOW_HELP) &&
         winfo.help == event.xany.window) {
         window_id = HELP_WINDOW;
      } else if ((winfo.windows & WINDOW_PGPLOT) &&
         winfo.pgplot == event.xany.window) {
         window_id = PGPLOT_WINDOW;
      } else if (winfo.top == event.xany.window) {
         window_id = TOP_WINDOW;
      } else {
         window_id = OTHER_WINDOW;
      }
      switch( event.type ) {
         case ButtonPress: {
            switch( window_id ) {
               case DISPLAY_WINDOW: {
                  if ((action & BLINK_ACTION) && !track_keyboard) {
                     track_display = 1;
                     blink_button = event.xbutton.button;
                     recording_button( blink_button, event.xmotion.x );
                  }
                  if (action & COLOR_ACTION) {
                     color_setlut( event.xbutton.button );
                     track_display = 1;
                     if (!color_transfer( event.xmotion.x, event.xmotion.y )) {
                        color_modify( );
                     }
                  }
                  if ((action & CURSOR_ACTION) && !track_keyboard) {
                     track_display = cursor_do( event.xmotion.x, event.xmotion.y, event.xbutton.button );
                  }
                  if ((action & DRAW_ACTION) && !track_keyboard) {
                     region_do_define( event.xmotion.x,
                        event.xmotion.y, event.xbutton.button );
                  }
                  if ((action & SLICE_ACTION) && !track_keyboard) {
                     track_display = 1;
                     slice_button = event.xbutton.button;
                     slice_do_slice( 0, event.xmotion.x, event.xmotion.y, 0,
                        slice_button, 0 );
                  }
                  if ((action & SPLIT_ACTION) && !track_keyboard) {
                     track_display = 1;
                     split_button = event.xbutton.button;
                     recording_do_split( event.xmotion.x, event.xmotion.y,
                        split_button );
                  }
                  if ((action & VIEW_ACTION) && !track_keyboard) {
                     track_display = 1;
                     recording_do_view( event.xbutton.button );
                  }
                  if ((action & ZOOM_ACTION) && !track_keyboard) {
                     zoom_modify( event.xmotion.x, event.xmotion.y,
                        event.xbutton.button );
                     data_position( 0, event.xmotion.x, event.xmotion.y );
                  }
                  if ((action & BLOT_ACTION) && !track_keyboard) {
                     region_blot( event.xmotion.x, event.xmotion.y );
                  }
                  break;
               }
               case HELP_WINDOW: {
                  display_help( 0 );
                  break;
               }
               case MENU_WINDOW: {
                  old_button = button;
                  break;
               }
               case WEDGE_WINDOW: {
                  if (action & WEDGE_ACTION) {
                     track_wedge = 1;
                     wedge_modify( event.xmotion.y );
                  }
                  break;
               }
               case XSLICE_WINDOW: {
                  if (action & SLICE_ACTION) {
                     track_display = 1;
                     slice_button = event.xbutton.button;
                     slice_do_slice( 1, event.xmotion.x, event.xmotion.y, 0,
                        slice_button, 0 );
                  }
                  break;
               }
               case YSLICE_WINDOW: {
                  if (action & SLICE_ACTION) {
                     track_display = 1;
                     slice_button = event.xbutton.button;
                     slice_do_slice( 2, event.xmotion.x, event.xmotion.y, 0,
                        slice_button, 0 );
                  }
                  break;
               }
               default: {
                  break;
               }
            }
            break;
         }
         case ButtonRelease: {
            switch( window_id ) {
               case DISPLAY_WINDOW: {
                  if ((action & BLINK_ACTION) && !track_keyboard) {
                     track_display = 0;
                     recording_button( blink_button, event.xmotion.x );
                  }
                  if ((action & COLOR_ACTION)) {
                     track_display = 0;
                     if (!color_transfer( event.xmotion.x, event.xmotion.y )) {
                        color_modify( );
                     }
                  }
                  if ((action & CURSOR_ACTION) && !track_keyboard) {
                     track_display = 0;
                  }
                  if ((action & SLICE_ACTION) && !track_keyboard) {
                     track_display = 0;
                     slice_do_slice( 0, event.xmotion.x, event.xmotion.y, 0,
                        event.xbutton.button, 1 );
                     slice_button = AnyButton;
                  }
                  if ((action & SPLIT_ACTION) && !track_keyboard) {
                     track_display = 0;
                     recording_do_split( event.xmotion.x, event.xmotion.y,
                        split_button );
                  }
                  if ((action & VIEW_ACTION) && !track_keyboard) {
                     track_display = 0;
                  }
                  break;
               }
               case MENU_WINDOW: {
                  if (old_button == button) {
                     int	(*f)();

                    if (event.xbutton.button == Button2) {
                        int	depth = menu[old_button].depth;
                        int	level = menu[old_button].level;

                        help_do_help( depth, level );
                     } else {
                        f = menu[old_button].f;
                        action = f( old_button );
                     }
                     XDrawRectangle( winfo.id, winfo.menus[button],
                        winfo.gcm, 0, 0, winfo.mwidth - 1,
                        winfo.mheight - 1 );
                  }
                  break;
               }
               case WEDGE_WINDOW: {
                  if (action & WEDGE_ACTION) {
                     track_wedge = 0;
                     wedge_modify( event.xmotion.y );
                  }
                  break;
               }
               case XSLICE_WINDOW: {
                  if (action & SLICE_ACTION) {
                     track_display = 0;
                     slice_do_slice( 1, event.xmotion.x, event.xmotion.y, 0,
                        event.xbutton.button, 1 );
                     slice_button = AnyButton;
                  }
                  break;
               }
               case YSLICE_WINDOW: {
                  if (action & SLICE_ACTION) {
                     track_display = 0;
                     slice_do_slice( 2, event.xmotion.x, event.xmotion.y, 0,
                        event.xbutton.button, 1 );
                     slice_button = AnyButton;
                  }
                  break;
               }
               default: {
                  break;
               }
            }
            old_button = -1;			/* reset previous button */
            break;
         }
         case ClientMessage: {
            misc_message( event );
            break;
         }
         case ConfigureNotify: {		/* changed configuration */
            int	height;
            int	width;
            Window	window;

            height = event.xconfigure.height;
            width  = event.xconfigure.width;
            window = event.xconfigure.window;
            switch( window_id ) {
               case TOP_WINDOW: {
                  if (window == winfo.top) {
                     if ((winfo.twidth != width) || (winfo.theight != height)) {
                        int	dh, dw;

                        if (winfo.clients || (action & SLICE_ACTION)) {
                           XBell( winfo.id, 100 );
                           XResizeWindow( winfo.id, winfo.top, winfo.twidth,
                              winfo.theight );
                        } else {

                           dh = height - winfo.theight + winfo.dheight;
                           dw = width - winfo.twidth + winfo.dwidth;
                           display_resize( dw, dh );
                        }
                     }
                  }
                  break;
               }
               case PGPLOT_WINDOW: {
                  if (window == winfo.pgplot) {
                     if ((width != winfo.pgw) || (height != winfo.pgh)) {
                        if (winfo.clients) {
                           XBell( winfo.id, 100 );
                           XResizeWindow( winfo.id, winfo.pgplot, winfo.pgw,
                              winfo.pgh );
                        } else {
                           winfo.pgw = width;
                           winfo.pgh = height;
                           XResizeWindow( winfo.id, winfo.pgplot, width, height );
                        }
                     }
                  }
                  break;
               }
               default: {
                  break;
               }
            }
            wedge_draw( 1 );
            break;
         }
         case KeyPress: {
            if (window_id == HELP_WINDOW) {
               help_show( );
            } else if (input_putchar( event.xkey, action ) == 1) {
               track_keyboard = 1;
               old_action = action;
               old_track_display = track_display;
               track_display = 0;
               action |= COLOR_ACTION;
            }
            break;
         }
         case KeyRelease: {
            if ((window_id != HELP_WINDOW) && track_keyboard ) {
               track_keyboard = 0;
               track_display = old_track_display;
               action = old_action;
            }
            break;
         }
         case MapNotify: {
            input_show( );
            misc_mask( );
            misc_recordings( );
            data_position( 0, -1, -1 );
            data_text( );
            menu_draw( );		/* menu */
            XCopyArea( winfo.id, winfo.wpixmap, winfo.wedge, winfo.gcm,
               0, 0, winfo.wwidth, winfo.wheight, 0, 0 );
            wedge_draw( 1 );		/* calibration wedge */
            if (winfo.windows & (WINDOW_XSLICE | WINDOW_YSLICE)) {
               slice_do_slice( 0, winfo.last_x, winfo.last_y, 1, slice_button, 0 );
            }
            break;
         }
         case Expose: 			/* show all windows */
         case MappingNotify:
         case VisibilityNotify: {
            switch( window_id ) {
               case HELP_WINDOW: {
                  help_continue( );
                  break;
               }
               case XSLICE_WINDOW: {
                  slice_do_slice( 0, winfo.last_x, winfo.last_y, 1, slice_button, 0 );
                  break;
               }
               case YSLICE_WINDOW: {
                  slice_do_slice( 0, winfo.last_x, winfo.last_y, 1, slice_button, 0 );
                  break;
               }
               /* VOG2010: Add also code to restore MENU, WEDGE and DISPLAY windows */
               case WEDGE_WINDOW: {
                  XCopyArea( winfo.id, winfo.wpixmap, winfo.wedge, winfo.gcm,
                             0, 0, winfo.wwidth, winfo.wheight, 0, 0 );
                  wedge_draw( 1 );		/* calibration wedge */
               }
               case DISPLAY_WINDOW: {
                  XCopyArea( winfo.id, winfo.record[winfo.currec].pixmap, winfo.display, winfo.gcm,
                             0, 0, winfo.dwidth, winfo.dheight, 0, 0 );
                  region_redraw( );
               }
               case MENU_WINDOW: {
                  misc_info(1);  /* Force reprint of info test */
                  menu_draw( );
               }
               default: {
                  break;
               }
            }
            break;
         }
         case LeaveNotify: {
            switch( window_id ) {
               case DISPLAY_WINDOW: {
                  data_position( 0, -1, -2 );
                  data_text( );
                  break;
               }
               case MENU_WINDOW: {
                  menu_leave( button );
                  break;
               }
               case WEDGE_WINDOW: {
                  wedge_position( -1 );
                  break;
               }
               case XSLICE_WINDOW: {
                  data_position( 1, -1, -1 );
                  data_text( );
                  break;
               }
               case YSLICE_WINDOW: {
                  data_position( 2, -1, -1 );
                  data_text( );
                  break;
               }
               default: {
                  break;
               }
            }
            break;
         }
         case EnterNotify: {
            switch( window_id ) {
               case DISPLAY_WINDOW: {
                  data_position( 0, event.xcrossing.x, event.xcrossing.y );
                  break;
               }
               case MENU_WINDOW: {
                  menu_enter( button );
                  break;
               }
               case WEDGE_WINDOW: {
                  wedge_position( event.xcrossing.y );
                  break;
               }
               case XSLICE_WINDOW: {
                  data_position( 1, event.xcrossing.x, event.xcrossing.y );
                  break;
               }
               case YSLICE_WINDOW: {
                  data_position( 2, event.xcrossing.x, event.xcrossing.y );
                  break;
               }
               default: {
                  break;
               }
            }
            break;
         }
         case MotionNotify: {		/* pointer movement */
            while (XCheckMaskEvent( winfo.id, ButtonMotionMask, &event ) == True);
            switch( window_id ) {
               case DISPLAY_WINDOW: {
                  data_position( 0, event.xmotion.x, event.xmotion.y );
                  if ((action & COLOR_ACTION) && track_display) {
                     if (!color_transfer( event.xmotion.x, event.xmotion.y )) {
                        color_modify( );
                     }
                  }
                  if (!track_keyboard) {
                     if ((action & BLINK_ACTION) && track_display) {
                        recording_button( blink_button, event.xmotion.x );
                     }
                     if ((action & CURSOR_ACTION) && track_display) {
                        cursor_box( event.xmotion.x, event.xmotion.y );
                     }
                     if ((action & SLICE_ACTION) && track_display) {
                        slice_do_slice( 0, event.xmotion.x, event.xmotion.y, 0,
                           slice_button, 0 );
                     }
                     if ((action & SPLIT_ACTION) && track_display) {
                        recording_do_split( event.xmotion.x, event.xmotion.y,
                           split_button );
                     }
                  }
                  break;
               }
               case MENU_WINDOW: {
                  break;
               }
               case WEDGE_WINDOW: {
                  wedge_position( event.xmotion.y );
                  if ((action & WEDGE_ACTION) && track_wedge ) {
                     wedge_modify( event.xmotion.y );
                  }
                  break;
               }
               case XSLICE_WINDOW: {
                  data_position( 1, event.xmotion.x, event.xmotion.y );
                  if ((action & SLICE_ACTION) && track_display) {
                     slice_do_slice( 1, event.xmotion.x, event.xmotion.y, 0,
                        slice_button, 0 );
                  }
                  break;
               }
               case YSLICE_WINDOW: {
                  data_position( 2, event.xmotion.x, event.xmotion.y );
                  if ((action & SLICE_ACTION) && track_display) {
                     slice_do_slice( 2, event.xmotion.x, event.xmotion.y, 0,
                        slice_button, 0 );
                  }
                  break;
               }
               default: {
                  break;
               }
            }
            break;
         }
         case SelectionClear: {
            cursor_selection_clear( &event );
            break;
         }
         case SelectionNotify: {
            break;
         }
         case SelectionRequest: {
            cursor_selection_request( &event );
            break;
         }
         default: {
            break;
         }
      }
      XFlush( winfo.id );
      cursor_reset( action );
   };
   return( action );
}


/*
 * display_xslice
 */

int	display_xslice( int nslice, int slices[] )
{
   int	n;
   int	th = winfo.theight;

   slice_cursor( 1 );
   if ((winfo.windows & WINDOW_XSLICE) && (nslice == winfo.nxslice)) {
      for ( n = 0; n < nslice; n++ ) winfo.xslices[n] = slices[n];
      winfo.last_y = winfo.dheight / 2;
      slice_do_slice( 0, winfo.last_x, winfo.last_y, 1, AnyButton, 0 );
   } else if ((winfo.windows & WINDOW_XSLICE) && (nslice == 0)) {
      th = winfo.dheight + 4;
      if (th < min_height) th = min_height;
      winfo.nxslice = 0;
      XDestroyWindow( winfo.id, winfo.xslice );
      winfo.windows -= WINDOW_XSLICE;
   } else if (winfo.windows & WINDOW_XSLICE) {
      th = ( winfo.dheight + nslice + 7 );
      if ( th < min_height ) th = min_height;
      winfo.nxslice = nslice;
      for ( n = 0; n < nslice; n++ ) winfo.xslices[n] = slices[n];
      XResizeWindow( winfo.id, winfo.xslice, winfo.dwidth, winfo.nxslice );
      winfo.last_y = winfo.dheight / 2;
   } else if (!(winfo.windows & WINDOW_XSLICE) && nslice) {
      XSetWindowAttributes	attributes;

      th = ( winfo.dheight + nslice + 7 );
      if (th < min_height) th = min_height;
      winfo.nxslice = nslice;
      for ( n = 0; n < nslice; n++ ) winfo.xslices[n] = slices[n];
      attributes.backing_store    = Always;
      attributes.backing_planes   = 0xff;
      attributes.background_pixel = winfo.black;
      attributes.border_pixel     = winfo.black;
      attributes.cursor           = XCreateFontCursor( winfo.id, XC_circle );
      winfo.xslice = XCreateWindow( winfo.id, winfo.top,
         winfo.mwidth + winfo.wwidth + winfo.cwidth + 10, winfo.dheight + 4,
         winfo.dwidth, winfo.nxslice, 1, winfo.depth, InputOutput, winfo.visual,
         CWBackingStore | CWBackingPlanes | CWCursor | CWBackPixel |
         CWBorderPixel, &attributes );
      XMapWindow( winfo.id, winfo.xslice );
      XSelectInput( winfo.id, winfo.xslice, ExposureMask |
         VisibilityChangeMask | PointerMotionMask | ButtonPressMask |
         ButtonReleaseMask | ButtonMotionMask | LeaveWindowMask |
         EnterWindowMask );
      winfo.windows |= WINDOW_XSLICE;
      winfo.last_y = winfo.dheight / 2;
   }
   if (th != winfo.theight) {
      XSizeHints		sizehints;	/* Sizehints */

      winfo.theight = th;
      sizehints.height     = winfo.theight;
      sizehints.width      = winfo.twidth;
      sizehints.min_height = winfo.theight - winfo.dheight;
      sizehints.min_width  = winfo.twidth - winfo.dwidth;
      sizehints.height_inc = 1;
      sizehints.width_inc  = 1;
      sizehints.flags      = PSize | PMinSize | PResizeInc;
      XSetNormalHints( winfo.id, winfo.top, &sizehints );
      XResizeWindow( winfo.id, winfo.top, winfo.twidth, winfo.theight );
   }
   XFlush( winfo.id );
   return( 0 );
}


/*
 * display_yslice
 */

int	display_yslice( int nslice, int slices[] )
{
   int	n;
   int	tw = winfo.twidth;

   slice_cursor( 1 );
   if ((winfo.windows & WINDOW_YSLICE) && (nslice == winfo.nyslice)) {
      for ( n = 0; n < nslice; n++ ) winfo.yslices[n] = slices[n];
      winfo.last_x = winfo.dwidth / 2;
      slice_do_slice( 0, winfo.last_x, winfo.last_y, 1, AnyButton, 0 );
   } else if ((winfo.windows & WINDOW_YSLICE) && (nslice == 0)) {
      tw = winfo.mwidth + winfo.cwidth + winfo.wwidth + winfo.dwidth + 13;
      if (tw < min_width) tw = min_width;
      winfo.nyslice = 0;
      XDestroyWindow( winfo.id, winfo.yslice );
      winfo.windows -= WINDOW_YSLICE;
   } else if (winfo.windows & WINDOW_YSLICE) {
      tw = winfo.mwidth + winfo.cwidth + winfo.wwidth + winfo.dwidth +
         nslice + 16;
      if ( tw < min_width ) tw = min_width;
      winfo.nyslice = nslice;
      for ( n = 0; n < nslice; n++ ) winfo.yslices[n] = slices[n];
      XResizeWindow( winfo.id, winfo.yslice, winfo.nyslice, winfo.dheight );
      winfo.last_x = winfo.dwidth / 2;
   } else if (!(winfo.windows & WINDOW_YSLICE) && nslice) {
      XSetWindowAttributes	attributes;

      tw = winfo.mwidth + winfo.cwidth + winfo.wwidth + winfo.dwidth +
         nslice + 16;
      if (tw < min_width) tw = min_width;
      winfo.nyslice = nslice;
      for ( n = 0; n < nslice; n++ ) winfo.yslices[n] = slices[n];
      attributes.backing_store    = Always;
      attributes.backing_planes   = 0xff;
      attributes.background_pixel = winfo.black;
      attributes.border_pixel     = winfo.black;
      attributes.cursor           = XCreateFontCursor( winfo.id, XC_circle );
      winfo.yslice = XCreateWindow( winfo.id, winfo.top, winfo.dwidth +
         winfo.mwidth + winfo.wwidth + winfo.cwidth + 13, 1,
         winfo.nyslice, winfo.dheight, 1, winfo.depth, InputOutput, winfo.visual,
         CWBackingStore | CWBackingPlanes | CWCursor | CWBackPixel |
         CWBorderPixel, &attributes );
      XMapWindow( winfo.id, winfo.yslice );
      XSelectInput( winfo.id, winfo.yslice, ExposureMask |
         VisibilityChangeMask | PointerMotionMask | ButtonPressMask |
         ButtonReleaseMask | ButtonMotionMask | LeaveWindowMask |
         EnterWindowMask );
      winfo.windows |= WINDOW_YSLICE;
      winfo.last_x = winfo.dwidth / 2;
   }
   if (tw != winfo.twidth) {
      XSizeHints		sizehints;	/* Sizehints */

      winfo.twidth = tw;
      sizehints.height     = winfo.theight;
      sizehints.width      = winfo.twidth;
      sizehints.min_height = winfo.theight - winfo.dheight;
      sizehints.min_width  = winfo.twidth - winfo.dwidth;
      sizehints.height_inc = 1;
      sizehints.width_inc  = 1;
      sizehints.flags      = PSize | PMinSize | PResizeInc;
      XSetNormalHints( winfo.id, winfo.top, &sizehints );
      XResizeWindow( winfo.id, winfo.top, winfo.twidth, winfo.theight );
   }
   XFlush( winfo.id );
   return( 0 );
}


/*
 * display_resize
 */

int	display_resize( int dw, int dh  )
{
   int		n;
   int		x, y;
   int		th, tw;
   int		wh;
   XSizeHints	sizehints;			/* Sizehints */


   if ( dh < MIN_HEIGHT ) dh = MIN_HEIGHT;
   if ( dw < MIN_WIDTH ) dw = MIN_WIDTH;
   if ( ( dw == winfo.dwidth ) && ( dh == winfo.dheight ) ) {
      XResizeWindow( winfo.id, winfo.top, winfo.twidth, winfo.theight );
      return( 0 );
   }
   if (winfo.windows & WINDOW_XSLICE) {
      winfo.nxslice = 0;
      XDestroyWindow( winfo.id, winfo.xslice );
      winfo.windows -= WINDOW_XSLICE;
   }
   if (winfo.windows & WINDOW_YSLICE) {
      winfo.nyslice = 0;
      XDestroyWindow( winfo.id, winfo.yslice );
      winfo.windows -= WINDOW_YSLICE;
   }
   tw = winfo.mwidth + winfo.cwidth + winfo.wwidth + dw + 13;
   th = dh + 4;
   if (th < min_height) th = min_height;
   recording_clear( );
   for ( n = 0; n <= winfo.mrecord; n++ ) {
      recording_delete( n );
   }
   winfo.dwidth    = dw;
   winfo.dheight   = dh;
   if (!(winfo.windows & WINDOW_PGPLOT)) {
      winfo.pgh    = winfo.dheight;
      winfo.pgw    = winfo.dwidth;
   }
   winfo.nrecord   = 0;
   winfo.nsequence = 0;
   winfo.mrecord = ( winfo.memory * 1024 ) /
      ( winfo.dwidth * winfo.dheight ) - 1;
   if (winfo.mrecord < 0) winfo.mrecord = 0;	/* just in case */
   if (winfo.mrecord >= MAXRECORD) winfo.mrecord = MAXRECORD - 1;
   for ( n = 0; n <= winfo.mrecord; n++ ) {
      winfo.record[n].mask = 0;
      winfo.record[n].xgt  = NULL;
      winfo.record[n].ygt  = NULL;
   }
   winfo.currec = 0;
   winfo.twidth = tw;
   winfo.theight = th;
   sizehints.height     = winfo.theight;
   sizehints.width      = winfo.twidth;
   sizehints.min_height = winfo.theight - winfo.dheight;
   sizehints.min_width  = winfo.twidth - winfo.dwidth;
   sizehints.height_inc = 1;
   sizehints.width_inc  = 1;
   sizehints.flags      = PSize | PMinSize | PResizeInc;
   XSetNormalHints( winfo.id, winfo.top, &sizehints );
   XResizeWindow( winfo.id, winfo.top, winfo.twidth, winfo.theight );
   XResizeWindow( winfo.id, winfo.display, winfo.dwidth, winfo.dheight );
   winfo.record[0].x_grid = calloc( sizeof( int ), winfo.dwidth );
   for ( n = 0; n < winfo.dwidth; n++ ) {
      winfo.record[0].x_grid[n] = n;
   }
   winfo.record[0].y_grid = calloc( sizeof( int ), winfo.dheight );
   for ( n = 0; n < winfo.dheight; n++ ) {
      winfo.record[0].y_grid[n] = winfo.dheight - 1 - n;
   }
   wh = winfo.theight - 4;
   if ( wh != winfo.wheight ) {
      winfo.wheight = wh;
      XResizeWindow( winfo.id, winfo.wedge, winfo.wwidth, winfo.wheight );
      winfo.cheight = wh;
      XResizeWindow( winfo.id, winfo.calib, winfo.cwidth, winfo.cheight );
      XDestroyImage( winfo.wimage );
      XFreePixmap( winfo.id, winfo.wpixmap );
      /* VOG2010: Changed allocation to support more bytes per pixel */
      winfo.wdata = calloc( sizeof(unsigned char), winfo.wwidth * winfo.wheight*(winfo.pad/8) );
      for ( n = 0, y = winfo.wheight; y-- > 0; ) {
         unsigned char   ch;
         ch = (float) (winfo.maxcolor - winfo.mincolor - 1) /
            (float) (winfo.wheight - 1) * (float) y + winfo.mincolor + 1;
         for ( x = 0; x < winfo.wwidth; x++ ) {
            /* VOG2010: Changed assignment pixel to data array to */
            /* support more bytes per pixel.                      */
            pixel2chars(winfo.table[ch].pixel, winfo.wdata, &n, winfo.bytespp, winfo.byte_order);
         }
      }
      winfo.wimage = XCreateImage( winfo.id, winfo.visual,
         winfo.depth, ZPixmap, 0, (char *) winfo.wdata,
         winfo.wwidth, winfo.wheight, winfo.pad, 0 );
      winfo.wpixmap = XCreatePixmap( winfo.id, winfo.wedge,
         winfo.wwidth, winfo.wheight, winfo.depth );
      XPutImage( winfo.id, winfo.wpixmap, winfo.gcm,
         winfo.wimage, 0, 0, 0, 0, winfo.wwidth, winfo.wheight );
      XCopyArea( winfo.id, winfo.wpixmap, winfo.wedge, winfo.gcm,
         0, 0, winfo.wwidth, winfo.wheight, 0, 0 );
   }
   XDestroyImage( winfo.iimage );
   /* VOG2010: Adjust number of bytes for allocation to support */
   /* more than one byte per pixel.                             */
   winfo.idata =  calloc( sizeof(unsigned char),
                          winfo.dwidth * winfo.dheight * (winfo.pad/8) );
   for ( n = 0, x = 0; x < winfo.dwidth; x++ ) {
      for ( y = 0; y < winfo.dheight; y++ ) {
         pixel2chars(winfo.blank, winfo.idata, &n, winfo.bytespp, winfo.byte_order);
      }
   }
   /* VOG2010: Changed padding from CHAR_BIT to winfo.pad */
   winfo.iimage = XCreateImage( winfo.id, winfo.visual, winfo.depth, ZPixmap,
      0, (char *) winfo.idata, winfo.dwidth, winfo.dheight, winfo.pad, 0 );
   winfo.record[0].pixmap = XCreatePixmap( winfo.id, winfo.display,
      winfo.dwidth, winfo.dheight, winfo.depth );
   winfo.record[0].mask = 1;
   if ( user.text1[0] ) strcpy( winfo.record[0].text1, user.text1 );
   if ( user.text2[0] ) strcpy( winfo.record[0].text2, user.text2 );
   XPutImage( winfo.id, winfo.record[0].pixmap, winfo.gcm, winfo.iimage,
      0, 0, 0, 0, winfo.dwidth, winfo.dheight );
   XCopyArea( winfo.id, winfo.record[0].pixmap, winfo.display, winfo.gcm,
      0, 0, winfo.dwidth, winfo.dheight, 0, 0 );
   zoom_xy( winfo.x_zoomc, winfo.y_zoomc, winfo.x_zoomf, winfo.y_zoomf );
   misc_recordings( );
   return( 0 );
}

int	display_pgplot( int pgw, int pgh )
{
   if (!(winfo.windows & WINDOW_PGPLOT)) {
      XSetWindowAttributes	attributes;
      XSizeHints		sizehints;

      winfo.pgw = pgw;
      winfo.pgh = pgh;
      sizehints.width      = pgw;
      sizehints.height     = pgh;
      sizehints.min_width  = 128;
      sizehints.min_height = 128;
      sizehints.max_width  = winfo.width - 2;
      sizehints.max_height = winfo.height - 2;
      sizehints.width_inc  = 1;
      sizehints.height_inc = 1;
      sizehints.flags = PSize | PMinSize | PMaxSize | PResizeInc;
      attributes.backing_store    = Always;
      attributes.backing_planes   = 0xff;
      attributes.colormap         = winfo.colormap;
      attributes.cursor           = XCreateFontCursor( winfo.id, XC_crosshair );
      attributes.background_pixel = winfo.black;
   						/* create main window */
      winfo.pgplot = XCreateWindow( winfo.id, winfo.root, 0, 0, winfo.pgw,
         winfo.pgh, 1, winfo.depth, InputOutput, winfo.visual,
         CWBackingStore | CWBackingPlanes | CWCursor | CWBackPixel | CWColormap,
         &attributes );
						/* set properties of window */
      XStoreName( winfo.id, winfo.pgplot, "GIDS-PLOT" );
      XSetNormalHints( winfo.id, winfo.pgplot, &sizehints );
      XMapWindow( winfo.id, winfo.pgplot );
      XSelectInput( winfo.id, winfo.pgplot, ExposureMask |
         StructureNotifyMask );
      winfo.windows |= WINDOW_PGPLOT;
   } else {
      XDestroyWindow( winfo.id, winfo.pgplot );
      winfo.pgplot = winfo.display;
      winfo.pgh    = winfo.dheight;
      winfo.pgw    = winfo.dwidth;
      winfo.windows -= WINDOW_PGPLOT;
   }
   return( 0 );
}

/*
 * display_help.
 */

int	display_help( int create )
{
   int	r = 0;

   if (create && (winfo.windows & WINDOW_HELP)) {
      XClearWindow( winfo.id, winfo.help );
   } else if (create) {
      

      XSetWindowAttributes	attributes;
      XSizeHints		sizehints;

      attributes.backing_store    = Always;
      attributes.backing_planes   = 0xff;
      attributes.border_pixel     = winfo.black;
      attributes.background_pixel = winfo.white;
      attributes.cursor           = XCreateFontCursor( winfo.id, XC_crosshair );
      /* VOG2010: colormap added. Without colormap no window in DirectColor */
      attributes.colormap         = winfo.colormap;
      attributes.override_redirect = True;
      attributes.save_under = True;
      winfo.help = XCreateWindow( winfo.id, winfo.root, 0, 0, winfo.hwidth,
         winfo.hheight, 1, winfo.depth, InputOutput, winfo.visual,
         /*CWBackingStore | CWBackingPlanes | CWCursor | CWBackPixel ,*/
         CWBackingStore | CWBackingPlanes | CWCursor | CWBackPixel |
               CWColormap /*| CWOverrideRedirect*/ | CWSaveUnder ,
         &attributes );
						/* set properties of window */
      sizehints.width      = winfo.hwidth;
      sizehints.height     = winfo.hheight;
      sizehints.min_width  = winfo.hwidth;
      sizehints.min_height = winfo.hheight;
      sizehints.max_width  = winfo.hwidth;
      sizehints.max_height = winfo.hheight;
      sizehints.flags = PSize | PMinSize | PMaxSize;
      XStoreName( winfo.id, winfo.help, "GIDS-HELP" );
      XSetNormalHints( winfo.id, winfo.help, &sizehints );
      XSetForeground(winfo.id, winfo.gch, winfo.black);
      XMapWindow( winfo.id, winfo.help );

      /*
      {
         XEvent      event;

         XMaskEvent( winfo.id, ExposureMask | VisibilityChangeMask |
             StructureNotifyMask | SubstructureNotifyMask, &event );
      }
      */
      
      /* XSelectInput( winfo.id, winfo.help, ButtonPressMask | ButtonReleaseMask |
      KeyPressMask | KeyReleaseMask | ExposureMask | VisibilityChangeMask );*/
      XSelectInput( winfo.id, winfo.help, ButtonPressMask | ButtonReleaseMask |
            KeyPressMask | KeyReleaseMask | ExposureMask | VisibilityChangeMask );
      winfo.windows |= WINDOW_HELP;
      r = 1;
   } else if ((!create) && (winfo.windows & WINDOW_HELP)) {
      XDestroyWindow( winfo.id, winfo.help );
      winfo.windows -= WINDOW_HELP;
   }
   return( r );
}
#<

#>            etcetera.c
/* etcetera.c

*/

#include	"gids.h"			/* gids symbols */
#<

#>            gdi.c
/* gdi.c

*/


/*
 * includes:
 */

#include	"gids.h"			/* gids definitions */
#include	"f2cvvdefs.h"			/* Fortran -> C definitions */
#include	"spfpfl.h"
#include	"spfplf.h"

int	gdi_open( int sid, Command_struct cmd )
{
   int	close( );				/* closes a socket */
   int	r = GDIE_SUCCESS;			/* return value */

   if (cmd.code != GDI_OPEN_CLIENT) {
      clients[sid].swap = 1;			/* try swapping the bytes */
   }
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   if (cmd.code == GDI_OPEN_CLIENT) {		/* open by client */
      int	ftype = OS_FLOATING_TYPE;	/* floating point type of client */

      r = misc_receive( clients[sid].socket, &ftype, cmd.nbytes );
      if (r == GDIE_SUCCESS) {
         misc_sl( clients[sid].swap, &ftype, 1 );
         clients[sid].ftype = ftype;		/* client floating type */
         cmd.code   = 0;			/* return code */
         cmd.nbytes = 0;			/* no next send */
         misc_cmd_swap( clients[sid].swap, &cmd );
         r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
      }
   } else {
      r = GDIE_ERROR_UNKNOWN;			/* unknown option */
   }
   if (r != GDIE_SUCCESS) {
      close( clients[sid].socket );		/* close it */
      clients[sid].open = 0;			/* say so */
   } else {
      winfo.clients++;				/* add a client */
   }
   return( r );					/* return to caller */
}

int	gdi_close( int sid, Command_struct cmd )
{
   int	close( );				/* closes a socket */
   int	r = GDIE_SUCCESS;			/* return value */

   cmd.code   = 0;				/* no error */
   cmd.nbytes = 0;				/* no next send */
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   close( clients[sid].socket );		/* close it */
   clients[sid].open = 0;			/* say so */
   if (winfo.clients) winfo.clients--;		/* remove a client */
   return( r );					/* return to caller */
}

int	gdi_reset( int sid, Command_struct cmd )
{
   int	r = GDIE_SUCCESS;			/* return value */

   cmd.code   = 0;				/* no error */
   cmd.nbytes = 0;				/* no next send */
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );					/* return to caller */
}

int	gdi_update( int sid, Command_struct cmd )
{
   int	r = GDIE_SUCCESS;			/* return value */

   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );
}

int	gdi_cinfo( int sid, Command_struct cmd )
{
   int	nw;					/* number of bytes to write */
   int	r = GDIE_SUCCESS;			/* return value */
   int  color_info[4];				/* contains color info */

   color_info[0] = winfo.mincolor + 1;		/* minimun value */
   color_info[1] = winfo.maxcolor;		/* maximum value */
   color_info[2] = winfo.ncolors - 1;		/* number of values */
   color_info[3] = winfo.blank;			/* reserved value */
   cmd.code   = 0;				/* no error */
   cmd.nbytes = nw = sizeof( color_info );	/* number of bytes to send */
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   misc_sl( clients[sid].swap, color_info, 4 );	/* swap it */
   r = misc_send( clients[sid].socket, color_info, nw );
   return( r );					/* return to caller */
}

int	gdi_colput( int sid, Command_struct cmd )
{
   int			idx;			/* table index */
   int			m;			/* table pointer */
   int			n;			/* loop counter */
   int			nc;			/* number of colors */
   int			nr;			/* number of bytes to read */
   int			ns = 0;			/* number of shorts */
   int			r = GDIE_SUCCESS;	/* return value */
   unsigned short	*table = NULL;		/* table pointer */

   nr = cmd.nbytes;				/* number of bytes to read */
   table = calloc( sizeof( char ), nr );	/* allocate memory */
   if (table == NULL) {				/* allocation error */
      cmd.code = GDIE_S_ALLOC;			/* error */
      r = misc_flush( clients[sid].socket, nr );
   } else {
      cmd.code = GDIE_SUCCESS;			/* no error */
      nc = nr / sizeof( unsigned short ) / 4;	/* number of colors */
      r = misc_receive( clients[sid].socket, table, nr );
      if (r != GDIE_SUCCESS) return( r );	/* return to caller */
      ns = nr / sizeof( unsigned short );	/* number of shorts */
      misc_ss( clients[sid].swap, table, ns );	/* swap it */
      for (m = 0, n = 0; n < nc; n++) {		/* loop */
         idx = table[m++];			/* get index */
         if ((idx < winfo.mincolor) || (idx > winfo.maxcolor)) {
            cmd.code = GDIE_COLOR_RANGE;	/* outside range */
            m += 3;				/* skip next entries */
         } else {
            idx -= winfo.mincolor;		/* table entry */
            user.colors[idx].red   = (float) table[m++] / (float) USHRT_MAX;
            user.colors[idx].green = (float) table[m++] / (float) USHRT_MAX;
            user.colors[idx].blue  = (float) table[m++] / (float) USHRT_MAX;
         }
      }
      free( table );				/* deallocate memory */
   }
   cmd.nbytes = 0;				/* no next send */
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );					/* return to caller */
}

int	gdi_colget( int sid, Command_struct cmd )
{
   int			idx;			/* table index */
   int			m;			/* table pointer */
   int			n;			/* loop counter */
   int			nc;			/* number of colors */
   int			nr;			/* number of bytes to read */
   int			ns = 0;			/* number of shorts */
   int			nw;			/* number of bytes to write */
   int			r = GDIE_SUCCESS;	/* return value */
   unsigned short	*values = NULL;		/* values pointer */
   unsigned short	*colors = NULL;		/* color pointer */

   nr = cmd.nbytes;				/* number of bytes to read */
   values = calloc( sizeof( char ), nr );	/* allocate memory */
   if (values == NULL) {			/* allocation error */
      cmd.code = GDIE_S_ALLOC;			/* error */
      cmd.nbytes = nw = 0;			/* no next send */
      misc_flush( clients[sid].socket, nr );	/* flush it */
   } else {
      cmd.code = 0;				/* return value */
      nc = nr / sizeof( unsigned short );	/* number of colors */
      r = misc_receive( clients[sid].socket, values, nr );
      if (r != GDIE_SUCCESS) {			/* error */
         free( values );			/* release memory */
         return( r );				/* return to caller */
      }
      misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
      if (r != GDIE_SUCCESS) {			/* error */
         free( values );			/* release memory */
         return( r );				/* return to caller */
      }
      ns = 3 * nc;				/* number of shorts */
      nw = ns * sizeof( unsigned short );	/* number of bytes to write */
      colors = calloc( sizeof( unsigned short ), ns );
      if (colors == NULL) {			/* allocation error */
         cmd.code = GDIE_S_ALLOC;		/* error code */
         cmd.nbytes = nw = 0;			/* no next send */
      } else {
         cmd.nbytes = nw;			/* return code */
         misc_ss( clients[sid].swap, values, nc );
         for (m = 0, n = 0; n < nc; n++) {	/* loop */
            idx = values[n];			/* get index */
            if ((idx < winfo.mincolor) || (idx > winfo.maxcolor)) {
               cmd.code = GDIE_COLOR_RANGE;	/* error */
               colors[m++] = 0;
               colors[m++] = 0;
               colors[m++] = 0;
            } else {
               idx -= winfo.mincolor;		/* table entry */
               colors[m++] = user.colors[idx].red * USHRT_MAX;
               colors[m++] = user.colors[idx].green * USHRT_MAX;
               colors[m++] = user.colors[idx].blue * USHRT_MAX;
            }
         }
      }
   }
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) {			/* error */
      if (colors != NULL) free( colors );	/* release memory */
      if (values != NULL) free( values );	/* release memory */
      return( r );				/* error */
   }
   if (nw) {
      misc_ss( clients[sid].swap, colors, ns );	/* swap it */
      r = misc_send( clients[sid].socket, colors, nw );
   }
   if (colors != NULL) free( colors );		/* release memory */
   if (values != NULL) free( values );		/* release memory */
   return( r );					/* return to caller */
}

#if	!defined(NO_GIPSY)
int	gdi_mhead( int sid, Command_struct cmd )
{
   char	*header = NULL;				/* data from client */
   int	nr;					/* number of bytes to read */
   int	r = GDIE_SUCCESS;			/* return value */

   nr = cmd.nbytes;				/* number of bytes to receive */
   cmd.code   = 0;				/* reset */
   cmd.nbytes = 0;				/* no next send */
   header = calloc( sizeof( char ), nr );	/* allocate memory */
   if (header == NULL) {
      cmd.code = GDIE_S_ALLOC;			/* allocation error */
   } else {
      r = misc_receive( clients[sid].socket, header, nr );
      if (r != GDIE_SUCCESS) {			/* error */
         free( header );			/* release memory */
         return( r );				/* return to caller */
      }
      cmd.code = coord_from_fits( header, nr );	/* decode header */
      free( header );				/* deallocate memory */
   }
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );					/* return to caller */
}
#endif

int	gdi_defimg( int sid, Command_struct cmd )
{
   char	buffer[42+4*sizeof(int)];		/* data buffer */
   int	n;					/* loop counter */
   int	nr;					/* number of bytes to read */
   int	r = GDIE_SUCCESS;			/* return value */
   int	l;					/* int */

   nr = cmd.nbytes;				/* number of bytes to read */
   cmd.code   = 0;
   cmd.nbytes = 0;
   clients[sid].iwc = 0;			/* reset */
   r = misc_receive( clients[sid].socket, buffer, nr );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   misc_sl( clients[sid].swap, buffer, 4 );	/* swap */
   memmove( &l, &buffer[0], sizeof( int ) );	/* copy */
   user.x_min = l;				/* lower x */
   memmove( &l, &buffer[sizeof(int)], sizeof(int) );
   user.y_min = l;				/* lower y */
   memmove( &l, &buffer[2*sizeof(int)], sizeof(int) );
   user.x_max = l;				/* upper x */
   memmove( &l, &buffer[3*sizeof(int)], sizeof(int) );
   user.y_max = l;				/* upper y */
   if (user.xgt != NULL) {
      free( user.xgt );
      user.xgt = NULL;
   }
   if (user.ygt != NULL) {
      free( user.ygt );
      user.ygt = NULL;
   }
   user.x_size  = user.x_max - user.x_min + 1;	/* x size */
   user.y_size  = user.y_max - user.y_min + 1;	/* y size */
   user.xregion = realloc( user.xregion, sizeof( Region_struct ) * user.x_size );
   user.yregion = realloc( user.yregion, sizeof( Region_struct ) * user.y_size );
   user.n_count = 0;				/* reset data counter */
   user.n_data  = user.x_size * user.y_size;	/* total number of pixels */
   /* VOG2010: This array 'idata' is part of the Data_struct structure       */
   /* This data receives the image data of a client in bytes representing    */
   /* color indices scaled between the minimum and maximum number of colors. */
   /* Note that this data is copied to winfo.idata in 'misc.c'. There we     */
   /* need to take care of pixels > 1 byte per pixel.                        */
   user.idata   = realloc( user.idata, user.n_data);
   user.imask   = realloc( user.imask, user.n_data );
   if (user.idata == NULL) {			/* allocation error */
      cmd.code = GDIE_S_ALLOC;			/* error */
   } else {
      for (n = 0; n < user.n_data; user.idata[n++] = winfo.blank);
      for (n = 0; n < user.n_data; user.imask[n++] = 0 );
   }
   if (nr == sizeof(buffer)) {
      user.bscale  = atof( &buffer[4*sizeof(int)] );
      user.b_zero   = atof( &buffer[4*sizeof(int)+21] );
   } else {
      fint	ftype = clients[sid].ftype;
      fint	one = 1;

      memmove( &user.bscale, &buffer[4*sizeof(int)], sizeof( float ) );
      spfpfl_c( &ftype, &user.bscale, &user.bscale, &one );
      memmove( &user.b_zero, &buffer[4*sizeof(int)+sizeof(float)], sizeof( float ) );
      spfpfl_c( &ftype, &user.b_zero, &user.b_zero, &one );
   }
   user.images  = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );					/* return to caller */
}

int	gdi_imwrite( int sid, Command_struct cmd )
{
   int	count;
   int	nr;					/* number of bytes to read */
   int	r = GDIE_SUCCESS;			/* return value */

   cmd.code = r;
   if (user.idata != NULL) {			/* image defined */
      count = clients[sid].iwc;
      nr = user.n_data - count;
      if (cmd.nbytes < nr) {
         nr = cmd.nbytes;
      } else if (cmd.nbytes > nr) {
         cmd.code = GDIE_IMWRITE_OVERFLOW;	/* too many bytes */
      }
      r = misc_receive( clients[sid].socket, &user.idata[count], nr );

      if (r != GDIE_SUCCESS) return( r );	/* return to caller */
      if (nr < cmd.nbytes) {
         r = misc_flush( clients[sid].socket, cmd.nbytes - nr );
         if (r != GDIE_SUCCESS) return( r );	/* return to caller */
      }
      clients[sid].iwc += nr;
      if (clients[sid].iwc == user.n_data) {	/* display image */
         int	xzc = winfo.x_zoomc;
         int    xzf = winfo.x_zoomf;
         int	yzc = winfo.y_zoomc;
         int	yzf = winfo.y_zoomf;


         clients[sid].iwc = 0;
         winfo.record[0].bscale = user.bscale;
         winfo.record[0].b_zero = user.b_zero;
         winfo.record[0].x_max  = user.x_max;
         winfo.record[0].x_min  = user.x_min;
         winfo.record[0].y_max  = user.y_max;
         winfo.record[0].y_min  = user.y_min;
         if (!user.images) {
            xzc = user.x_min + user.x_size / 2 - 1;
            xzf = 0;
            yzc = user.y_min + user.y_size / 2 - 1;
            yzf = 0;
            if (user.x_size > winfo.dwidth) {
               while (((1<<(1-xzf)) * winfo.dwidth) < user.x_size ) xzf--;
               xzf -= 1;
            } else if (user.x_size < winfo.dwidth ) {
               while (((1<<(xzf+1)) * user.x_size) <= winfo.dwidth ) xzf++;
            }
            if (user.y_size > winfo.dheight) {
               while (((1<<(1-yzf)) * winfo.dheight) < user.y_size ) yzf--;
               yzf -= 1;
            } else if (user.y_size < winfo.dheight) {
               while (((1<<(yzf+1)) * user.y_size) <= winfo.dheight ) yzf++;
            }
            if (xzf > yzf) xzf = yzf; else yzf = xzf;
         }
         zoom_xy( xzc, yzc, xzf, yzf );		/* zoom image */
         if ( !user.images ) wedge_draw( 1 );	/* draw the wedge */
         user.images += 1;			/* increase image counter */
      }
   } else {
      cmd.code = GDIE_NO_IMAGE;
      r = misc_flush( clients[sid].socket, cmd.nbytes );
      if (r != GDIE_SUCCESS) return( r );	/* return to caller */
   }
   

   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );					/* return to caller */
}

int	gdi_rinfo( int sid, Command_struct cmd )
{
   int	nw;					/* number of bytes to write */
   int	r = GDIE_SUCCESS;			/* return value */
   int	record_info[2];				/* contains recordings info */

   record_info[0] = winfo.nrecord;
   record_info[1] = winfo.mrecord;
   cmd.code   = 0;
   cmd.nbytes = nw = sizeof( record_info );
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   misc_sl( clients[sid].swap, record_info, 2 );/* swap it */
   r = misc_send( clients[sid].socket, record_info, nw );
   return( r );					/* return to caller */
}

int	gdi_record( int sid, Command_struct cmd )
{
   int	r = GDIE_SUCCESS;			/* return value */

   if (cmd.code < 1 || cmd.code > winfo.mrecord) {
      r = GDIE_RECORD_RANGE;
   } else if (user.idata == NULL) {
      r = GDIE_RECORD_NO_IMAGE;
   } else {
      int	rec = cmd.code;

      r = recording_do_record( 0, rec );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );
}

int	gdi_remove( int sid, Command_struct cmd )
{
   int	r = GDIE_SUCCESS;			/* return value */

   if (cmd.code < 1 || cmd.code >= winfo.mrecord) {
      r = GDIE_RECORD_RANGE;
   } else {
      int	rec = cmd.code;

      if (winfo.record[rec].mask) recording_delete( rec );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );
}

int	gdi_restore( int sid, Command_struct cmd )
{
   cmd.code   = recording_restore( );
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   return( misc_send( clients[sid].socket, &cmd, sizeof( cmd ) ) );
}

int	gdi_rmask( int sid, Command_struct cmd )
{
   int	mrec;
   int	rec;
   int	nw;
   int	r = GDIE_SUCCESS;
   int	*mask;

   mrec = cmd.code;
   mask = calloc( sizeof(int), mrec );
   if (mask == NULL) {
      cmd.code   = GDIE_S_ALLOC;
      cmd.nbytes = 0;
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
      return( r );
   }
   for (rec = 1; rec <= mrec && rec <= winfo.mrecord; rec++) {
      mask[rec] = winfo.record[rec].mask;
   }
   for (; rec <= mrec; rec++) {
      mask[rec] = 0;
   }
   cmd.code   = r;
   cmd.nbytes = nw = mrec * sizeof(int);
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) {
      free( mask );
      return( r );
   }
   misc_sl( clients[sid].swap, mask, mrec );
   r = misc_send( clients[sid].socket, mask, nw );
   free( mask );
   return( r );					/* return to caller */
}

int	gdi_save( int sid, Command_struct cmd )
{
   cmd.code   = recording_save( );
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   return( misc_send( clients[sid].socket, &cmd, sizeof( cmd ) ) );
}

int	gdi_sequence( int sid, Command_struct cmd )
{
   int	m;
   int	mrec;
   int	n;
   int	nr;
   int	r = GDIE_SUCCESS;
   int	*sequence;

   nr = cmd.nbytes;
   mrec = nr / sizeof(int);
   sequence = calloc( sizeof( int ), mrec );
   if (sequence == NULL) {
      r = GDIE_S_ALLOC;
      r = misc_flush( clients[sid].socket, nr );
   } else {
      r = misc_receive( clients[sid].socket, sequence, nr );
      if (r != GDIE_SUCCESS) {
         free( sequence );
         return( r );
      }
      misc_sl( clients[sid].swap, sequence, mrec );
      winfo.nsequence = 0;
      for (m = 0, n = 0; n < mrec && m < MAXSEQUENCE; n++) {
         int	rec = sequence[n];

         if (rec < 1 || rec > winfo.mrecord || !winfo.record[rec].mask) {
            r = GDIE_RECORD_ILLEGAL;
         } else {
            winfo.sequence[m++] = rec;
         }
      }
      winfo.nsequence = m;
      free( sequence );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );
}

int	gdi_ginfo( int sid, Command_struct cmd )
{
   int	nw;					/* number of bytes to write */
   int	r = GDIE_SUCCESS;			/* return value */
   int	graphics_info[2];			/* contains graphics info */

   graphics_info[0] = MAXPLANES;
   graphics_info[1] = user.mask2;
   cmd.code   = 0;
   cmd.nbytes = nw = sizeof( graphics_info );
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   misc_sl( clients[sid].swap, graphics_info, 2 );
   r = misc_send( clients[sid].socket, graphics_info, nw );
   return( r );					/* return to caller */
}

int	gdi_grcol( int sid, Command_struct cmd )
{
   int		idx;
   int		nr;
   int		r = GDIE_SUCCESS;
   fint		ftype = clients[sid].ftype;
   fint		ns;
   float	color_info[3];

   nr = cmd.nbytes;
   r = misc_receive( clients[sid].socket, color_info, nr );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   ns = nr / sizeof( float );
   spfpfl_c( &ftype, color_info, color_info, &ns );
   if (cmd.code < 1 || cmd.code > MAXPLANES) {
      r = GDIE_GRAPHICS_RANGE;
   } else {
      idx = (1<<(cmd.code-1));
      winfo.gcolors[idx].red   = color_info[0];
      winfo.gcolors[idx].green = color_info[1];
      winfo.gcolors[idx].blue  = color_info[2];
      color_modify_graphics( );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   return( r );					/* return to caller */
}

int	gdi_gron( int sid, Command_struct cmd )
{
   int			idx;
   int			r = GDIE_SUCCESS;

   idx = cmd.code;
   if (idx < 0 || idx > ( MAXGCOLORS - 1 )) {
      r = GDIE_GRAPHICS_RANGE;
   } else {
      user.mask2 = idx;
      misc_mask( );
      misc_show( );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   return( r );					/* return to caller */
}

int	gdi_groff( int sid, Command_struct cmd )
{
   int			idx;
   int			r = GDIE_SUCCESS;

   idx = cmd.code;
   if (idx < 0 || idx > ( MAXGCOLORS - 1 )) {
      r = GDIE_GRAPHICS_RANGE;
   } else {
      user.mask2 = (MAXGCOLORS - 1 - idx);
      misc_mask( );
      misc_show( );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   return( r );					/* return to caller */
}

int	gdi_grclear( int sid, Command_struct cmd )
{
   int			idx;
   int			n;
   int			r = GDIE_SUCCESS;
   unsigned char	pmask;

   idx = cmd.code;
   if (idx < 1 || idx > ( MAXGCOLORS - 1 )) {
      r = GDIE_GRAPHICS_RANGE;
   } else {
      pmask = (MAXGCOLORS - 1 - idx);
      for (n = 0; n < user.n_data; user.imask[n++] &= pmask);
      misc_show( );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   return( r );					/* return to caller */
}

int	gdi_grregion( int sid, Command_struct cmd )
{
   int			r = GDIE_SUCCESS;

   if (clients[sid].wstate) {
      cmd.code   = GDIE_OTHER_REQUEST;
      cmd.nbytes = 0;
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   } else {
      if (cmd.code < 1 || cmd.code > ( MAXGCOLORS - 1 )) {
         r = GDIE_GRAPHICS_RANGE;
      } else {
         user.mask1 = cmd.code;
         misc_mask( );
      }
      clients[sid].wstate = cmd.cmd;
   }
   return( r );					/* return to caller */
}

int	gdi_grread( int sid, Command_struct cmd )
{
   int		nleft;
   int		nw = 0;
   int		r = GDIE_SUCCESS;

   if (user.n_data == 0) {
      cmd.code   = GDIE_NO_IMAGE;
      cmd.nbytes = 0;
   } else {
      nw = cmd.code;
      nleft = user.n_data - clients[sid].grc;
      if (nleft < nw) {
         nw = nleft;
         r = GDIE_DATA_LEFT;
      }
      cmd.code   = r;
      cmd.nbytes = nw;
   }
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );
   if (nw) {
      unsigned char	*data;

      data = &user.imask[clients[sid].grc];
      r = misc_send( clients[sid].socket, data, nw );
      clients[sid].grc += nw;
      if (clients[sid].grc == user.n_data) clients[sid].grc = 0;
      if (r != GDIE_SUCCESS) return( r );
   }
   return( r );
}

int	gdi_grwrite( int sid, Command_struct cmd )
{
   int		count;
   int		nr = 0;
   int		r = GDIE_SUCCESS;

   cmd.code = r;
   if (user.idata != NULL) {			/* image defined */
      count = clients[sid].gwc;
      nr = user.n_data - count;
      if (cmd.nbytes < nr) {
         nr = cmd.nbytes;
      } else if (cmd.nbytes > nr) {
         cmd.code = GDIE_GRWRITE_OVERFLOW;	/* too many bytes */
      }
      r = misc_receive( clients[sid].socket, &user.imask[count], nr );
      if (r != GDIE_SUCCESS) return( r );	/* return to caller */
      if (nr < cmd.nbytes) {
         r = misc_flush( clients[sid].socket, cmd.nbytes - nr );
         if (r != GDIE_SUCCESS) return( r );	/* return to caller */
      }
      clients[sid].gwc += nr;
      if (clients[sid].gwc == user.n_data) {	/* display image */
         misc_show( );
         clients[sid].gwc = 0;
      }
   } else {
      cmd.code = GDIE_NO_IMAGE;
      r = misc_flush( clients[sid].socket, cmd.nbytes );
      if (r != GDIE_SUCCESS) return( r );       /* return to caller */
   }
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );					/* return to caller */
}

int	gdi_immid( int sid, Command_struct cmd )
{
   int	nr;
   int	r = GDIE_SUCCESS;

   nr = cmd.nbytes;
   if (nr > winfo.i_nchr) {
      nr = winfo.i_nchr;
   }
   r = misc_receive( clients[sid].socket, user.text1, nr );
   user.text1[nr] = 0;
   if (r != GDIE_SUCCESS) return( r );
   if (nr < cmd.nbytes) {
      r = GDIE_TOO_LONG;
      misc_flush( clients[sid].socket, cmd.nbytes - nr );
   } else {
      strcpy( winfo.record[0].text1, user.text1 );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   data_text( );
   XFlush( winfo.id );
   return( r );
}

int	gdi_imsid( int sid, Command_struct cmd )
{
   int	nr;
   int	r = GDIE_SUCCESS;

   nr = cmd.nbytes;
   if (nr > winfo.i_nchr) {
      nr = winfo.i_nchr;
   }
   r = misc_receive( clients[sid].socket, user.text2, nr );
   user.text2[nr] = 0;
   if (r != GDIE_SUCCESS) return( r );
   if (nr < cmd.nbytes) {
      r = GDIE_TOO_LONG;
      r = misc_flush( clients[sid].socket, cmd.nbytes - nr );
   } else {
      strcpy( winfo.record[0].text2, user.text2 );
   }
   cmd.code   = r;
   cmd.nbytes = 0;
   data_text( );
   XFlush( winfo.id );
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );
}

int	gdi_gdsid( int sid, Command_struct cmd )
{
   int	nr;
   int	r = GDIE_SUCCESS;

   nr = cmd.nbytes;
   if (user.idata != NULL) {
      user.subset = cmd.code;
      if (nr > MAXSETNAMELEN) nr = MAXSETNAMELEN;
      r = misc_receive( clients[sid].socket, user.set, nr );
      if (nr < cmd.nbytes) {
         r = GDIE_TOO_LONG;
         r = misc_flush( clients[sid].socket, cmd.nbytes - nr );
      }
      cmd.code   = r;
      cmd.nbytes = 0;
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   } else {
      r = misc_flush( clients[sid].socket, nr );
      r = GDIE_NO_IMAGE;
      cmd.code   = r;
      cmd.nbytes = 0;
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   }
   return( r );
}

int	gdi_iinfo( int sid, Command_struct cmd )
{
   int	r = GDIE_SUCCESS;
   int	grids[4];

   if (user.idata != NULL) {
      cmd.code   = user.subset;
      cmd.nbytes = MAXSETNAMELEN + sizeof( grids );
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
      grids[0] = user.x_min;
      grids[1] = user.y_min;
      grids[2] = user.x_max;
      grids[3] = user.y_max;
      misc_sl( clients[sid].swap, grids, 4 );
      r = misc_send( clients[sid].socket, user.set, MAXSETNAMELEN );
      r = misc_send( clients[sid].socket, grids, sizeof( grids ) );
   } else {
      cmd.code   = GDIE_NO_IMAGE;
      cmd.nbytes = 0;
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   }
   return( r );
}


int	gdi_frame( int sid, Command_struct cmd )
{
   int	nr;
   int	r = GDIE_SUCCESS;

   nr = cmd.nbytes;
   if (user.idata != NULL) {
      double	xzf, yzf;
      int	xzc, yzc;
      int	x_c, y_c;
      float	frame[4];
      float	xsh, ysh;
      fint	four = 4;
      fint	ftype = clients[sid].ftype;

      xzf = pow( 2.0, (double) -winfo.x_zoomf );
      if (winfo.x_zoomf > 0) xsh = 0.5 * (1.0 - xzf); else xsh = 0.0;
      xzc = winfo.x_zoomc;
      x_c = ( winfo.dwidth - 1 ) / 2;
      yzf = pow( 2.0, (double) -winfo.y_zoomf );
      if (winfo.y_zoomf > 0) ysh = 0.5 * (1.0 - yzf); else ysh = 0.0;
      yzc = winfo.y_zoomc;
      y_c = ( winfo.dheight + 1 ) / 2;
      frame[0] = xzf * (double) (0 - x_c) + (double) xzc + xsh;
      frame[1] = yzf * (double) (y_c - winfo.dheight + 1) + (double) yzc + ysh;
      frame[2] = xzf * (double) (winfo.dwidth - 1 - x_c) + (double) xzc + xsh;
      frame[3] = yzf * (double) (y_c - 0) + (double) yzc + ysh;
      spfplf_c( &ftype, frame, frame, &four );
      cmd.code = r;
      cmd.nbytes = four * sizeof( float );
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
      r = misc_send( clients[sid].socket, frame, four * sizeof( float ) );
   } else {
      r = misc_flush( clients[sid].socket, nr );
      r = GDIE_NO_IMAGE;
      cmd.code   = r;
      cmd.nbytes = 0;
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   }
   return( r );
}


int	gdi_blankcol( int sid, Command_struct cmd )
{
   int			nr;			/* number of bytes to read */
   int			ns = 0;			/* number of shorts */
   int			r = GDIE_SUCCESS;	/* return value */
   unsigned short	table[3];		/* color table */

   nr = cmd.nbytes;				/* number of bytes to read */
   cmd.code = GDIE_SUCCESS;			/* no error */
   r = misc_receive( clients[sid].socket, table, nr );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   ns = nr / sizeof( unsigned short );		/* number of shorts */
   misc_ss( clients[sid].swap, table, ns );	/* swap it */
   winfo.table[0].red   = table[0];
   winfo.table[0].green = table[1];
   winfo.table[0].blue  = table[2];
   XStoreColors( winfo.id, winfo.colormap, winfo.table, 1 );
   XFlush( winfo.id );
   cmd.nbytes = 0;				/* no next send */
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );					/* return to caller */
}


int	gdi_idlen( int sid, Command_struct cmd )
{
   int	nw;					/* number of bytes to write */
   int	r = GDIE_SUCCESS;			/* return value */
   int	id_info[1];				/* contains id info */

   id_info[0] = winfo.i_nchr;			/* put it there */
   cmd.code   = 0;				/* no error */
   cmd.nbytes = nw = sizeof( id_info );		/* number of bytes to send */
   misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r != GDIE_SUCCESS) return( r );		/* return to caller */
   misc_sl( clients[sid].swap, id_info, 1 );	/* swap it */
   r = misc_send( clients[sid].socket, id_info, nw );
   return( r );					/* return to caller */
}


int	gdi_iinfo2( int sid, Command_struct cmd )
{
   int	r = GDIE_SUCCESS;
   int	grids[4];
   float	ab[2];

   if (user.idata != NULL) {
      fint	ftype = clients[sid].ftype;
      fint	two = 2;

      cmd.code   = user.subset;
      cmd.nbytes = MAXSETNAMELEN + sizeof( grids );
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
      grids[0] = user.x_min;
      grids[1] = user.y_min;
      grids[2] = user.x_max;
      grids[3] = user.y_max;
      ab[0] = user.bscale;
      ab[1] = user.b_zero;
      misc_sl( clients[sid].swap, grids, 4 );
      spfplf_c( &ftype, ab, ab, &two );
      r = misc_send( clients[sid].socket, user.set, MAXSETNAMELEN );
      r = misc_send( clients[sid].socket, grids, sizeof( grids ) );
      r = misc_send( clients[sid].socket, ab, sizeof( ab ) );
   } else {
      cmd.code   = GDIE_NO_IMAGE;
      cmd.nbytes = 0;
      misc_cmd_swap( clients[sid].swap, &cmd );
      r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   }
   return( r );
}


int	gdi_getlut( int sid, Command_struct cmd )
{
   int		n, nw;
   int		r = GDIE_SUCCESS;
   float	red[MAXCOLORS];
   float	green[MAXCOLORS];
   float	blue[MAXCOLORS];
   fint		nf;

   nf = winfo.ncolors;
   nw = cmd.nbytes = winfo.ncolors * sizeof( float ) * 3;
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   if (r == GDIE_SUCCESS) {
      fint	ftype = clients[sid].ftype;

      for ( n = 0; n < winfo.ncolors; n++ ) {
         red[n]   = (float) winfo.modify[n].red   / USHRT_MAX;
         green[n] = (float) winfo.modify[n].green / USHRT_MAX;
         blue[n]  = (float) winfo.modify[n].blue  / USHRT_MAX;
      }
      spfplf_c( &ftype, red  , red  , &nf );
      spfplf_c( &ftype, green, green, &nf );
      spfplf_c( &ftype, blue , blue , &nf );
      r = misc_send( clients[sid].socket, red  , nf * sizeof( float ) );
      r = misc_send( clients[sid].socket, green, nf * sizeof( float ) );
      r = misc_send( clients[sid].socket, blue , nf * sizeof( float ) );
   }
   return( r );
}


int	gdi_setxgrid( int sid, Command_struct cmd )
{
   int		nr;
   int		r = GDIE_SUCCESS;

   nr = cmd.nbytes;
   if (user.idata == NULL) {
      cmd.code   = GDIE_NO_IMAGE;
      r = misc_flush( clients[sid].socket, nr );
   } else {
      char	*xgridt;

      xgridt = calloc( sizeof(char), nr );
      if (xgridt == NULL) {
         cmd.code = GDIE_S_ALLOC;
         r = misc_flush( clients[sid].socket, nr );
      } else {
         int	n;
         int	tl;
         int	x;

         cmd.code = GDIE_SUCCESS;
         r = misc_receive( clients[sid].socket, xgridt, nr );
         if (r!= GDIE_SUCCESS) return( r );
         tl = nr / user.x_size;
         user.xgt = realloc( user.xgt, sizeof( Gtext_struct ) * user.x_size );
         for ( n = 0, x = 0; x < user.x_size; x++ ) {
            int	l = tl;
            int	m = 0;

            while (l >= MAXGTLEN) { n++; l--; }
            while (l < (MAXGTLEN-1)) { user.xgt[x].text[m++] = ' '; l++; }
            while (m < (MAXGTLEN-1)) { user.xgt[x].text[m++] = xgridt[n++]; }
            user.xgt[x].text[m] = 0;
         }
         free( xgridt );
         if (user.images) misc_setgridtext( );
      }
   }
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );
}


int	gdi_setygrid( int sid, Command_struct cmd )
{
   int		nr;
   int		r = GDIE_SUCCESS;

   nr = cmd.nbytes;
   if (user.idata == NULL) {
      cmd.code   = GDIE_NO_IMAGE;
      r = misc_flush( clients[sid].socket, nr );
   } else {
      char	*ygridt;

      ygridt = calloc( sizeof(char), nr );
      if (ygridt == NULL) {
         cmd.code = GDIE_S_ALLOC;
         r = misc_flush( clients[sid].socket, nr );
      } else {
         int	n;
         int	tl;
         int	y;

         cmd.code = GDIE_SUCCESS;
         r = misc_receive( clients[sid].socket, ygridt, nr );
         if (r!= GDIE_SUCCESS) return( r );
         tl = nr / user.y_size;
         user.ygt = realloc( user.ygt, sizeof( Gtext_struct ) * user.y_size );
         for ( n = 0, y = 0; y < user.y_size; y++ ) {
            int	l = tl;
            int	m = 0;

            while (l >= MAXGTLEN) { n++; l--; }
            while (l < (MAXGTLEN-1)) { user.ygt[y].text[m++] = ' '; l++; }
            while (m < (MAXGTLEN-1)) { user.ygt[y].text[m++] = ygridt[n++]; }
            user.ygt[y].text[m] = 0;
         }
         free( ygridt );
         if (user.images) misc_setgridtext( );
      }
   }
   misc_cmd_swap( clients[sid].swap, &cmd );
   r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
   return( r );
}
/*
 * The PGPLOT Functions:
 */

#define INT(x)  ( (int) ( (x) + 0.5 ) )

static	GC		xgc;
static	XGCValues	xgcvl;
static	int		append;
static	int		cindex = 1;
static	int		NPOLY = 0;
static	int		POLY = 0;
static	XPoint		VERTEX[500];

int	gdi_pgplot( int sid, Command_struct cmd )
{
   fint	ftype;
   int	ifunc;
   int	r = GDIE_SUCCESS;

   ifunc = cmd.code;				/* PGPLOT Function */
   ftype = clients[sid].ftype;			/* Floating Point type */
   switch( ifunc ) {
      case 1: {		/* return device name */
         break;
      }
      case 2: {		/* return minimum range of view surface and color index */
         float	rbuf[6];
         fint	nrbf;

         rbuf[0] = 0.0;
         rbuf[1] = winfo.pgw - 1;
         rbuf[2] = 0.0;
         rbuf[3] = winfo.pgh - 1;
         rbuf[4] = 0.0;
         if (winfo.class == PseudoColor) {
            rbuf[5] = MAXPCOLORS - 1;
         } else {
            rbuf[5] = 1;
         }
         nrbf = sizeof( rbuf ) / sizeof( float );
         cmd.nbytes = sizeof( rbuf );
         misc_cmd_swap( clients[sid].swap, &cmd );
         r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
         spfplf_c( &ftype, rbuf, rbuf, &nrbf );
         r = misc_send( clients[sid].socket, rbuf, sizeof( rbuf ) );
         break;
      }
      case 3: {		/* return device scale */
         float	rbuf[3];
         fint	nrbf;

         rbuf[0] = ( (float) winfo.width ) / ( (float) winfo.widthMM ) * 25.4;
         rbuf[1] = ( (float) winfo.height ) / ( (float) winfo.heightMM ) * 25.4;
         rbuf[2] = 1.0;
         nrbf = sizeof( rbuf ) / sizeof( float );
         cmd.nbytes = sizeof( rbuf );
         misc_cmd_swap( clients[sid].swap, &cmd );
         r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
         spfplf_c( &ftype, rbuf, rbuf, &nrbf );
         r = misc_send( clients[sid].socket, rbuf, sizeof( rbuf ) );
         break;
      }
      case 4: {		/* return device capabilities */
         char cbuf[10];

         strncpy( cbuf, "ICNATRNNNN", sizeof( cbuf ) );
         cmd.nbytes = sizeof( cbuf );
         misc_cmd_swap( clients[sid].swap, &cmd );
         r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
         r = misc_send( clients[sid].socket, cbuf, sizeof( cbuf ) );
         break;
      }
      case 5: {		/* return default device/file name */
         break;
      }
      case 6: {		/* return default size of view */
         float	rbuf[4];
         fint	nrbf;

         rbuf[0] = 0;
         rbuf[1] = winfo.pgw - 1;
         rbuf[2] = 0;
         rbuf[3] = winfo.pgh - 1;
         nrbf = sizeof( rbuf ) / sizeof( float );
         cmd.nbytes = sizeof( rbuf );
         misc_cmd_swap( clients[sid].swap, &cmd );
         r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
         spfplf_c( &ftype, rbuf, rbuf, &nrbf );
         r = misc_send( clients[sid].socket, rbuf, sizeof( rbuf ) );
         break;
      }
      case 7: {		/* return miscellaneous defaults */
         float	rbuf[1];
         fint	nrbf;

         rbuf[0] = 2.0;
         nrbf = sizeof( rbuf ) / sizeof( float );
         cmd.nbytes = sizeof( rbuf );
         misc_cmd_swap( clients[sid].swap, &cmd );
         r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
         spfplf_c( &ftype, rbuf, rbuf, &nrbf );
         r = misc_send( clients[sid].socket, rbuf, sizeof( rbuf ) );
         break;
      }
      case 8: {		/* select device */
         break;
      }
      case 9: {		/* open workstation */
         float	rbuf[3];
         fint	nrbf;
         int	n;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         cindex = 1;
         for (n = 0; n < MAXPCOLORS; n++) {
            switch( n ) {			/* color index */
               case 0: {			/* black (background) */
                  winfo.pcolors[n].red   = 0.00;
                  winfo.pcolors[n].green = 0.00;
                  winfo.pcolors[n].blue  = 0.00;
                  break;
               }
               case 1: {			/* white (default) */
                  winfo.pcolors[n].red   = 1.00;
                  winfo.pcolors[n].green = 1.00;
                  winfo.pcolors[n].blue  = 1.00;
                  break;
               }
               case 2: {			/* red */
                  winfo.pcolors[n].red   = 1.00;
                  winfo.pcolors[n].green = 0.00;
                  winfo.pcolors[n].blue  = 0.00;
                  break;
               }
               case 3: {			/* green */
                  winfo.pcolors[n].red   = 0.00;
                  winfo.pcolors[n].green = 1.00;
                  winfo.pcolors[n].blue  = 0.00;
                  break;
               }
               case 4: {			/* blue */
                  winfo.pcolors[n].red   = 0.00;
                  winfo.pcolors[n].green = 0.00;
                  winfo.pcolors[n].blue  = 1.00;
                  break;
               }
               case 5: {			/* cyan (green + blue) */
                  winfo.pcolors[n].red   = 0.00;
                  winfo.pcolors[n].green = 1.00;
                  winfo.pcolors[n].blue  = 1.00;
                  break;
               }
               case 6: {			/* magenta (red + blue) */
                  winfo.pcolors[n].red   = 1.00;
                  winfo.pcolors[n].green = 0.00;
                  winfo.pcolors[n].blue  = 1.00;
                  break;
               }
               case 7: {			/* yellow (red + green) */
                  winfo.pcolors[n].red   = 1.00;
                  winfo.pcolors[n].green = 1.00;
                  winfo.pcolors[n].blue  = 0.00;
                  break;
               }
               case 8: {			/* red + yellow (orange) */
                  winfo.pcolors[n].red   = 1.00;
                  winfo.pcolors[n].green = 0.50;
                  winfo.pcolors[n].blue  = 0.00;
                  break;
               }
               case 9: {			/* green + yellow */
                  winfo.pcolors[n].red   = 0.50;
                  winfo.pcolors[n].green = 1.00;
                  winfo.pcolors[n].blue  = 0.00;
                  break;
               }
               case 10: {			/* green + cyan */
                  winfo.pcolors[n].red   = 0.00;
                  winfo.pcolors[n].green = 1.00;
                  winfo.pcolors[n].blue  = 0.50;
                  break;
               }
               case 11: {			/* blue + cyan */
                  winfo.pcolors[n].red   = 0.00;
                  winfo.pcolors[n].green = 0.50;
                  winfo.pcolors[n].blue  = 1.00;
                  break;
               }
               case 12: {			/* blue + magenta */
                  winfo.pcolors[n].red   = 0.50;
                  winfo.pcolors[n].green = 0.00;
                  winfo.pcolors[n].blue  = 1.00;
                  break;
               }
               case 13: {			/* red + magenta */
                  winfo.pcolors[n].red   = 1.00;
                  winfo.pcolors[n].green = 0.00;
                  winfo.pcolors[n].blue  = 0.50;
                  break;
               }
               case 14: {			/* dark gray */
                  winfo.pcolors[n].red   = 0.33;
                  winfo.pcolors[n].green = 0.33;
                  winfo.pcolors[n].blue  = 0.33;
                  break;
               }
               case 15: {			/* light gray */
                  winfo.pcolors[n].red   = 0.66;
                  winfo.pcolors[n].green = 0.66;
                  winfo.pcolors[n].blue  = 0.66;
                  break;
               }
               default: {			/* undefined (white) */
                  winfo.pcolors[n].red   = 1.00;
                  winfo.pcolors[n].green = 1.00;
                  winfo.pcolors[n].blue  = 1.00;
                  break;
               }
            }
         }
         for (n = 0; n < MAXPCOLORS; n++) {
            int	p = winfo.ncolors + MAXGCOLORS + n;

            winfo.table[p].red   = USHRT_MAX * winfo.pcolors[n].red;
            winfo.table[p].green = USHRT_MAX * winfo.pcolors[n].green;
            winfo.table[p].blue  = USHRT_MAX * winfo.pcolors[n].blue;
            winfo.modify[p] = winfo.table[p];
         }
         XStoreColors( winfo.id, winfo.colormap, &winfo.table[winfo.ncolors+MAXGCOLORS], MAXPCOLORS );
         xgcvl.foreground = WhitePixel( winfo.id, winfo.screen );
         xgcvl.background = BlackPixel( winfo.id, winfo.screen );
         xgc = XCreateGC( winfo.id, winfo.pgplot, GCForeground | GCBackground, &xgcvl );
         XSetForeground( winfo.id, xgc, winfo.pcells[cindex] );
         XSetFont( winfo.id, xgc, XLoadFont( winfo.id, "-ADOBE-NEW CENTURY SCHOOLBOOK-MEDIUM-R-NORMAL--*-140-*-*-P-*" ) );
         XSetLineAttributes( winfo.id, xgc, 1, LineSolid, CapButt, JoinRound );
         XMapWindow( winfo.id, winfo.pgplot );
         rbuf[0] = 0.0;
         rbuf[1] = 1.0;
         append = INT( rbuf[2] );
         nrbf = 2;
         cmd.nbytes = nrbf * sizeof( float );
         misc_cmd_swap( clients[sid].swap, &cmd );
         r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
         spfplf_c( &ftype, rbuf, rbuf, &nrbf );
         r = misc_send( clients[sid].socket, rbuf, nrbf * sizeof( float ) );
         XFlush( winfo.id );
         break;
      }
      case 10: {	/* close workstation */
         XFlush( winfo.id );
         break;
      }
      case 11: {	/* begin picture */
         if (winfo.autoraise) {
            if (winfo.windows & WINDOW_PGPLOT) {
               XRaiseWindow( winfo.id, winfo.pgplot );
            } else {
               XRaiseWindow( winfo.id, winfo.top );
            }
         }
         if (!append) {
            XClearWindow( winfo.id, winfo.pgplot );
         }
         XFlush( winfo.id );
         break;
      }
      case 12: {	/* draw line */
         float	rbuf[4];
         fint	nrbf;
         int	i0, i1, j0, j1;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         i0 = INT( rbuf[0] );
         j0 = winfo.pgh - 1 - INT( rbuf[1] );
         i1 = INT( rbuf[2] );
         j1 = winfo.pgh - 1 - INT( rbuf[3] );
         XDrawLine( winfo.id, winfo.pgplot, xgc, i0, j0, i1, j1 );
         break;
      }
      case 13: {	/* draw dot */
         float	rbuf[2];
         fint	nrbf;
         int	i0, j0;
         int	w;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         i0 = INT( rbuf[0] );
         j0 = winfo.pgh - 1 - INT( rbuf[1] );
         w = xgcvl.line_width;
         if (w == 1) {
            XDrawPoint( winfo.id, winfo.pgplot, xgc, i0, j0 );
         } else {
            XFillArc( winfo.id, winfo.pgplot, xgc, i0 - w / 2,
               j0 - w / 2, w, w, 0, 359 * 64 );
         }
         break;
      }
      case 14: {	/* end picture */
         float	rbuf[1];
         fint	nrbf;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         XFlush( winfo.id );
         XSync( winfo.id, True );
         if (INT( rbuf[0] )) {
/*            XClearWindow( winfo.id, winfo.pgplot );*/
         }
         break;
      }
      case 15: {	/* set color index */
         float	rbuf[1];
         fint	nrbf;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         cindex = INT( rbuf[0] );
         if ( cindex > 0 && cindex < MAXPCOLORS ) {
            XSetForeground( winfo.id, xgc, winfo.pcells[cindex] );
         } else {
            XSetForeground( winfo.id, xgc, BlackPixel( winfo.id, winfo.screen ) );
         }
         break;
      }
      case 16: {	/* flush buffer */
         XFlush( winfo.id );
         XSync( winfo.id, True );
         break;
      }
      case 17: {	/* read cursor */
         XEvent		event;
         char		cbuf[1];
         float		rbuf[2];
         fint		nrbf;
         int		done = 0;
         int		i0, j0;
         int		thecursor;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         i0 = INT( rbuf[0] );
         j0 = winfo.pgh - 1 - INT( rbuf[1] );
         XWarpPointer( winfo.id, None, winfo.pgplot, i0, j0,
                        winfo.pgw, winfo.pgh, i0, j0 );
         thecursor = XCreateFontCursor( winfo.id, XC_crosshair );
         XDefineCursor( winfo.id, winfo.pgplot, thecursor );
         XGrabPointer( winfo.id, winfo.pgplot, True, KeyPressMask | ButtonPressMask,
            GrabModeAsync, GrabModeAsync, winfo.pgplot, None, CurrentTime );
         XGrabKeyboard( winfo.id, winfo.pgplot, False,
            GrabModeAsync, GrabModeAsync, CurrentTime );
         do {
            XMaskEvent( winfo.id, KeyPressMask | ButtonPressMask, &event) ;
            if (event.xkey.window == winfo.pgplot) {
               switch( event.type ) {
                  case ButtonPress: {
                     i0 = event.xbutton.x;
                     j0 = event.xbutton.y;
                     cbuf[0] = (char) (event.xbutton.button + 060);
                     done = 1;
                     break;
                  }
                  case KeyPress: {
                     KeySym		key;
                     XComposeStatus	compose;
                     char		buffer[10];
                     int		count;

                     i0 = event.xkey.x;
                     j0 = event.xkey.y;
                     count = XLookupString( (XKeyEvent *) &event, buffer, sizeof( buffer ), &key, &compose );
                     if (((key >= XK_KP_Space) && (key <= XK_KP_9)) || ((key >= XK_space && key <= XK_asciitilde))) {
                        cbuf[0] = buffer[0];
                        done = 1;
                     } else if ((key == XK_Return) || (key == XK_KP_Enter)) {
                        cbuf[0] = 13;
                        done = 1;
                     } else {
                        cbuf[0] = 0;
                     }
                     break;
                  }
                  default: {
                     break;
                  }
               }
            }
         } while (!done);
         XUngrabKeyboard( winfo.id, CurrentTime );
         XUngrabPointer( winfo.id, CurrentTime );
         thecursor = XCreateFontCursor( winfo.id, XC_circle );
         XDefineCursor( winfo.id, winfo.pgplot, thecursor );
         rbuf[0] = i0;
         rbuf[1] = winfo.pgh - 1 - j0;
         cmd.nbytes = sizeof( rbuf ) + sizeof( cbuf );
         nrbf = sizeof( rbuf ) / sizeof( float );
         misc_cmd_swap( clients[sid].swap, &cmd );
         r = misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
         spfplf_c( &ftype, rbuf, rbuf, &nrbf );
         r = misc_send( clients[sid].socket, rbuf, sizeof( rbuf ) );
         r = misc_send( clients[sid].socket, cbuf, sizeof( cbuf ) );
         break;
      }
      case 18: {	/* erase alpha screen */
         break;
      }
      case 19: {	/* set line style */
         xgcvl.line_style = LineSolid;
         XChangeGC( winfo.id, xgc, GCLineStyle, &xgcvl );
         break;
      }
      case 20: {	/* polygon fill */
         float	rbuf[2];
         fint	nrbf;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         if (POLY == 0) {
            NPOLY = INT( rbuf[0] );
            POLY = NPOLY;
         } else {
            VERTEX[POLY].y = winfo.pgh - 1 - INT( rbuf[1] );
            VERTEX[POLY].x = INT( rbuf[0] );
            --POLY;
            if (POLY == 0) {
               XFillPolygon( winfo.id, winfo.pgplot, xgc,
                  &(VERTEX[1]), NPOLY, Complex, CoordModeOrigin );
            }
         }
         XFlush( winfo.id );
         break;
      }
      case 21: {	/* set color represention */
         float	rbuf[4];
         fint	nrbf;
         int	ci;
         int	n;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         ci = INT( rbuf[0] );
         if ( ci > 0 && ci < MAXPCOLORS ) {
            winfo.pcolors[ci].red   = rbuf[1];
            winfo.pcolors[ci].green = rbuf[2];
            winfo.pcolors[ci].blue  = rbuf[3];
            n = winfo.ncolors + MAXGCOLORS + ci;
            winfo.table[n].flags = DoRed | DoGreen | DoBlue;
            winfo.table[n].red   = USHRT_MAX * winfo.pcolors[ci].red;
            winfo.table[n].green = USHRT_MAX * winfo.pcolors[ci].green;
            winfo.table[n].blue  = USHRT_MAX * winfo.pcolors[ci].blue;
            winfo.modify[n] = winfo.table[n];
            XStoreColors( winfo.id, winfo.colormap, &winfo.table[n], 1 );
            XFlush( winfo.id );
         }
         break;
      }
      case 22: {	/* set line width */
         float	rbuf[1];
         fint	nrbf;
         int	lw;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         lw = INT( rbuf[0] );
         if (lw < 1 || lw > 40) lw = 1;
         if (lw > 1) lw = lw / 2;
         xgcvl.line_width = lw;
         XChangeGC( winfo.id, xgc, GCLineWidth, &xgcvl );
         break;
      }
      case 23: {	/* escape function */
         break;
      }
      case 24: {	/* rectangle fill */
         float	rbuf[4];
         fint	nrbf;
         int	i0, il, j0, jl;

         nrbf = cmd.nbytes / sizeof( float );
         r = misc_receive( clients[sid].socket, rbuf, cmd.nbytes );
         spfpfl_c( &ftype, rbuf, rbuf, &nrbf );
         i0 = INT( rbuf[0] );
         j0 = winfo.pgh - 1 - INT( rbuf[3] );
         il = INT( rbuf[2] - rbuf[0] );
         jl = INT( rbuf[3] - rbuf[1] );
         XFillRectangle( winfo.id, winfo.pgplot, xgc , i0, j0, il, jl );
         XFlush( winfo.id );
         break;
      }
      case 25: {	/* not implemented */
         break;
      }
      default: {
         break;
      }
   }
   return( r );
}
#<

#>            help.c
/* help.c
 *
 */

#include	"gids.h"

#define	HELPFILE	"gids.doc"
static	FILE		*hf = NULL;
static	char		helpfile[FILENAME_MAX];
static	char		line[90];
static	int		queued = 0;
static	int		queued_depth;
static	int		queued_level;

int	help_init( char *hfile )
{
   FILE	*f;

   if (hfile == NULL) return( 0 );
   f = fopen( hfile, "r" );
   if ( f != NULL ) {
      strcpy( helpfile, hfile );
      fclose( f );
   }
   return( 0 );
}

static	int	get_help_file( void )
{
   int	n;

   for ( n = 0; !helpfile[0] && n < 4; n++ ) {
      char	buf[FILENAME_MAX];
      char	*ptr;

      switch( n ) {
         case 0: {
            ptr = getenv( "gids_setup" );
            break;
         }
         case 1: {
            ptr = getenv( "gip_doc" );
            break;
         }
         case 2: {
            strcpy( buf, "." );
            ptr = buf;
            break;
         }
         case 3: {
            int	l;

            strcpy( buf, myargv[0] );
            l = strlen( buf );
            while ( l && ( buf[l-1] != '/' ) ) buf[--l] = 0;
            if (l) buf[--l] = 0;
            if (!l) strcpy( buf, "." );
            ptr = buf;
            break;
         }
         default: {
            ptr = NULL;
            break;
         }
      }
      if ( ptr != NULL ) {
         sprintf( helpfile, "%s/%s", ptr, HELPFILE );
         hf = fopen( helpfile, "r" );
         if (hf != NULL ) {
            fclose( hf );
            hf = NULL;
         } else {
            helpfile[0] = 0;
         }
      }
   }
   if (helpfile[0]) return( 0 ); else return( 1 );
}

int	help_show( void )
{
   char	*tp = line;
   int	count = 0;
   int	done;
   int	y, dy = ( winfo.hfont->ascent + winfo.hfont->descent );

   if (hf == NULL) return( 0 );
   display_help( 1 );
   y = 0;
   do {
      int	nc = strlen( tp );

      y += dy;
      XDrawString( winfo.id, winfo.help, winfo.gch, 25, y, &tp[14], nc - 15 );
      tp = fgets( line, sizeof(line), hf );
      done = ((tp == NULL) || (!isspace(tp[0])));
   } while (!done && (++count < MAXHELPLINES));
   if (done) {
      fclose( hf );
      hf = NULL;
   } else {
      char	text[80];

      strcpy( text, ">>> PRESS ANY KEY IN THIS WINDOW FOR MORE <<<" );
      y += dy;
      XDrawString( winfo.id, winfo.help, winfo.gch, 25, y, text, strlen( text ) );
   }
   XFlush( winfo.id );
   return( 0 );
}

static	int	get_help( char *string )
{
   char	*tp;
   char	text[75];
   int	nc;
   int	x, y;

   if (hf != NULL) { fclose( hf ); hf = NULL; }
   if (get_help_file( )) {
      nc = sprintf( text, "NO HELP FILE (%s) found!", HELPFILE );
      x = ( winfo.hwidth - XTextWidth( winfo.hfont, text, nc ) ) / 2;
      y = winfo.hheight / 2;
      XDrawString( winfo.id, winfo.help, winfo.gch, x, y, text, nc );
      XBell( winfo.id, 100 );
      XFlush( winfo.id );
      return( 0 );
   }
   hf = fopen( helpfile, "r" );
   if ( hf == NULL ) {
      XBell( winfo.id, 100 );
      return( 0 );
   }
   while ( ((tp = fgets( line, sizeof( line ), hf )) == line) && (strstr( line, string ) != tp));
   if (tp == NULL) {
      fclose( hf );
      hf = NULL;
      nc = sprintf( text, "NO HELP ON THIS MENU ITEM %s!", string );
      x = ( winfo.hwidth - XTextWidth( winfo.hfont, text, nc ) ) / 2;
      y = winfo.hheight / 2;
      XDrawString( winfo.id, winfo.help, winfo.gch, x, y, text, nc );
      XBell( winfo.id, 100 );
      XFlush( winfo.id );
      return( 0 );
   }
   help_show( );
   return( 0 );
}

int	help_help( int button )
{
   if (winfo.windows & WINDOW_HELP) {
      display_help( 0 );
   } else {
      help_do_help( menu[button].depth, menu[button].level );
   }
   return( menu[button].ret );
}

int	help_continue( void )
{
   if (queued) {
      help_do_help( queued_depth, queued_level );
   }
   queued = 0;
   return( 0 );
}

int	help_do_help( int depth, int level )
{
   char	string[20];
   int	k, n = 0;

   if (depth == 0) return( 0 );
   if (display_help( 1 )) {
      queued = 1;
      queued_depth = depth;
      queued_level = level;
      return( 0 );
   }
   string[n] = '(';
   for ( k = 0; k < depth; k++ ) {
      string[++n] = '0' + level % MAXMENUS;
      level = level / MAXMENUS;
      string[++n] = '.';
   }
   string[n++] = ')';
   string[n] = '\0';
   get_help( string );
   return( 0 );
}
#<

#>            input.c
/* input.c

*/

#include	"gids.h"
#include	"f2cvvdefs.h"
#include	"dcdint.h"
#include	"dcdreal.h"

#define	MAXCHAR		1024
#define	MAXDISPLAY	winfo.i_nchr

static	char	input_buffer[MAXCHAR+1];
static	int	input_nchars = 0;

int	input_putchar( XKeyEvent event, int action )
{
   char			buffer[10];
   int			count;
   int			n;
   KeySym		keysym;
   XComposeStatus	compose;

   count = XLookupString( &event, buffer, sizeof(buffer), &keysym, &compose );
   if (((keysym == XK_Control_L) || (keysym == XK_Control_R)) &&
      (event.window == winfo.display)) {
      return( 1 );
   } else if ((action | BLOT_ACTION) && ((keysym == XK_Up) ||
      (keysym == XK_Down) || (keysym == XK_Left) || (keysym == XK_Right)) &&
      (event.window == winfo.display)) {
      region_blot_change( keysym );
      return( 0 );
   } else if ((keysym == XK_Return) || (keysym == XK_KP_Enter) ||
      (keysym == XK_Linefeed)) {
      return( 0 );
   } else if (((keysym >= XK_KP_Space) && (keysym <= XK_KP_9)) ||
      ((keysym >= XK_space) && (keysym <= XK_asciitilde))) {
      for (n = 0; n < count && input_nchars < MAXCHAR; n++) {
         if (isprint( buffer[n] )) {
            input_buffer[input_nchars++] = buffer[n];
         }
      }
   } else if ((keysym == XK_BackSpace) || (keysym == XK_Delete)) {
      if (input_nchars) input_buffer[--input_nchars] = 0;
   }
   input_show( );
   return( 0 );
}

int	input_show( void )
{
   int	nc;
   if (input_nchars == 0) {
      nc = 0;
   } else if (input_nchars <= MAXDISPLAY) {
      nc = input_nchars;
      strncpy( winfo.text[6], input_buffer, nc );
   } else {
      nc = MAXDISPLAY;
      strncpy( winfo.text[6], &input_buffer[input_nchars-MAXDISPLAY], nc );
   }
   winfo.text[6][nc] = 0;
   misc_info( 0 );
   return( 0 );
}

int	input_read_int( int *values, int nvalues )
{
   fchar	expr;
   fint		ierh = 0;
   fint		nout;
   fint		outv[1024];
   fint		nret;
   int		n;

   if (input_nchars == 0) return( 0 );		/* nothing in input buffer */
   expr.a = input_buffer;
   expr.l = input_nchars;
   if (nvalues > ( sizeof( outv ) / sizeof( fint ) )) {
      nout = sizeof( outv ) / sizeof( fint );
   } else {
      nout = nvalues;
   }
   nret = dcdint_c( expr, outv, &nout, &ierh );
   if (ierh == 0) {
      for (n = 0; n < nret; n++) {
         values[n] = outv[n];
      }
   } else {
      nret = ierh;
   }
   while (input_nchars) input_buffer[--input_nchars] = 0;
   input_show( );
   return( nret );
}

int	input_read_float( float *values, int nvalues )
{
   fchar	expr;
   fint		ierh = 0;
   fint		nout;
   float	outv[1024];
   fint		nret;
   int		n;

   if (input_nchars == 0) return( 0 );		/* nothing in input buffer */
   expr.a = input_buffer;
   expr.l = input_nchars;
   if (nvalues > ( sizeof( outv ) / sizeof( float ) )) {
      nout = sizeof( outv ) / sizeof( float );
   } else {
      nout = nvalues;
   }
   nret = dcdreal_c( expr, outv, &nout, &ierh );
   if (ierh == 0) {
      for (n = 0; n < nret; n++) {
         values[n] = outv[n];
      }
   } else {
      nret = ierh;
   }
   while (input_nchars) input_buffer[--input_nchars] = 0;
   input_show( );
   return( nret );
}
#<

#>            main.c
/* main.c

*/


/*
 * includes:
 */

#include	"gids.h"			/* GIDS symbols and definitions */
#if	defined(NO_GIPSY)
#define	cmain(argc,argv)	main(argc,argv)
#else
#include	"cmain.h"			/* main programme in C */
#endif

char	*myargv[MAXARG];
int	myargc;

/*
 * close_all_open_fds closes all file descriptors which are open except
 * the character special files (stin, stdout, stderr ).
 */

void	close_all_open_fds( void )
{
   int		close( );
   int		fd = 0;
   struct stat	buf;

   for ( fd = 0; fd < FOPEN_MAX; fd++ ) {
      int	r = fstat( fd, &buf );

      if ( !r && fd != fileno(stdin) && fd != fileno(stdout) && fd != fileno(stderr) ) {
         close( fd );
      }
   }
}


int cmain( int argc, char *argv[] )		/* main programme */
{
   char		*dis_name = NULL;		/* name of X11 display */
   char		*fil_name = NULL;		/* name of file */
   char		*key_name = NULL;		/* name of alternate keyboard */
   char		*gwn_name = NULL;		/* name of GIDS window */
   int		n = 0;				/* loop counter */
   int		r;				/* return value */

   close_all_open_fds( );			/* closes all sockets */
   myargc = 0;					/* reset */
   myargv[myargc++] = argv[0];			/* program name */
   winfo.memory = 1024;				/* reset */
   while (++n < argc) {				/* loop through arguments */
      myargv[myargc++] = argv[n];		/* next argument */
      if (argv[n][0] == '-') {			/* - switch */
         if (!strcmp( argv[n], "-display" )) {
            dis_name = argv[++n];		/* X11 display name */
            myargv[myargc++] = argv[n];		/* next argument */
         } else if (!strcmp( argv[n], "-keyboard" )) {
            key_name = argv[++n];
            myargv[myargc++] = argv[n];		/* next argument */
         } else if (!strcmp( argv[n], "-memory" )) {
            winfo.memory = atoi( argv[++n] );	/* display memory available */
            myargv[myargc++] = argv[n];		/* next argument */
         } else if (!strcmp( argv[n], "-file" )) {
            fil_name = argv[++n];		/* setup file */
            myargv[myargc++] = argv[n];		/* next argument */
         } else if (!strcmp( argv[n], "-name" )) {
            gwn_name = argv[++n];		/* name of GIDS window */
            myargv[myargc++] = argv[n];		/* next argument */
         }
      }
   }
   if (fil_name == NULL) {			/* the default */
      fil_name = ".default_display";
      myargv[myargc++] = "-file";
      myargv[myargc++] = fil_name;
   }
   if (gwn_name == NULL) {
      gwn_name = "GIDS";
   }
   r = display_open( dis_name, gwn_name );	/* open display */
   if (r == GDIE_SUCCESS && !winfo.con_string[0]) {	/* no error, continue */
      r = server_open( fil_name );		/* open server */
      if (r > 0) {				/* no error, continue */
         int	fork( );

         fclose( stdin );
         fclose( stdout );
         fclose( stderr );
         if (fork( ) > 0) {
            return( EXIT_SUCCESS );
         }
         cursor_init( key_name );		/* init keyboard */
         signal( SIGPIPE, misc_broken_pipe );	/* catch boken pipes */
         r = server_main_loop( );		/* continue */
      } else if (r == 0) {
         FILE	*f;

         f = fopen( fil_name, "w" );
         if (f != NULL) {
            fprintf( f, "%d\n", GDIE_S_NOCON );
            fclose( f );
         }
      } else {
         FILE	*f;

         f = fopen( fil_name, "w" );
         if (f != NULL) {
            fprintf( f, "%d\n", GDIE_S_NOCOMFILE );
            fclose( f );
         }
      }
      if (!r) {					/* no error, continue */
         r = server_close( );
         remove( fil_name );			/* remove file */
      }
      if (!r) {					/* no error, continue */
         r = display_close( dis_name );		/* clean up display */
      }
   } else {
      FILE	*f;

      f = fopen( fil_name, "w" );		/* open com. file */
      if (f != NULL) {				/* open o.k. */
         if (r == GDIE_SUCCESS) {
            fprintf( f, "%s\n", winfo.con_string );
         } else {
            fprintf( f, "%d\n", r );
         }
         fclose( f );
      }
   }
   return( r ? EXIT_FAILURE : EXIT_SUCCESS );	/* return last status */
}
#<

#>            menu.c
/* menu.c

*/

#include	"gids.h"

typedef	struct menu_bindings {			/* menu setup struct */
   char			*menu_text;
   int			 (*menu_function)(int);
   int			 menu_return;
   struct menu_bindings	*menu_next;
} Menu_bindings;

static	Menu_bindings	zoom_bindings[] = {	/* zoom menu */
   { "Reset",	zoom_reset,	ZOOM_ACTION,	NULL },
   { "In",	zoom_in,	ZOOM_ACTION,	NULL },
   { "Out",	zoom_out,	ZOOM_ACTION,	NULL },
   { "In X",	zoom_in_x,	ZOOM_ACTION,	NULL },
   { "Out X",	zoom_out_x,	ZOOM_ACTION,	NULL },
   { "In Y",	zoom_in_y,	ZOOM_ACTION,	NULL },
   { "Out Y",	zoom_out_y,	ZOOM_ACTION,	NULL },
   { "Return",	menu_previous,	ZOOM_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	subcolor_bindings[] = {	/* color sub menu */
   { "Background",	color_background,	COLOR_ACTION,	NULL },
   { "Heat",		color_heat,		COLOR_ACTION,	NULL },
   { "Isophot",		color_isophot,		COLOR_ACTION,	NULL },
   { "Mousse",		color_mousse,		COLOR_ACTION,	NULL },
   { "Random",		color_random,		COLOR_ACTION,	NULL },
   { "RGB",		color_rgb,		COLOR_ACTION,	NULL },
   { "Smooth",		color_smooth,		COLOR_ACTION,	NULL },
   { "Return",		menu_previous,		COLOR_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	color_bindings[] = {	/* color menu */
   { "Reset",		color_reset,	COLOR_ACTION,	NULL              },
   { "Mono",		color_mono,	COLOR_ACTION,	NULL              },
   { "Rainbow",		color_rainbow,	COLOR_ACTION,	NULL              },
   { "Ronekers",	color_ronekers,	COLOR_ACTION,	NULL              },
   { "Staircase",	color_staircase,COLOR_ACTION,	NULL              },
   { "User",		color_user,	COLOR_ACTION,	NULL              },
   { "Other",		menu_next,	COLOR_ACTION,	subcolor_bindings },
   { "Return",		menu_previous,	NONE_ACTION,	NULL              },
   { NULL }
};

static	Menu_bindings	scale_bindings[] = {	/* scale menu */
   { "Inverse",	scale_inverse,	COLOR_ACTION,	NULL },
   { "Linear",	scale_linear,	COLOR_ACTION,	NULL },
   { "Log",	scale_log,	COLOR_ACTION,	NULL },
   { "Exp",	scale_exp,	COLOR_ACTION,	NULL },
   { "Sqrt",	scale_sqrt,	COLOR_ACTION,	NULL },
   { "Square",	scale_square,	COLOR_ACTION,	NULL },
   { "Blank",   scale_blank,    COLOR_ACTION,   NULL },
   { "Return",	menu_previous,	NONE_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	wedge_bindings[] = {	/* wedge menu */
   { "Reset",	wedge_reset,	WEDGE_ACTION,	NULL },
   { "Red",	wedge_red,	WEDGE_ACTION,	NULL },
   { "Green",	wedge_green,	WEDGE_ACTION,	NULL },
   { "Blue",	wedge_blue,	WEDGE_ACTION,	NULL },
   { "Yellow",	wedge_yellow,	WEDGE_ACTION,	NULL },
   { "Purple",	wedge_purple,	WEDGE_ACTION,	NULL },
   { "White",	wedge_white,	WEDGE_ACTION,	NULL },
   { "Return",	menu_previous,	NONE_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	quit_bindings[] = {	/* quit menu */
   { "No",	menu_previous,	NONE_ACTION,	NULL },
   { "Yes",	menu_null,	QUIT_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	recording_bindings[] = {	/* recording menu */
   { "Record",	recording_record,	NONE_ACTION,	NULL },
   { "View",	recording_view,		VIEW_ACTION,	NULL },
   { "Blink",	recording_blink,	BLINK_ACTION,	NULL },
   { "Loop",	recording_loop,		BLINK_ACTION,	NULL },
   { "Split",	recording_split,	SPLIT_ACTION,	NULL },
   { "Remove",	recording_remove,	NONE_ACTION,	NULL },
   { "Return",	menu_previous,		NONE_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	blot_bindings[] = {		/* shape menu */
   { "Ellipse",		region_blot_e,		BLOT_ACTION,	NULL },
   { "Rectangle",	region_blot_r,		BLOT_ACTION,	NULL },
   { "Return",		region_blot_reset,	NONE_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	region_bindings[] = {	/* region menu */
   { "Define",		region_define,		DRAW_ACTION,	NULL },
   { "Undefine",	region_undefine,	DRAW_ACTION,	NULL },
   { "On",		region_on,		NONE_ACTION,	NULL },
   { "Clear",		region_clear,		NONE_ACTION,	NULL },
   { "Ready",		region_ready,		NONE_ACTION,	NULL },
   { "Blots",		region_blot_menu,	BLOT_ACTION,	blot_bindings },
   { "Return",		menu_previous,		NONE_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	extra_bindings[] = {	/* extra slice menu */
   { "Coords",		slice_coords,	SLICE_ACTION,	NULL },
   { "Profile",		slice_profile,	SLICE_ACTION,	NULL },
   { "Return",		menu_previous,	SLICE_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	slice_bindings[] = {	/* slice menu */
   { "X Slice",		slice_X,	SLICE_ACTION,	NULL },
   { "Y Slice",		slice_Y,	SLICE_ACTION,	NULL },
   { "Zoom X",		slice_X_zoom,	SLICE_ACTION,	NULL },
   { "Zoom Y",		slice_Y_zoom,	SLICE_ACTION,	NULL },
   { "Dezoom X",	slice_X_dezoom,	SLICE_ACTION,	NULL },
   { "Dezoom Y",	slice_Y_dezoom,	SLICE_ACTION,	NULL },
   { "Extra",		menu_next,	SLICE_ACTION,	extra_bindings },
   { "Return",		menu_previous,	NONE_ACTION,	NULL },
   { NULL }
};

static	Menu_bindings	etcetera_bindings[] = {	/* etcetera main menu */
   { "Quit",		menu_next,	NONE_ACTION,	quit_bindings      },
   { "Graphics",	misc_graphics,	NONE_ACTION,	NULL               },
   { "Recording",	menu_next,	NONE_ACTION,	recording_bindings },
   { "Region",		region_next,	NONE_ACTION,	region_bindings    },
   { "Resize",		misc_resize,	NONE_ACTION,	NULL               },
   { "Slice",		menu_next,	SLICE_ACTION,	slice_bindings     },
   { "Return",		menu_previous,	NONE_ACTION,	NULL               },
   { NULL }
};

static	Menu_bindings	cursor_bindings[] = {	/* cursor menu */
   { "Selection",	cursor_select,		CURSOR_ACTION,	NULL	},
   { "Sendevent",	cursor_sendev,		CURSOR_ACTION,	NULL	},
   { "Socket",		cursor_socket,		CURSOR_ACTION,	NULL	},
   { "Append-CR",	cursor_appendcr,	CURSOR_ACTION,	NULL	},
   { "Return",		menu_previous,		CURSOR_ACTION,	NULL	},
   { NULL }
};

static	Menu_bindings	main_bindings[] = {	/* main MENU */
   { "Help",		help_help,	NONE_ACTION,	NULL              },
   { "Zoom",		zoom_next,	ZOOM_ACTION,	zoom_bindings     },
   { "Color",		menu_next,	COLOR_ACTION,	color_bindings    },
   { "Scale",		menu_next,	COLOR_ACTION,	scale_bindings    },
   { "Wedge",		menu_next,	WEDGE_ACTION,	wedge_bindings    },
   { "Cursor",		menu_next,	CURSOR_ACTION,	cursor_bindings   },
   { "Etcetera",	menu_next,	NONE_ACTION,	etcetera_bindings },
   { NULL }
};

static	Menu_bindings	*bindings = main_bindings;
static	Menu_struct	 root_menu[MAXMENUS];		/* here is the real thing */

Menu_struct	*menu = root_menu;

int	menu_draw( )
{
   int	n;					/* loop counter */

   for (n = 0; n < MAXMENUS; n++) {
      XClearWindow( winfo.id, winfo.menus[n] );
      if (menu[n].textlen) {
         XDrawString( winfo.id, winfo.menus[n], winfo.gcm,
            menu[n].xpos, menu[n].ypos, menu[n].text,
            menu[n].textlen );
      }
      XDrawRectangle( winfo.id, winfo.menus[n], winfo.gcm, 1, 1,
         winfo.mwidth - 3, winfo.mheight - 3 );
   }
   return( 0 );					/* return to caller */
}

int	menu_enter( int button )
{
   XDrawRectangle( winfo.id, winfo.menus[button], winfo.gcm,
      0, 0, winfo.mwidth - 1, winfo.mheight - 1 );
   return( 0 );					/* return to caller */
}

int	menu_leave( int button )
{
   XDrawRectangle( winfo.id, winfo.menus[button], winfo.gcmreverse,
      0, 0, winfo.mwidth - 1, winfo.mheight - 1 );
   return( 0 );					/* return to caller */
}

int	menu_next( int button )
{
   int	r = menu[button].ret;			/* return value */

   menu = menu[button].next;			/* next menu */
   menu_draw( );				/* show menu */
   return( r );					/* return to caller */
}

int	menu_previous( int button )
{
   int	r = menu[button].ret;			/* return value */

   menu = menu[button].previous;		/* previous menu */
   menu_draw( );				/* show menu */
   return( r );					/* return to caller */
}

int	menu_null( int button )
{
   return( menu[button].ret );			/* return to caller */
}

int	menu_init( void )
{
   static int	depth = 1;			/* depth of recursion */
   static int	level = 0;
   int		ch;				/* character height */
   int 		i;				/* loop counter */
   int		f;
   int		l;
   int		m;				/* loop counter */
   int		n;				/* loop counter */
   int		r = 0;				/* return value */

   ch = winfo.mfont->ascent + winfo.mfont->descent;
   for ( f = 1, n = 1; n < depth; n++ ) f *= MAXMENUS;
   for (n = 0; n < MAXMENUS; n++) {
      menu[n].depth   = depth;
      menu[n].level   = level + n * f;
      menu[n].textlen = 0;
      menu[n].next    = NULL;
      if (bindings[n].menu_text == NULL) break;
      for (i = 0; i < MAXMENUTEXTLEN; i++) {
         menu[n].text[i] = bindings[n].menu_text[i];
         if (bindings[n].menu_text[i] == '\0') break;
      }
      menu[n].f       = bindings[n].menu_function;
      menu[n].ret     = bindings[n].menu_return;
      menu[n].textlen = i;
      menu[n].xpos    = ( winfo.mwidth -
         XTextWidth( winfo.mfont, bindings[n].menu_text, i ) ) / 2;
      menu[n].ypos    = ( winfo.mheight + winfo.mfont->ascent -
         winfo.mfont->descent ) / 2;
      if (bindings[n].menu_next != NULL) {
         Menu_bindings	*old_bindings;		/* save this one */
         Menu_struct	*old_menu;		/* and this one */

         menu[n].next = (Menu_struct *) calloc( sizeof( Menu_struct ),
            MAXMENUS );
         if (menu[n].next == NULL) {
            return( -1 );
         }
         for (m = 0; m < MAXMENUS; m++) {
            menu[n].next[m].previous = menu;
         }
         l = level;
         level = menu[n].level;
         old_bindings = bindings;		/* save current bindings */
         old_menu = menu;			/* save current menu */
         bindings = bindings[n].menu_next;	/* set next bindings */
         menu = menu[n].next;			/* set next menu */
         depth += 1;
         r = menu_init( );			/* do next menu */
         depth -= 1;
         level = l;
         bindings = old_bindings;		/* restore old bindings */
         menu = old_menu;			/* restore old menu */
         if (r) return( r );			/* error, then return */
      }
   }
   if (!r) {
      while (n < MAXMENUS) {
         menu[n].depth    = 0;
         menu[n].level    = 0;
         menu[n].textlen  = 0;
         menu[n].f        = menu_null;
         menu[n].next     = NULL;
         menu[n].previous = NULL;
         menu[n].ret      = 0;
         n += 1;
      }
   }
   return( r );					/* return to caller */
}
#<

#>            misc.c
/* misc.c

*/

#include	"gids.h"			/* GIDS symbols */


extern	int	read( );
extern	int	select( );
extern	int	write( );

void pixel2chars(unsigned long pixel,
                 unsigned char *chararray,
                 int *n, int bytespp, int order)
{
   int cn = *n;

   /* VOG2010: Function added to allow for more than 1 byte per */
   /* pixel as in 24 bit DirectColor.                           */
   if (bytespp==1) {
         chararray[cn++] = pixel;
   } else if (bytespp==4) {
      if (order==LSBFirst) {
            chararray[cn++] = pixel     & 0xFF;
            chararray[cn++] = pixel>>8  & 0xFF;
            chararray[cn++] = pixel>>16 & 0xFF;
            chararray[cn++] = pixel>>24 & 0xFF;
      } else {
            chararray[cn++] = pixel>>24 & 0xFF;
            chararray[cn++] = pixel>>16 & 0xFF;
            chararray[cn++] = pixel>>8  & 0xFF;
            chararray[cn++] = pixel     & 0xFF;
      }
   } else {
      if (order==LSBFirst) {
            chararray[cn++] = pixel     & 0xFF;
            chararray[cn++] = pixel>>8  & 0xFF;
      } else {
            chararray[cn++] = pixel>>8  & 0xFF;
            chararray[cn++] = pixel     & 0xFF;
      }
   }
   *n = cn;
}


void	misc_broken_pipe( int sig )
{
   if (sig == SIGPIPE) {
      signal( sig, misc_broken_pipe );
   }
}


int	misc_max( int x, int y )
{
   return( x > y ? x : y );
}


int	misc_min( int x, int y )
{
   return( x < y ? x : y );
}

int	misc_nint( double d )
{
   int	r;

   if (d > 0) r = d + 0.5; else { r = -d + 0.5; r = -r; }
   return( r );
}

int	misc_error_handler1( Display *display, XErrorEvent *event )
{
   FILE	*efile;
   char	msg[80];

   winfo.e_code = event->error_code;
   winfo.r_code = event->request_code;
   sprintf( msg, "/tmp/gids%d.errors", winfo.pid );
   efile = fopen( msg, "a" );
   if (efile != NULL) {
      XGetErrorText( display, event->error_code, msg, 80 );
      fprintf( efile, "Error_text   = %s\n", msg );
      fprintf( efile, "Request_code = %d\n", (int) event->request_code );
      fprintf( efile, "Error_code   = %d\n", (int) event->error_code );
      fclose( efile );
   }
   return( 0 );
}

int	misc_error_handler2( Display *display )
{
   FILE	*efile;
   char	msg[80];

   sprintf( msg, "/tmp/gids%d.errors", winfo.pid );
   efile = fopen( msg, "a" );
   if (efile != NULL) {
      fprintf( efile, "Fatal error on %s\n", DisplayString( display ) );
      fclose( efile );
   }
   server_close( );
   display_close( DisplayString( display ) );
   exit( EXIT_FAILURE );
   return( 0 );
}

int	misc_cmd_swap( int swap, Command_struct *cmd )
{
   if (swap) {
      misc_sl( swap, &cmd->cmd, 1 );
      misc_sl( swap, &cmd->code, 1 );
      misc_sl( swap, &cmd->nbytes, 1 );
   }
   return( 0 );
}

int	misc_ss( int swap, short *si, int ns )
{
   if (	swap ) {
      int	l;
      int	m;
      int	n;
      union {
         short	s;
         char	b[sizeof(short)];
      } i, o;

      for (n = 0; n < ns; n++) {
         i.s = si[n];
         for (l = sizeof( short ), m = 0; m < sizeof( short ); o.b[--l] = i.b[m++] );
         si[n] = o.s;
      }
   }
   return( 0 );
}

int	misc_sl( int swap, int *li, int nl )
{
   if (	swap ) {
      int	l;
      int	m;
      int	n;
      union {
         int	l;
         char	b[sizeof(int)];
      } i, o;

      for (n = 0; n < nl; n++) {
         i.l = li[n];
         for (l = sizeof( int ), m = 0; m < sizeof( int ); o.b[--l] = i.b[m++]);
         li[n] = o.l;
      }
   }
   return( 0 );
}

static	int	read_wait( int fd )
{
   fd_set	read_fds;
   int		nfound;
   int		r = GDIE_SUCCESS;

   do {
      FD_ZERO( &read_fds );
      FD_SET( fd, &read_fds );
      nfound = select( fd + 1, (void *) &read_fds, NULL, NULL, NULL );
      if (nfound == -1 && errno != EINTR) {
         r = GDIE_S_RECEIVE;
      }
   } while (nfound <= 0 && r == GDIE_SUCCESS);
   return( r );
}

static	int	write_wait( int fd )
{
   fd_set	write_fds;
   int		nfound;
   int		r = GDIE_SUCCESS;

   do {
      FD_ZERO( &write_fds );
      FD_SET( fd, &write_fds );
      nfound = select( fd + 1, NULL, (void *) &write_fds, NULL, NULL );
      if (nfound == -1 && errno != EINTR) {
         r = GDIE_S_SEND;
      }
   } while (nfound <= 0 && r == GDIE_SUCCESS);
   return( r );
}

int	misc_send( int socket, void *data, int ndata )
{
   char	*p = (char *) data;			/* make character pointer */
   int	nd = 0;					/* current byte count */
   int	nl = ndata;				/* number of bytes left  */
   int	nt = 0;					/* number of bytes done */
   int	r = GDIE_SUCCESS;			/* return value */

   while (nl && r == GDIE_SUCCESS) {
      while ((nd = write( socket, &p[nt], nl )) == -1 && errno == EINTR);
      if (nd > 0) {
         nl -= nd;
         nt += nd;
#if	defined(EWOULDBLOCK)
      } else if (nd == -1 && errno == EWOULDBLOCK) {
         r = write_wait( socket );
#endif
      } else {
         r = GDIE_S_SEND;
      }
   }
   return( r );					/* return to caller */
}

int	misc_receive( int socket, void *data, int ndata )
{
   char	*p = (char *) data;			/* make character pointer */
   int	nd = 0;					/* current byte count */
   int	nl = ndata;				/* number of bytes left  */
   int	nt = 0;					/* number of bytes done */
   int	r = GDIE_SUCCESS;			/* return value */

   while (nl && r == GDIE_SUCCESS) {
      while ((nd = read( socket, &p[nt], nl )) == -1 && errno == EINTR);
      if (nd > 0) {
         nl -= nd;
         nt += nd;
#if	defined(EWOULDBLOCK)
      } else if (nd == -1 && errno == EWOULDBLOCK) {
         r = read_wait( socket );
#endif
      } else {
         r = GDIE_S_RECEIVE;
      }
   }
   return( r );					/* return to caller */
}

int	misc_flush( int socket, int nflush )
{
   char	c;					/* flush buffer */
   int	n;					/* loop counter */
   int	nd;					/* byte count */
   int	r = GDIE_SUCCESS;			/* return value */

   for (n = 0; r == GDIE_SUCCESS && n < nflush; n++) {
      while (( nd = read( socket, &c, 1 )) == -1 && errno == EINTR);
      if (nd == -1) {
#if	defined(EWOULDBLOCK)
         if (errno == EWOULDBLOCK) {
            r = read_wait( socket );
         } else {
            r = GDIE_S_FLUSH;
         }
#else
         f = GDIE_S_FLUSH;
#endif
      }
   }
   return( r );					/* return to caller */
}

int	misc_settimer( int xc )
{
   float	delay;

   if (xc <= 0) {
      xc = 1;
   } else if ( xc > ( winfo.dwidth - 1 ) ) {
      xc = winfo.dwidth - 1;
   }
   delay = 2.0 * (float) xc / (float) winfo.dwidth;
   return( server_timer_delay( delay * delay ) );
}

int	misc_recordings( void )
{
   data_text( );
   sprintf( winfo.text[2], "REC=%4d,%4d,%4d", winfo.mrecord, winfo.nrecord,
      winfo.currec );
   misc_info( 0 );
   return( 0 );
}

int	misc_mask( )
{
   sprintf( winfo.text[3], "MASK=%4d  ON=%4d", user.mask1, user.mask2 );
   misc_info( 0 );
   return( 0 );
}

int	misc_setgridtext( void )
{
   int	x, y;

   if (user.idata == NULL) return( 0 );
   if (user.xgt != NULL) {
      if (winfo.record[0].xgt == NULL) {
         winfo.record[0].xgt = calloc( sizeof( Gtext_struct ), winfo.dwidth );
      }
   } else {
      if (winfo.record[0].xgt != NULL) free( winfo.record[0].xgt );
      winfo.record[0].xgt = NULL;
   }
   if (winfo.record[0].xgt != NULL) {
      for ( x = 0; x < winfo.dwidth; x++ ) {
         int	xu = winfo.record[0].x_grid[x];

         if (xu < winfo.record[0].x_min || xu > winfo.record[0].x_max) {
            winfo.record[0].xgt[x].text[0] = 0;
         } else {
            strcpy( winfo.record[0].xgt[x].text, user.xgt[xu-user.x_min].text );
         }
      }
   }
   if (user.ygt != NULL) {
      if (winfo.record[0].ygt == NULL) {
         winfo.record[0].ygt = calloc( sizeof( Gtext_struct ), winfo.dheight );
      }
   } else {
      if (winfo.record[0].ygt != NULL) free( winfo.record[0].ygt );
      winfo.record[0].ygt = NULL;
   }
   if (winfo.record[0].ygt != NULL) {
      for ( y = 0; y < winfo.dheight; y++ ) {
         int	yu = winfo.record[0].y_grid[y];

         if (yu < winfo.record[0].y_min || yu > winfo.record[0].y_max) {
            winfo.record[0].ygt[y].text[0] = 0;
         } else {
            strcpy( winfo.record[0].ygt[y].text, user.ygt[yu-user.y_min].text );
         }
      }
   }
   return( 0 );
}

int	misc_show( void )
{
   int	m;
   int	x;
   int	y;

   DATA_CHECK( 0 );
   if (winfo.autoraise) XRaiseWindow( winfo.id, winfo.top );
   if (winfo.currec != 0) {
      winfo.currec = 0;
      misc_recordings( );
   }
   /* VOG2010: This is a crucial part of the code. The client data */
   /* stored in an unsigned character array 'user.idata' is copied */
   /* to the array with the display data 'winfo.wdata'. So at this */
   /* point we need to take care of pixels with more than one byte */
   /* per pixel. */
   for (m = 0, y = 0; y < winfo.dheight; y++) {
      int	yu = winfo.record[0].y_grid[y];

      if (yu < user.y_min || yu > user.y_max) {
         for (x = 0; x < winfo.dwidth; x++) {
            /* winfo.idata[m++] = winfo.black; */
            pixel2chars(winfo.black, winfo.idata, &m, winfo.bytespp, winfo.byte_order);
         }
      } else {
         int	offy = (yu - user.y_min) * user.x_size;

         for (x = 0; x < winfo.dwidth; x++) {
            int	xu = winfo.record[0].x_grid[x];

            if (xu < user.x_min || xu > user.x_max) {
               /* winfo.idata[m++] = winfo.black; */
               pixel2chars(winfo.black, winfo.idata, &m, winfo.bytespp, winfo.byte_order);
            } else {
               int		mask;
               int		offset = offy + xu - user.x_min;
               unsigned char    pixelindx;
               unsigned long    pixel;

               mask = user.imask[offset] & user.mask2;
               if (mask) {
                  pixel = winfo.gcells[mask];
               } else {
                  pixelindx = user.idata[offset];
                  pixel = winfo.table[pixelindx].pixel;
               }
               /* ORIG: winfo.idata[m++] = pixel; */
               pixel2chars(pixel, winfo.idata, &m, winfo.bytespp, winfo.byte_order);
            }
         }
      }
   }
   misc_setgridtext( );
   XPutImage( winfo.id, winfo.record[0].pixmap, winfo.gcm, winfo.iimage,
      0, 0, 0, 0, winfo.dwidth, winfo.dheight );
   XCopyArea( winfo.id, winfo.record[0].pixmap, winfo.display, winfo.gcm,
      0, 0, winfo.dwidth, winfo.dheight, 0, 0 );
   region_redraw( );
   XFlush( winfo.id );
   return( 0 );
}


/*
 * misc_resize.
 */

int	misc_resize( int button )
{
   int	r;
   int	size[2];

   r = input_read_int( &size, 2 );
   if ( r == 2 ) {
      if (winfo.clients) {
         XBell( winfo.id, 100 );
      } else {
         display_resize( size[0], size[1] );
      }
   } else {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );
}

int	misc_graphics( int button )
{
   int	r = 0;
   int	size[2];

   if (!(winfo.windows & WINDOW_PGPLOT)) {
      r = input_read_int( size, 2 );
   }
   if ( r == 2 ) {
      display_pgplot( size[0], size[1] );
   } else if ( r == 0 ) {
      display_pgplot( 512, 512 );
   } else {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );
}

int	misc_readval( int window_id, int x, int y )
{
   static XImage	*myimage = NULL;
   Window		w;
   XImage		*subimage;
   int			r;
   int			rec = 0;

   switch( window_id ) {
      case 0: {
         w = winfo.display;
         rec = winfo.currec;
         break;
      }
      case 1: {
         w = winfo.xslice;
         rec = winfo.xslices[y];
         break;
      }
      case 2: {
         w = winfo.yslice;
         rec = winfo.yslices[x];
         break;
      }
      default: {
         return( winfo.blank );
         break;
      }
   }
   if (rec == 0) {
      int	u_x = 0;
      int	u_y = 0;

      switch( window_id ) {
         case 0: {
            u_x = winfo.record[0].x_grid[x];
            u_y = winfo.record[0].y_grid[y];
            break;
         }
         case 1: {
            u_x = winfo.record[0].x_grid[x];
            u_y = winfo.record[0].y_grid[winfo.last_y];
            break;
         }
         case 2: {
            u_x = winfo.record[0].x_grid[winfo.last_x];
            u_y = winfo.record[0].y_grid[y];
            break;
         }
         default: {
            break;
         }
      }
      r = user.idata[(u_y-user.y_min)*user.x_size+u_x-user.x_min];
   } else {
      if (myimage == NULL) {
         /* orig: static char	mydata[1];*/
         static unsigned char 	mydata[4];
         myimage = XCreateImage( winfo.id, winfo.visual, winfo.depth,
                    ZPixmap, 0, (char *)mydata, 1, 1, winfo.pad, 0 );
            /*ZPixmap, 0, mydata, 1, 1, CHAR_BIT, 0 );*/
      }
      subimage = XGetSubImage( winfo.id, w,
         x, y,  1, 1, 255, ZPixmap, myimage, 0, 0 );
      r = XGetPixel( myimage, 0, 0 );
   }
   return( r );
}

int	misc_info( int	force )
{
   static char	misc_text[MAXINFO][MAXIDTEXTLEN+1];
   int		n, nc;

   for ( n = 0; n < MAXINFO; n++ ) {
      if (force || strcmp( misc_text[n], winfo.text[n] )) {
         XClearWindow( winfo.id, winfo.info[n] );
         nc = strlen( winfo.text[n] );
         strcpy( misc_text[n], winfo.text[n] );
         if (nc) {
            XDrawString( winfo.id, winfo.info[n], winfo.gci, winfo.i_xpos,
               winfo.i_ypos, misc_text[n], nc );
         }
      }
   }
   XFlush( winfo.id );
   return( 0 );
}

int	misc_message( XEvent R )
{
   if (R.xclient.format == 8 && R.xclient.message_type == XA_STRING) {
      XEvent	S;

      S.xclient.type         = ClientMessage;
      S.xclient.send_event   = True;
      S.xclient.window       = winfo.top;
      S.xclient.message_type = XA_STRING;
      S.xclient.format       = 8;
      if (!strcmp( R.xclient.data.b, "COLORMAP" )) {
         sprintf( S.xclient.data.b, "CMAP=%14.14d", (long) winfo.colormap );
      } else if (!strcmp( R.xclient.data.b, "COLORMIN" )) {
         sprintf( S.xclient.data.b, "CMIN=%14.14d", (long) winfo.mincolor + 1 );
      } else if (!strcmp( R.xclient.data.b, "COLORMAX" )) {
         sprintf( S.xclient.data.b, "CMAX=%14.14d", (long) winfo.maxcolor );
      } else if (!strcmp( R.xclient.data.b, "BLANK" )) {
         sprintf( S.xclient.data.b, "BVAL=%14.14d", (long) winfo.mincolor );
      } else if (!strcmp( R.xclient.data.b, "HOSTADDRESS" )) {
         sprintf( S.xclient.data.b, "NET=%15.15s", winfo.netaddr );
      } else if (!strcmp( R.xclient.data.b, "HOSTNAME" )) {
         sprintf( S.xclient.data.b, "HOST=%14.14s", winfo.hostname );
      } else if (!strcmp( R.xclient.data.b, "PLOTCMIN" )) {
         int	pmin = winfo.maxcolor + MAXGCOLORS + 1;

         sprintf( S.xclient.data.b, "PMIN=%14.14d", pmin );
      } else if (!strcmp( R.xclient.data.b, "PLOTCMAX" )) {
         int	pmax = winfo.maxcolor + MAXGCOLORS + MAXPCOLORS;

         sprintf( S.xclient.data.b, "PMIN=%14.14d", pmax);
      } else {
         strcpy( S.xclient.data.b, "UNKNOWN REQUEST" );
      }
      XSendEvent( winfo.id, R.xclient.window, False, 0, &S );
      XFlush( winfo.id );
   }
   return( 0 );
}
#<

#>            recording.c
/* recording.c

*/

#include	"gids.h"

static	int	blink_action = 0;
static	int	loop_direction = 1;
static	int	loop_record_id = 0;
static	int	blink_records[2];
static	int	blink_record_id = -1;
static	int	split_records[2];
static	int	split_record_id = -1;

extern void pixel2chars( );

int	recording_button( int button, int x )
{
   if ( blink_action ) {
      misc_settimer( x );
   } else {
      switch( button ) {
         case Button1: loop_direction = -1; break;
         case Button3: loop_direction = 1; break;
         default: misc_settimer( x ); break;
      }
   }
   return( 0 );
}

int	recording_do_record( int crec, int rec )
{
   int		r = GDIE_SUCCESS;

   if (!winfo.record[crec].mask) return( GDIE_RECORD_ERROR );
   if (winfo.record[rec].mask) recording_delete( rec );
   winfo.e_code = Success;
   winfo.record[rec].pixmap = XCreatePixmap( winfo.id, winfo.display,
      winfo.dwidth, winfo.dheight, winfo.depth );
   XSync( winfo.id, False );
   if ( winfo.e_code == BadAlloc && winfo.r_code == X_CreatePixmap ) {
      return( GDIE_RECORD_ERROR );
   }
   if (crec || !user.mask2) {
      XCopyArea( winfo.id, winfo.record[crec].pixmap,
         winfo.record[rec].pixmap, winfo.gcm, 0, 0, winfo.dwidth,
         winfo.dheight, 0, 0 );
   } else {
      XImage		*myimage;
      int		m, x, y;
      unsigned char	*mydata;

      /* VOG2010: Adapt code to receive pixels with more than one */
      /* byte per pixel.                                          */
      mydata = calloc( sizeof( unsigned char),
                       winfo.dwidth * winfo.dheight * (winfo.pad/8) );
      for ( m = 0, y = 0; y < winfo.dheight; y++ ) {
         int	yu = winfo.record[0].y_grid[y];

         if (yu < user.y_min || yu > user.y_max) {
            for (x = 0; x < winfo.dwidth; x++) {
               /* ORIG: mydata[m++] = winfo.blank;*/
               pixel2chars(winfo.blank, mydata, &m, winfo.bytespp, winfo.byte_order);
            }
         } else {
            int    offy = (yu - user.y_min) * user.x_size;

            for (x = 0; x < winfo.dwidth; x++) {
               int xu = winfo.record[0].x_grid[x];

               if (xu < user.x_min || xu > user.x_max) {
                  /* ORIG: mydata[m++] = winfo.blank; */
                  pixel2chars(winfo.blank, mydata, &m, winfo.bytespp, winfo.byte_order);
               } else {
                  int	offset = offy + xu - user.x_min;

                  /* ORIG: mydata[m++] = user.idata[offset];*/
                  pixel2chars(user.idata[offset], mydata, &m, winfo.bytespp, winfo.byte_order);
               }
            }
         }
      }
      /* VOG2010: Changed padding parameter from CHAR_BIT to winfo.pad */
      myimage = XCreateImage( winfo.id, winfo.visual, winfo.depth,
         ZPixmap, 0, (char *) mydata, winfo.dwidth, winfo.dheight,
         winfo.pad, 0 );
      XPutImage( winfo.id, winfo.record[rec].pixmap, winfo.gcm,
         myimage, 0, 0, 0, 0, winfo.dwidth, winfo.dheight );
      XDestroyImage( myimage );
   }
   if ( r == GDIE_SUCCESS ) {
      int	n;

      strcpy( winfo.record[rec].text1, winfo.record[crec].text1 );
      strcpy( winfo.record[rec].text2, winfo.record[crec].text2 );
      winfo.record[rec].bscale = winfo.record[crec].bscale;
      winfo.record[rec].b_zero  = winfo.record[crec].b_zero;
      winfo.record[rec].x_grid = calloc( sizeof( int ), winfo.dwidth );
      for ( n = 0; n < winfo.dwidth; n++ ) {
         winfo.record[rec].x_grid[n] = winfo.record[crec].x_grid[n];
      }
      winfo.record[rec].y_grid = calloc( sizeof( int ), winfo.dheight );
      for ( n = 0; n < winfo.dheight; n++ ) {
         winfo.record[rec].y_grid[n] = winfo.record[crec].y_grid[n];
      }
      winfo.record[rec].x_max = winfo.record[crec].x_max;
      winfo.record[rec].x_min = winfo.record[crec].x_min;
      winfo.record[rec].y_max = winfo.record[crec].y_max;
      winfo.record[rec].y_min = winfo.record[crec].y_min;
      if (winfo.record[crec].xgt != NULL) {
         winfo.record[rec].xgt =  calloc( sizeof( Gtext_struct ), winfo.dwidth );
      }
      if (winfo.record[rec].xgt != NULL) {
         for ( n = 0; n < winfo.dwidth; n++ ) {
            strcpy( winfo.record[rec].xgt[n].text,
               winfo.record[crec].xgt[n].text );
         }
      }
      if (winfo.record[crec].ygt != NULL) {
         winfo.record[rec].ygt =  calloc( sizeof( Gtext_struct ), winfo.dheight );
      }
      if (winfo.record[rec].ygt != NULL) {
         for ( n = 0; n < winfo.dheight; n++ ) {
            strcpy( winfo.record[rec].ygt[n].text,
               winfo.record[crec].ygt[n].text );
         }
      }
      winfo.nrecord += 1;
      winfo.record[rec].mask = 1;
      misc_recordings( );
   }
   return( r );
}

int	recording_show( int rec )
{
   int	r = -1;

   DATA_CHECK( 0 );
   if (winfo.currec == rec) return( 0 );
   if ( rec > winfo.mrecord ) rec = winfo.mrecord;
   if ( rec < 0 ) rec = 0;
   winfo.currec = rec;
   misc_recordings( );
   if (rec >= 0 && rec <= winfo.mrecord && winfo.record[rec].mask) {
      XCopyArea( winfo.id, winfo.record[rec].pixmap, winfo.display,
         winfo.gcm, 0, 0, winfo.dwidth, winfo.dheight, 0, 0 );
      r = 0;
   } else {
      XClearWindow( winfo.id, winfo.display );
   }
   wedge_draw( 0 );
   XFlush( winfo.id );
   return( r );
}

int	recording_record( int button )
{
   int	r;
   int	rec;

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( &rec, 1 );
   if (r == 1) {
      if (rec < 1 || rec > winfo.mrecord) {
         XBell( winfo.id, 100 );
      } else if (!winfo.record[winfo.currec].mask) {
         XBell( winfo.id, 100 );
      } else {
         if (recording_do_record( winfo.currec, rec )) XBell( winfo.id, 100 );
      }
   } else {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );			/* return to caller */
}

int	recording_view( int button )
{
   int	r;
   int	rec;

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( &rec, 1 );
   if (r == 0) { rec = winfo.currec; r = 1; }		/* default */
   if (r == 1) {
      r = recording_show( rec );
   }
   if (r < 0) {
      XBell( winfo.id, 100 );
      return( NONE_ACTION );
   } else {
      return( menu[button].ret );
   }
}

int	recording_do_view( int button )
{
   int	rec = winfo.currec;

   DATA_CHECK( NONE_ACTION );
   if (!winfo.mrecord) return( 0 );		/* quick exit */
   switch( button ) {
      case Button1: {				/* view previous */
         rec -= 1;				/* previous recording */
         if (rec < 0) rec = winfo.mrecord;
         while (rec > -1 && !winfo.record[rec].mask) rec--;
         if (rec < 0) rec = 0;
         if (rec == winfo.currec) break;
         recording_show( rec );
         break;
      }
      case Button3: {				/* view next */
         rec += 1;				/* next recording */
         while (rec <= winfo.mrecord && !winfo.record[rec].mask) rec++;
         if (rec > winfo.mrecord) rec = 0;
         if (rec == winfo.currec) break;
         recording_show( rec );
         break;
      }
      default: {
         break;
      }
   }
   return( 0 );					/* return to caller */
}

int	recording_blink( int button )
{
   int	r;
   int	rec[2];

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( &rec, 2 );
   if (r == 0 && ( blink_record_id != -1 )) {
      rec[0] = blink_records[0];		/* default */
      rec[1] = blink_records[1];
      r = 2;
   }
   if (r == 1) {
      rec[1] = rec[0]; rec[0] = 0;
      r = 2;
   }
   if (r == 2) {
      if (rec[0] < 0 || rec[0] > winfo.mrecord) {
         r = -1;
      } else if (rec[1] < 0 || rec[1] > winfo.mrecord) {
         r = -1;
      } else if (!winfo.record[rec[0]].mask) {
         r = -1;
      } else if (!winfo.record[rec[1]].mask) {
         r = -1;
      } else {
         blink_record_id = 0;
         blink_records[0] = rec[0];
         blink_records[1] = rec[1];
      }
   }
   if (r != 2) {
      XBell( winfo.id, 100 );
      return( NONE_ACTION );
   } else {
      blink_action = 1;
      server_timer_function( recording_do_blink );
      server_timer_delay( 1.0 );
      return( menu[button].ret );		/* return to caller */
   }
}

int	recording_do_blink( void )
{
   int		rec = blink_records[blink_record_id];

   recording_show( rec );
   blink_record_id = ( (++blink_record_id) % 2 );
   return( 0 );
}

int	recording_loop( int button )
{
   int	usequence[1024];
   int	r;

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( usequence, MAXSEQUENCE );
   if (r < 0) {
      XBell( winfo.id, 100 );
   } else if (r > 0) {
      int	m, n;

      winfo.nsequence = 0;
      for (m = 0, n = 0; n < r; n++) {
         int	rec = usequence[n];

         if (rec < 1 || rec > winfo.mrecord || !winfo.record[rec].mask) {
            XBell( winfo.id, 100 );
         } else {
            winfo.sequence[m++] = rec;
         }
      }
      winfo.nsequence = m;
   }
   if (winfo.nsequence) {
      loop_record_id = 0;
      blink_action = 0;
      loop_direction = 1;
      server_timer_function( recording_do_loop );
      server_timer_delay( 1.0 );
      return( menu[button].ret );			/* return to caller */
   } else {
      XBell( winfo.id, 100 );
      return( NONE_ACTION );
   }
}

int	recording_do_loop( void )
{
   int		rec;

   rec = winfo.sequence[loop_record_id];
   loop_record_id += loop_direction;
   while ( loop_record_id < 0 ) loop_record_id += winfo.nsequence;
   loop_record_id %= winfo.nsequence;
   recording_show( rec );
   return( 0 );
}

int	recording_split( int button )
{
   int	r;
   int	rec[2];

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( &rec, 2 );
   if (r == 0 && ( split_record_id != -1)) {
      rec[0] = split_records[0];		/* default */
      rec[1] = split_records[1];
      r = 2;
   }
   if (r == 1) {
      rec[1] = rec[0]; rec[0] = 0;
      r = 2;
   }
   if (r == 2) {
      if (rec[0] < 0 || rec[0] > winfo.mrecord) {
         r = -1;
      } else if (rec[1] < 0 || rec[1] > winfo.mrecord) {
         r = -1;
      } else if (!winfo.record[rec[0]].mask) {
         r = -1;
      } else if (!winfo.record[rec[1]].mask) {
         r = -1;
      } else {
         split_record_id = 0;
         split_records[0] = rec[0];
         split_records[1] = rec[1];

      }
   }
   if (r != 2) {
      XBell( winfo.id, 100 );
      return( NONE_ACTION );
   } else {
      recording_show( rec[0] );
      return( menu[button].ret );		/* return to caller */
   }
}

int	recording_do_split( int xc, int yc, int button )
{
   int	rec1 = split_records[0];
   int	rec2 = split_records[1];

   if (xc < 0) xc = 0;
   if (yc < 0) yc = 0;
   if (xc >= winfo.dwidth) xc = winfo.dwidth - 1;
   if (yc >= winfo.dheight) yc = winfo.dheight - 1;
   switch( button ) {				/* which button */
      case Button1: {				/* split in x */
         XCopyArea( winfo.id, winfo.record[rec1].pixmap, winfo.display,
            winfo.gcm, 0, 0, xc + 1, winfo.dheight, 0, 0 );
         XCopyArea( winfo.id, winfo.record[rec2].pixmap, winfo.display,
            winfo.gcm, xc + 1, 0, winfo.dwidth - xc -1, winfo.dheight,
            xc + 1, 0 );
         break;
      }
      case Button2: {				/* split in y */
         XCopyArea( winfo.id, winfo.record[rec2].pixmap, winfo.display,
            winfo.gcm, 0, 0, winfo.dwidth, yc, 0, 0 );
         XCopyArea( winfo.id, winfo.record[rec1].pixmap, winfo.display,
            winfo.gcm, 0, yc, winfo.dwidth, winfo.dheight - yc, 0, yc );
         break;
      }
      case Button3: {				/* split in x and y */
         XCopyArea( winfo.id, winfo.record[rec1].pixmap, winfo.display,
            winfo.gcm, 0, 0, xc + 1, winfo.dheight, 0, 0 );
         XCopyArea( winfo.id, winfo.record[rec1].pixmap, winfo.display,
            winfo.gcm, xc + 1, yc + 1, winfo.dwidth - xc - 1,
            winfo.dheight - yc - 1, xc + 1, yc + 1 );
         XCopyArea( winfo.id, winfo.record[rec2].pixmap, winfo.display,
            winfo.gcm, xc + 1, 0, winfo.dwidth - xc - 1, yc, xc + 1, 0 );
         break;
      }
      default: {
         break;
      }
   }
   XFlush( winfo.id );
   return( 0 );					/* return to caller */
}


int	recording_remove( int button )
{
   int	r;
   int	recs[MAXRECORD];

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( recs, MAXRECORD );
   if (r > 0) {
      int	i;

      for ( i = 0; i < r; i++ ) {
         if (recs[i] < 1 || recs[i] > winfo.mrecord) {
            XBell( winfo.id, 100 );
         } else {
            if (recording_delete( recs[i] )) XBell( winfo.id, 100 );
         }
      }
   } else {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );			/* return to caller */
}

int	recording_clear( void )
{
   if (winfo.Saved) {
      winfo.Saved = 0;
      XFreePixmap( winfo.id, winfo.Save );
   }
   return( 0 );
}

int	recording_restore( void )
{
   if (winfo.Saved) {
      XCopyArea( winfo.id, winfo.Save, winfo.display, winfo.gcm, 0, 0,
         winfo.dwidth, winfo.dheight, 0, 0 );
      XFlush( winfo.id );
      return( GDIE_SUCCESS );
   } else {
      return( GDIE_RECORD_NOSAVE );
   }
}

int	recording_save( void )
{
   if (!winfo.Saved) {
      winfo.Save = XCreatePixmap( winfo.id, winfo.display,
         winfo.dwidth, winfo.dheight, winfo.depth );
      XSync( winfo.id, False );
      if ( winfo.e_code == BadAlloc && winfo.r_code == X_CreatePixmap ) {
         return( GDIE_RECORD_ERROR );
      } else {
         winfo.Saved = 1;
      }
   }
   XCopyArea( winfo.id, winfo.display, winfo.Save, winfo.gcm, 0, 0,
      winfo.dwidth, winfo.dheight, 0, 0 );
   return( GDIE_SUCCESS );
}

int	recording_delete( int rec )
{
   int	r = 0;

   if (winfo.record[rec].mask) {
      XFreePixmap( winfo.id, winfo.record[rec].pixmap );
      winfo.nrecord -= 1;
      winfo.record[rec].mask = 0;
      winfo.record[rec].text1[0] = 0;
      winfo.record[rec].text2[0] = 0;
      free( winfo.record[rec].x_grid );
      free( winfo.record[rec].y_grid );
      if (winfo.record[rec].xgt != NULL) {
         free( winfo.record[rec].xgt );
         winfo.record[rec].xgt = NULL;
      }
      if (winfo.record[rec].ygt != NULL) {
         free( winfo.record[rec].ygt );
         winfo.record[rec].ygt = NULL;
      }
      misc_recordings( );
   } else {
      r = 1;
   }
   return( r );
}
#<

#>            region.c
/* region.c

*/

#include	"gids.h"

#define	MAXPOINTS	1024

static	int	recolor_cursor( void );
static	int	define = 1;
static	int	npoints = 0;
static	int	xpoints[MAXPOINTS+1];
static	int	ypoints[MAXPOINTS+1];

extern void pixel2chars( );

/*
 * Used to draw a horizontal line.
 *
 * Inputs:
 *
 * x1        - x (horizontal) coordinate of start of line.
 * x2        - x (horizontal) coordinate of end of line.
 * y         - y (vertical)   coordinate of line
 * code      - action code: 0 undraw, do not save.
 *                          1 draw, do not save.
 *                          2 undraw, do save.
 *                          3 draw, do save.
 *
 */

static	int	drawhorizontalline( int x1, int x2, int y, int code )
{
   int	draw;
   int	mask;
   int	offset;
   int	save;
   int	x;
   int	xe;
   int	xs;

   if (y < user.y_min || y > user.y_max) return( 0 );
   if (x1 > user.x_max) return( 0 );
   if (x2 < user.x_min) return( 0 );
   if (x1 < user.x_min) xs = user.x_min; else xs = x1;
   if (x2 > user.x_max) xe = user.x_max; else xe = x2;
   draw = (code & 1);
   save = (code & 2);
   offset = ( y - user.y_min ) * user.x_size - user.x_min;
   if (save) {
      if (draw) {
         mask = user.mask1;
         for (x = xs; x <= xe; x++) {
            user.imask[offset+x] |= mask;
         }
      } else {
         mask = MAXGCOLORS - 1 - user.mask1;
         for (x = xs; x <= xe; x++) {
            user.imask[offset+x] &= mask;
         }
      }
   }
   if (user.yregion[y-user.y_min].s != -1) {
      int	x1, x2;
      int	xx;
      int	xl = 0;
      int	yl = user.yregion[y-user.y_min].l;
      int	yp = user.yregion[y-user.y_min].s;

      x1 = winfo.dwidth - 1;
      x2 = 0;
      for (xx = xs; xx <= xe; xx++) {
         int		l;
         int		m;
         int		x = user.xregion[xx-user.x_min].s;
         unsigned int	pixel;

         if (x != -1) {
            xl = user.xregion[xx-user.x_min].l;
            if ( x < x1 ) x1 = x;
            if ( x > x2 ) x2 = x;
            if (draw) {
               mask = ( user.imask[offset+winfo.record[0].x_grid[x]] |
                  user.mask1 );
            } else {
               mask = ( user.imask[offset+winfo.record[0].x_grid[x]] &
                  ( MAXGCOLORS - 1 - user.mask1 ) );
               if (!save) {
                  mask |= ( user.imask[offset+winfo.record[0].x_grid[x]] &
                     user.mask1 );
               }
            }
            mask &= user.mask2;
            if (mask) {
               pixel = winfo.gcells[mask];
            } else {
               pixel = user.idata[offset+winfo.record[0].x_grid[x]];
            }
            for (l = 0; l < xl; l++) {
               for (m = 0; m < yl; m++) {
                  /* VOG2010: ORIG: winfo.idata[winfo.dwidth*(yp+m)+x+l] = pixel; */
                  /* Also here we have to take into account that the depth can    */
                  /* vary. The original index therefore is multiplied with pad/8. */
                  /* Note that the data in user.idata are just plain bytes and    */
                  /* correction there is not necessary, only in winfo.idata.      */
                  int p = (winfo.dwidth*(yp+m)+x+l) * (winfo.pad/8);
                  pixel2chars(pixel, winfo.idata, &p, winfo.bytespp, winfo.byte_order);
               }
            }
         }
      }
      if ( x1 <= x2 ) {
         XPutImage( winfo.id, winfo.display, winfo.gcm,
            winfo.iimage, x1, yp, x1, yp, x2 - x1 + xl, yl );
         XPutImage( winfo.id, winfo.record[0].pixmap, winfo.gcm,
            winfo.iimage, x1, yp, x1, yp, x2 - x1 + xl, yl );
      }
   }
   return( 0 );
}


/*
 * Finds the rotation angle between the points (x1,y1) and (x2,y2)
 * relative to the central pivot point (x0,y0).
 */

static	double	angle( int x0, int y0, int x1, int y1, int x2, int y2 )
{
   double	cross;
   double	dot;
   double	r;
   int		xx1 = x1 - x0;
   int		xx2 = x2 - x0;
   int		yy1 = y1 - y0;
   int		yy2 = y2 - y0;

   cross = xx1 * yy2 - xx2 * yy1;
   dot   = xx1 * xx2 + yy1 * yy2;
   if (fabs( dot ) < 0.00001) {
      r = 1.5707863;
   } else {
      r = atan( fabs( cross / dot ) );
      if (dot < 0.0) r = 3.1415927 - r;
   }
   if (cross < 0.0) r = -r;
   return( r );
}


/*
 * Used to determine whether a point is interior to a polygon.
 *
 * Inputs:
 *
 * xverts     - x (horizontal) coordinates of vertexes.
 * yverts     - y (vertical)   coordinates of vertexes.
 * nverts     - number of vertexes.
 * xpos       - x coordinate of test point.
 * ypos       - y coordinate of test point.
 *
 * Returns:
 *
 * insde      - 1 if inside, 0 if outside.
 *
 * The algorithm used is based on Cauchy's integral theorem.
 * Consider the collection of vectors formed by connecting the
 * test point to each of the vertexes. Add up all the rotation
 * angles between the vertexes (sequence dependent). If the sum
 * is zero, the point is exterior.
 *
 */

static	int	insde( int *xverts, int *yverts, int nverts, int xpos, int ypos )
{
   int	r = 0;

   if (nverts > 2) {
      double	angsum = 0.0;
      int	i;

      for (i = 1; i < nverts; i++) {
         angsum += angle( xpos, ypos, xverts[i-1], yverts[i-1],
            xverts[i], yverts[i] );
      }
      if (fabs( angsum ) > 3.1415927) r = 1;
   }
   return( r );
}


/*
 * Used to calculate the intersection of line number "line" with the
 * line segments connecting the vertices.
 *
 * Inputs:
 *
 * xverts     - x (horizontal) coordinates of vertexes.
 * yverts     - y (vertical)   coordinates of vertexes.
 * nverts     - number of vertexes.
 *
 * Outputs:
 *
 * xsects     - x coordinates of intersections (sorted in ascending order).
 *
 * Returns:
 *
 * nxsect     - number of intersections.
 *
 */

static	int	xsect( int *xverts, int *yverts, int nverts, int line, int *xsects )
{
   int	i;
   int	nxsect = 0;
   int	sorted;
   int	x1;
   int	x2;
   int	y1;
   int	y2;

   for (i = 1; i < nverts; i++) {
      double	a;

      y1 = yverts[i-1];
      y2 = yverts[i];
      if (y1 == y2) continue;
      if (line < misc_min( y1, y2 )) continue;
      if (line > misc_max( y1, y2 )) continue;
      x1 = xverts[i-1];
      x2 = xverts[i];
      a = (double) ( x2 - x1 ) / (double) ( y2 - y1 );
      xsects[nxsect++] = misc_nint( a * ( line - y1 ) ) + x1;
   }
   do {
      sorted = 1;
      for (i = 1; i < nxsect; i++) {
         int	itemp;

         if (xsects[i-1] <= xsects[i]) continue;
         itemp       = xsects[i-1];
         xsects[i-1] = xsects[i];
         xsects[i]   = itemp;
         sorted = 0;
      }
   } while (!sorted);
   return( nxsect );				/* return to caller */
}


/*
 * Used to fill in the interior region of a polygon defined by the
 * vertexes in the xverts and yverts arrays.
 *
 * Inputs:
 *
 * xverts     - x (horizontal) coordinates of vertexes.
 * yverts     - y (vertical)   coordinates of vertexes.
 * nverts     - number of vertexes.
 *
 */

static	void	fill( int *xverts, int *yverts, int nverts, int code )
{
   int	enline;
   int	i;
   int	line;
   int	nxsect;
   int	stline;
   int	xsects[MAXPOINTS+1];

   stline = user.y_max;
   enline = user.y_min;
   for (i = 0; i < nverts; i++) {
      enline = misc_max( enline, yverts[i] );
      stline = misc_min( stline, yverts[i] );
   }
   enline = misc_min( user.y_max, enline + 1 );
   stline = misc_max( user.y_min, stline - 1 );
   for (line = stline; line <= enline; line++) {
      nxsect = xsect( xverts, yverts, nverts, line, xsects );
      if (nxsect < 2) continue;
      for (i = 1; i < nxsect; i++) {
         int	ix = ( xsects[i-1] + xsects[i] ) / 2;

         if (!insde( xverts, yverts, nverts, ix, line )) continue;
         drawhorizontalline( xsects[i-1], xsects[i], line, code );
      }
   }
}


/*
 * Used to draw a line between the point (x1,y1) and the point
 * (x2,y2).
 *
 * Inputs:
 *
 * x1, y1      - The starting coordinates.
 * x2, y2      - The ending coordinates.
 * code        - Drawing code.
 *
 */

static	void	dvect( int x1, int y1, int x2, int y2, int code )
{
   double	slope;
   int		newx;
   int		oldx;
   int		ydraw;
   int		yinc;

   if (y1 == y2) {
      drawhorizontalline( misc_min( x1, x2 ), misc_max( x1, x2 ), y1, code );
   } else {
      slope = (double) ( x2 - x1 ) / (double) ( y2 - y1 );
      if (y2 < y1) yinc = -1; else yinc = 1;
      ydraw = y1;
      oldx = x1;
      do {
         newx = misc_nint( slope * (double) ( ydraw - y1 ) + (double) x1 );
         drawhorizontalline( misc_min( oldx, newx ), misc_max( oldx, newx ), ydraw, code );
         oldx = newx;
         ydraw += yinc;
      } while (ydraw != ( y2 + yinc ));
   }
}

int	region_do_define( int xc, int yc, int button )
{
   if (xc < 0) return( -1 );
   if (xc >= (winfo.dwidth-1)) return( -2 );
   if (yc < 0) return( -3 );
   if (yc >= (winfo.dheight-1)) return( -4 );
   switch( button ) {
      case Button1: {
         if (npoints == MAXPOINTS) {
            XBell( winfo.id, 100 );
            break;
         }
         xpoints[npoints] = winfo.record[0].x_grid[xc];
         ypoints[npoints] = winfo.record[0].y_grid[yc];
         if (npoints) {
            int	x1_u;
            int	x2_u;
            int	y1_u;
            int	y2_u;

            x1_u = xpoints[npoints-1];
            y1_u = ypoints[npoints-1];
            x2_u = winfo.record[0].x_grid[xc];
            y2_u = winfo.record[0].y_grid[yc];
            dvect( x1_u, y1_u, x2_u, y2_u, 1 );
         } else {
            int	x_u;
            int	y_u;

            x_u = xpoints[npoints];
            y_u = ypoints[npoints];
            dvect( x_u, y_u, x_u, y_u, 1 );
         }
         npoints += 1;
         break;
      }
      case Button2: {
         if (!npoints) break;
         if (npoints > 1) {
            int	x1_u;
            int	x2_u;
            int	y1_u;
            int	y2_u;

            x1_u = xpoints[npoints-1];
            y1_u = ypoints[npoints-1];
            x2_u = xpoints[npoints-2];
            y2_u = ypoints[npoints-2];
            dvect( x2_u, y2_u, x1_u, y1_u, 0 );
         } else {
            int	x_u;
            int	y_u;

            x_u = xpoints[npoints-1];
            y_u = ypoints[npoints-1];
            dvect( x_u, y_u, x_u, y_u, 0 );
         }
         npoints -= 1;
         break;
      }
      case Button3: {
         int	code;
         int	n;

         if (!npoints) break;
         if (define) code = 3; else code = 2;
         xpoints[npoints] = xpoints[0];
         ypoints[npoints] = ypoints[0];
         npoints += 1;
         for (n = 1; n < npoints; n++) {
            dvect( xpoints[n-1], ypoints[n-1], xpoints[n], ypoints[n], code );
         }
         fill( xpoints, ypoints, npoints, code );
         npoints = 0;
         break;
      }
      default: {
         break;
      }
   }
   return( 0 );
}

int	region_redraw( void )
{
   if (npoints) {
      int	n;
      dvect( xpoints[0], ypoints[0], xpoints[0], ypoints[0], 1 );
      for (n = 1; n < npoints; n++) {
         dvect( xpoints[n-1], ypoints[n-1], xpoints[n], ypoints[n], 1 );
      }
   }
   return( 0 );
}

int	region_define( int button )
{
   int	r;
   int	mask;

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( &mask, 1 );
   if (r == 1) {
      if (mask < 0 || mask > ( MAXGCOLORS - 1 )) {
         XBell( winfo.id, 100 );
      } else {
         user.mask1 = mask;
         misc_mask( );
         recolor_cursor( );
      }
   } else if (r != 0) {
      XBell( winfo.id, 100 );
   }
   define = 1;
   return( menu[button].ret );			/* return to caller */
}

int	region_undefine( int button )
{
   int	r;
   int	mask;

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( &mask, 1 );
   if (r == 1) {
      if (mask < 0 || mask > ( MAXGCOLORS - 1 )) {
         XBell( winfo.id, 100 );
      } else {
         user.mask1 = mask;
         misc_mask( );
         recolor_cursor( );
      }
   } else if (r != 0) {
      XBell( winfo.id, 100 );
   }
   define = 0;
   return( menu[button].ret );			/* return to caller */
}

int	region_clear( int button )
{
   int			m;
   int			n;
   int			r;
   unsigned char	mask = MAXGCOLORS - 1;

   DATA_CHECK( NONE_ACTION );
   r = input_read_int( &m, 1 );
   if (r == 1) {
      if (m < 0 || m > ( MAXGCOLORS - 1 )) {
         XBell( winfo.id, 100 );
      } else {
         user.mask1 = m;
         misc_mask( );
         recolor_cursor( );
      }
   } else if (r != 0) {
      XBell( winfo.id, 100 );
   }
   npoints = 0;					/* reset */
   mask -= user.mask1;
   for (n = 0; n < user.n_data; user.imask[n++] &= mask);
   misc_show( );
   return( menu[button].ret );			/* return to caller */
}

int	region_on( int button )
{
   int	r;
   int	mask;

   r = input_read_int( &mask, 1 );
   if (r == 1) {
      if (mask < 0 || mask > ( MAXGCOLORS - 1 )) {
         XBell( winfo.id, 100 );
      } else {
         user.mask2 = mask;
         misc_mask( );
         misc_show( );
      }
   } else if (r != 0) {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );			/* return to caller */
}

int	region_ready( int button )
{
   double	dt = 36000.0;
   int		nc = 0;
   int		sid = -1;

   DATA_CHECK( NONE_ACTION );
   while (nc < MAXCLIENTS) {
      if (clients[nc].open && clients[nc].wstate == GDI_GRREGION) {
         double	difft;

         difft = difftime( clients[nc].time2, time( NULL ) );
         if (difft < dt) {
            dt = difft;
            sid = nc;
         }
      }
      nc += 1;
   }
   if (sid == -1) {
      XBell( winfo.id, 100 );
   } else {
      Command_struct	cmd;

      cmd.cmd    = GDI_GRREGION;
      cmd.code   = 0;
      cmd.nbytes = 0;
      misc_cmd_swap( clients[sid].swap, &cmd );	/* swap it */
      misc_send( clients[sid].socket, &cmd, sizeof( cmd ) );
      clients[sid].wstate = 0;
   }
   return( menu[button].ret );			/* return to caller */
}

int	region_next( int button )
{
   recording_show( 0 );
   return( menu_next( button ) );
}

/*
 * The stuff for BLOT action:
 */


#define	MAX_CURSOR_H	128
#define	MAX_CURSOR_W	128

#define	SHAPE_N		-1
#define	SHAPE_E		0
#define	SHAPE_R		1

#define	ClearBit( byte, bit )	if ( byte & ( 1 << bit ) ) byte -= 1 << bit
#define	IsBit( byte, bit )	( byte & ( 1 << bit ) )
#define	SetBit( byte, bit )	byte |= ( 1 << bit )

static	Cursor		Orig;
static	Cursor		Shape;
static	int		Cursor_Shape = SHAPE_N;
static	int		Cursor_H = 0;
static	int		Cursor_W = 0;
static	unsigned int	Max_Cursor_H = 0;
static	unsigned int	Max_Cursor_W = 0;
static	char		*S, *M;
static	int		*X, *Y;


static	int	init_cursor_shape( void )
{
   int	r = 1;

   if ( Max_Cursor_H == 0 || Max_Cursor_W == 0 ) {
      Orig = XCreateFontCursor( winfo.id, XC_circle );
      r = XQueryBestCursor( winfo.id, winfo.display, MAX_CURSOR_W,
                            MAX_CURSOR_H, &Max_Cursor_W, &Max_Cursor_H );
      if ( r ) {
         S = malloc( Max_Cursor_W * Max_Cursor_H / CHAR_BIT );
         M = malloc( Max_Cursor_W * Max_Cursor_H / CHAR_BIT );
         if ( S == NULL || M == NULL ) {
            r = 0;
         } else {
            X = malloc( ( Max_Cursor_H * 2 + 1 ) * sizeof( int ) );
            Y = malloc( ( Max_Cursor_H * 2 + 1 ) * sizeof( int ) );
            if ( X == NULL || Y == NULL ) {
               r = 0;
            } else {
               Cursor_H = Max_Cursor_H;
               Cursor_W = Max_Cursor_W;
            }
         }
      }
   }
   if ( !r ) {
      Max_Cursor_H = Max_Cursor_W = 0;
   }
   return( r );
}

static	int	set_cursor_shape( void )
{
   if (Cursor_Shape != SHAPE_N) {
      XDefineCursor( winfo.id, winfo.display, Shape );
      XFlush( winfo.id );
   }
   return( 0 );
}

static	int	reset_cursor_shape( void )
{
   if (Cursor_Shape != SHAPE_N) {
      XDefineCursor( winfo.id, winfo.display, Orig );
      XFlush( winfo.id );
   }
   return( 0 );
}

static	int	make_cursor_shape( void )
{
   Pixmap	source, mask;
   XColor	fg, bg;
   int		i, j, ic, jc, cc;
   int		done = 0;

   cc = winfo.ncolors + user.mask1;
   fg.red   = winfo.table[cc].red;
   fg.green = winfo.table[cc].green;
   fg.blue  = winfo.table[cc].blue;
   bg.red   = 0;
   bg.green = 0;
   bg.blue  = 0;
   ic = Cursor_W / 2; jc = Cursor_H / 2;
   switch( Cursor_Shape ) {
      case SHAPE_N: {
         XBell( winfo.id, 100 );
         XFlush( winfo.id );
         break;
      }
      case SHAPE_E: {
         double	ONE = 1.0;
         done = 1;
         for ( i = 0; i < Cursor_W; i++ ) {
            for ( j = 0; j < Cursor_H; j++ ) {
               double	rx, ry;
               int	k, l, m;

               k = j * Cursor_W + i;
               if ( Cursor_W % CHAR_BIT ) k += j * ( CHAR_BIT - Cursor_W % CHAR_BIT );
               l = k % CHAR_BIT;
               m = k / CHAR_BIT;
               rx = (double) ( i + i ) / (double) ( Cursor_W - 1 ) - 1.0;
               ry = (double) ( j + j ) / (double) ( Cursor_H - 1 ) - 1.0;
               if ( ( rx * rx + ry * ry ) <= ONE || i == ic || j == jc ) {
                  SetBit( M[m], l );
                  SetBit( S[m], l );
               } else {
                  ClearBit( M[m], l );
                  ClearBit( S[m], l );
               }
            }
         }
         break;
      }
      case SHAPE_R: {
         done = 1;
         for ( i = 0; i < Cursor_W; i++ ) {
            for ( j = 0; j < Cursor_H; j++ ) {
               int	k, l, m;

               k = j * Cursor_W + i;
               if ( Cursor_W % CHAR_BIT ) k += j * ( CHAR_BIT - Cursor_W % CHAR_BIT );
               l = k % CHAR_BIT;
               m = k / CHAR_BIT;
               SetBit( M[m], l );
               SetBit( S[m], l );
            }
         }
         break;
      }
   }
   if ( done ) {
      source = XCreateBitmapFromData( winfo.id, winfo.display, S, Cursor_W,
         Cursor_H );
      mask = XCreateBitmapFromData( winfo.id, winfo.display, M, Cursor_W,
         Cursor_H );
      Shape = XCreatePixmapCursor( winfo.id, source, mask, &fg, &bg, ic, jc );
      XFreePixmap( winfo.id, source );
      XFreePixmap( winfo.id, mask );
      XFlush( winfo.id );
   }
   return( 0 );
}

static	int	recolor_cursor( )
{
   XColor	fg, bg;
   int		cc;

   if ( Cursor_Shape == SHAPE_N ) return( 0 );
   cc = winfo.ncolors + user.mask1;

   fg.red   = winfo.table[cc].red;
   fg.green = winfo.table[cc].green;
   fg.blue  = winfo.table[cc].blue;
   bg.red   = 0;
   bg.green = 0;
   bg.blue  = 0;
   XRecolorCursor( winfo.id, Shape, &fg, &bg );
   XFlush( winfo.id );
   return( 0 );
}

int	region_blot_reset( int button )
{
   reset_cursor_shape( );
   return( menu_previous( button ) );
}

int	region_blot_e( int button )
{
   DATA_CHECK( NONE_ACTION );
   if ( user.mask1 && init_cursor_shape( ) ) {
      Cursor_Shape = SHAPE_E;
      make_cursor_shape( );
      set_cursor_shape( );
      return( menu[button].ret );		/* return to caller */
   } else {
      return( NONE_ACTION );
   }
}

int	region_blot_r( int button )
{
   DATA_CHECK( NONE_ACTION );
   if ( user.mask1 && init_cursor_shape( ) ) {
      Cursor_Shape = SHAPE_R;
      make_cursor_shape( );
      set_cursor_shape( );
      return( menu[button].ret );		/* return to caller */
   } else {
      return( NONE_ACTION );
   }
}

int	region_blot_change( KeySym key )
{
   int	change = 0;

   DATA_CHECK( NONE_ACTION );
   if (!user.mask1) return( NONE_ACTION );
   if ( key == XK_Left ) {
      if ( Cursor_W > 1 ) { Cursor_W--; change = 1; };
   } else if ( key == XK_Right ) {
      if ( Cursor_W < Max_Cursor_W ) { Cursor_W++; change = 1; };
   } else if ( key == XK_Down ) {
      if ( Cursor_H > 1 ) { Cursor_H--; change = 1; };
   } else if ( key == XK_Up ) {
      if ( Cursor_H < Max_Cursor_H ) { Cursor_H++; change = 1; };
   }
   if ( change ) {
      make_cursor_shape( );
      set_cursor_shape( );
   }
   return( 0 );
}

int	region_blot( int xc, int yc )
{
   int	code;
   int	i, ic, j, jc;
   int	n1, n2;

   n1 = Cursor_H;
   n2 = Cursor_H - 1;
   DATA_CHECK( NONE_ACTION );
   if (!user.mask1) return( NONE_ACTION );
   if (define) code = 3; else code = 2;
   ic = Cursor_W / 2;
   jc = Cursor_H / 2;
   for ( j = 0; j < Cursor_H; j++ ) {
      int	xs = 0, xe = 0, draw = 0;
      int	y = j - jc + yc, yy;

      if ( y < 0 || y > (winfo.dheight-1) ) continue;
      yy = winfo.record[0].y_grid[y];
      for ( i = 0; i < Cursor_W; i++ ) {
         int	k, l, m;
         int	x;

         x = ( i - ic + xc );
         if ( x < 0 || x > (winfo.dwidth-1) ) continue;
         k = j * Cursor_W + i;
         if ( Cursor_W % CHAR_BIT ) k += j * ( CHAR_BIT - Cursor_W % CHAR_BIT );
         l = k % CHAR_BIT;
         m = k / CHAR_BIT;
         if (IsBit( S[m], l )) {
            if (draw) {
               xe = winfo.record[0].x_grid[x];
            } else {
               draw = 1;
               xe = xs = winfo.record[0].x_grid[x];
            }
         } else if (draw) {
            n1--; X[n1] = xs ; Y[n1] = yy;
            n2++; X[n2] = xe ; Y[n2] = yy;
            draw = 0;
         }
      }
      if (draw) {
         n1--; X[n1] = xs ; Y[n1] = yy;
         n2++; X[n2] = xe ; Y[n2] = yy;
         draw = 0;
      }
   }
   if ( n1 < n2 ) {
      int	n;

      n2++; X[n2] = X[n1]; Y[n2] = Y[n1];
      for ( n = n1; n < n2; n++ ) {
         dvect( X[n], Y[n], X[n+1], Y[n+1], code );
      }
      for ( n = n2; n > n1; n-- ) {
         dvect( X[n], Y[n], X[n-1], Y[n-1], code );
      }
      fill( &X[n1], &Y[n1], n2 - n1 + 1, code );
   }
   return( 0 );
}

int	region_blot_menu( int button )
{
   int	r = menu_next( button );
   set_cursor_shape( );
   return( r );
}
#<

#>            scale.c
/* scale.c

*/

#include	"gids.h"			/* gids symbols */

int	scale_init( )
{
   int			m;
   int			n;
   unsigned char	v;

   winfo.inverse = 1;
   for (n = 0; n < MAXCOLORS; n++) {
      if (n <= winfo.mincolor) {
         v = winfo.mincolor;
      } else if (n > winfo.maxcolor) {
         v = winfo.maxcolor;
      } else {
         v = n;
      }
      winfo.scale[LINEAR_SCALE][n] = v;
   }
   for (m = 1, n = 0; n < MAXCOLORS; n++) {
      if (n <= winfo.mincolor) {
         v = winfo.mincolor;
      } else if (n > winfo.maxcolor) {
         v = winfo.maxcolor;
      } else {
         v = misc_nint( (double) (winfo.ncolors - 2) /
            log10( (double) (winfo.ncolors - 1) ) *
            log10( (double) (m++) ) ) + winfo.mincolor + 1;
      }
      winfo.scale[LOG_SCALE][n] = v;
   }
   for (m = 0, n = 0; n < MAXCOLORS; n++) {
      if (n <= winfo.mincolor) {
         v = winfo.mincolor;
      } else if (n > winfo.maxcolor) {
         v = winfo.maxcolor;
      } else {
         v = misc_nint( (double) (winfo.ncolors - 2) /
            ( pow( 10.0, (double) (winfo.ncolors - 2) / 100.0 ) - 1.0 ) *
            ( pow( 10.0, (double) (m++) / 100.0 ) - 1.0 ) ) +
            winfo.mincolor + 1;
      }
      winfo.scale[EXP_SCALE][n] = v;
   }
   for (m = 0, n = 0; n < MAXCOLORS; n++) {
      if (n <= winfo.mincolor) {
         v  = winfo.mincolor;
      } else if (n > winfo.maxcolor) {
         v = winfo.maxcolor;
      } else {
         v = misc_nint( (double) (winfo.ncolors - 2) /
            sqrt( (double) (winfo.ncolors - 2) ) *
            sqrt( (double) ( m++ ) ) ) + winfo.mincolor + 1;
      }
      winfo.scale[SQRT_SCALE][n] = v;
   }
   for (m = 0, n = 0; n < MAXCOLORS; n++) {
      if (n <= winfo.mincolor) {
         v  = winfo.mincolor;
      } else if (n > winfo.maxcolor) {
         v = winfo.maxcolor;
      } else {
         v = misc_nint( (double) (winfo.ncolors - 2) /
            pow( (double) (winfo.ncolors - 2), 2.0 ) *
            pow( (double) ( m++ ), 2.0 ) ) + winfo.mincolor + 1;
      }
      winfo.scale[SQUARE_SCALE][n] = v;
   }
   {
      char	*ptr;

      ptr = XGetDefault( winfo.id, "gids", "scaling" );
      if (ptr != NULL) {
         if (!strcmp( ptr, "Linear" )) {
            winfo.scaling = LINEAR_SCALE;
         } else if (!strcmp( ptr, "Log" )) {
            winfo.scaling = LOG_SCALE;
         } else if (!strcmp( ptr, "Exp" )) {
            winfo.scaling = EXP_SCALE;
         } else if (!strcmp( ptr, "Sqrt" )) {
            winfo.scaling = SQRT_SCALE;
         } else if (!strcmp( ptr, "Square" )) {
            winfo.scaling = SQUARE_SCALE;
         }
      }
   }
   {
      char	*ptr;

      ptr = XGetDefault( winfo.id, "gids", "inverse_scaling" );
      if (ptr != NULL) {
         if (!strcmp( ptr, "True" )) {
            winfo.inverse = -1.0;
         } else if (!strcmp( ptr, "False" )) {
            winfo.inverse = 1.0;
         }
      }
   }
   color_modify( );
   return( 0 );
}

int	scale_linear( int button )
{
   winfo.scaling = LINEAR_SCALE;

   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	scale_log( int button )
{
   winfo.scaling = LOG_SCALE;

   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	scale_exp( int button )
{
   winfo.scaling = EXP_SCALE;

   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	scale_sqrt( int button )
{
   winfo.scaling = SQRT_SCALE;

   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	scale_square( int button )
{
   winfo.scaling = SQUARE_SCALE;

   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	scale_inverse( int button )
{
   winfo.inverse *= -1.0;
   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	scale_blank( int button )
{
   float	rgb[3];
   int		r;

   r = input_read_float( rgb, 3 );
   if (r != 3) {
      XBell( winfo.id, 100 );
   } else {
      int	i, e = 0;
      for ( i = 0; i < 3 ; i++ ) {
         if (rgb[i]<0.0) e++;
         if (rgb[i]>1.0) e++;
      }
      if (e) {
         XBell( winfo.id, 100 );
      } else {
         winfo.modify[0].red   = winfo.table[0].red   = rgb[0] * USHRT_MAX;
         winfo.modify[0].green = winfo.table[0].green = rgb[1] * USHRT_MAX;
         winfo.modify[0].blue  = winfo.table[0].blue  = rgb[2] * USHRT_MAX;
         XStoreColors( winfo.id, winfo.colormap, winfo.table, 1 );
      }
   }
   return( menu[button].ret );
}
#<

#>            server.c
/* server.c

*/


/*
 * includes:
 */

#include	"gids.h"			/* gids definitions */

static	int	socks[] = { -1, -1, -1 };	/* connection sockets */

#define	MAXCONTYPE	(sizeof(socks)/sizeof(int))	/* max. connection types */
#define	MAXSOCKNAMELEN	80			/* max length of socket name */

Client_struct	clients[MAXCLIENTS];		/* the clients */
static	char	sockname[MAXSOCKNAMELEN+1];	/* name of unix socket */

typedef	struct timer_struct {			/* the timer struct */
   int			(*f)(void);		/* function to call */
   int			delay;			/* time to wait (microsecs) */
   struct timeval	initt;			/* time when timer started */
} Timer_struct;

static	Timer_struct	st;			/* the struct */


/*
 * server_timer_delay set the time to wait before action should be taken.
 * The action consists of executing the function set by server_timer_function.
 * A treshold delay time of 0.005 (5000 usec) is maintained so that one can
 * still do something with the machine.
 * VOG2010: Changed treshold 0.05 to 0.005.
 */

int	server_timer_delay( float delay )
{
   if (delay < 0.005) delay = 0.005;		/* a treshold */
   st.delay = 1000000 * delay;			/* delay in micro seconds */
   if (st.delay < 0) st.delay = 1000000;	/* one second */
   return( 0 );					/* success */
}


/*
 * server_timer_function sets the function which will be called each
 * time the wait time has elapsed.
 */

int	server_timer_function( int (*f)(void) )
{
   st.f = f;					/* set function */
   return( 0 );					/* success */
}


/*
 * server_main_loop handles all actions. After setting up the display
 * and establishing the connections, GIDS remains in this routine until
 * the user wants to quit.
 * The main part of this routine is the select call. Here all open sockets
 * are scanned for incomming requests. The programme waits until one or
 * more sockets become readable. Then it its checked which socket has become
 * readable. If the X11 socket has become readable, display_do() is called.
 * This routine handles all display events by looping until all pending
 * requests have been delt with. If one (or more) of the listening connection
 * sockets have become readable, then a client has made a request to
 * establish a connection. The socket connected with the client is obtained
 * with a call to accept. This new socket is then but in the select check
 * mask. If a client socket has become readable, a client is sending a
 * request which is then handled by server_do().
 * The call to select take also care of timer functions like blinking and
 * looping. In case of loop/blink mode select is used to handle these
 * time events. Since it is not always certain that the required time
 * has passed after returning from select, we have to check ourselves
 * whether action should be taken.
 */

int	server_main_loop( void )
{
   int		Xsock;				/* X socket number */
#ifndef	__alpha__				/* is a void on alpha's */
   int		b_zero( );			/* maybe used in FD macros */
#endif
   int		close( );			/* close a fd */
   int		gettimeofday( );		/* returns current time */
   int		select( );			/* select fd for work */
   int		status;				/* return status */
   int		m;				/* counter */
   int		n;				/* counter */
   int		nfound;				/* number of fd with pending io */
   int		action = NONE_ACTION;		/* loop control */
   fd_set	mask_fds, read_fds;		/* fd masks */

   {
      struct timeval	now;			/* current time */

      gettimeofday( &now, NULL );		/* get current time */
      st.initt = now;				/* initialize */
   }
   Xsock = XConnectionNumber( winfo.id );	/* get X socket fd */
   FD_ZERO( &mask_fds );			/* clear all flags */
   FD_SET( Xsock, &mask_fds );			/* insert X socket */
   for (m = 0; m < MAXCONTYPE; m++) {		/* loop over all connections */
      if (socks[m] != -1) {			/* this one listens */
         FD_SET( socks[m], &mask_fds );		/* insert it */
      }
   }
   XFlush( winfo.id );				/* flush */
   while (!(action & QUIT_ACTION)) {		/* loop until user says quit */
      struct timeval	*to = NULL;		/* pointer to argument */
      struct timeval	work;			/* argument to select */

      if (action & BLINK_ACTION) {		/* timing should be checked */
         int		ms;			/* difference in milli secs */
         struct timeval	ct;			/* current time */

         gettimeofday( &ct, NULL );		/* get time of day */
         ms = ( ct.tv_sec - st.initt.tv_sec ) * 1000000;
         ms += ( ct.tv_usec - st.initt.tv_usec );
         if (ms < 0) ms = st.delay;		/* just in case */
         if (ms >= st.delay) {			/* enough time elapsed */
            st.initt = ct;			/* new initiating time */
            work.tv_sec  = (int) st.delay / 1000000;
            work.tv_usec = (int) st.delay % 1000000;
            st.f( );				/* do the function */
         } else {
            ms = st.delay - ms;			/* new delay time */
            work.tv_sec  = (int) ms / 1000000;
            work.tv_usec = (int) ms % 1000000;
         }
         to = &work;				/* set timer trap */
      } else {
         to = NULL;				/* no timer traps */
      }
      memcpy( &read_fds, &mask_fds, sizeof( fd_set ) );
      while ((nfound = select( FD_SETSIZE, (void *) &read_fds, NULL, NULL, to )) == -1 && errno == EINTR);
      if (nfound == -1) continue;		/* implement error handling later */
      if (!nfound) continue;			/* go on */
      if (FD_ISSET( Xsock, &read_fds )) {	/* X wants us */
         nfound -= 1;				/* decrement */
         action = display_do( action );		/* finish some events */
      }
      for (n = 0; nfound && n < MAXCLIENTS; n++) {
         if (clients[n].open && FD_ISSET( clients[n].socket, &read_fds )) {
            int	msgsock = clients[n].socket;	/* save socket */

            nfound -= 1;			/* decrement */
            status = server_do( n );
            if (!clients[n].open) {		/* closed */
               FD_CLR( msgsock, &mask_fds );	/* clear flag */
            }
         }
      }
      for (m = 0; nfound && m < MAXCONTYPE; m++) {
         if (socks[m] != -1 && FD_ISSET( socks[m], &read_fds )) {
            int	accept( );			/* accept a connection */
            int	msgsock;			/* new socket */

            nfound -= 1;			/* decrement */
            msgsock = accept( socks[m], (struct sockaddr *)0, (int *)0 );
            if (msgsock != -1) {		/* we got a socket */
               time_t	time1 = time( NULL );	/* set age */

               for (n = 0; n < MAXCLIENTS; n++) {
                  if (!clients[n].open) {	/* free client space */
                     clients[n].socket = msgsock;
                     clients[n].ftype  = OS_FLOATING_TYPE;
                     clients[n].open   = 1;
                     clients[n].time2  = time1;
                     clients[n].wstate = 0;
                     clients[n].menu   = -1;
                     clients[n].swap   = 0;
                     FD_SET( msgsock, &mask_fds );	/* set flag */
                     break;
                  } else if (difftime( clients[n].time2, time1 ) > 3600.0 ) {
                     close( clients[n].socket );
                     if (winfo.clients) winfo.clients--;
                     clients[n].socket = msgsock;
                     clients[n].time2  = time1;
                     clients[n].wstate = 0;
                     clients[n].menu   = -1;
                     clients[n].swap   = 0;
                     break;
                  }
               }
               if ( n == MAXCLIENTS ) {		/* out of client space */
                  close( msgsock );
               }
            }
         }
      }
   }
   return( 0 );
}


/*
 * server_do handles the client request.
 */

int	server_do( int n )
{
   Command_struct	cmd;			/* for command */
   int			r;			/* resturn code */
   int			status = GDIE_SUCCESS;	/* status */

   r = misc_receive( clients[n].socket, &cmd, sizeof( cmd ) );
   if (r == GDIE_SUCCESS) {
      clients[n].time2 = time( NULL );
      misc_cmd_swap( clients[n].swap, &cmd );	/* swap it */
      switch( cmd.cmd ) {			/* which function */
         case GDI_OPEN: {			/* open display */
            status = gdi_open( n, cmd );
            break;
         }
         case GDI_CLOSE: {			/* close display */
            status = gdi_close( n, cmd );
            break;
         }
         case GDI_RESET: {			/* reset display */
            status = gdi_reset( n, cmd );
            break;
         }
         case GDI_UPDATE: {			/* update display */
            status = gdi_update( n, cmd );
            break;
         }
         case GDI_CINFO: {			/* obtain color info */
            status = gdi_cinfo( n, cmd );
            break;
         }
         case GDI_COLPUT: {			/* get colors from client */
            status = gdi_colput( n, cmd );
            break;
         }
         case GDI_COLGET: {			/* send colors to client */
            status = gdi_colget( n, cmd );
            break;
         }
#if	!defined(NO_GIPSY)
         case GDI_MHEAD: {			/* get image header */
            status = gdi_mhead( n, cmd );
            break;
         }
#endif
         case GDI_IMWRITE: {			/* write image */
            status = gdi_imwrite( n, cmd );
            break;
         }
         case GDI_DEFIMG: {			/* define an image */
            status = gdi_defimg( n, cmd );
            break;
         }
         case GDI_RINFO: {			/* get recordings info */
            status = gdi_rinfo( n, cmd );
            break;
         }
         case GDI_RECORD: {			/* record an image */
            status = gdi_record( n, cmd );
            break;
         }
         case GDI_REMOVE: {			/* remove a recording */
            status = gdi_remove( n, cmd );
            break;
         }
         case GDI_RESTORE: {			/* restore an image */
            status = gdi_restore( n, cmd );
            break;
         }
         case GDI_RMASK: {			/* obtain recordings mask */
            status = gdi_rmask( n, cmd );
            break;
         }
         case GDI_SAVE: {			/* save an image */
            status = gdi_save( n, cmd );
            break;
         }
         case GDI_SEQUENCE: {			/* set playback sequence */
            status = gdi_sequence( n, cmd );
            break;
         }
         case GDI_GINFO: {			/* obtain graphics info */
            status = gdi_ginfo( n, cmd );
            break;
         }
         case GDI_GRCOL: {			/* set graphics color */
            status = gdi_grcol( n, cmd );
            break;
         }
         case GDI_GRON: {			/* turn graphics planes on */
            status = gdi_gron( n, cmd );
            break;
         }
         case GDI_GROFF: {			/* turn graphics planes off */
            status = gdi_groff( n, cmd );
            break;
         }
         case GDI_GRCLEAR: {			/* clear graphics planes */
            status = gdi_grclear( n, cmd );
            break;
         }
         case GDI_GRREGION: {			/* let user define a region */
            status = gdi_grregion( n, cmd );
            break;
         }
         case GDI_GRREAD: {			/* read graphics data */
            status = gdi_grread( n, cmd );
            break;
         }
         case GDI_GRWRITE: {			/* write graphics data */
            status = gdi_grwrite( n, cmd );
            break;
         }
         case GDI_IMMID: {			/* main image id */
            status = gdi_immid( n, cmd );
            break;
         }
         case GDI_IMSID: {			/* image sub id */
            status = gdi_imsid( n, cmd );
            break;
         }
         case GDI_GDSID: {			/* GDS id */
            status = gdi_gdsid( n, cmd );
            break;
         }
         case GDI_IINFO: {			/* obtain image info */
            status = gdi_iinfo( n, cmd );
            break;
         }
         case GDI_PGPLOT: {			/* PGPLOT functions */
            status = gdi_pgplot( n, cmd );
            break;
         }
         case GDI_FRAME: {			/* return current frame */
            status = gdi_frame( n, cmd );
            break;
         }
         case GDI_BLANKCOL: {			/* set colors for blanks */
            status = gdi_blankcol( n, cmd );
            break;
         }
         case GDI_IDLEN: {			/* return length of text id */
            status = gdi_idlen( n, cmd );
            break;
         }
         case GDI_IINFO2: {			/* obtain image info */
            status = gdi_iinfo2( n, cmd );
            break;
         }
         case GDI_GETLUT: {			/* obtain current colors */
            status = gdi_getlut( n, cmd );
            break;
         }
         case GDI_SETXGRID: {			/* set text for X grids */
            status = gdi_setxgrid( n, cmd );
            break;
         }
         case GDI_SETYGRID: {			/* set text for Y grids */
            status = gdi_setygrid( n, cmd );
            break;
         }
         default: {
            cmd.code   = GDIE_NOT_IMPLEMENTED;
            cmd.nbytes = 0;
            misc_cmd_swap( clients[n].swap, &cmd );
            r = misc_send( clients[n].socket, &cmd, sizeof( cmd ) );
            status = GDIE_ERROR_UNKNOWN;
            break;
         }
      }
   } else {
      int	close( );

      close( clients[n].socket );
      clients[n].open = 0;
      if (winfo.clients) winfo.clients--;
   }
   return( status );
}


/*
 * server_open creates all possible sockets (UNIX, INET, DNET) and sets
 * them listening for connections wanted by the clients. server_main_loop
 * handles all incomming requests, be it from X or the sockets created
 * here.
 */

int	server_open( char *fil_name )
{
   FILE	*f;					/* setup file descriptor */
   char	hostname[MAXSTRING];			/* for hostname */
   int	bind( );				/* binds a socket */
   int	fcntl( );				/* file control */
   int	gethostname( );				/* obtains hostname */
   int	getsockname( );				/* obtains socketname */
   int	listen( );				/* starts listening on socket */
   int	socket( );				/* creates socket */
   int	n;					/* counter */
   int	r = 0;					/* return value */

   if (gethostname( hostname, MAXSTRING ) == -1) return( r );
   strcpy( winfo.hostname, hostname );
   /*
    * Now get inet address of host.
    */
   {
      char		*addr;
      char		*inet_ntoa( );
      struct hostent	*hp;
      struct hostent	*gethostbyname( );
      struct in_addr	ha;

      hp = gethostbyname( hostname );
#if   0
      if (hp == NULL) {
         int		endhostent( );
         int		sethostent( );
         struct hostent	*gethostent( );

         sethostent( 1 );
         while (((hp = gethostent( )) != NULL) && (strcmp( hostname, hp->h_name )));
         endhostent( );
      }
#endif
      if ((hp == NULL) && (strchr( hostname, '.' ) == NULL)) {
         char	dname[MAXSTRING];
         int	getdomainname( );

         if (!getdomainname( dname, sizeof( dname ))) {
            strcat( hostname, "." );
            strcat( hostname, dname );
            hp = gethostbyname( hostname );
         }
      }
      if (hp != NULL) {
         memmove( (void *) &ha, (void *) hp->h_addr, hp->h_length );
#if	defined(__sun__) & defined(__GNUC__) & !defined(__i386__)
         addr = inet_ntoa( &ha );
#else
         addr = inet_ntoa( ha );
#endif
         strcpy( winfo.netaddr, addr );
         strcpy( winfo.con_string, addr );
      } else {
         strcpy( winfo.netaddr, hostname );
         strcpy( winfo.con_string, hostname );
      }
   }
   for (n = 0; n < MAXCONTYPE; n++) {
      strcat( winfo.con_string, ":" );		/* start next field */
      switch( n ) {				/* which type of connection */
         case 0: {				/* unix connection */
#if	defined(AF_UNIX)
            int			status;		/* reset status */
            struct sockaddr_un	server;		/* unix socket address struct */

						/* create socket */
            status = socket( AF_UNIX, SOCK_STREAM, 0 );
            if (status != -1) {			/* success */
               socks[0] = status;		/* save socket descriptor */
               server.sun_family = AF_UNIX;	/* unix socket */
						/* constitute socket name */
               sprintf( sockname, "/tmp/gids%d", winfo.pid );
						/* copy socket name */
               strcpy( server.sun_path, sockname );
						/* bind socket*/
               status = bind( socks[0], (struct sockaddr *) &server, sizeof( server ) );
            }
            if (!status) {
               status = listen( socks[0], 5 );	/* start listening */
            }
            if (status == -1) {
               socks[0] = -1;			/* not in use */
            } else {
               strcat( winfo.con_string, sockname );	/* concatenate socket name */
               r += 1;				/* increase #cons */
            }
#endif
            break;
         }
         case 1: {				/* inet connection */
#if	defined(AF_INET)
            int			length;		/* length of struct */
            int			status;		/* status */
            struct sockaddr_in	server;		/* inet socket address struct */

						/* create socket */
            status = socket( AF_INET, SOCK_STREAM, 0 );
            if (status != -1) {			/* success */
               socks[1] = status;		/* save socket descriptor */
               server.sin_family = AF_INET;	/* inet socket */
						/* find free address */
               server.sin_addr.s_addr = INADDR_ANY;
               server.sin_port = 0;
						/* bind to socket */
               status = bind( socks[1], (struct sockaddr *)&server, sizeof( server ) );
            }
            if (status != -1) {
               length = sizeof( server );	/* for return */
						/* get socket name */
               status = getsockname( socks[1], (struct sockaddr *) &server, &length );
            }
            if (!status) {
               status = listen( socks[1], 5 );	/* start listening */
            }
            if (status == -1) {
               socks[1] = -1;			/* not in use */
            } else {
               char	portnumber[10];		/* port number */

               sprintf( portnumber, "%d", (int) ntohs( server.sin_port ) );
               strcat( winfo.con_string, portnumber );/* concatenate socket name */
               r += 1;				/* increase #cons */
            }
#endif
            break;
         }
         case 2: {				/* dnet connection */
            break;
         }
         default: {				/* wrong connection type */
            break;
         }
      }
   }
   f = fopen( fil_name, "w" );
   if (f == NULL) {
      r = -1;
   } else {
      if (r) {
         fprintf( f, "%s\n", winfo.con_string );
         display_command( );
      }
      fclose( f );
   }
   return( r );					/* number of connections */
}

int	server_close( void )
{
   int	close( );				/* closes a socket */
   int	n;					/* counter */
   int	r = 0;					/* return code */

   for (n = 0; n < MAXCONTYPE; n++) {		/* all possible connections */
      if (socks[n] != -1) switch( n ) {
         case 0: {				/* UNIX socket */
            r = close( socks[n] );		/* close it */
            if (r != -1) {
               r = remove( sockname );		/* remove socket */
            }
            break;
         }
         case 1: {				/* INET socket */
            r = close( socks[n] );		/* close it */
            break;
         }
         case 2: {				/* DNET socket */
            r = -2;				/* not implemented */
            break;
         }
         default: {				/* unknown connection type */
            r = -2;				/* not implemented */
            break;
         }
      }
   }
   return( r );					/* return to caller */
}
#<

#>            slice.c
/* slice.c
 *
 */

#include	"gids.h"

#define	CLIENT_CHECK( r )	\
if (winfo.clients) {		\
   XBell( winfo.id, 100 );	\
   return( r );			\
}

static	int	old_x = -1;
static	int	old_y = -1;
static	int	old_r = -1;
static	int	cursor = 0;
static	int	slices[MAXRECORD];
static	int	coords = 0;
static	int	profile[MAXRECORD];
static	int	nprofile = 0;

int	slice_X( int button )
{
   int	r;

   DATA_CHECK( NONE_ACTION );
   CLIENT_CHECK( NONE_ACTION );
   r = input_read_int( slices, MAXRECORD );
   if (r < 0) {
      XBell( winfo.id, 100 );
      return( NONE_ACTION );
   } else {
      int	n, nslice;

      for ( nslice = 0, n = 0; n < r; n++ ) {
         if ( slices[n] >= 0 && slices[n] <= winfo.mrecord ) {
            if ( nslice == n ) {
               nslice += 1;
            } else {
               slices[nslice++] = slices[n];
            }
         }
      }
      display_xslice( nslice, slices );
      return( menu[button].ret );
   }
}

int	slice_X_dezoom( int button )
{
   int	n, nslice;

   DATA_CHECK( NONE_ACTION );
   CLIENT_CHECK( NONE_ACTION );
   if (winfo.nxslice > 2) {
      for ( nslice = 0, n = 0; n < winfo.nxslice; n++ ) {
         if (!(n%2)) slices[nslice++] = winfo.xslices[n];
      }
      display_xslice( nslice, slices );
   } else {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );
}

int	slice_X_zoom( int button )
{
   int	m, n, nslice;

   DATA_CHECK( NONE_ACTION );
   CLIENT_CHECK( NONE_ACTION );
   if (winfo.nxslice) {
      nslice = 2 * winfo.nxslice;
      if (nslice > MAXRECORD) nslice = MAXRECORD;
      for ( m = 0, n = 0; n < nslice; n++ ) {
         slices[n] = winfo.xslices[m];
         if (n%2) m++;
      }
      display_xslice( nslice, slices );
   } else {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );
}

int	slice_Y( int button )
{
   int	r;

   DATA_CHECK( NONE_ACTION );
   CLIENT_CHECK( NONE_ACTION );
   r = input_read_int( slices, MAXRECORD );
   if (r < 0) {
      XBell( winfo.id, 100 );
      return( NONE_ACTION );
   } else {
      int	n, nslice;

      for ( nslice = 0, n = 0; n < r; n++ ) {
         if ( slices[n] >= 0 && slices[n] <= winfo.mrecord ) {
            if ( nslice == n ) {
               nslice += 1;
            } else {
               slices[nslice++] = slices[n];
            }
         }
      }
      display_yslice( nslice, slices );
      return( menu[button].ret );
   }
}

int	slice_Y_dezoom( int button )
{
   int	n, nslice;

   DATA_CHECK( NONE_ACTION );
   CLIENT_CHECK( NONE_ACTION );
   if (winfo.nyslice > 2) {
      for ( nslice = 0, n = 0; n < winfo.nyslice; n++ ) {
         if (!(n%2)) slices[nslice++] = winfo.yslices[n];
      }
      display_yslice( nslice, slices );
   } else {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );
}

int	slice_Y_zoom( int button )
{
   int	m, n, nslice;

   DATA_CHECK( NONE_ACTION );
   CLIENT_CHECK( NONE_ACTION );
   if (winfo.nyslice) {
      nslice = 2 * winfo.nyslice;
      if (nslice > MAXRECORD) nslice = MAXRECORD;
      for ( m = 0, n = 0; n < nslice; n++ ) {
         slices[n] = winfo.yslices[m];
         if (n%2) m++;
      }
      display_yslice( nslice, slices );
   } else {
      XBell( winfo.id, 100 );
   }
   return( menu[button].ret );
}

static	int	slice_do_sliceX( int d_y, int force )
{
   int	n;

   if ((winfo.windows & WINDOW_XSLICE) && ((winfo.last_y != d_y) || force)) {
      winfo.last_y = d_y;
      for ( n = 0; n < winfo.nxslice; n++ ) {
         int	rec = winfo.xslices[n];

         if (rec >= 0 && rec <= winfo.mrecord && winfo.record[rec].mask) {
            XCopyArea( winfo.id, winfo.record[rec].pixmap, winfo.xslice,
               winfo.gcm, 0, d_y, winfo.dwidth, 1, 0, n );
         } else {
            XClearArea( winfo.id, winfo.xslice, 0, n, winfo.dwidth, 1, False );
         }
      }
   }
   return( 0 );
}

static	int	slice_do_sliceY( int d_x, int force )
{
   int	n;

   if ((winfo.windows & WINDOW_YSLICE) && ((winfo.last_x != d_x) || force)) {
      winfo.last_x = d_x;
      for ( n = 0; n < winfo.nyslice; n++ ) {
         int	rec = winfo.yslices[n];

         if (rec >= 0 && rec <= winfo.mrecord && winfo.record[rec].mask) {
            XCopyArea( winfo.id, winfo.record[rec].pixmap, winfo.yslice,
               winfo.gcm, d_x, 0, 1, winfo.dheight, n, 0 );
         } else {
            XClearArea( winfo.id, winfo.yslice, n, 0, 1, winfo.dheight, False );
         }
      }
   }
   return( 0 );
}

int	slice_do_slice( int window_id, int d_x, int d_y, int force, int button, int press  )
{
   Window	window;
   int		h, w;
   int		rec = 0;

   switch( window_id ) {
      case 0: {
         window = winfo.display;
         h = winfo.dheight;
         w = winfo.dwidth;
         break;
      }
      case 1: {
         window = winfo.xslice;
         h = winfo.nxslice;
         w = winfo.dwidth;
         break;
      }
      case 2: {
         window = winfo.yslice;
         h = winfo.dheight;
         w = winfo.nyslice;
         break;
      }
      default: {
         return( 0 );
      }
   }
   if ( d_x < 0 || d_x >= w ) return( 0 );
   if ( d_y < 0 || d_y >= h ) return( 0 );
   slice_cursor( 1 );
   if (window_id) {
      if (window_id == 1) {
         rec = winfo.xslices[d_y];
         recording_show( rec );
         slice_do_sliceY( d_x, force );
      } else if (window_id == 2) {
         rec = winfo.yslices[d_x];
         recording_show( rec );
         slice_do_sliceX( d_y, force );
      }
   } else {
      rec = winfo.currec;
      slice_do_sliceX( d_y, force );
      slice_do_sliceY( d_x, force );
   }
   slice_cursor( button != Button2 );
   if ( press && coords && button == Button1 ) {
      char		string[2*MAXIDTEXTLEN+1];

      if ( strlen( winfo.text[1] ) ) {
         sprintf( string, "%s,%s", winfo.text[5], winfo.text[1] );
      } else {
         sprintf( string, "%s,%7d", winfo.text[5], rec );
      }
      cursor_send_text( string );
   }
   XFlush( winfo.id );
   return( 0 );
}

int	slice_cursor( int clear )
{
   int	r;

   if (clear && !cursor) return( 0 );
   if (clear) {
      if (winfo.nyslice) {
         XDrawLine( winfo.id, winfo.display, winfo.gcb, old_x, 0, old_x,
            winfo.dheight - 1 );
      }
      if (winfo.nxslice) {
         XDrawLine( winfo.id, winfo.display, winfo.gcb, 0, old_y,
            winfo.dwidth - 1, old_y );
      }
      for (r = 0; r < winfo.nxslice; r++) {
         if (old_r == winfo.xslices[r]) {
            XDrawLine( winfo.id, winfo.xslice, winfo.gcb, 0, r,
               winfo.dwidth - 1, r );
         }
      }
      for (r = 0; r < winfo.nyslice; r++) {
         if (old_r == winfo.yslices[r]) {
            XDrawLine( winfo.id, winfo.yslice, winfo.gcb, r, 0,
               r, winfo.dheight - 1 );
         }
      }
      cursor = 0;
   } else {
      old_x = winfo.last_x;
      if (winfo.nyslice) {
         XDrawLine( winfo.id, winfo.display, winfo.gcb, old_x, 0, old_x,
            winfo.dheight - 1 );
      }
      old_y = winfo.last_y;
      if (winfo.nxslice) {
         XDrawLine( winfo.id, winfo.display, winfo.gcb, 0, old_y,
            winfo.dwidth - 1, old_y );
      }
      old_r = winfo.currec;
      for (r = 0; r < winfo.nxslice;  r++) {
         if (old_r == winfo.xslices[r]) {
            XDrawLine( winfo.id, winfo.xslice, winfo.gcb, 0, r,
               winfo.dwidth - 1, r );
         }
      }
      for (r = 0; r < winfo.nyslice; r++) {
         if (old_r == winfo.yslices[r]) {
            XDrawLine( winfo.id, winfo.yslice, winfo.gcb, r, 0,
               r, winfo.dheight - 1 );
         }
      }
      cursor = 1;
   }
   XFlush( winfo.id );
   return( 0 );
}

int	slice_coords( int button )
{
   coords = !coords;
   return( menu[button].ret );
}

int	slice_profile( int button )
{
   XBell( winfo.id, 100 );
   XFlush( winfo.id );
   return( menu[button].ret );
}
#<

#>            wedge.c
/* wedge

*/

#include	"gids.h"

static	int	half_width = 2;
static	int	wedge_color = NO_WEDGE;

extern void pixel2chars( );

int	wedge_init( void )
{
   int	n;					/* loop counter */

   for (n = 1; n < winfo.ncolors - 1; n++) {	/* loop */
      winfo.wedge_code[n] = NO_WEDGE;		/* reset */
   }
   winfo.Blue.blue    = 1.0;
   winfo.Blue.green   = 0.0;
   winfo.Blue.red     = 0.0;
   winfo.Green.blue   = 0.0;
   winfo.Green.green  = 1.0;
   winfo.Green.red    = 0.0;
   winfo.Purple.blue  = 1.0;
   winfo.Purple.green = 0.0;
   winfo.Purple.red   = 1.0;
   winfo.Red.blue     = 0.0;
   winfo.Red.green    = 0.0;
   winfo.Red.red      = 1.0;
   winfo.White.blue   = 1.0;
   winfo.White.green  = 1.0;
   winfo.White.red    = 1.0;
   winfo.Yellow.blue  = 0.0;
   winfo.Yellow.green = 1.0;
   winfo.Yellow.red   = 1.0;
   return( 0 );					/* return to caller */
}

int	wedge_reset( int button )
{
   int	n;					/* loop counter */

   wedge_color = NO_WEDGE;
   for (n = 1; n < winfo.ncolors; n++) {	/* loop */
      winfo.wedge_code[n] = NO_WEDGE;		/* reset */
   }
   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	wedge_blue( int button )
{
   int	n;					/* loop counter */

   wedge_color = BLUE_WEDGE;
   for (n = 1; n < winfo.ncolors; n++) {
      if (winfo.wedge_code[n] & wedge_color) {
         winfo.wedge_code[n] -= wedge_color;
      }
   }
   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	wedge_green( int button )
{
   int	n;					/* loop counter */

   wedge_color = GREEN_WEDGE;
   for (n = 1; n < winfo.ncolors; n++) {
      if (winfo.wedge_code[n] & wedge_color) {
         winfo.wedge_code[n] -= wedge_color;
      }
   }
   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	wedge_purple( int button )
{
   int	n;					/* loop counter */

   wedge_color = PURPLE_WEDGE;
   for (n = 1; n < winfo.ncolors; n++) {
      if (winfo.wedge_code[n] & wedge_color) {
         winfo.wedge_code[n] -= wedge_color;
      }
   }
   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	wedge_red( int button )
{
   int	n;					/* loop counter */

   wedge_color = RED_WEDGE;
   for (n = 1; n < winfo.ncolors; n++) {
      if (winfo.wedge_code[n] & wedge_color) {
         winfo.wedge_code[n] -= wedge_color;
      }
   }
   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	wedge_yellow( int button )
{
   int	n;					/* loop counter */

   wedge_color = YELLOW_WEDGE;
   for (n = 1; n < winfo.ncolors; n++) {
      if (winfo.wedge_code[n] & wedge_color) {
         winfo.wedge_code[n] -= wedge_color;
      }
   }
   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	wedge_white( int button )
{
   int	n;					/* loop counter */

   wedge_color = WHITE_WEDGE;
   for (n = 1; n < winfo.ncolors; n++) {
      if (winfo.wedge_code[n] & wedge_color) {
         winfo.wedge_code[n] -= wedge_color;
      }
   }
   color_modify( );
   return( menu[button].ret );			/* return to caller */
}

int	wedge_modify( int yc )
{
   int	c;					/* centre of range */
   int	n;					/* loop counter */
   int	r1;					/* start of range */
   int	r2;					/* end of range */

   if (yc < 0) {
      yc = 0;
   } else if (yc >= winfo.wheight) {
      yc = winfo.wheight - 1;
   }
   yc = winfo.wheight - 1 - yc;
   if (wedge_color == NO_WEDGE) return( 0 );	/* fast exit */
   c = (float) (winfo.ncolors - 2) / (float) (winfo.wheight - 1) *
      (float) yc + 1.5;
/* made comment by kgb: c = winfo.scale[winfo.scaling][c+winfo.mincolor] - winfo.mincolor; */
   r1 = c - half_width;
   r2 = c + half_width;
   for (n = 1; n < winfo.ncolors; n++) {
      if ((n < r1) || (n > r2)) {
         if (winfo.wedge_code[n] & wedge_color) {
            winfo.wedge_code[n] -= wedge_color;
         }
      } else {
         winfo.wedge_code[n] |= wedge_color;
      }
   }
   color_modify( );
   return( 0 );					/* return to caller */
}

int	wedge_draw( int force )
{
   char		format[20];
   char		string[20];
   static float	bscale = 0.0;
   static float	b_zero  = 0.0;
   static int	clear = 1;
   double	zz;
   float	v;
   float	vmin;
   float	vmax;
   float	vrange;
   float	vstart;
   float	vstep;
   int		last_ya = winfo.cheight;
   int		nc;
   int		rec = winfo.currec;
   int		y;
   int		z;

   if (!winfo.record[rec].mask) {
      if (clear) {
         return( 0 );
      } else {
         XClearWindow( winfo.id, winfo.calib );
         clear = 1;
         return( 0 );
      }
   }

   if ((bscale == winfo.record[rec].bscale) && (b_zero == winfo.record[rec].b_zero) && !clear && !force) return( 0 );
   XClearWindow( winfo.id, winfo.calib );
   bscale = winfo.record[rec].bscale;
   b_zero  = winfo.record[rec].b_zero;
   vmin = bscale * (float) winfo.mincolor + b_zero;
   vmax = bscale * (float) winfo.maxcolor + b_zero;
   vrange = vmax - vmin;
   if (vrange <= 0.0) return( 0 );
   zz = log10( (double) vrange );
   z = (zz + 1.0);
   vstep = pow( 10.0, (double) ( z - 1 ) );
   while (floor(vrange/vstep) > 20.0) { vstep *= 10.0; z++; }
   if (floor(vrange/vstep) < 2.0) { vstep *= 0.1; z--; }
   if (floor(vrange/vstep) < 4.0) { vstep *= 0.25; z--; }
   if (floor(vrange/vstep) < 5.0) { vstep *= 0.5; z--; }
   if (z > -3 && z < 5) {
      sprintf( format, "%%%d.%df", MINCALIBWIDTH, (z < 1 ? 2 - z : 1 ) ) ;
   } else {
      sprintf( format, "%%%d.2E", MINCALIBWIDTH );
   }
   vstart = ceil( (double) ( vmin / vstep) ) * vstep;
   for (v = vstart; v < vmax; v += vstep ) {
      float	value;
      int	yb, ya, yd;

      y = (float) winfo.cheight / vrange * (v - vmin ) + 0.5;
      y = winfo.cheight - y - 1;
      /* VOG2010: variable 'value' seems not te be used in this function */
      /* That's ok because if there are more bytes per pixel, then the  */
      /* wrong array index in winfo.wdata is used.                      */
      value = bscale * (float) winfo.wdata[y*winfo.wwidth] + b_zero;
      yb = y + winfo.cfont->ascent / 2;
      ya = yb - winfo.cfont->ascent / 2;
      yd = yb + winfo.cfont->ascent / 2;
      if ((ya > 0) && (yd < winfo.cheight) && (yd < last_ya)) {
         int	xoff;

         last_ya = ya;
         XDrawLine( winfo.id, winfo.calib, winfo.gcc, 0, y, 5, y );
         nc = sprintf( string, format, v );
         xoff = winfo.cwidth - XTextWidth( winfo.cfont, string, nc ) - 8;
         XDrawString( winfo.id, winfo.calib, winfo.gcc, xoff, yb, string, nc );
         XDrawLine( winfo.id, winfo.calib, winfo.gcc, winfo.cwidth - 6, y,
            winfo.cwidth - 1, y );
      }
   }
   clear = 0;
   return( 0 );					/* return to caller */
}

int	wedge_position( int d_y )
{
   double		u_v;
   float		bscale;
   float		b_zero;
   int			rec = winfo.currec;
   int			valid = 0;
   unsigned char	d_v;

   if (user.idata == NULL) {
      valid = 0;
   } else if (!winfo.record[rec].mask) {
      valid = 0;
   } else if ((d_y >= 0) && (d_y < winfo.wheight)) {
      valid = 1;
   }
   if (valid) {
      bscale = winfo.record[rec].bscale;
      b_zero  = winfo.record[rec].b_zero;
      d_y = winfo.wheight - 1 - d_y;
      d_v = (float) ( winfo.ncolors - 1 ) / (float) ( winfo.wheight - 1 ) *
         (float) d_y + winfo.mincolor + 1;
      u_v = bscale * d_v + b_zero;			/* translation */
      sprintf( winfo.text[4], "VALUE= % 10.2E", u_v );
   } else {
      strcpy( winfo.text[4], "VALUE=" );
   }
   misc_info( 0 );
   return( 0 );					/* return to caller */
}

int	wedge_change( )
{
   int	n;
   int	x;
   int	y;

   for (n = 0, y = winfo.wheight; y-- > 0;) {
      unsigned char	ch;

      ch = (float) (winfo.maxcolor - winfo.mincolor - 1) /
         (float) (winfo.wheight - 1) * (float) y + winfo.mincolor + 1;
      for (x = 0; x < winfo.wwidth; x++) {
         /* ORIG: winfo.wdata[n++] = ch;*/
         /* winfo.wdata[n++] = winfo.table[ch].pixel;*/
         pixel2chars(winfo.table[ch].pixel, winfo.wdata, &n,
                     winfo.bytespp, winfo.byte_order);
      }
   }
   XPutImage( winfo.id, winfo.wpixmap, winfo.gcm, winfo.wimage, 0, 0, 0, 0,
      winfo.wwidth, winfo.wheight );
   XCopyArea( winfo.id, winfo.wpixmap, winfo.wedge, winfo.gcm, 0, 0,
      winfo.wwidth, winfo.wheight, 0, 0 );
   return( 0 );
}
#<

#>            zoom.c
/* zoom.c

*/

#include	"gids.h"

int	zoom_xy( int x_zc, int y_zc, int x_zf, int y_zf )
{
   double	xsh;
   double	ysh;
   double	xzf;				/* x-zoom factor */
   double	yzf;				/* y-zoom factor */
   int		x;				/* x counter */
   int		xu;
   int		x_c;				/* x centre */
   int		y;				/* y counter */
   int		yu;
   int		y_c;				/* y centre */

   DATA_CHECK( 0 );
   if (x_zf > MAXZOOMFACTOR) x_zf = MAXZOOMFACTOR;
   if (x_zf < -MAXZOOMFACTOR) x_zf = -MAXZOOMFACTOR;
   if (y_zf > MAXZOOMFACTOR) y_zf = MAXZOOMFACTOR;
   if (y_zf < -MAXZOOMFACTOR) y_zf = -MAXZOOMFACTOR;
   winfo.x_zoomf = x_zf;
   winfo.y_zoomf = y_zf;
   winfo.x_zoomc = x_zc;
   winfo.y_zoomc = y_zc;
   xzf = pow( 2.0, (double) -x_zf );		/* real zoom factor */
   if (x_zf > 0) xsh = 0.5 * ( 1.0 - xzf ); else xsh =0.0;
   x_c = ( winfo.dwidth - 1 ) / 2;		/* x zoom centre */
   for (xu = user.x_min; xu <= user.x_max; xu++) {
      user.xregion[xu-user.x_min].s = -1;
      user.xregion[xu-user.x_min].l = 0;
   }
   for (x = 0; x < winfo.dwidth; x++) {
      xu = winfo.record[0].x_grid[x] = misc_nint( xzf * (double) (x - x_c) + (double) x_zc + xsh );
      if (xu >= user.x_min && xu <= user.x_max) {
         if (user.xregion[xu-user.x_min].s == -1) {
            user.xregion[xu-user.x_min].s = x;
         }
         user.xregion[xu-user.x_min].l += 1;
      }
   }
   yzf = pow( 2.0, (double) -y_zf );		/* real zoom factor */
   if (y_zf > 0) ysh = 0.5 * ( 1.0 - yzf ); else ysh =0.0;
   y_c = ( winfo.dheight + 1 ) / 2;		/* y zoom centre */
   for (yu = user.y_min; yu <= user.y_max; yu++) {
      user.yregion[yu-user.y_min].s = -1;
      user.yregion[yu-user.y_min].l = 0;
   }
   for (y = 0; y < winfo.dheight; y++) {
      yu = winfo.record[0].y_grid[y] = misc_nint( yzf * (double) (y_c - y) + (double) y_zc + ysh );
      if (yu >= user.y_min && yu <= user.y_max) {
         if (user.yregion[yu-user.y_min].s == -1) {
            user.yregion[yu-user.y_min].s = y;
         }
         user.yregion[yu-user.y_min].l += 1;
      }
   }
   return( misc_show( ) );			/* return to caller */
}

int	zoom_in( int button )
{
   int	x_zf;
   int	y_zf;

   DATA_CHECK( NONE_ACTION );
   x_zf = winfo.x_zoomf + 1;
   y_zf = winfo.y_zoomf + 1;
   zoom_xy( winfo.x_zoomc, winfo.y_zoomc, x_zf, y_zf );
   return( menu[button].ret );			/* return to caller */
}

int	zoom_out( int button )
{
   int	x_zf;
   int	y_zf;

   DATA_CHECK( NONE_ACTION );
   x_zf = winfo.x_zoomf - 1;
   y_zf = winfo.y_zoomf - 1;
   zoom_xy( winfo.x_zoomc, winfo.y_zoomc, x_zf, y_zf );
   return( menu[button].ret );			/* return to caller */
}

int	zoom_reset( int button )
{
   int	x_zc;
   int	x_zf;
   int  y_zc;
   int	y_zf;

   DATA_CHECK( NONE_ACTION );
   x_zc = ( user.x_max + user.x_min ) / 2;
   x_zf = 0;
   y_zc = ( user.y_max + user.y_min ) / 2;
   y_zf = 0;
   zoom_xy( x_zc, y_zc, x_zf, y_zf );
   return( menu[button].ret );			/* return to caller */
}

int	zoom_in_x( int button )
{
   int	x_zf;
   int	y_zf;

   DATA_CHECK( NONE_ACTION );
   x_zf = winfo.x_zoomf + 1;
   y_zf = winfo.y_zoomf;
   zoom_xy( winfo.x_zoomc, winfo.y_zoomc, x_zf, y_zf );
   return( menu[button].ret );			/* return to caller */
}

int	zoom_out_x( int button )
{
   int	x_zf;
   int	y_zf;

   DATA_CHECK( NONE_ACTION );
   x_zf = winfo.x_zoomf - 1;
   y_zf = winfo.y_zoomf;
   zoom_xy( winfo.x_zoomc, winfo.y_zoomc, x_zf, y_zf );
   return( menu[button].ret );			/* return to caller */
}

int	zoom_in_y( int button )
{
   int	x_zf;
   int	y_zf;

   DATA_CHECK( NONE_ACTION );
   x_zf = winfo.x_zoomf;
   y_zf = winfo.y_zoomf + 1;
   zoom_xy( winfo.x_zoomc, winfo.y_zoomc, x_zf, y_zf );
   return( menu[button].ret );			/* return to caller */
}

int	zoom_out_y( int button )
{
   int	x_zf;
   int	y_zf;

   DATA_CHECK( NONE_ACTION );
   x_zf = winfo.x_zoomf;
   y_zf = winfo.y_zoomf - 1;
   zoom_xy( winfo.x_zoomc, winfo.y_zoomc, x_zf, y_zf );
   return( menu[button].ret );			/* return to caller */
}

int	zoom_modify( int xc, int yc, int button )
{
   int	xzc;
   int	xzf;
   int	yzc;
   int	yzf;

   DATA_CHECK( 0 );
   if (xc < 0) return( -1 );
   if (xc > (winfo.dwidth - 1)) return( -2 );
   if (yc < 0) return( -3 );
   if (yc > (winfo.dheight - 1)) return( -4 );
   xzc = winfo.record[0].x_grid[xc];
   yzc = winfo.record[0].y_grid[yc];
   xzf = winfo.x_zoomf;
   yzf = winfo.y_zoomf;
   switch( button ) {
      case Button1: {
         xzf += 1;
         yzf += 1;
         break;
      }
      case Button3: {
         xzf -= 1;
         yzf -= 1;
         break;
      }
      default: {
         break;
      }
   }
   zoom_xy( xzc, yzc, xzf, yzf );
   return( 0 );					/* return to caller */
}

int	zoom_next( int button )
{
   recording_show( 0 );
   return( menu_next( button ) );
}
#<
