[comp.sources.x] v08i077: chaos, Part01/10

ken@uunet.UU.NET (Ken Marks (x2425)) (08/21/90)

Submitted-by: balr!panasun!ken@uunet.UU.NET (Ken Marks (x2425))
Posting-number: Volume 8, Issue 77
Archive-name: chaos/part01

This is a network based Mandelbrot generator for X11. 
See the README and man pages for more info.

	Ken Marks  ...uunet!tellab5!balr!panasun!ken -or- ken@panasun


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 10)."
# Contents:  README MANIFEST common drone fonts gencmap headers maps
#   master widgets widgets/Canvas.c widgets/Label.c
# Wrapped by ken@panasun on Mon Jul 30 14:59:47 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1722 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XOverview
X--------
XThis code was developed on a SUN 3/60 and a SPARCstation 1 with the help of
XSaber-C which has been a blessing.  The code has been also been tested on
Xa DECstation 3100 and a SUN 386i.  The messages passed between the chaos
Xclient and the drone daemons are byte-order independent and therefore drones
Xmay be run on a variety of different machines.
X
X
XBuilding, Installing and Executing
X----------------------------------
X
X	1. From the top level type "xmkmf" to create a makefile for 
X	   the top level. (Sample makefiles are supplied for users who
X	   cannot use Imakefiles.)
X
X	2. Type "make World".
X
X	3. Watch for any errors during the build.
X
X        4. As root, type "make install".  If you want manual pages installed,
X	   also type "make install.man".
X
X	5. Read the man pages for chaos(6), drone(6), and gencmap(6).
X
X	6. Copy the contents of master/Chaos.ad to the end of your .Xdefaults
X	   file and customize as desired.
X
X	7. If you wish to run drones remotely on other hosts, add them to the
X	   access control list with xhost.  For example, to allow drones to
X	   be run on hosts "calvin" and "hobbes", type "xhost calvin hobbes".
X
X	8. Type "chaos" and have fun.
X
X
XBugs and Enhancements
X---------------------
X
XThere will undoubtedly be be some bugs remaining in the code although Saber-C
Xwas used to point out a lot of insideous bugs that would have caused me hours
Xof greif otherwise.  When bugs or portability issues arise, please send them
Xback to me so that I may include the patches in future releases of the code.
X
XAny enhancements are welcome but please direct them back to me so that I can
Xkeep a single version of the code.
X
XKen Marks	...uunet!tellab5!balr!panasun!ken  -or-  ken@panasun
END_OF_FILE
if test 1722 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(3537 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X COPYRIGHT                 10	
X Imakefile                 10	
X MANIFEST                   1	
X README                     1	
X TODO                       6	
X common                     1	
X common/Imakefile          10	
X common/byteSwap.c         10	
X common/colormap.c          7	
X common/error.c            10	
X common/file.c              8	
X common/imageIO.c           9	
X common/ipc.c               8	
X common/makefile           10	
X common/showEvent.c         2	
X drone                      1	
X drone/Imakefile           10	
X drone/doPropNotify.c       8	
X drone/drone.c              9	
X drone/drone.man           10	
X drone/init.c               9	
X drone/makefile            10	
X drone/mandelbrot.c         7	
X drone/propNotify.c         8	
X fonts                      1	
X fonts/Imakefile           10	
X fonts/chaos-bold.bdf       6	
X fonts/chaos-norm.bdf       6	
X fonts/makefile            10	
X fonts/push-norm.bdf        3	
X fonts/push-rev.bdf         4	
X gencmap                    1	
X gencmap/Imakefile          2	
X gencmap/gencmap.c          2	
X gencmap/gencmap.man        9	
X gencmap/makefile          10	
X headers                    1	
X headers/Canvas.h          10	
X headers/CanvasP.h          9	
X headers/Chaos.h           10	
X headers/Colormap.h        10	
X headers/Compound.h        10	
X headers/CompoundP.h       10	
X headers/DlgShell.h        10	
X headers/DlgShellP.h       10	
X headers/Ipc.h              9	
X headers/Label.h           10	
X headers/LabelP.h          10	
X headers/List.h            10	
X headers/ListP.h            9	
X headers/LocalDefs.h        5	
X headers/Menu.h            10	
X headers/MenuItems.h       10	
X headers/MenuP.h           10	
X headers/Palette.h         10	
X headers/PaletteP.h        10	
X headers/Push.h            10	
X headers/PushP.h           10	
X headers/Queue.h           10	
X headers/Slider.h          10	
X headers/SliderP.h          9	
X headers/Task.h            10	
X headers/Text.h            10	
X headers/TextP.h           10	
X headers/patchlevel.h       8	
X makefile                  10	
X maps                       1	
X maps/default.map           8	
X maps/gray4.map             9	
X maps/gray8.map             9	
X maps/hsb.map               9	
X maps/hsb2.map              9	
X maps/hsb3.map              9	
X maps/hsb4.map              9	
X maps/hsb8.map              9	
X maps/octo.map              9	
X maps/random.map            9	
X maps/rgb.map               9	
X maps/special.map           9	
X maps/special2.map          9	
X maps/special3.map          8	
X maps/special4.map          8	
X maps/special8.map          8	
X maps/white.map             8	
X maps/zebra.map             9	
X master                     1	
X master/Chaos.ad            8	
X master/Imakefile          10	
X master/chaos.man           7	
X master/colormapDb.c        4	
X master/droneDb.c           6	
X master/fileDb.c            7	
X master/makefile           10	
X master/master.c            3	
X master/messageDb.c         8	
X master/queue.c             8	
X master/settingsDb.c        7	
X master/task.c              8	
X widgets                    1	
X widgets/Canvas.c           1	
X widgets/Compound.c         4	
X widgets/DlgShell.c         6	
X widgets/Imakefile         10	
X widgets/Label.c            1	
X widgets/List.c             2	
X widgets/Menu.c             5	
X widgets/Palette.c          3	
X widgets/Push.c             7	
X widgets/Slider.c           5	
X widgets/Text.c             5	
X widgets/makefile          10	
END_OF_FILE
if test 3537 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test ! -d 'common' ; then
    echo shar: Creating directory \"'common'\"
    mkdir 'common'
fi
if test ! -d 'drone' ; then
    echo shar: Creating directory \"'drone'\"
    mkdir 'drone'
fi
if test ! -d 'fonts' ; then
    echo shar: Creating directory \"'fonts'\"
    mkdir 'fonts'
fi
if test ! -d 'gencmap' ; then
    echo shar: Creating directory \"'gencmap'\"
    mkdir 'gencmap'
fi
if test ! -d 'headers' ; then
    echo shar: Creating directory \"'headers'\"
    mkdir 'headers'
fi
if test ! -d 'maps' ; then
    echo shar: Creating directory \"'maps'\"
    mkdir 'maps'
fi
if test ! -d 'master' ; then
    echo shar: Creating directory \"'master'\"
    mkdir 'master'
fi
if test ! -d 'widgets' ; then
    echo shar: Creating directory \"'widgets'\"
    mkdir 'widgets'
fi
if test -f 'widgets/Canvas.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'widgets/Canvas.c'\"
else
echo shar: Extracting \"'widgets/Canvas.c'\" \(37474 characters\)
sed "s/^X//" >'widgets/Canvas.c' <<'END_OF_FILE'
X/*
X * Copyright (c) Ken W. Marks 1989, 1990.
X */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <math.h>
X#include <X11/IntrinsicP.h>
X#include <X11/StringDefs.h>
X#include <X11/XWDFile.h>
X#include <Chaos.h>
X#include <LocalDefs.h>
X#include <Ipc.h>
X#include <Menu.h>
X#include <MenuItems.h>
X#include <CanvasP.h>
X#include <Task.h>
X#include <Queue.h>
X#include <Colormap.h>
X
Xstatic Cardinal pad_amount[] = {0, 3, 2, 1};
X
X/* macro for padding a length to an even multiple of 4 (uses pad_amount[]) */
X#define PAD(length) ((length) + pad_amount[(length) & 3])
X
X#define STARTING_RADIUS		2.5
X
X#define IN_BOUNDS_X(w, x)	((int) ((x) < 0 ? 0 : \
X				(x) >= (w)->core.width ? \
X				(w)->core.width - 1 : (x)))
X
X#define IN_BOUNDS_Y(w, y)	((int) ((y) < 0 ? 0 : \
X				(y) >= (w)->core.height ? \
X				(w)->core.height - 1 : (y)))
X
X#define MAX_SAVE_IMAGE_SIZE	65536
X
X
X#define offset(field) XtOffset(CanvasWidget,canvas.field)
X#define goffset(field) XtOffset(Widget,core.field)
X
Xstatic XtResource resources[] = {
X    {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
X    goffset(width), XtRString, "512"},
X    {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
X    goffset(height), XtRString, "512"},
X};
X
X#undef offset
X#undef goffset
X
Xstatic void CanvasInitialize(), CanvasRealize(), CanvasResize();
Xstatic void CanvasRedisplay();
X
Xstatic void CanvasRegister(), CanvasUnregister(), CanvasMessage();
Xstatic void CanvasBtnDown(), CanvasBtnUp(), CanvasMotion();
Xstatic void CanvasMoveBox();
Xstatic void CanvasQuit();
Xstatic void CanvasReverse();
Xstatic void CanvasStartStop();
Xextern void MenuPopup();
X
Xstatic XtActionsRec canvas_actions[] =
X{
X    {"unregister", CanvasUnregister},
X    {"receive_msg", CanvasMessage},
X    {"press", CanvasBtnDown},
X    {"release", CanvasBtnUp},
X    {"move", CanvasMotion},
X    {"popup", MenuPopup},
X    {"quit", CanvasQuit},
X    {"reverse", CanvasReverse},
X    {"start_stop", CanvasStartStop},
X};
X
Xstatic char canvas_translations[] =
X"<Destroy>:	unregister()\n\
X <Prop>:	receive_msg()\n\
X <Btn1Down>:	press()\n\
X <Btn1Up>:	release()\n\
X <Btn1Motion>:	move()\n\
X <Btn3Down>:	popup(menu_popup.menu)\n\
X Ctrl<Key>C:	quit()\n\
X <Key>Q:	quit()\n\
X <Key>Return:	reverse()\n\
X <Key>0x20:	start_stop()\n\
X";
X
X#define superclass              (&widgetClassRec)
X
XCanvasClassRec canvasClassRec = {
X    {
X	/* core fields 		 */
X	 /* superclass		 */ (WidgetClass) superclass,
X	 /* class_name		 */ "Canvas",
X	 /* widget_size		 */ sizeof(CanvasRec),
X	 /* class_initialize	 */ NULL,
X	 /* class_part_initialize */ NULL,
X	 /* class_inited         */ FALSE,
X	 /* initialize		 */ CanvasInitialize,
X	 /* initialize_hook	 */ NULL,
X	 /* realize		 */ CanvasRealize,
X	 /* actions		 */ canvas_actions,
X	 /* num_actions		 */ XtNumber(canvas_actions),
X	 /* resources		 */ resources,
X	 /* resource_count	 */ XtNumber(resources),
X	 /* xrm_class		 */ NULL,
X	 /* compress_motion	 */ TRUE,
X	 /* compress_exposure	 */ TRUE,
X	 /* compress_enterleave	 */ TRUE,
X	 /* visible_interest	 */ FALSE,
X	 /* destroy		 */ NULL,
X	 /* resize		 */ CanvasResize,
X	 /* expose		 */ CanvasRedisplay,
X	 /* set_values		 */ NULL,
X	 /* set_values_hook	 */ NULL,
X	 /* set_values_almost	 */ XtInheritSetValuesAlmost,
X	 /* get_values_hook	 */ NULL,
X	 /* accept_focus         */ NULL,
X	 /* version		 */ XtVersion,
X	 /* callback_private	 */ NULL,
X	 /* tm_table		 */ canvas_translations,
X	 /* query_geometry       */ NULL,
X    }
X};
X
XWidgetClass canvasWidgetClass = (WidgetClass) & canvasClassRec;
X
X
X/************************************************************/
X/******************** Private Procedures ********************/
X/************************************************************/
X
X
X/*ARGSUSED*/
Xstatic void CanvasInitialize(request, new)
XWidget request;			/* unused */
XWidget new;
X{
X    CanvasWidget w = (CanvasWidget) new;
X    Screen *screen = XtScreen(w);
X    extern Boolean retain_aspect_ratio;
X    extern int iteration_limit;
X    extern int task_width;
X    extern int task_height;
X
X    w->canvas.p_inc = (double) (2 * STARTING_RADIUS) / (w->core.width - 1);
X    w->canvas.q_inc = (double) (2 * STARTING_RADIUS) / (w->core.height - 1);
X
X    w->canvas.p_inc = w->canvas.q_inc = MAX(w->canvas.p_inc, w->canvas.q_inc);
X
X    w->canvas.p_lo = (double) -(w->core.width * w->canvas.p_inc / 2);
X    w->canvas.p_hi = (double) (w->canvas.p_lo + w->canvas.p_inc *
X      (w->core.width - 1));
X
X    w->canvas.q_lo = (double) -(w->core.height * w->canvas.q_inc / 2);
X    w->canvas.q_hi = (double) (w->canvas.q_lo + w->canvas.q_inc *
X      (w->core.height - 1));
X
X    w->canvas.task_x = 0;
X    w->canvas.task_y = 0;
X    w->canvas.num_drones = 0;
X
X    w->canvas.num_colors = CellsOfScreen(screen);
X    w->canvas.pixmap = NULL;
X    w->canvas.image = NULL;
X
X    w->canvas.serial = 0;
X    w->canvas.method = MANDELBROT;
X
X    w->canvas.finished = False;
X    w->canvas.paused = False;
X    w->canvas.needs_saving = True;
X
X    /* set up the initial iteration limit */
X    w->canvas.curr_limit = iteration_limit;
X
X    /* set up the initial aspect ratio retention state */
X    w->canvas.retain_aspect_ratio = retain_aspect_ratio;
X
X    /* set size to zero to force initial change in CanvasChangeTaskSize() */
X    w->canvas.curr_task_width = 0;
X    w->canvas.curr_task_height = 0;
X
X    CanvasChangeTaskSize(new, (unsigned int) task_width,
X      (unsigned int) task_height);
X}
X
X
Xstatic void CanvasRealize(widget, valueMask, attrs)
XWidget widget;
XXtValueMask *valueMask;
XXSetWindowAttributes *attrs;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Screen *screen = XtScreen(w);
X    XtGCMask valuemask;
X    XGCValues gcv;
X    extern Colormap colormap;
X    extern Widget top_level;
X
X    /* we assign the colormap here since we know that the top level shell has
X     * been realized. */
X    colormap = CreateColormap(dpy, screen, XtWindow(top_level));
X
X    XtCreateWindow(widget, InputOutput, (Visual *) CopyFromParent,
X      *valueMask, attrs);
X
X    gcv.function = GXinvert;
X    gcv.plane_mask = 0xff;
X    valuemask = GCFunction | GCPlaneMask;
X    w->canvas.xor_gc = XtGetGC((Widget) w, valuemask, &gcv);
X
X    gcv.background = w->core.background_pixel;
X    gcv.fill_style = FillSolid;
X    valuemask = GCBackground | GCFillStyle;
X    w->canvas.normal_gc = XtGetGC((Widget) w, valuemask, &gcv);
X
X    gcv.foreground = BLACK;
X    gcv.background = WHITE;
X    gcv.fill_style = FillTiled;
X    gcv.tile = XmuCreateStippledPixmap(screen, BlackPixelOfScreen(screen),
X      WhitePixelOfScreen(screen), (unsigned) DefaultDepthOfScreen(screen));
X
X    valuemask = GCForeground | GCBackground | GCTile | GCFillStyle;
X    w->canvas.clear_gc = XtGetGC((Widget) w, valuemask, &gcv);
X
X    /* Call CanvasResize() to initialize pixmap at creation time since the
X     * CanvasRedisplay() will be called before CanvasResize() would.   */
X    (*XtClass(widget)->core_class.resize) (widget);
X}
X
X
Xstatic void CanvasResize(widget)
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Window window = XtWindow(w);
X    static unsigned int height = 0, width = 0;
X
X    if (XtIsRealized(widget) &&
X      (height != w->core.height || width != w->core.width))
X    {
X	height = w->core.height;
X	width = w->core.width;
X
X	CanvasChangeSize(widget);
X
X	MakeTasksStale();
X	WasteTasks();
X
X	if (w->canvas.pixmap)
X	    XFreePixmap(dpy, w->canvas.pixmap);
X
X	w->canvas.pixmap = XCreatePixmap(dpy, window, width, height,
X	  w->core.depth);
X	if (!w->canvas.pixmap)
X	{
X	    eprintf("Insufficient space for pixmap");
X	    abort();
X	}
X
X	XFillRectangle(dpy, w->canvas.pixmap, w->canvas.clear_gc,
X	  0, 0, width, height);
X    }
X}
X
X
X/*ARGSUSED*/
Xstatic void CanvasRedisplay(widget, event, region)
XWidget widget;
XXExposeEvent *event;
XRegion region;			/* unused */
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Window window = XtWindow(w);
X
X    /* Reset any previously drawn zoom box */
X    CanvasMoveBox(w, -1, -1, -1, -1);
X
X    if (XtIsRealized(widget) == False)
X	return;
X
X    if (event == NULL)
X	XCopyArea(dpy, w->canvas.pixmap, window, w->canvas.normal_gc,
X	  0, 0, w->core.width, w->core.height, 0, 0);
X    else
X	XCopyArea(dpy, w->canvas.pixmap, window, w->canvas.normal_gc,
X	  event->x, event->y, (unsigned) event->width,
X	  (unsigned) event->height, event->x, event->y);
X}
X
X
Xstatic void CanvasRegister(widget, resp, offset)
XWidget widget;
XRegistrationResponse *resp;
Xunsigned long *offset;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Task *task;
X    extern Widget menu;
X    extern void ByteSwapLong();
X    extern void DroneRegister();
X    char hostname[32];
X
X    /* Copy hostname before we get a chance to byteswap */
X    strcpy(hostname, resp->hostname);
X
X    if (resp->byte_order != 0x11223344)
X	ByteSwapLong((char *) resp, sizeof(RegistrationResponse));
X
X    DroneRegister(resp->window, hostname);
X
X    task = AllocTask();
X    task->window = resp->window;
X
X    if (w->canvas.finished == True || w->canvas.paused == True)
X    {
X	/* If the widget is not currently drawing, add the new drone to the
X	 * wait list. */
X	TaskNQ(waitQ, task);
X#ifdef DEBUG
X	dprintf("Enqueued new drone (window=0x%x) on wait list\n",
X	  task->window);
X#endif
X    }
X    else
X    {
X	/* If the widget is actively drawing, give the drone a task and send
X	 * it on its way. */
X	CanvasFillTask(widget, task);
X	TaskNQ(runQ, task);
X	if (SendTask(task) == False)
X	    eprintf("SendTask() failed\n");
X#ifdef DEBUG
X	dprintf("Enqueued new drone (window=0x%x) on run list\n",
X	  task->window);
X#endif
X    }
X
X    /* select for DestroyNotify events on the drone's window */
X    XSelectInput(dpy, task->window, StructureNotifyMask);
X
X    /* unstipple draw & redraw menu items when 1st drone added */
X    if (w->canvas.num_drones++ == 0)
X    {
X	(void) MenuChangeSensitivity(menu, MENU_DRAW_ITEM, True);
X	(void) MenuChangeSensitivity(menu, MENU_REDRAW_ITEM, True);
X    }
X    *offset += PAD(sizeof(RegistrationResponse));
X}
X
X
X#define CHEEZY_OPTIMIZATION
X
Xvoid CanvasImageResponse(widget, resp, offset)
XWidget widget;
XImageResponse *resp;
Xunsigned long *offset;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Window window = XtWindow(w);
X    Task *task;
X#ifdef CHEEZY_OPTIMIZATION
X    int ii;
X    char *ptr;
X#else
X    int x, y;
X#endif
X    unsigned char *value;
X    int num_colors = w->canvas.num_colors;
X    long width = resp->width;
X    long height = resp->height;
X
X    if (resp->byte_order != 0x11223344)
X    {
X#ifdef DEBUG
X	dprintf("ImageResponse\n");
X	dprintf("  byte_order:   0x%x\n", resp->byte_order);
X	dprintf("        type:   %d\n", resp->type);
X	dprintf("      serial:   %d\n", resp->serial);
X	dprintf("       width:   %d\n", resp->width);
X	dprintf("      height:   %d\n", resp->height);
X	dprintf("    max_iter:   %d\n", resp->max_iter);
X#endif
X	eprintf("Incorrect byte ordering (0x%x)\n", resp->byte_order);
X	abort();
X    }
X    if ((task = TaskDQ(runQ, (Window) NULL, resp->serial)) != NULL)
X    {
X#ifdef DEBUG
X	dprintf("Task located on the runQ\n");
X#endif
X	/* dp points past the ImageResponse header */
X	value = (unsigned char *) &resp[1];
X
X#ifdef CHEEZY_OPTIMIZATION
X	if (num_colors != 256)
X	    for (ii = height * width, value += ii; ii >= 0; --ii, --value)
X		*value %= num_colors;
X
X	if (width == w->canvas.image->width)
X	    (void) memcpy(w->canvas.image->data, (char *) value,
X	      (int) (height * width));
X	else
X	{
X	    /* narrow ImageResponse - copy line at a time */
X	    ptr = w->canvas.image->data;
X	    for (ii = height; ii > 0; --ii, value += width,
X	      ptr += w->canvas.image->width)
X		(void) memcpy(ptr, (char *) value, (int) width);
X	}
X#else
X	if (num_colors == 256)
X	    /* No need to perform modulus */
X	    for (y = 0; y < height; ++y)
X		for (x = 0; x < width; ++x)
X		    XPutPixel(w->canvas.image, x, y, *(value++));
X	else
X	    for (y = 0; y < height; ++y)
X		for (x = 0; x < width; ++x)
X		    XPutPixel(w->canvas.image, x, y, *(value++) %
X		      num_colors);
X#endif
X
X	XPutImage(dpy, w->canvas.pixmap, w->canvas.normal_gc,
X	  w->canvas.image, 0, 0, task->x, task->y, (unsigned) width,
X	  (unsigned) height);
X
X	XCopyArea(dpy, w->canvas.pixmap, window,
X	  w->canvas.normal_gc, task->x, task->y, (unsigned) width,
X	  (unsigned) height, task->x, task->y);
X
X	/* We need to save everything on the next zoom */
X	w->canvas.needs_saving = True;
X    }
X    else
X    {
X	/* Was this a stale response from a drone? */
X	if ((task = TaskDQ(staleQ, (Window) NULL, resp->serial)) == NULL)
X	{
X	    eprintf("Received bad ImageResponse\n");
X	    abort();
X	}
X#ifdef DEBUG
X	dprintf("Task located on the staleQ\n");
X#endif
X    }
X
X    if (w->canvas.finished == False && w->canvas.paused == False)
X    {
X	CanvasFillTask(widget, task);
X
X#ifdef DEBUG
X	dprintf("Sending following task to run queue:\n");
X	PrintTask(task);
X#endif
X
X	TaskNQ(runQ, task);
X	if (SendTask(task) == False)
X	    eprintf("SendTask() failed\n");
X    }
X    else
X    {
X
X#ifdef DEBUG
X	dprintf("Sending drone 0x%x to the wait queue:\n", task->window);
X#endif
X
X	TaskNQ(waitQ, task);
X    }
X    *offset += PAD(DATA_SIZE(width, height));
X}
X
X
X/***********************************************************/
X/******************** Action Procedures ********************/
X/***********************************************************/
X
X
X/*ARGSUSED*/
Xstatic void CanvasUnregister(widget, event, params, num_params)
XWidget widget;
XXEvent *event;
XString *params;			/* unused */
XCardinal *num_params;		/* unused */
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    XDestroyWindowEvent *ev = (XDestroyWindowEvent *) event;
X    Task *task;
X    extern Widget menu;
X    extern void DroneUnregister();
X
X#ifdef DEBUG
X    dprintf("Drone (window=0x%x) has terminated:\n", ev->window);
X#endif
X
X    /* update the drone control dialogbox */
X    DroneUnregister(ev->window);
X
X    /* remove task for window which was destroyed. */
X
X    if ((task = TaskDQ(runQ, ev->window, (long) NULL)) != NULL)
X    {
X	/* Window's task structure was on the run list. The task is placed on
X	 * the zombie list here for later re-assigned to a new drone */
X
X#ifdef DEBUG
X	dprintf("Task removed from run list\n");
X#endif
X
X	TaskNQ(zombieQ, task);
X    }
X    else if ((task = TaskDQ(waitQ, ev->window, (long) NULL)) != NULL)
X    {
X	/* Window's task structure was on the wait list. Since it wasn't doing
X	 * anything (but waiting) when it terminated, we can simply purge it
X	 * from our lists. */
X
X#ifdef DEBUG
X	dprintf("Task removed from wait list\n");
X#endif
X
X	FreeTask(task);
X    }
X    else if ((task = TaskDQ(staleQ, ev->window, (long) NULL)) != NULL)
X    {
X	/* Window's task structure was on the stale list. Since it was
X	 * calculating a stale task when it terminated, we can simply purge it
X	 * from our lists. */
X
X#ifdef DEBUG
X	dprintf("Task removed from stale list\n");
X#endif
X
X	FreeTask(task);
X    }
X    else
X    {
X	eprintf("Task structure for drone (window=0x%x) not found!\n",
X	  ev->window);
X	abort();
X    }
X
X    /* stipple draw and redraw menu items when last drone removed */
X    if (--w->canvas.num_drones == 0)
X    {
X	(void) MenuChangeSensitivity(menu, MENU_DRAW_ITEM, False);
X	(void) MenuChangeSensitivity(menu, MENU_REDRAW_ITEM, False);
X    }
X}
X
X
X/*ARGSUSED*/
Xstatic void CanvasMessage(widget, event, params, num_params)
XWidget widget;
XXEvent *event;
XString *params;			/* unused */
XCardinal *num_params;		/* unused */
X{
X    XPropertyEvent *ev = (XPropertyEvent *) event;
X    char *msg;
X    unsigned long msg_len;
X    unsigned long offset;
X    GenericMessage generic;
X    static int read_ahead = 0;
X
X    if (ev->atom != MAILBOX)
X    {
X	/* must have been some other property (handle as usual) */
X	return;
X    }
X
X    if (ev->state != PropertyNewValue)
X    {
X	/* generally, ignore the PropertyDelete events. they are generated by
X	 * our destructive reads  on the property and since we can't stop them
X	 * we must simply ignore them. */
X	return;
X    }
X
X    /* The counter read_ahead will become greater than zero when multiple
X     * messages are read from the property in response to a single
X     * PropertyNotify event.  By keeping track of how many messages we have
X     * "read ahead" of the events, we do not attempt to read from an empty
X     * property. */
X    if (read_ahead-- > 0)
X	return;
X
X    if (RecvMsg(&msg, &msg_len) == False)
X    {
X	eprintf("RecvMsg() failed\n");
X	return;
X    }
X
X    offset = 0;
X    do
X    {
X	(void) memcpy((char *) &generic, &msg[offset], sizeof(GenericMessage));
X	if (generic.byte_order != 0x11223344)
X	    ByteSwapLong((char *) &generic, 2 * sizeof(long));
X
X	if (generic.type == REGISTRATION_RESPONSE)
X	    CanvasRegister(widget, (RegistrationResponse *) & msg[offset],
X	      &offset);
X	else if (generic.type == IMAGE_RESPONSE)
X	    CanvasImageResponse(widget, (ImageResponse *) & msg[offset],
X	      &offset);
X	else
X	{
X	    eprintf("Unknown message type: %d\n", generic.type);
X	    abort();
X	}
X	++read_ahead;
X    } while (offset < msg_len);
X    free(msg);
X}
X
X
Xstatic void CanvasMoveBox(w, x1, y1, x2, y2)
XCanvasWidget w;
Xint x1, y1;
Xint x2, y2;
X{
X    Display *dpy = XtDisplay(w);
X    Window window = XtWindow(w);
X    static int last_x1 = -1, last_y1 = -1;
X    static int last_x2 = -1, last_y2 = -1;
X    static Boolean prev_box = False;
X    int tmp;
X
X    if (x1 == last_x1 && y1 == last_y1 && x2 == last_x2 && y2 == last_y2)
X	return;
X
X    if (prev_box)
X	XDrawRectangle(dpy, window, w->canvas.xor_gc, last_x1, last_y1,
X	  (unsigned) (last_x2 - last_x1), (unsigned) (last_y2 - last_y1));
X
X    /* Make sure x1 < x2 */
X    if (x1 > x2)
X    {
X	tmp = x1;
X	x1 = x2;
X	x2 = tmp;
X    }
X
X    /* Make sure y1 < y2 */
X    if (y1 > y2)
X    {
X	tmp = y1;
X	y1 = y2;
X	y2 = tmp;
X    }
X
X    last_x1 = x1;
X    last_y1 = y1;
X    last_x2 = x2;
X    last_y2 = y2;
X
X    if (x1 != x2 && y1 != y2)
X    {
X	XDrawRectangle(dpy, window, w->canvas.xor_gc, x1, y1,
X	  (unsigned) (x2 - x1), (unsigned) (y2 - y1));
X	prev_box = True;
X    }
X    else
X    {
X	prev_box = False;
X    }
X}
X
X
X/*ARGSUSED*/
Xstatic void CanvasBtnDown(widget, event, params, num_params)
XWidget widget;
XXEvent *event;
XString *params;			/* unused */
XCardinal *num_params;		/* unused */
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    XButtonEvent *ev = (XButtonEvent *) & event->xbutton;
X
X
X    w->canvas.x_from = ev->x;
X    w->canvas.y_from = ev->y;
X
X    CanvasMoveBox(w, w->canvas.x_from, w->canvas.y_from,
X      w->canvas.x_from, w->canvas.y_from);
X}
X
X
X/*ARGSUSED*/
Xstatic void CanvasBtnUp(widget, event, params, num_params)
XWidget widget;
XXEvent *event;
XString *params;			/* unused */
XCardinal *num_params;		/* unused */
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    XButtonEvent *ev = (XButtonEvent *) & event->xbutton;
X    int tmp;
X    extern Widget menu;
X
X    w->canvas.x_to = IN_BOUNDS_X(w, ev->x);
X    w->canvas.y_to = IN_BOUNDS_Y(w, ev->y);
X    CanvasMoveBox(w, w->canvas.x_from, w->canvas.y_from, w->canvas.x_to,
X      w->canvas.y_to);
X
X    /* Make sure the final points are in "proper" order */
X
X    /* Make sure w->canvas.x_from < w->canvas.x_to */
X    if (w->canvas.x_from > w->canvas.x_to)
X    {
X	tmp = w->canvas.x_from;
X	w->canvas.x_from = w->canvas.x_to;
X	w->canvas.x_to = tmp;
X    }
X
X    /* Make sure w->canvas.y_from < w->canvas.y_to */
X    if (w->canvas.y_from > w->canvas.y_to)
X    {
X	tmp = w->canvas.y_from;
X	w->canvas.y_from = w->canvas.y_to;
X	w->canvas.y_to = tmp;
X    }
X
X    /* stipple zoom menu item if NULL zoom range */
X    if (w->canvas.y_from == w->canvas.y_to
X      && w->canvas.x_from == w->canvas.x_to)
X	(void) MenuChangeSensitivity(menu, MENU_ZOOM_ITEM, False);
X    else
X	(void) MenuChangeSensitivity(menu, MENU_ZOOM_ITEM, True);
X}
X
X
X/*ARGSUSED*/
Xstatic void CanvasMotion(widget, event, params, num_params)
XWidget widget;
XXEvent *event;
XString *params;			/* unused */
XCardinal *num_params;		/* unused */
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    XMotionEvent *ev = (XMotionEvent *) & event->xmotion;
X
X    CanvasMoveBox(w, w->canvas.x_from, w->canvas.y_from, IN_BOUNDS_X(w, ev->x),
X      IN_BOUNDS_Y(w, ev->y));
X}
X
X
X/*ARGSUSED*/
Xstatic void CanvasQuit(widget, event, params, num_params)
XWidget widget;			/* unused */
XXEvent *event;			/* unused */
XString *params;			/* unused */
XCardinal *num_params;		/* unused */
X{
X    extern void CleanupAndDie();
X
X    CleanupAndDie();
X}
X
X
X/*ARGSUSED*/
Xstatic void CanvasReverse(widget, event, params, num_params)
XWidget widget;			/* unused */
XXEvent *event;			/* unused */
XString *params;			/* unused */
XCardinal *num_params;		/* unused */
X{
X    extern Widget colormap_dialogbox;
X    extern Rotation rotation_dir;
X
X    if (rotation_dir == forward)
X	rotation_dir = backward;
X    else
X	rotation_dir = forward;
X}
X
X
X/*ARGSUSED*/
Xstatic void CanvasStartStop(widget, event, params, num_params)
XWidget widget;			/* unused */
XXEvent *event;			/* unused */
XString *params;			/* unused */
XCardinal *num_params;		/* unused */
X{
X    extern Boolean rotating;
X
X    rotating = !rotating;
X}
X
X
X/***********************************************************/
X/******************** Public Procedures ********************/
X/***********************************************************/
X
X
Xvoid CanvasClear(widget)
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Window window = XtWindow(w);
X    extern int iteration_limit;
X    extern int task_width;
X    extern int task_height;
X
X    /* Reset any previously drawn zoom box */
X    CanvasMoveBox(w, -1, -1, -1, -1);
X
X    w->canvas.task_x = 0;
X    w->canvas.task_y = 0;
X    w->canvas.finished = False;
X    w->canvas.paused = False;
X
X    /* New iteration limit should now be observed */
X    w->canvas.curr_limit = iteration_limit;
X
X    /* Check and see if a new task size should now be observed */
X    CanvasChangeTaskSize(widget, (unsigned int) task_width,
X      (unsigned int) task_height);
X
X    XFillRectangle(dpy, w->canvas.pixmap, w->canvas.clear_gc,
X      0, 0, w->core.width, w->core.height);
X
X    XCopyArea(dpy, w->canvas.pixmap, window, w->canvas.normal_gc,
X      0, 0, w->core.width, w->core.height, 0, 0);
X}
X
X
Xvoid CanvasZoom(widget)
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    double p_mid, q_mid;
X    double x_zoom, y_zoom;
X    int x_avg, y_avg;
X    int width;
X    int height;
X
X#ifdef DEBUG
X    dprintf("p_lo=%.10G p_hi=%.10G p_inc=%.10G\n",
X      w->canvas.p_lo, w->canvas.p_hi, w->canvas.p_inc);
X
X    dprintf("q_lo=%.10G q_hi=%.10G q_inc=%.10G\n",
X      w->canvas.q_lo, w->canvas.q_hi, w->canvas.q_inc);
X#endif
X
X    x_avg = (w->canvas.x_from + w->canvas.x_to) / 2;
X    y_avg = (w->canvas.y_from + w->canvas.y_to) / 2;
X
X    p_mid = w->canvas.p_lo + w->canvas.p_inc * x_avg;
X    q_mid = w->canvas.q_lo + w->canvas.q_inc * y_avg;
X
X    width = w->canvas.x_to - w->canvas.x_from;
X    height = w->canvas.y_to - w->canvas.y_from;
X
X    x_zoom = (double) w->core.width / width;
X    y_zoom = (double) w->core.height / height;
X
X    if (w->canvas.retain_aspect_ratio)
X	x_zoom = y_zoom = MIN(x_zoom, y_zoom);
X
X    w->canvas.p_inc /= x_zoom;
X    w->canvas.q_inc /= y_zoom;
X
X    w->canvas.p_lo = p_mid - w->canvas.p_inc * w->core.width / 2;
X    w->canvas.q_lo = q_mid - w->canvas.q_inc * w->core.height / 2;
X
X    w->canvas.p_hi = w->canvas.p_lo + w->canvas.p_inc * (w->core.width - 1);
X    w->canvas.q_hi = w->canvas.q_lo + w->canvas.q_inc * (w->core.height - 1);
X
X#ifdef DEBUG
X    dprintf("p_lo=%.10G p_hi=%.10G p_inc=%.10G\n",
X      w->canvas.p_lo, w->canvas.p_hi, w->canvas.p_inc);
X
X    dprintf("q_lo=%.10G q_hi=%.10G q_inc=%.10G\n",
X      w->canvas.q_lo, w->canvas.q_hi, w->canvas.q_inc);
X#endif
X}
X
X
Xvoid CanvasChangeSize(widget)
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    double p_mid, q_mid;
X
X#ifdef DEBUG
X    dprintf("p_lo=%.10G p_hi=%.10G p_inc=%.10G\n",
X      w->canvas.p_lo, w->canvas.p_hi, w->canvas.p_inc);
X
X    dprintf("q_lo=%.10G q_hi=%.10G q_inc=%.10G\n",
X      w->canvas.q_lo, w->canvas.q_hi, w->canvas.q_inc);
X#endif
X
X    p_mid = (w->canvas.p_hi + w->canvas.p_lo) / 2;
X    q_mid = (w->canvas.q_hi + w->canvas.q_lo) / 2;
X
X    w->canvas.p_inc = (double) (w->canvas.p_hi - w->canvas.p_lo) /
X      (w->core.width - 1);
X    w->canvas.q_inc = (double) (w->canvas.q_hi - w->canvas.q_lo) /
X      (w->core.height - 1);
X
X    if (w->canvas.retain_aspect_ratio)
X	w->canvas.p_inc = w->canvas.q_inc =
X	  MAX(w->canvas.p_inc, w->canvas.q_inc);
X
X    w->canvas.p_lo = p_mid - w->canvas.p_inc * w->core.width / 2;
X    w->canvas.q_lo = q_mid - w->canvas.q_inc * w->core.height / 2;
X
X    w->canvas.p_hi = w->canvas.p_lo + w->canvas.p_inc * (w->core.width - 1);
X    w->canvas.q_hi = w->canvas.q_lo + w->canvas.q_inc * (w->core.height - 1);
X
X#ifdef DEBUG
X    dprintf("p_lo=%.10G p_hi=%.10G p_inc=%.10G\n",
X      w->canvas.p_lo, w->canvas.p_hi, w->canvas.p_inc);
X
X    dprintf("q_lo=%.10G q_hi=%.10G q_inc=%.10G\n",
X      w->canvas.q_lo, w->canvas.q_hi, w->canvas.q_inc);
X#endif
X
X    w->canvas.task_x = 0;
X    w->canvas.task_y = 0;
X    w->canvas.finished = True;
X}
X
X
Xvoid CanvasFillTask(widget, task)
XWidget widget;
XTask *task;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Task *unfinished;
X    Task *zombie;
X    Window saved_window;
X    extern int task_width;
X    extern int task_height;
X
X    /* We need to save everything on the next zoom */
X    w->canvas.needs_saving = True;
X
X    /* Check first to see if any unfinished task should be completed */
X    if ((unfinished = TaskDQ(unfinishedQ, (Window) NULL, (long) NULL)) != NULL)
X    {
X	/* save the window from the task structure */
X	saved_window = task->window;
X
X	/* copy in the info from the unfinished task */
X	(void) memcpy((char *) task, (char *) unfinished, sizeof(Task));
X
X	/* restore original window to task */
X	task->window = saved_window;
X
X	/* don't need this task anymore */
X	FreeTask(unfinished);
X	return;
X    }
X
X    /* Check next to see if any zombie task should be rejuvinated */
X    if ((zombie = TaskDQ(zombieQ, (Window) NULL, (long) NULL)) != NULL)
X    {
X	/* save the window from the task structure */
X	saved_window = task->window;
X
X	/* copy in the info from the zombie task */
X	(void) memcpy((char *) task, (char *) zombie, sizeof(Task));
X
X	/* restore original window to task */
X	task->window = saved_window;
X
X	/* R.I.P. ex-zombie */
X	FreeTask(zombie);
X	return;
X    }
X
X    /* Otherwise, fill in the info for the next task... */
X
X    task->serial = ++(w->canvas.serial);
X    task->limit = w->canvas.curr_limit;
X    task->method = w->canvas.method;
X
X    /* If we are at the start of the canvas, check to see if we should update
X     * the current task width and height. */
X    if (w->canvas.task_x == 0 && w->canvas.task_y == 0)
X	CanvasChangeTaskSize(widget, (unsigned int) task_width,
X	  (unsigned int) task_height);
X
X    task->width = MIN(w->canvas.curr_task_width, w->core.width -
X      w->canvas.task_x);
X    task->height = MIN(w->canvas.curr_task_height, w->core.height -
X      w->canvas.task_y);
X
X    task->x = w->canvas.task_x;
X    task->y = w->canvas.task_y;
X    task->p_lo = w->canvas.p_lo + task->x * w->canvas.p_inc;
X    task->p_hi = task->p_lo + (task->width - 1) * w->canvas.p_inc;
X    task->q_lo = w->canvas.q_lo + task->y * w->canvas.q_inc;
X    task->q_hi = task->q_lo + (task->height - 1) * w->canvas.q_inc;
X
X    w->canvas.finished = False;
X
X    w->canvas.task_x += w->canvas.curr_task_width;
X    if (w->canvas.task_x >= w->core.width)
X    {
X	w->canvas.task_x = 0;
X	w->canvas.task_y += w->canvas.curr_task_height;
X	if (w->canvas.task_y >= w->core.height)
X	{
X	    /* Reset for next drawing session */
X	    w->canvas.task_x = 0;
X	    w->canvas.task_y = 0;
X	    w->canvas.finished = True;
X	}
X    }
X}
X
X
Xvoid CanvasChangeTaskSize(widget, width, height)
XWidget widget;
Xunsigned int width;
Xunsigned int height;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Screen *screen = XtScreen(w);
X
X    /* no need to update if nothing changed */
X    if (w->canvas.curr_task_width == width &&
X      w->canvas.curr_task_height == height)
X	return;
X
X    if (w->canvas.image)
X	XDestroyImage(w->canvas.image);
X
X    w->canvas.image = XCreateImage(dpy, DefaultVisualOfScreen(screen),
X      DefaultDepthOfScreen(screen), ZPixmap, 0, malloc(width * height),
X      width, height, 8, 0);
X
X    w->canvas.curr_task_width = width;
X    w->canvas.curr_task_height = height;
X}
X
X
Xvoid CanvasChangeRetainAspect(widget)
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X
X    w->canvas.retain_aspect_ratio = !w->canvas.retain_aspect_ratio;
X}
X
X
Xvoid CanvasUnpause(widget)
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X
X    w->canvas.paused = False;
X}
X
X
Xvoid CanvasTouchCanvas(widget)
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X
X    w->canvas.needs_saving = TRUE;
X}
X
X
XBoolean CanvasNeedsSaving(widget)
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X
X    return (w->canvas.needs_saving);
X}
X
X
XBoolean CanvasSaveImage(fd, widget)
Xint fd;
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    XImage *image;
X    int image_height, image_width;
X    int curr_y = 0;
X    XWindowAttributes win_attrib;
X    XWDFileHeader header;
X    XColor *colors;
X    char *name = "Chaos-Image";
X    int name_len = strlen(name) + 1;
X    unsigned long swap_test = 1;
X    Boolean header_written = False;
X    int ii;
X    extern void ByteSwapShort();
X    extern void ByteSwapLong();
X
X    image_width = w->core.width;
X    image_height = MAX_SAVE_IMAGE_SIZE / image_width;
X    image_height = MIN(image_height, w->core.height);
X
X    if (!XGetWindowAttributes(dpy, XtWindow(w), &win_attrib))
X    {
X	eprintf("CanvasSaveImage: cannot get attributes\n");
X	return (False);
X    }
X
X    while (curr_y < w->core.height)
X    {
X	image = XGetImage(dpy, w->canvas.pixmap, 0, curr_y, image_width,
X	  image_height, AllPlanes, ZPixmap);
X
X	if (header_written == False)
X	{
X	    header_written = True;
X	    colors = GetColors(w->canvas.num_colors);
X
X	    header.header_size = (CARD32) sizeof(header) + name_len;
X	    header.file_version = (CARD32) XWD_FILE_VERSION;
X	    header.pixmap_format = (CARD32) ZPixmap;
X	    header.pixmap_depth = (CARD32) image->depth;
X	    header.pixmap_width = (CARD32) w->core.width;
X	    header.pixmap_height = (CARD32) w->core.height;
X	    header.xoffset = (CARD32) image->xoffset;
X	    header.byte_order = (CARD32) image->byte_order;
X	    header.bitmap_unit = (CARD32) image->bitmap_unit;
X	    header.bitmap_bit_order = (CARD32) image->bitmap_bit_order;
X	    header.bitmap_pad = (CARD32) image->bitmap_pad;
X	    header.bits_per_pixel = (CARD32) image->bits_per_pixel;
X	    header.bytes_per_line = (CARD32) image->bytes_per_line;
X	    header.visual_class = (CARD32) win_attrib.visual->class;
X	    header.red_mask = (CARD32) win_attrib.visual->red_mask;
X	    header.green_mask = (CARD32) win_attrib.visual->green_mask;
X	    header.blue_mask = (CARD32) win_attrib.visual->blue_mask;
X	    header.bits_per_rgb = (CARD32) win_attrib.visual->bits_per_rgb;
X	    header.colormap_entries = (CARD32) win_attrib.visual->map_entries;
X	    header.ncolors = w->canvas.num_colors;
X	    header.window_width = (CARD32) win_attrib.width;
X	    header.window_height = (CARD32) win_attrib.height;
X	    header.window_x = 0;
X	    header.window_y = 0;
X	    header.window_bdrwidth = (CARD32) win_attrib.border_width;
X
X	    if (*(char *) &swap_test)
X	    {
X		ByteSwapLong((char *) &header, sizeof(XWDFileHeader));
X		for (ii = 0; ii < w->canvas.num_colors; ++ii)
X		{
X		    ByteSwapLong((char *) &colors[ii].pixel, sizeof(long));
X		    ByteSwapShort((char *) &colors[ii].red,
X		      3 * sizeof(short));
X		}
X	    }
X
X	    (void) write(fd, (char *) &header, sizeof(XWDFileHeader));
X	    (void) write(fd, name, name_len);
X	    (void) write(fd, (char *) colors, sizeof(XColor) *
X	      w->canvas.num_colors);
X	    free((char *) colors);
X	}
X	(void) write(fd, image->data, image->bytes_per_line * image->height);
X	XDestroyImage(image);
X	curr_y += image_height;
X	if (curr_y + image_height > w->core.height)
X	    image_height = w->core.height - curr_y;
X    }
X    return (True);
X}
X
X
XBoolean CanvasLoadImage(fd, widget)
Xint fd;
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Screen *screen = XtScreen(w);
X    XImage *image;
X    char *image_data;
X    XWDFileHeader header;
X    XColor *colors;
X    XSizeHints hints;
X    unsigned int image_height, image_width, image_size;
X    int curr_y = 0;
X    int ii;
X    unsigned long swap_test = 1;
X    extern Colormap colormap;
X    extern Widget top_level;
X    extern void ColormapResetControls();
X    Boolean resized = False;
X    extern long lseek();
X
X    (void) read(fd, (char *) &header, sizeof(XWDFileHeader));
X
X    if (*(char *) &swap_test)
X	ByteSwapLong((char *) &header, sizeof(XWDFileHeader));
X
X    /* skip past name (at end of header) */
X    (void) lseek(fd, (long) header.header_size, 0);
X
X    colors = (XColor *) malloc((unsigned) (sizeof(XColor) * header.ncolors));
X    (void) read(fd, (char *) colors, (int) (sizeof(XColor) * header.ncolors));
X
X    if (*(char *) &swap_test)
X	for (ii = 0; ii < header.ncolors; ++ii)
X	{
X	    ByteSwapLong((char *) &colors[ii].pixel, sizeof(long));
X	    ByteSwapShort((char *) &colors[ii].red, 3 * sizeof(short));
X	}
X
X    PutColors(colors, (int) header.ncolors);
X    StoreColormap(dpy, colormap);
X    (void) free((char *) colors);
X
X    /* since a new colormap has been loaded, remove the text from the colormap
X     * dialogbox text input field and reset listbox. */
X    ColormapResetControls();
X
X    if (header.pixmap_width != w->core.width ||
X      header.pixmap_height != w->core.height)
X    {
X	/* We need to resize the before we can load in the image */
X	hints.width = header.pixmap_width;
X	hints.height = header.pixmap_height;
X	hints.flags = USSize;
X
X	XSetNormalHints(dpy, XtWindow(top_level), &hints);
X
X	XtConfigureWidget(top_level, top_level->core.x, top_level->core.y,
X	  header.pixmap_width, header.pixmap_height,
X	  top_level->core.border_width);
X
X	resized = True;
X    }
X
X    image_width = header.pixmap_width;
X    image_height = MAX_SAVE_IMAGE_SIZE / image_width;
X    image_height = MIN(image_height, header.pixmap_height);
X    image_size = PAD(image_width) * image_height;
X
X    if ((image_data = malloc(image_size)) == NULL)
X    {
X	eprintf("Cannot malloc %d bytes\n", image_size);
X	return (False);
X    }
X
X    image = XCreateImage(dpy, DefaultVisualOfScreen(screen),
X      DefaultDepthOfScreen(screen), ZPixmap, 0, image_data,
X      image_width, image_height, 32, 0);
X
X    while (curr_y < w->core.height)
X    {
X	if (read(fd, image->data, image->bytes_per_line * image->height) < 0)
X	{
X	    XDestroyImage(image);
X	    return (False);
X	}
X
X	XPutImage(dpy, w->canvas.pixmap, w->canvas.normal_gc, image,
X	  0, 0, 0, curr_y, image_width, image_height);
X
X	curr_y += image_height;
X	if (curr_y + image_height > w->core.height)
X	    image->height = w->core.height - curr_y;
X    }
X    XDestroyImage(image);
X
X    if (resized == False)
X	/* slap the new pixmap up on the screen */
X	CanvasRedisplay(widget, (XExposeEvent *) NULL, (Region) NULL);
X
X    return (True);
X}
X
X
XBoolean CanvasSaveState(fd, widget)
Xint fd;
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    CanvasSaveStateStruct package;
X    unsigned long swap_test = 1;
X
X    package.width = (long) w->core.width;
X    package.height = (long) w->core.height;
X    package.task_x = (long) w->canvas.task_x;
X    package.task_y = (long) w->canvas.task_y;
X    package.limit = (long) w->canvas.curr_limit;
X    package.finished = (long) w->canvas.finished;
X    package.curr_task_width = (long) w->canvas.curr_task_width;
X    package.curr_task_height = (long) w->canvas.curr_task_height;
X
X    /* do the necessary swapping before laying in the strings */
X    if (*(char *) &swap_test)
X	ByteSwapLong((char *) &package, sizeof(CanvasSaveStateStruct));
X
X    (void) sprintf(package.p_lo, "%.20G", w->canvas.p_lo);
X    (void) sprintf(package.p_hi, "%.20G", w->canvas.p_hi);
X    (void) sprintf(package.q_lo, "%.20G", w->canvas.q_lo);
X    (void) sprintf(package.q_hi, "%.20G", w->canvas.q_hi);
X    (void) sprintf(package.p_inc, "%.20G", w->canvas.p_inc);
X    (void) sprintf(package.q_inc, "%.20G", w->canvas.q_inc);
X
X    (void) write(fd, (char *) &package, sizeof(CanvasSaveStateStruct));
X    return (True);
X}
X
X
XBoolean CanvasLoadState(fd, widget)
Xint fd;
XWidget widget;
X{
X    CanvasWidget w = (CanvasWidget) widget;
X    CanvasSaveStateStruct package;
X    unsigned long swap_test = 1;
X    extern void SettingsSetLimit();
X
X    (void) read(fd, (char *) &package, sizeof(CanvasSaveStateStruct));
X
X    /* grab the strings before doing the necessary swapping */
X    w->canvas.p_lo = atof(package.p_lo);
X    w->canvas.p_hi = atof(package.p_hi);
X    w->canvas.q_lo = atof(package.q_lo);
X    w->canvas.q_hi = atof(package.q_hi);
X    w->canvas.p_inc = atof(package.p_inc);
X    w->canvas.q_inc = atof(package.q_inc);
X
X    if (*(char *) &swap_test)
X	ByteSwapLong((char *) &package, sizeof(CanvasSaveStateStruct));
X
X    w->core.width = (Dimension) package.width;
X    w->core.height = (Dimension) package.height;
X    w->canvas.task_x = (short) package.task_x;
X    w->canvas.task_y = (short) package.task_y;
X    w->canvas.curr_limit = (short) package.limit;
X    w->canvas.finished = (Boolean) package.finished;
X
X    /* We don't need to save everything again unless we change something */
X    w->canvas.needs_saving = False;
X
X    /* Pause until told to restart drawing */
X    w->canvas.paused = True;
X
X    /* Update the current limit in the settings dialogbox */
X    SettingsSetLimit((int) package.limit);
X
X    CanvasChangeTaskSize(widget, (unsigned int) package.curr_task_width,
X      (unsigned int) package.curr_task_height);
X
X    return (True);
X}
END_OF_FILE
if test 37474 -ne `wc -c <'widgets/Canvas.c'`; then
    echo shar: \"'widgets/Canvas.c'\" unpacked with wrong size!
