[comp.sources.x] v03i075: xgraph -- graph points and functions, Part06/06

argv@island.uu.net (Dan Heller) (04/11/89)

Submitted-by: David Harrison <davidh@ic.berkeley.edu>
Posting-number: Volume 3, Issue 75
Archive-name: xgraph/part06

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./xgraph-11`
then
  mkdir ./xgraph-11
  echo "mkdir ./xgraph-11"
fi
if `test ! -s ./xgraph-11/Makefile`
then
echo "writing ./xgraph-11/Makefile"
cat > ./xgraph-11/Makefile << '\End\Of\Shar\'
#
# Makefile for the xgraph program
#
# David Harrison
# University of California,  Berkeley
# 1987
#
# NOTE: the libCreate library is a library I wrote to replace XCreate
#       and XCreateTerm with ones I think provide a better interface.
#       If you do not have this library,  you can get it from hoser.
#       If you don't want to use it,  just take it out of the LIBS
#	line below.
#

CLEVEL	=
CFLAGS	= $(CLEVEL) -Ixtb -Iux11
CC	= cc

SRC	= xgraph.c xgX.c hard_devices.c dialog.c hpgl.c new_ps.c
OBJ	= xgraph.o xgX.o hard_devices.o dialog.o hpgl.o new_ps.o

UX11	= libux11.a
XTB	= libxtb.a
LIBS	= xtb/$(XTB) ux11/$(UX11) -lX11 -lm

TARGET	= xgraph

#--------

$(TARGET):	$(OBJ) xtb_m ux11_m
		$(CC) $(CFLAGS) -o $(TARGET) $(OBJ) $(LIBS)

xg11:		$(TOBJ) xtb_m ux11_m
		$(CC) $(CFLAGS) -o xg11 $(TOBJ) $(LIBS)		

xtb_m:
		cd xtb; make CLEVEL=$(CLEVEL) $(XTB)

ux11_m:
		cd ux11; make CLEVEL=$(CLEVEL) $(UX11)

xgtest:		xgtest.o
		cc $(CFLAGS) -o xgtest xgtest.o -lm

clean:
		rm -f $(OBJ) $(TARGET) xgtest.o xgtest #* *~
		cd xtb; make clean
		cd ux11; make clean
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/Makefile"
fi
if `test ! -s ./xgraph-11/README.ANNOUNCE`
then
echo "writing ./xgraph-11/README.ANNOUNCE"
cat > ./xgraph-11/README.ANNOUNCE << '\End\Of\Shar\'

Xgraph for X11 is now available.  This program is a port of the
popular 2-dimensional plotting program orginally developed under
X10.  In almost all respects,  this program is compatible with
the older xgraph.

This program is NOT a widget.  Like its predecessor,  it is a 
stand-alone program that accepts input in a graph-like format
and plots the data on an X11 screen.  Scatter plots and a limited
form of bar graph plotting is also possible.  Zooming in on regions
of a graph is supported.  This version also includes much improved
support for generating hardcopy graphs to Postscript printers
and HPGL plotters.

The source for the program is available through anonymous ftp to
shambhala.Berkeley.EDU (128.32.132.54):

	% ftp shambhala.Berkeley.EDU
	Name: anonymous
	Password: <your login>
	ftp> cd pub
	ftp> binary
	ftp> get xgraph-11.tar.Z
	ftp> quit
	% uncompress xgraph-11.tar.Z
	% tar xf xgraph-11.tar

This will create a directory called xgraph-11.  In that directory
you will find a file called README.INSTALL that contains directions
for building the program.  The source has also been submitted to the 
moderator of comp.sources.x in shar format.

Please send all bug reports, questions, comments or suggestions to
the electronic address below.

			David Harrison
			UC Berkeley Electronics Research Lab
			(davidh@ic.Berkeley.EDU, ...!ucbvax!ucbcad!davidh)



\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/README.ANNOUNCE"
fi
if `test ! -s ./xgraph-11/README.GENERAL`
then
echo "writing ./xgraph-11/README.GENERAL"
cat > ./xgraph-11/README.GENERAL << '\End\Of\Shar\'

This directory contains source for the X11 version of xgraph,  a
two-dimensional data plotting program.  Those familar with the X10
version of this program will find that is completely compatible.
However,  there are a few important notes and changes you should
be aware of:

1. The program was developed and tested on X11 release 3 on a
   color VAXstation GPX.  It should work on most other servers
   without change but has not been tested on these other configurations.
   If you have problems,  please send a note to

	davidh@ic.Berkeley.EDU
	        or
	...!ucbvax!ucbcad!davidh

2. This version includes an improved hardcopy facility.  See the
   manual page for details about the hardcopy dialog.

3. In some cases,  xgraph uses dashed lines to distinguish different
   data sets.  Some servers are notoriously slow at rendering dashed
   lines.  Be prepared for a significantly reduced performance on
   those servers.

4. Xgraph now uses software clipping to clip data to its display
   windows.  This means you should be able to zoom in much farther
   on large data sets than was possible under the X10 version.

5. Xgraph tries to handle visuals and colormaps in a correct manner.
   However,  you may have to make changes if your window manager does
   not install colormaps for applications requesting such installations.

6. This program was constructed before the release of the ICCCM of
   February, 1989.  Since it is not a X toolkit based program,  it
   may not conform to all of the conventions laid out in that document.

7. As a follow-on to (6),  note that the operation of the program
   is heavily influenced by your choice of window managers.  Focus
   based window managers (like dxwm from Digital) will require you
   to set focus in the text input slots of the hardcopy dialog box.

8. Since xgraph has become quite popular,  those in positions of power
   have recommended I add the standard UC Berkeley copyright notice
   to this software.  See copyright.h for details.

			David Harrison
			UC Berkeley Electronics Research Lab
			(davidh@ic.Berkeley.EDU, ...!ucbvax!ucbcad!davidh)

\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/README.GENERAL"
fi
if `test ! -s ./xgraph-11/README.HARDCOPY`
then
echo "writing ./xgraph-11/README.HARDCOPY"
cat > ./xgraph-11/README.HARDCOPY << '\End\Of\Shar\'
/*
 * Hardcopy Interface for Xgraph
 *
 * Major differences from first version:
 *   Four new parameters are passed to the device initialization routine:
 *   title_family, title_size, axis_family, and axis_size.  See the 
 *   description of xg_init() for details.
 *   
 *   Clipping is done automatically by xgraph.  The xg_clip() routine
 *   is obsolete.
 *
 *   The xg_line() routine has become the xg_seg() routine.  It now
 *   draws segments rather than a series of lines.  
 * 
 *   A new field (max_segs) in the device structure now specifies 
 *   the maximum number of segments the device can handle in a group.
 */


/*
 * Adding an output device to xgraph
 *
 * Step 1
 *   Write versions of the following routines for your device:
 *   xg_init(), xg_text(), xg_seg(), xg_dot(), and xg_end().
 *   The interface and function of these routines are described
 *   in detail below.  These routines should be named according
 *   to your device.  For example,  the initialization routine
 *   for the Postscript output device is psInit().  Also,  name
 *   your source file after your device (e.g. the postscript
 *   routines are in the file ps.c).  Instructions continue
 *   after the description of the interface routines.
 */

#define D_COLOR		0x01
#define ERRBUFSIZE	2048

typedef struct xg_out {
    int dev_flags;		/* Device characteristic flags           */
    int area_w, area_h;		/* Width and height in pixels            */
    int bdr_pad;		/* Padding from border                   */
    int axis_pad;		/* Extra space around axis labels        */
    int tick_len;		/* Length of a tick mark                 */
    int legend_pad;		/* Top of legend text to legend line     */
    int axis_width;		/* Width of big character of axis font   */
    int axis_height;		/* Height of big character of axis font  */
    int title_width;		/* Width of big character of title font  */
    int title_height;		/* Height of big character of title font */
    int max_segs;		/* Maximum number of segments in group   */

    void (*xg_text)();		/* Draws text at a location              */
    void (*xg_seg)();		/* Draws a series of segments            */
    void (*xg_dot)();		/* Draws a dot or marker at a location   */
    void (*xg_end)();		/* Stops the drawing sequence            */

    char *user_state;		/* User supplied state information       */
} xgOut;


int xg_init(strm, width, height, title_family, title_size,
            axis_family, axis_size, out_info, errmsg)
FILE *strm;			/* Output stream              */
int width, height;		/* Size of space (microns)    */
char *title_family;		/* Name of title font family  */
double title_size;		/* Title font height (points) */
char *axis_family;		/* Name of axis font family   */
double axis_size;		/* Axis font height (points)  */
xgOut *out_info;		/* Device info (RETURN)       */
char errmsg[ERRBUFSIZE];	/* Error message area         */
/*
 * This routine is called by xgraph just before drawing is to
 * begin.  The desired size of the plot is given by `width'
 * and `height'.  The parameters `title_family', `title_size',
 * `axis_family', and `axis_size' specify the names of the
 * title and axis fonts and their vertical sizes (in points).
 * These parameters can be ignored if your device does not
 * support multiple fonts.  The routine should fill in all of 
 * the fields of `out_info' with appropriate values.  The values 
 * are described below:
 *  area_w, area_h:  
 * 	Size of the drawing space in device coordinates.
 *	This should take in account the requested area
 *	given by `width', and `height'.
 *  bdr_pad:  
 * 	Xgraph will leave this number of device coordinates around
 *	all of the outer edges of the graph.
 *  axis_pad: 
 *	Additional space around axis labels (in devcoords)
 *	so that the labels do not appear crowded.
 *  legend_pad:
 *	Space (in devcoords) from the top of legend text to
 *	the representative line drawn above the legend text.
 *  tick_len:    
 *	Size of a tick mark placed on axis (in devcoords)
 *  axis_width:  
 *	An estimate of the width of a large character in
 *      the axis font (in devcoords).  This can be an overestimate.  An
 *      underestimate may produce bad results.
 *  axis_height: 
 *	An estimate of the height of a large character in
 *      the axis labeling font (in devcoords).
 *  title_width, title_height:  
 *	Same as above except for the title font.
 *  max_segs:
 *	Due to buffering constraints,  some devices may not be able to
 *	handle massive segment lists.  This parameter tells xgraph not
 *	to send more than `max_segs' segments in one request.
 * Output to the device should be written to the stream `strm'.
 * The functions are described individually below.  After filling
 * in the parameters and setting the function pointers,  the routine
 * should initialize its drawing state and store any extra needed
 * information in `user_state'.  This value will be passed to all
 * other routines during the drawing sequence.  If the device
 * cannot initialize,  it should return a zero status and fill
 * `errmsg' with an informative error message.
 */