fi
# end of 'widgets/Canvas.c'
fi
if test -f 'widgets/Label.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'widgets/Label.c'\"
else
echo shar: Extracting \"'widgets/Label.c'\" \(6500 characters\)
sed "s/^X//" >'widgets/Label.c' <<'END_OF_FILE'
X/*
X * Copyright (c) Ken W. Marks 1989, 1990.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <X11/IntrinsicP.h>
X#include <X11/StringDefs.h>
X#include <Chaos.h>
X#include <LocalDefs.h>
X#include <LabelP.h>
X
X#define LABEL_ALLOC_COUNT	10
X
Xstatic void LabelInitialize();
Xstatic void LabelRedisplay();
Xstatic void LabelDestroy();
X
X#define offset(field) XtOffset(LabelWidget, field)
X
Xstatic XtResource resources[] = {
X    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
X    offset(label.foreground), XtRString, "XtDefaultForeground"},
X    {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
X    offset(label.font), XtRString, "chaos-bold"},
X    {XtNlabel, XtCLabel, XtRString, sizeof(String),
X    offset(label.label), XtRString, NULL},
X    {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension),
X    offset(label.internal_width), XtRImmediate, (caddr_t) 4},
X    {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
X    offset(label.internal_height), XtRImmediate, (caddr_t) 2},
X};
X
X#define superclass		(&simpleClassRec)
X
XLabelClassRec labelClassRec = {
X    {
X	/* core_class fields */
X	 /* superclass	  	 */ (WidgetClass) superclass,
X	 /* class_name	  	 */ "Label",
X	 /* widget_size	  	 */ sizeof(LabelRec),
X	 /* class_initialize   	 */ NULL,
X	 /* class_part_initialize */ NULL,
X	 /* class_inited       	 */ FALSE,
X	 /* initialize	  	 */ LabelInitialize,
X	 /* initialize_hoo	 */ NULL,
X	 /* realize	  	 */ XtInheritRealize,
X	 /* actions	  	 */ NULL,
X	 /* num_actions	  	 */ 0,
X	 /* resources	  	 */ resources,
X	 /* num_resources	 */ XtNumber(resources),
X	 /* xrm_class	  	 */ NULLQUARK,
X	 /* compress_motion	 */ TRUE,
X	 /* compress_exposure  	 */ TRUE,
X	 /* compress_enterleave	 */ TRUE,
X	 /* visible_interest	 */ FALSE,
X	 /* destroy		 */ LabelDestroy,
X	 /* resize		 */ NULL,
X	 /* expose		 */ LabelRedisplay,
X	 /* set_values	  	 */ NULL,
X	 /* set_values_hook	 */ NULL,
X	 /* set_values_almost	 */ XtInheritSetValuesAlmost,
X	 /* get_values_hook	 */ NULL,
X	 /* accept_focus	 */ NULL,
X	 /* version		 */ XtVersion,
X	 /* callback_private   	 */ NULL,
X	 /* tm_table		 */ NULL,
X	 /* query_geometry	 */ NULL,
X	 /* display_accelerator	 */ XtInheritDisplayAccelerator,
X	 /* extension		 */ NULL
X    },
X    {
X	/* Simple class fields initialization */
X	 /* change_sensitive	 */ XtInheritChangeSensitive
X    }
X};
X
XWidgetClass labelWidgetClass = (WidgetClass) & labelClassRec;
X
X
X/************************************************************/
X/******************** Private Procedures ********************/
X/************************************************************/
X
X
Xstatic void LabelGetGC(w)
XLabelWidget w;
X{
X    XGCValues values;
X
X    values.foreground = w->label.foreground;
X    values.background = w->core.background_pixel;
X    values.font = w->label.font->fid;
X
X    w->label.normal_gc = XtGetGC((Widget) w, (unsigned) GCForeground |
X      GCBackground | GCFont, &values);
X}
X
X
Xstatic void LabelSetSize(w)
XLabelWidget w;
X{
X    XtWidgetGeometry my_request;
X    char *label = w->label.label;
X    char *start = label;
X    char *end = label;
X    int line_width;
X
X    w->label.label_len = strlen(label);
X    w->label.num_lines = 0;
X    w->label.label_width = 0;
X
X    while (1)
X    {
X	if (*end == '\0' || *end == '\n' || (*end == '\\' && end[1] == 'n'))
X	{
X	    if (w->label.num_lines >= w->label.num_lines_alloced)
X	    {
X		w->label.num_lines_alloced += LABEL_ALLOC_COUNT;
X		w->label.line_start =
X		  (int *) realloc((char *) w->label.line_start,
X		  w->label.num_lines_alloced * sizeof(int));
X		w->label.line_len = (int *) realloc((char *) w->label.line_len,
X		  w->label.num_lines_alloced * sizeof(int));
X	    }
X	    w->label.line_start[w->label.num_lines] = (int) (start - label);
X	    w->label.line_len[w->label.num_lines] = (int) (end - start);
X
X	    line_width = (end - start) * w->label.char_width;
X	    if (line_width > w->label.label_width)
X		w->label.label_width = line_width;
X	    w->label.num_lines++;
X	    if (*end == '\0')
X		break;
X	    if (*end != '\n')
X		++end;
X	    start = end + 1;
X	}
X	++end;
X    }
X
X    w->label.label_height = w->label.num_lines * w->label.char_height;
X
X    my_request.request_mode = CWWidth | CWHeight;
X    my_request.width = w->label.label_width + 2 * w->label.internal_width;
X    my_request.height = w->label.label_height + 2 * w->label.internal_height;
X
X    XtMakeGeometryRequest((Widget) w, &my_request, NULL);
X}
X
X
X/* ARGSUSED */
Xstatic void LabelInitialize(request, new)
XWidget request, new;
X{
X    LabelWidget w = (LabelWidget) new;
X    XFontStruct *fs = w->label.font;
X
X    if (w->label.label == NULL)
X    {
X	eprintf("XtNLabel not set\n");
X	abort();
X    }
X
X    w->label.label = STRCOPY(w->label.label);
X    w->label.num_lines_alloced = LABEL_ALLOC_COUNT;
X    w->label.line_start = (int *) malloc(LABEL_ALLOC_COUNT * sizeof(int));
X    w->label.line_len = (int *) malloc(LABEL_ALLOC_COUNT * sizeof(int));
X    w->label.char_height = fs->max_bounds.ascent + fs->max_bounds.descent;
X    w->label.char_width = fs->max_bounds.width;
X    w->label.label_x = w->label.internal_width;
X    w->label.label_y = w->label.internal_height + fs->max_bounds.ascent;
X
X    LabelGetGC(w);
X    LabelSetSize(w);
X}
X
X
X/* ARGSUSED */
Xstatic void LabelRedisplay(widget, event, region)
XWidget widget;
XXEvent *event;
XRegion region;
X{
X    LabelWidget w = (LabelWidget) widget;
X    Display *dpy = XtDisplay(w);
X    Window window = XtWindow(w);
X    Position line_y = w->label.label_y;
X    int *line_start = w->label.line_start;
X    int *line_len = w->label.line_len;
X    char *label;
X    int ii;
X
X    if (XtIsRealized(widget) == False)
X	return;
X
X    for (ii = 0; ii < w->label.num_lines; ++ii)
X    {
X	label = &(w->label.label[*line_start]);
X
X	XDrawImageString(dpy, window, w->label.normal_gc, w->label.label_x,
X	  line_y, label, *line_len);
X
X	line_y += w->label.char_height;
X	++line_start;
X	++line_len;
X    }
X}
X
X
Xstatic void LabelDestroy(widget)
XWidget widget;
X{
X    LabelWidget w = (LabelWidget) widget;
X
X    XtReleaseGC(widget, w->label.normal_gc);
X}
X
X
X/***********************************************************/
X/******************** Public Procedures ********************/
X/***********************************************************/
X
X
Xvoid LabelChangeLabel(widget, label)
XWidget widget;
Xchar *label;
X{
X    LabelWidget w = (LabelWidget) widget;
X
X    if (label == NULL)
X    {
X	eprintf("Label may not be NULL\n");
X	abort();
X    }
X
X    free(w->label.label);
X    w->label.label = STRCOPY(label);
X    LabelSetSize(w);
X    LabelRedisplay(widget, (XEvent *) NULL, (Region) NULL);
X}
END_OF_FILE
if test 6500 -ne `wc -c <'widgets/Label.c'`; then
    echo shar: \"'widgets/Label.c'\" unpacked with wrong size!
fi
# end of 'widgets/Label.c'
fi
echo shar: End of archive 1 \(of 10\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 10 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.