/* Text justifications */
#define T_CENTER	0
#define T_LEFT		1
#define T_UPPERLEFT	2
#define T_TOP		3
#define T_UPPERRIGHT	4
#define T_RIGHT		5
#define T_LOWERRIGHT	6
#define T_BOTTOM	7
#define T_LOWERLEFT	8

/* Text styles */
#define T_AXIS		0
#define T_TITLE		1

void xg_text(user_state, x, y, text, just, style)
char *user_state;		/* Value set in xg_init   */
int x, y;			/* Text position (pixels) */
char *text;			/* Null terminated text   */
int just;			/* Justification (above)  */
int style;			/* Text style (above)     */
/*
 * This routine should draw text at the indicated position using
 * the indicated justification and style.  The justification refers
 * to the location of the point in reference to the text.  For example,
 * if just is T_LOWERLEFT,  (x,y) should be located at the lower left
 * edge of the text string.
 */

/* Line Styles */
#define L_AXIS		0
#define L_ZERO		1
#define L_VAR		2

void xg_seg(user_state, ns, seglist, width, style, lappr, color)
char *user_state;		/* Value set in xg_init */
int ns;				/* Number of segments   */
XSegment *seglist;		/* X array of segments  */
int width;			/* Width of lines       */
int style;			/* See above            */
int lappr;			/* Line appearence      */
int color;			/* Line color (if any)  */
/*
 * This routine draws a number of line segments at the points
 * given in `seglist'.  Note that contiguous segments need not share
 * endpoints but often do.  All segments should be `width' devcoords wide
 * and drawn in style `style'.  If `style' is L_VAR,  the parameters
 * `color' and `lappr' should be used to draw the line.  Both
 * parameters vary from 0 to 7.  If the device is capable of
 * color,  `color' varies faster than `style'.  If the device 
 * has no color,  `style' will vary faster than `color' and
 * `color' can be safely ignored.  However,  if the
 * the device has more than 8 line appearences,  the two can
 * be combined to specify 64 line style variations.
 * Xgraph promises not to send more than the `max_segs' in the
 * xgOut structure passed back from xg_init().
 */

/* Marker styles */
#define P_PIXEL		0
#define P_DOT		1
#define P_MARK		2

void xg_dot(user_state, x, y, style, type, color)
char *user_state;		/* Value set in xg_init    */
int x, y;			/* Location in pixel units */
int style;			/* Dot style               */
int type;			/* Type of marker          */
int color;			/* Marker color (if any)   */
/*
 * This routine should draw a marker at location `x,y'.  If the
 * style is P_PIXEL,  the dot should be a single pixel.  If
 * the style is P_DOT,  the dot should be a reasonably large
 * dot.  If the style is P_MARK,  it should be a distinguished
 * mark which is specified by `type' (0-7).  If the output
 * device is capable of color,  the marker should be drawn in
 * `color' (0-7) which corresponds with the color for xg_line.
 */

void xg_end(user_state)
char *user_state;
/*
 * This routine is called after a drawing sequence is complete.
 * It can be used to clean up the user state and set the device
 * state appropriately.  This routine is optional in the structure.
 */

/*
 * Adding an output device to xgraph
 *
 * Step 2
 *   Edit the file hard_devices.c.  Declare your initialization
 *   function and add your device to the list of devices,
 *   hard_devices[].  The structure hard_dev is described below:
 */

typedef struct hard_dev {
    char *dev_name;		/* Device name                */
    int (*dev_init)();		/* Initialization function    */
    char *dev_spec;		/* Default pipe program       */
    char dev_file[MFNAME];	/* Default file name          */
    char dev_printer[MFNAME];	/* Default printer name       */
    double dev_max_dim;		/* Default maximum dimension (cm)    */
    char dev_title_font[MFNAME];/* Default name of title font        */
    double dev_title_size;	/* Default size of title font (pnts) */
    char dev_axis_font[MFNAME];	/* Default name of axis font         */
    double dev_axis_size;	/* Default size of axis font (pnts)  */
};

/*
 * dev_spec:
 *    The dev_spec field should be a command that directly outputs to
 *    your device.  The command should contain one %s directive that
 *    will be filled in with the name of the device from the hardcopy
 *    dialog.
 * dev_file:
 *    The default file to write output to if the user selects `To File'.
 * dev_printer:
 *    The default printer to write output to if the user selects
 *    `To Device'.
 * dev_max_dim:
 *    The default maximum dimension for the device in centimeters.
 * dev_title_font, dev_title_size:
 *    The default title font and size.  Sizes are specified in
 *    points (1/72 inch).
 * dev_axis_font, dev_axis_size:
 *    The default axis font and size.
 */

/*
 * Adding an output device to xgraph
 *
 * Step 3
 *   Edit the file Makefile.  Add your source file to the SRC variable
 *   and the corresponding object file to the OBJ variable.  Finally,
 *   remake xgraph.  Your device should now be available in the
 *   hardcopy dialog.
 */
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/README.HARDCOPY"
fi
if `test ! -s ./xgraph-11/README.INSTALL`
then
echo "writing ./xgraph-11/README.INSTALL"
cat > ./xgraph-11/README.INSTALL << '\End\Of\Shar\'

This file contains instructions for building the X11 version of xgraph.
When unpacked,  the source is distributed into three directories:

	xgraph-11	Top level source for the main program
	xgraph-11/xtb	A mini-toolbox for constructing the hardcopy dialog
	xgraph-11/ux11	A library of useful X11 programming utilities

A Makefile is provided in each directory.  Type "make" in the top level
directory to build the system.  The program assumes the machine already
has X11 libraries and include files installed in standard locations.
After a binary has been built,  you can move it to a standard location
and type "make clean" to remove object files and library archives.  The
manual page is in the file xgraph-11/xgraph.1.  This file can be moved
into standard manual page locations if desired.

A test program for xgraph is included.  To make this test program,  type
"make xgtest" in the top level directory.  Try the following command
to check out xgraph:

	% xgtest 7 -5.0 5.0 0.1 | xgraph

This should produce a graph with a series of parabolic curves.

Normally,  the program is compiled without debugging, profiling, 
or optimization flags.  You can change this by declaring the
appropriate flags in the Makefile variable CLEVEL in the top level
Makefile.

Other documentation files are included.  A summary of these
files is given below:

README.ANNOUNCE		Message submitted to comp.windows.x announcing
			the program and how to obtain it.

README.GENERAL		Important notes about differences and quirks
			of the program.

README.HARDCOPY		Documenation for writing your own hardcopy
			driver library.

README.INSTALL		This file.


			David Harrison
			UC Berkeley Electronics Research Lab
			(davidh@ic.Berkeley.EDU, ...!ucbvax!ucbcad!davidh)


\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/README.INSTALL"
fi
if `test ! -s ./xgraph-11/TAGS`
then
echo "writing ./xgraph-11/TAGS"
cat > ./xgraph-11/TAGS << '\End\Of\Shar\'

dialog.c,325
static int can_fun(129,3306
static void del_err_box(561,16026
static int df_fun(55,1154
void do_error(380,11494
static int err_func(439,12899
int getline(539,15726
void ho_dialog(320,9553
static Window make_dialog(144,3705
static Window make_err_box(453,13225
Window make_shadow(295,9010
static int ok_fun(80,1842

dummy.c,39
int hpglInit(9,116
int psInit(21,330

format.c,211
#define ERROR(10,84
cwtype *a_cwclist(63,1001
struct llist *a_llist(51,788
void c_hort(199,4047
void do_hort(127,2429
char *f_alloc(45,723
cwtype *hort(103,1917
void s_hort(161,3052
cwtype *wls(77,1267

format2.c,339
#define ERROR(7,101
void fill_widget(295,6010
static void fmt_addpos(112,1959
static char *fmt_alloc(11,184
void fmt_do(241,5081
static void fmt_hort(136,2354
void fmt_print(257,5301
static void fmt_setpos(87,1582
static void fmt_top(201,4238
static void fmt_vert(169,3299
fmt *fmt_w(17,258
fmt *hort(32,489
fmt *vert(60,1042

hard_devices.c,32
int hard_count = sizeof(18,345

hpgl.c,145
#define MAX(7,79
#define MIN(8,122
hpglClip(79,2036
hpglDot(254,7823
hpglEnd(286,8926
hpglInit(47,1111
hpglSeg(170,4598
hpglText(95,2433

ps.c,169
#define MAX(40,616
#define MIN(39,572
#define XSUCKSY(69,1339
psClip(163,4980
psDot(333,9323
psEnd(374,10356
int psInit(72,1396
psLine(266,7394
psText(180,5571

toolbox.c,823
#define STRDUP(32,827
void br_del(433,11125
int br_get(420,10813
static int br_h(347,8441
Window br_new(373,9094
void bt_del(316,7871
static void bt_draw(170,4157
int bt_get(281,7030
static int bt_h(204,4933
static void bt_line(190,4607
int bt_set(295,7318
static GC set_gc(55,1397
static int text_width(563,13940
int ti_dch(777,20362
void ti_del(807,21337
static void ti_draw(578,14289
void ti_get(700,17954
static int ti_h(616,15350
int ti_ins(747,19392
static void ti_line(602,15002
Window ti_new(654,16194
int ti_set(717,18479
void to_del(527,13227
static void to_draw(464,11660
static int to_h(477,11927
Window to_new(496,12231
Window xtb_bt_init(237,5563
int xtb_dispatch(121,2967
void xtb_init(38,946
xtb_data xtb_lookup(106,2711
void xtb_register(85,2140
int xtb_unregister(136,3359

xawdialog.c,49
make_dialog(10,175
Widget make_whichone(34,861

xawtest.c,82
void dump_core(28,540
int dump_x11(35,652
main(51,907
void push_button(43,773

xgX.c,182
static GC dotGC(132,3501
void dot_X(279,7784
void init_X(68,1829
static GC segGC(101,2592
void seg_X(231,5930
void set_X(31,641
static GC textGC(77,1987
void text_X(161,4301

xgraph.c,1320
#define ABS(48,1208
#define ADD_GRID(1761,51835
#define BWMARK(67,1647
#define COLMARK(64,1605
#define C_CODE(1905,55145
DelWindow(589,16761
int DrawData(1912,55382
int DrawGridAndAxis(1568,45569
int DrawLegend(2053,59591
DrawTitle(1460,41887
int DrawWindow(1430,41176
unsigned long GetColor(748,20444
int HandleZoom(654,18175
int InitSets(787,21408
#define LINESTYLE(58,1463
#define MARKSTYLE(61,1538
#define MAX(46,1126
#define MIN(47,1167
Window NewWindow(441,12439
#define PIXVALUE(56,1421
int ParseArgs(1112,31201
PrintWindow(610,17212
int ProcessStyle(953,26520
#define RDDBL(938,26090
#define RDFLG(929,25863
#define RDFONT(923,25640
#define RDINT(913,25326
#define RDPIX(909,25205
#define RDSTR(920,25557
#define RND(2107,61175
int ReadData(1310,37455
int ReadDefaults(981,27241
int ReversePixel(944,26305
double RoundUp(1828,53470
#define SCREENX(106,2908
#define SCREENY(108,3011
#define TRANX(647,17977
#define TRANY(650,18069
int TransformCompute(1479,42344
int WriteValue(1864,54231
static int XErrHandler(2231,64684
int argerror(1082,29670
int del_func(394,11322
void do_hardcopy(2111,61243
int hcpy_func(414,11837
if 629,17601
double initGrid(1763,51895
main(250,7518
#define nlog10(52,1313
double stepGrid(1819,53315
static char *tildeExpand(2192,63677

xgtest.c,33
double func(16,380
main(24,523
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/TAGS"
fi
if `test ! -s ./xgraph-11/copyright.h`
then
echo "writing ./xgraph-11/copyright.h"
cat > ./xgraph-11/copyright.h << '\End\Of\Shar\'
/*
 * xgraph - program to graphically display numerical data
 *
 * David Harrison
 * University of California, Berkeley
 * 1989
 *
 * Copyright (c) 1988, 1989, Regents of the University of California.
 * All rights reserved.
 *
 * Use and copying of this software and preparation of derivative works
 * based upon this software are permitted.  However, any distribution of
 * this software or derivative works must include the above copyright
 * notice.
 *
 * This software is made available AS IS, and neither the Electronics
 * Research Laboratory or the University of California make any
 * warranty about the software, its performance or its conformity to
 * any specification.
 */

#ifndef _RIGHTS_
#define _RIGHTS_

static char copyright[] = "Copyright (c) 1989, Regents of the University of California.  All rights reserved.";

#endif /* _RIGHTS_ */
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/copyright.h"
fi
if `test ! -s ./xgraph-11/dialog.c`
then
echo "writing ./xgraph-11/dialog.c"
cat > ./xgraph-11/dialog.c << '\End\Of\Shar\'
/*
 * Xgraph Dialog Boxes
 *
 * This file constructs the hardcopy and error dialog
 * boxes used by xgraph.  It uses the mini-toolbox given
 * in toolbox.c.
 */

#include "copyright.h"
#include "xgout.h"
#include "xgraph.h"
#include "hard_devices.h"
#include "xtb.h"
#include <X11/Xutil.h>

void do_error();

#define MAXCHBUF	1024

#ifdef SHADOW
#define gray_width 16
#define gray_height 16
static short gray_bits[] = {
   0x5555, 0xaaaa, 0x5555, 0xaaaa,
   0x5555, 0xaaaa, 0x5555, 0xaaaa,
   0x5555, 0xaaaa, 0x5555, 0xaaaa,
   0x5555, 0xaaaa, 0x5555, 0xaaaa};
#endif

static void make_err_box();
static void del_err_box();


#define D_VPAD	2
#define D_HPAD	2
#define D_INT	4
#define D_BRDR	2
#define D_INP	35
#define D_DSP	10
#define D_FS	10

typedef struct d_info {
    char *prog;			/* Program name              */
    xtb_data cookie;		/* Info used by do_harcopy   */
    Window choices;		/* Output device choices     */
    Window fod;			/* File or device flag       */
    Window fodspec;		/* File or device spec       */
    Window dimspec;		/* Maximum dimension spec    */
    Window tf_family;		/* Title font family spec    */
    Window tf_size;		/* Title font size spec      */
    Window af_family;		/* Axis font family spec     */
    Window af_size;		/* Axis font size spec       */
};

#define	BACKSPACE	0010
#define DELETE		0177
#define CONTROL_U	0025
#define CONTROL_X	0030

/*ARGSUSED*/
static xtb_hret df_fun(win, ch, text, val)
Window win;			/* Widget window   */
int ch;				/* Typed character */
char *text;			/* Copy of text    */
xtb_data val;			/* User info       */
/*
 * This is the handler function for the text widget for
 * specifing the file or device name.  It supports simple
 * line editing operations.
 */
{
    if ((ch == BACKSPACE) || (ch == DELETE)) {
	if (!xtb_ti_dch(win)) XBell(disp, 0);
    } else if ((ch == CONTROL_U) || (ch == CONTROL_X)) {
	(void) xtb_ti_set(win, "", (xtb_data) 0);
    } else {
	/* Insert if printable - ascii dependent */
	if ((ch < ' ') || (ch >= DELETE) || !xtb_ti_ins(win, ch)) {
	    XBell(disp, 0);
	}
    }
    return XTB_HANDLED;
}

/*ARGSUSED*/
static xtb_hret ok_fun(win, bval, info)
Window win;			/* Button window     */
int bval;			/* Button value      */
xtb_data info;			/* Local button info */
/*
 * This is the handler function for when the `Ok' button
 * is hit.  It sets the button,  does the hardcopy output,
 * and turns the button off.  It returns a status which
 * deactivates the dialog.
 */
{
    struct d_info *real_info = (struct d_info *) info;
    int val, dev_p;
    char file_or_dev[MAXCHBUF], dim_spec[MAXCHBUF], *dev_spec;
    char tfam[MAXCHBUF], afam[MAXCHBUF];
    char tsizstr[MAXCHBUF], asizstr[MAXCHBUF];
    double centimeters, tsize, asize;
    xtb_hret rtn;

    (void) xtb_bt_set(win, 1, (xtb_data) 0);
    val = xtb_br_get(real_info->choices);
    if ((val >= 0) && (val < hard_count)) {
	dev_p = xtb_br_get(real_info->fod);
	if ((dev_p == 0) || (dev_p == 1)) {
	    xtb_ti_get(real_info->fodspec, file_or_dev, (xtb_data *) 0);
	    xtb_ti_get(real_info->dimspec, dim_spec, (xtb_data *) 0);
	    if (sscanf(dim_spec, "%lf", &centimeters) == 1) {
		xtb_ti_get(real_info->tf_family, tfam, (xtb_data *) 0);
		xtb_ti_get(real_info->af_family, afam, (xtb_data *) 0);
		xtb_ti_get(real_info->tf_size, tsizstr, (xtb_data *) 0);
		if (sscanf(tsizstr, "%lf", &tsize) == 1) {
		    xtb_ti_get(real_info->af_size, asizstr, (xtb_data *) 0);
		    if (sscanf(asizstr, "%lf", &asize) == 1) {
			/* Got all the info */
			if (dev_p) {
			    dev_spec = (char *) 0;
			} else {
			    dev_spec = hard_devices[val].dev_spec;
			}
			do_hardcopy(real_info->prog, real_info->cookie,
				    hard_devices[val].dev_init, dev_spec,
				    file_or_dev, centimeters,
				    tfam, tsize, afam, asize);
			rtn = XTB_STOP;
		    } else {
			/* Bad axis size */
			do_error("Bad axis font size\n");
			rtn = XTB_HANDLED;
		    }
		} else {
		    /* Bad title size */
		    do_error("Bad title font size\n");
		    rtn = XTB_HANDLED;
		}
	    } else {
		/* Bad max dimension */
		do_error("Bad maximum dimension\n");
		rtn = XTB_HANDLED;
	    }
	} else {
	    /* Bad device spec */
	    do_error("Must specify `To File' or `To Device'\n");
	    rtn = XTB_HANDLED;
	}
    } else {
	/* Bad value spec */
	do_error("Must specify an output device\n");
	rtn = XTB_HANDLED;
    }
    (void) xtb_bt_set(win, 0, (xtb_data) 0);
    return rtn;
}

/*ARGSUSED*/
static xtb_hret can_fun(win, val, info)
Window win;			/* Button window     */
int val;			/* Button value      */
xtb_data info;			/* Local button info */
/*
 * This is the handler function for the cancel button.  It
 * turns itself on and off and then exits with a status 
 * which kills the dialog.
 */
{
    (void) xtb_bt_set(win, 1, (xtb_data) 0);
    (void) xtb_bt_set(win, 0, (xtb_data) 0);
    return XTB_STOP;
}

static xtb_hret dev_fun(win, old, new, info)
Window win;			/* Button row window */
int old;			/* Previous button   */
int new;			/* Current button    */
xtb_data info;			/* User data         */
/*
 * This routine swaps the device specific information
 * in the dialog based on what device is selected.  The
 * information passed is the information for the whole
 * dialog.
 */
{
    struct d_info *data = (struct d_info *) info;
    char text[MAXCHBUF];
    int fod_spot;

    fod_spot = xtb_br_get(data->fod);
    if ((old >= 0) && (old < hard_count)) {
	/* Save old info */
	xtb_ti_get(data->fodspec, text, (xtb_data *) 0);
	if (fod_spot == 1) {
	    strncpy(hard_devices[old].dev_file, text, MFNAME-1);
	} else if (fod_spot == 0) {
	    strncpy(hard_devices[old].dev_printer, text, MFNAME-1);
	}
	xtb_ti_get(data->dimspec, text, (xtb_data *) 0);
	if (sscanf(text, "%lf", &hard_devices[old].dev_max_dim) != 1) {
	    do_error("Warning: can't read maximum dimension");
	}
	xtb_ti_get(data->tf_family, text, (xtb_data *) 0);
	strncpy(hard_devices[old].dev_title_font, text, MFNAME-1);
	xtb_ti_get(data->tf_size, text, (xtb_data *) 0);
	if (sscanf(text, "%lf", &hard_devices[old].dev_title_size) != 1) {
	    do_error("Warning: can't read title font size");
	}
	xtb_ti_get(data->af_family, text, (xtb_data *) 0);
	strncpy(hard_devices[old].dev_axis_font, text, MFNAME-1);
	xtb_ti_get(data->af_size, text, (xtb_data *) 0);
	if (sscanf(text, "%lf", &hard_devices[old].dev_axis_size) != 1) {
	    do_error("Warning: can't read axis font size");
	}
    }
    /* Insert new info */
    if ((new >= 0) && (new < hard_count)) {
	if (fod_spot == 1) {
	    xtb_ti_set(data->fodspec, hard_devices[new].dev_file, (xtb_data) 0);
	} else if (fod_spot == 0) {
	    xtb_ti_set(data->fodspec, hard_devices[new].dev_printer,
		       (xtb_data) 0);
	} else {
	    xtb_ti_set(data->fodspec, "", (xtb_data) 0);
	}
	(void) sprintf(text, "%lg", hard_devices[new].dev_max_dim);
	xtb_ti_set(data->dimspec, text, (xtb_data) 0);
	xtb_ti_set(data->tf_family, hard_devices[new].dev_title_font,
		   (xtb_data) 0);
	(void) sprintf(text, "%lg", hard_devices[new].dev_title_size);
	xtb_ti_set(data->tf_size, text, (xtb_data) 0);
	xtb_ti_set(data->af_family, hard_devices[new].dev_axis_font,
		   (xtb_data) 0);
	(void) sprintf(text, "%lg", hard_devices[new].dev_axis_size);
	xtb_ti_set(data->af_size, text, (xtb_data) 0);
    }
    return XTB_HANDLED;
}

static xtb_hret fd_fun(win, old, new, info)
Window win;			/* Button row window */
int old;			/* Previous button   */
int new;			/* Current button    */
xtb_data info;			/* User data         */
/*
 * This routine swaps the default file or device names
 * based on the state of the file or device buttons.
 * The information passed is the information for the whole
 * dialog.
 */
{
    struct d_info *data = (struct d_info *) info;
    char text[MAXCHBUF];
    int which_one;
    
    which_one = xtb_br_get(data->choices);
    if ((which_one >= 0) && (which_one < hard_count)) {
	if (old == 0) {
	    /* Save into device space */
	    xtb_ti_get(data->fodspec, text, (xtb_data *) 0);
	    strncpy(hard_devices[which_one].dev_printer, text, MFNAME-1);
	} else if (old == 1) {
	    /* Save into file space */
	    xtb_ti_get(data->fodspec, text, (xtb_data *) 0);
	    which_one = xtb_br_get(data->choices);
	    strncpy(hard_devices[which_one].dev_file, text, MFNAME-1);
	}
	if (new == 0) {
	    /* Restore into device */
	    xtb_ti_set(data->fodspec, hard_devices[which_one].dev_printer,
		       (xtb_data *) 0);
	} else if (new == 1) {
	    xtb_ti_set(data->fodspec, hard_devices[which_one].dev_file,
		       (xtb_data *) 0);
	}
    }
    return XTB_HANDLED;
}


/* Indices for frames made in make_dialog */
enum d_frames_defn {
    TITLE_F, ODEVLBL_F, ODEVROW_F, DISPLBL_F, DISPROW_F, FDLBL_F,
    FDINP_F, OPTLBL_F, MDIMLBL_F, MDIMI_F, TFLBL_F, TFFAMLBL_F, TFFAM_F,
    TFSIZLBL_F, TFSIZ_F, AFLBL_F, AFFAMLBL_F, AFFAM_F, AFSIZLBL_F, AFSIZ_F,
    OK_F, CAN_F, BAR_F, LAST_F
} d_frames;

#define AF(ix)	af[(int) (ix)]

#define BAR_SLACK	10

static void make_dialog(win, spawned, prog, cookie, okbtn, frame)
Window win;			/* Parent window          */
Window spawned;			/* Spawned from window    */
char *prog;			/* Program name           */
xtb_data cookie;		/* Info for do_hardcopy   */
xtb_frame *okbtn;		/* Frame for OK button    */
xtb_frame *frame;		/* Returned window/size   */
/*
 * This routine constructs a new dialog for asking the user about
 * hardcopy devices.  The dialog and its size is returned in 
 * `frame'.  The window of the `ok' button is returned in `btnwin'.  
 * This can be used to reset some of the button state to reuse the dialog.
 */
{
    Window overall;
    xtb_frame AF(LAST_F);
    xtb_fmt *def, *cntrl, *mindim, *tfarea, *afarea;
    Cursor diag_cursor;
    XColor fg_color, bg_color;
    XSizeHints hints;
    unsigned long wamask;
    XSetWindowAttributes wattr;
    struct d_info *info;
    int i, found, max_width;
    char **names;
    static char *fodstrs[] = { "To Device", "To File" };

    wamask = ux11_fill_wattr(&wattr, CWBackPixel, bgPixel,
			     CWBorderPixel, bdrPixel,
			     CWOverrideRedirect, True,
			     CWSaveUnder, True,
			     CWColormap, cmap, UX11_END);
    overall = XCreateWindow(disp, win, 0, 0, 1, 1, D_BRDR,
			    depth, InputOutput, vis,
			    wamask, &wattr);
    frame->win = overall;
    frame->width = frame->height = frame->x_loc = frame->y_loc = 0;
    XStoreName(disp, overall, "Hardcopy Dialog");
    XSetTransientForHint(disp, spawned, overall);
    info = (struct d_info *) malloc(sizeof(struct d_info));
    info->prog = prog;
    info->cookie = cookie;

    /* Make all frames */
    xtb_to_new(overall, "Hardcopy Options", titleFont, &AF(TITLE_F));
    xtb_to_new(overall, "Output device:", axisFont, &AF(ODEVLBL_F));
    found = -1;
    names = (char **) malloc((unsigned) (sizeof(char *) * hard_count));
    for (i = 0;  i < hard_count;  i++) {
	names[i] = hard_devices[i].dev_name;
	if (strcmp(Odevice, names[i]) == 0) {
	    found = i;
	}
    }
    xtb_br_new(overall, hard_count, names, found,
	       dev_fun, (xtb_data) info, &AF(ODEVROW_F));
    info->choices = AF(ODEVROW_F).win;
    xtb_to_new(overall, "Disposition:", axisFont, &AF(DISPLBL_F));
    found = -1;
    for (i = 0;  i < 2;  i++) {
	if (strcmp(Odisp, fodstrs[i]) == 0) {
	    found = i;
	}
    }
    xtb_br_new(overall, 2, fodstrs, found,
	       fd_fun, (xtb_data) info, &AF(DISPROW_F));
    info->fod = AF(DISPROW_F).win;
    xtb_to_new(overall, "File or Device Name:", axisFont, &AF(FDLBL_F));
    xtb_ti_new(overall, OfileDev, D_INP, df_fun, (xtb_data) 0, &AF(FDINP_F));
    info->fodspec = AF(FDINP_F).win;
    xtb_to_new(overall, "Optional Parameters", titleFont, &AF(OPTLBL_F));
    xtb_to_new(overall, "Maximum Dimension (cm):", axisFont, &AF(MDIMLBL_F));
    xtb_ti_new(overall, "", D_DSP, df_fun, (xtb_data) 0, &AF(MDIMI_F));
    info->dimspec = AF(MDIMI_F).win;
    xtb_to_new(overall, "Title Font", axisFont, &AF(TFLBL_F));
    xtb_to_new(overall, "Family:", axisFont, &AF(TFFAMLBL_F));
    xtb_ti_new(overall, "", MFNAME, df_fun, (xtb_data) 0, &AF(TFFAM_F));
    info->tf_family = AF(TFFAM_F).win;
    xtb_to_new(overall, "Size (pnts):", axisFont, &AF(TFSIZLBL_F));
    xtb_ti_new(overall, "", D_FS, df_fun, (xtb_data) 0, &AF(TFSIZ_F));
    info->tf_size = AF(TFSIZ_F).win;
    xtb_to_new(overall, "Axis Font", axisFont, &AF(AFLBL_F));
    xtb_to_new(overall, "Family:", axisFont, &AF(AFFAMLBL_F));
    xtb_ti_new(overall, "", MFNAME, df_fun, (xtb_data) 0, &AF(AFFAM_F));
    info->af_family = AF(AFFAM_F).win;
    xtb_to_new(overall, "Size (pnts):", axisFont, &AF(AFSIZLBL_F));
    xtb_ti_new(overall, "", D_FS, df_fun, (xtb_data) 0, &AF(AFSIZ_F));
    info->af_size = AF(AFSIZ_F).win;
    xtb_bt_new(overall, "  Ok  ", ok_fun, (xtb_data) info, &AF(OK_F));
    xtb_bt_new(overall, "Cancel", can_fun, (xtb_data) 0, &AF(CAN_F));
    /* Dividing bar */
    max_width = 0;
    for (i = 0;  i < ((int) BAR_F);  i++) {
	if (AF(i).width > max_width) max_width = AF(i).width;
    }
    xtb_bk_new(overall, max_width - BAR_SLACK, 1, &AF(BAR_F));

    /* Set device specific info */
    (void) dev_fun(info->choices, -1,xtb_br_get(info->choices),(xtb_data) info);
    (void) fd_fun(info->fod, -1, xtb_br_get(info->fod), (xtb_data) info);

    /* 
     * Now place elements - could make this one expression but pcc
     * is too wimpy.
     */
    cntrl = xtb_vert(XTB_LEFT, D_VPAD, D_INT,
		     xtb_hort(XTB_CENTER, D_HPAD, D_INT,
			      xtb_w(&AF(ODEVLBL_F)),
			      xtb_w(&AF(ODEVROW_F)), NE),
		     xtb_hort(XTB_CENTER, D_HPAD, D_INT,
			      xtb_w(&AF(DISPLBL_F)),
			      xtb_w(&AF(DISPROW_F)), NE),
		     xtb_hort(XTB_CENTER, D_HPAD, D_INT,
			      xtb_w(&AF(FDLBL_F)),
			      xtb_w(&AF(FDINP_F)), NE),
		     NE);

    mindim = xtb_vert(XTB_LEFT, D_VPAD, D_INT,
		      xtb_hort(XTB_CENTER, D_HPAD, D_INT,
			       xtb_w(&AF(MDIMLBL_F)),
			       xtb_w(&AF(MDIMI_F)), NE),
		      NE);

    tfarea = xtb_vert(XTB_LEFT, D_VPAD, D_INT,
		      xtb_hort(XTB_CENTER, D_HPAD, D_INT,
			       xtb_w(&AF(TFFAMLBL_F)),
			       xtb_w(&AF(TFFAM_F)),
			       xtb_w(&AF(TFSIZLBL_F)),
			       xtb_w(&AF(TFSIZ_F)), NE),
		      NE);

    afarea = xtb_vert(XTB_LEFT, D_VPAD, D_INT,
		      xtb_hort(XTB_CENTER, D_HPAD, D_INT,
			       xtb_w(&AF(AFFAMLBL_F)),
			       xtb_w(&AF(AFFAM_F)),
			       xtb_w(&AF(AFSIZLBL_F)),
			       xtb_w(&AF(AFSIZ_F)), NE),
		      NE);

    def = xtb_fmt_do
      (xtb_vert(XTB_CENTER, D_VPAD, D_INT,
		xtb_w(&AF(TITLE_F)),
		cntrl,
		xtb_w(&AF(BAR_F)),
		xtb_w(&AF(OPTLBL_F)),
		mindim,
		xtb_w(&AF(TFLBL_F)),
		tfarea,
		xtb_w(&AF(AFLBL_F)),
		afarea,
		xtb_hort(XTB_CENTER, D_HPAD, D_INT,
			 xtb_w(&AF(OK_F)), xtb_w(&AF(CAN_F)), NE),
		NE),
       &frame->width, &frame->height);
    xtb_mv_frames(LAST_F, af);
    xtb_fmt_free(def);

    /* Make window large enough to contain the info */
    XResizeWindow(disp, overall, frame->width, frame->height);
    hints.flags = PSize;
    hints.width = frame->width;
    hints.height = frame->height;
    XSetNormalHints(disp, overall, &hints);
    diag_cursor = XCreateFontCursor(disp, XC_dotbox);
    fg_color.pixel = normPixel;
    XQueryColor(disp, cmap, &fg_color);
    bg_color.pixel = bgPixel;
    XQueryColor(disp, cmap, &bg_color);
    XRecolorCursor(disp, diag_cursor, &fg_color, &bg_color);
    XDefineCursor(disp, overall, diag_cursor);
    frame->width += (2 * D_BRDR);
    frame->height += (2 * D_BRDR);
    *okbtn = AF(OK_F);
}



#ifdef SHADOW
Window make_shadow(w, h)
int w, h;
/*
 * Makes a shadow window for a pop-up window of the specified size.
 * Needs hint work as well.  Try no background window.
 */
{
    Window shadow;
    Bitmap gray_bm;
    Pixmap gray_pm;

    gray_bm = XStoreBitmap(gray_width, gray_height, gray_bits);
    gray_pm = XMakePixmap(gray_bm, normPixel, bgPixel);
    shadow = XCreateWindow(RootWindow, 0, 0, w, h, 0, BlackPixmap, gray_pm);
    XFreePixmap(gray_pm);
    XFreeBitmap(gray_bm);
    return shadow;
}
#endif
    


#define SH_W	5
#define SH_H	5

void ho_dialog(parent, prog, cookie)
Window parent;			/* Parent window              */
char *prog;			/* Program name               */
xtb_data cookie;		/* Info passed to do_hardcopy */
/*
 * Asks the user about hardcopy devices.  A table of hardcopy
 * device names and function pointers to their initialization
 * functions is assumed to be in the global `hard_devices' and
 * `hard_count'.  Returns a non-zero status if the dialog was
 * sucessfully posted.  Calls do_hardcopy in xgraph to actually
 * output information.
 */
{
    static Window shadow, dummy;
    static xtb_frame overall = { (Window) 0, 0, 0, 0, 0 };
    static xtb_frame okbtn;
    XEvent evt;
    XWindowAttributes winInfo;
    XSizeHints hints;
    struct d_info *info;

    if (!overall.win) {
	make_dialog(RootWindow(disp, screen), parent, prog, cookie,
		    &okbtn, &overall);
#ifdef SHADOW
	shadow = make_shadow(d_w, d_h);
#endif
    } else {
	/* Change the button information */
	(void) xtb_bt_get(okbtn.win, (xtb_data *) &info);
	info->prog = prog;
	info->cookie = cookie;
    }
    XGetWindowAttributes(disp, parent, &winInfo);
    XTranslateCoordinates(disp, parent, RootWindow(disp, screen),
			  0, 0, &winInfo.x, &winInfo.y, &dummy);
    XMoveWindow(disp, overall.win,
		(int) (winInfo.x + winInfo.width/2 - overall.width/2),
		(int) (winInfo.y + winInfo.height/2 - overall.height/2));
    hints.flags = PPosition;
    hints.x = winInfo.x + winInfo.width/2 - overall.width/2;
    hints.y = winInfo.y + winInfo.height/2 - overall.height/2;
    XSetNormalHints(disp, overall.win, &hints);
#ifdef SHADOW
    XMoveWindow(disp, shadow, winInfo.x + winInfo.width/2 - d_w/2 + SH_W,
		winInfo.y + winInfo.height/2 - d_h/2 + SH_H);
    hints.flags = PPosition;
    hints.x = winInfo.x + winInfo.width/2 - d_w/2 + SH_W;
    hints.y = winInfo.y + winInfo.height/2 - d_h/2 + SH_H;
    XSetNormalHints(disp, shadow, &hints);
    XRaiseWindow(disp, shadow);
    XMapWindow(disp, shadow);
#endif
    XRaiseWindow(disp, overall.win);
    XMapWindow(disp, overall.win);
    do {
	XNextEvent(disp, &evt);
    } while (xtb_dispatch(&evt) != XTB_STOP);
    XUnmapWindow(disp, overall.win);
#ifdef SHADOW
    XUnmapWindow(disp, shadow);
#endif
}



/*ARGSUSED*/
static xtb_hret err_func(win, bval, info)
Window win;			/* Button window     */
int bval;			/* Button value      */
xtb_data info;			/* Local button info */
/*
 * Handler function for button in error box.  Simply stops dialog.
 */
{
    (void) xtb_bt_set(win, 1, (xtb_data) 0);
    (void) xtb_bt_set(win, 0, (xtb_data) 0);
    return XTB_STOP;
}


typedef struct err_info {
    Window title;
    Window contbtn;
    int num_lines;
    int alloc_lines;
    Window *lines;
};

#define E_LINES	2
#define E_VPAD	3
#define E_HPAD	3
#define E_INTER	1


static void make_err_box(text, title, frame)
char *text;			/* Error text    */
char *title;			/* Title text    */
xtb_frame *frame;		/* Returned frame */
/*
 * Makes an error box with a title.
 */
{
    XSizeHints hints;
    struct err_info *new_info;
    xtb_frame tf, cf, lf;
    char *lineptr, *line;
    int y, i;
    unsigned long wamask;
    XSetWindowAttributes wattr;

    wamask = ux11_fill_wattr(&wattr, CWBackPixel, bgPixel,
			     CWBorderPixel, bdrPixel,
			     CWOverrideRedirect, True,
			     CWSaveUnder, True,
			     CWColormap, cmap, UX11_END);
    frame->win = XCreateWindow(disp, RootWindow(disp, screen),
			       0, 0, 1, 1, D_BRDR,
			       depth, InputOutput, vis,
			       wamask, &wattr);
    frame->x_loc = frame->y_loc = frame->width = frame->height = 0;
    XStoreName(disp, frame->win, "Error Dialog");
    XSetTransientForHint(disp, RootWindow(disp, screen), frame->win);
    new_info = (struct err_info *) malloc((unsigned) sizeof(struct err_info));
    xtb_to_new(frame->win, title, titleFont, &tf);
    new_info->title = tf.win;
    if (tf.width > frame->width) frame->width = tf.width;

    xtb_bt_new(frame->win, "Continue", err_func, (xtb_data) 0, &cf);
    new_info->contbtn = cf.win;
    if (cf.width > frame->width) frame->width = cf.width;

    new_info->alloc_lines = E_LINES;
    new_info->num_lines = 0;
    new_info->lines = (Window *) malloc((unsigned) (sizeof(Window) * E_LINES));

    lineptr = text;
    while (getline(&lineptr, &line)) {
	if (new_info->num_lines >= new_info->alloc_lines) {
	    new_info->alloc_lines *= 2;
	    new_info->lines = (Window *) realloc((char *) new_info->lines,
						 (unsigned) new_info->alloc_lines);
	}
	xtb_to_new(frame->win, line, axisFont, &lf);
	new_info->lines[new_info->num_lines] = lf.win;
	new_info->num_lines += 1;
	if (lf.width > frame->width) frame->width = lf.width;
    }


    /* Placement */
    frame->width += (2 * E_HPAD);
    y = E_VPAD;
    /* Title */
    XMoveWindow(disp, new_info->title, (int) (frame->width/2 - tf.width/2), y);
    y += (tf.height + E_INTER);
    /* All lines */
    for (i = 0;  i < new_info->num_lines;  i++) {
	XMoveWindow(disp, new_info->lines[i], E_HPAD, y);
	y += (lf.height + E_INTER);
    }
    /* Button */
    XMoveWindow(disp, new_info->contbtn, (int) (frame->width/2 - cf.width/2), y);
    y += (cf.height + E_INTER);

    /* Make dialog the right size */
    y += (E_VPAD - E_INTER);
    XResizeWindow(disp, frame->win, frame->width, (unsigned int) y);
    hints.flags = PSize;
    hints.width = frame->width;
    hints.height = (unsigned int) y;
    XSetNormalHints(disp, frame->win, &hints);
    frame->width += (2 * D_BRDR);
    frame->height = y + (2 * D_BRDR);
    xtb_register(frame->win, (xtb_hret (*)()) 0, (xtb_data) new_info);
}


void do_error(err)
char *err;
/*
 * This posts a dialog that contains lines of text and a continue
 * button.  The text may be multiple lines.  The dialog is remade
 * each time.
 */
{
    Window shadow;
    XWindowAttributes info;
    XEvent evt;
    XSizeHints hints;
    xtb_frame err_frame;

    make_err_box(err, "XGraph Error", &err_frame);
#ifdef SHADOW
    shadow = make_shadow(w, h);
#endif
    XGetWindowAttributes(disp, RootWindow(disp, screen), &info);
    XMoveWindow(disp, err_frame.win, (int) (info.width/2 - err_frame.width/2),
		(int) (info.height/2 - err_frame.height/2));
    hints.flags = PPosition;
    hints.x = info.width/2 - err_frame.width/2;
    hints.y = info.height/2 - err_frame.height/2;
    XSetNormalHints(disp, err_frame.win, &hints);
#ifdef SHADOW
    XMoveWindow(disp, shadow, info.width/2 - w/2 + SH_W,
		info.height/2 - h/2 + SH_H);
    hints.flags = PPosition;
    hints.x = info.width/2 - w/2 + SH_W;
    hints.y = info.height/2 - h/2 + SH_H;
    XSetNormalHints(disp, err_frame.win, &hints);
    XRaiseWindow(disp, shadow);
    XMapWindow(disp, shadow);
#endif
    XRaiseWindow(disp, err_frame.win);
    XMapWindow(disp, err_frame.win);
    do {
	XNextEvent(disp, &evt);
    } while (xtb_dispatch(&evt) != XTB_STOP);
#ifdef SHADOW
    XDestroyWindow(disp, shadow);
#endif
    del_err_box(err_frame.win);
}


int getline(tptr, lptr)
char **tptr;
char **lptr;
/*
 * Returns next line from tptr.  The text of tptr is changed!
 */
{
    *lptr = *tptr;
    while (**tptr && (**tptr != '\n')) {
	(*tptr)++;
    }
    if (**tptr == '\n') {
	**tptr = '\0';
	(*tptr)++;
	return 1;
    } else {
	return 0;
    }
}



static void del_err_box(err)
Window err;
/*
 * Deletes all components of an error
 */
{
    struct err_info *info;
    char *dummy;
    int i;

    if (xtb_unregister(err, (xtb_data *) &info)) {
	xtb_to_del(info->title);
	xtb_bt_del(info->contbtn, (xtb_data *) &dummy);
	for (i = 0;  i < info->num_lines;  i++) {
	    xtb_to_del(info->lines[i]);
	}
	free((char *) info->lines);
	free((char *) info);
	XDestroyWindow(disp, err);
    }
}
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/dialog.c"
fi
echo "Finished archive 6 of 6"