/******************************************************************************/
/* Copyright 1995 MBARI                                                       */
/******************************************************************************/
/* Summary  : CTD Data Display Callbacks Module                               */
/* Filename : displayCallbacks.c                                              */
/* Author   : Janice Tarrant                                                  */
/* Project  : Tiburon                                                         */
/* Version  : Version 1.0                                                     */
/* Created  : 02/13/95                                                        */
/* Modified :                                                                 */
/* Archived :                                                                 */
/******************************************************************************/
/* Modification History :                                                     */
/* $Header: /usr/tiburon/unix/gui/ctd/RCS/displayCallbacks.c,v 1.1 1998/03/12 17:52:41 oreilly Exp $
 * $Log: displayCallbacks.c,v $
 * Revision 1.1  1998/03/12 17:52:41  oreilly
 * Initial revision
 *
 *
 */
/******************************************************************************/

#include <math.h>
#include <Xm/Xm.h>
#include <mbari/types.h>
#include <dmUnix.h>             /* unix data manager definitions              */
#include <semLib.h>             /* semaphore library                          */
#include <time.h>               /* MBARI time declarations                    */
#include <datamgr.h>            /* data manager declarations                  */
#include <dm_errno.h>           /* data manager error declarations            */
#include "ctdDisplay.h"

extern GC              gc;
extern configurationParameters configParams;
extern MBool         startDisplay;
extern MBool         resetYTickLabels;
extern MBool         plotScrolling;
extern Int16         loopNumber;
extern Int32         pointCount;
extern Int32         numDataPoints;
extern Int32         plotStart;
extern Int32         plotEnd;
extern Flt32         yTimeUnitsScale;			/* y time units scale */
extern Flt32         *dataValues[NUM_DATA_POINTS];

void redisplayCallback(Widget w, XtPointer clientData, XtPointer callData);
void drawAxes(Display *display, Drawable drawable, XSegment *segments,
	      Int16 numSegments, plotParameters *plotParams, varNum var);
void makeTickLabel(varNum var, plotParameters *plotParams);
void plotDataPoints(displayUpdateData *displayData, Display *display,
		    Drawable drawable, MBool erase);
void checkAxisLimits(Int16 *x1, Int16 *x2, Int16 *y1, Int16 *y2,
                     displayUpdateData *displayData);
void plotMarks(plotParameters *plotParams, Display *display, Drawable drawable,
	       MBool erase);
void resizeCallback(Widget w, XtPointer clientData, XtPointer callData);
void closeDisplayCallback(Widget w, XtPointer clientData, XtPointer callData);


/******************************************************************************/
/* Function : redisplayCallback                                               */
/* Purpose  : Redisplays the graphics display.                                */
/* Inputs   : Widget, plotting data and call data.                            */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
redisplayCallback(Widget w, XtPointer clientData, XtPointer callData)
{
    plotParameters *plotParams = (plotParameters *) clientData;
    Int16          var;				/* loop counter               */
    Int16          largestYLabel;		/* largest y label word       */
    Display        *display = XtDisplay(w);
    Drawable       drawable = XtWindow(w);

/* draw the axes                                                              */
    switch (configParams.numXVariables)
    {
        case 4 :
	    drawAxes(display, drawable, plotParams->segments+5, 1, plotParams,
		     X4);

        case 3 :
	    drawAxes(display, drawable, plotParams->segments+4, 1, plotParams,
		     X3);

        case 2 :
	    drawAxes(display, drawable, plotParams->segments+3, 1, plotParams,
		     X2);

        default :
	    if (resetYTickLabels)		/* reset y tick axis labels to*/
	    {					/* original values            */
		plotParams->displayData.minValues[Y] =
		    configParams.yVariable.minValue;
		plotParams->displayData.maxValues[Y] =
		    configParams.yVariable.maxValue;
		makeTickLabel(Y, plotParams);
    		plotParams->xFirstTickLabelPos[Y] =
		    plotParams->displayData.xAxisStart -
                    plotParams->firstTickLabelLength[Y] * OFFSET_PER_CHAR;
    		plotParams->xLastTickLabelPos[Y] =
		    plotParams->displayData.xAxisStart -
                    plotParams->lastTickLabelLength[Y] * OFFSET_PER_CHAR;
		resetYTickLabels = FALSE;
	    }
	    else if (plotScrolling)		/* set y axis tick labels to  */
	    {					/* update with scrolling      */
		makeTickLabel(Y, plotParams);
    		plotParams->xFirstTickLabelPos[Y] =
		    plotParams->displayData.xAxisStart -
                    plotParams->firstTickLabelLength[Y] * OFFSET_PER_CHAR;
    		plotParams->xLastTickLabelPos[Y] =
		    plotParams->displayData.xAxisStart -
                    plotParams->lastTickLabelLength[Y] * OFFSET_PER_CHAR;

		if ( (plotParams->xFirstTickLabelPos[Y] < 0) ||
		     (plotParams->xLastTickLabelPos[Y] < 0) )
		{
		    largestYLabel = MAX(plotParams->firstTickLabelLength[Y],
				        plotParams->lastTickLabelLength[Y]);
		    plotParams->displayData.xAxisStart =
			AXES_OFFSET3 + largestYLabel * OFFSET_PER_CHAR;
		    initAxesGeom(plotParams);
		}
	    }
	    if (configParams.numXVariables == 0)
	    {
	    	drawAxes(display, drawable, plotParams->segments, 4,
			 plotParams, Y);
	    }
	    else
	    {
	    	if (configParams.numXVariables == 1)
	    	    drawAxes(display, drawable, plotParams->segments, 4,
			     plotParams, Y);
	    	else
	    	    drawAxes(display, drawable, plotParams->segments, 2,
			     plotParams, Y);
	    	drawAxes(display, drawable, plotParams->segments+2, 1,
			 plotParams, X1);
	    }
            break;
    }

/* plot the data values                                                       */
    plotDataPoints(&plotParams->displayData, display, drawable, ERASE_OFF);

/* draw the mark value lines                                                  */
    if (plotParams->numMarks > 0)
	plotMarks(plotParams, display, drawable, ERASE_OFF);

/* draw the xy coordinate strings                                             */
    if (configParams.showXY && plotParams->inDisplayWindow)
    {
        XSetForeground(display, gc, plotParams->displayData.colours[Y]);
	for (var = 0; var < configParams.numXVariables; var++)
	    XDrawString(display, drawable, gc, plotParams->xCoordPosition,
			plotParams->yCoordPositions[var],
			plotParams->coordString[var],
			strlen(plotParams->coordString[var]));
    }

}


/******************************************************************************/
/* Function : drawAxes                                                        */
/* Purpose  : Draws the data display axes.                                    */
/* Inputs   : Display, drawable, line segments, number of segments, plotting  */
/*            data and item variable.                                         */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
drawAxes(Display *display, Drawable drawable, XSegment *segments,
	 Int16 numSegments, plotParameters *plotParams, varNum var)
{
    Int16 word;					/* loop counter               */

    XSetForeground(display, gc, plotParams->displayData.colours[var]);

    if (var == Y)			
    {
        XDrawString(display, drawable, gc, plotParams->xLabelPosition[var],
                    plotParams->yLabelPosition[var], plotParams->axisLabel[var],
                    plotParams->yLabelSpace[0] - 1);
						/* multiple word y label      */
	for (word = 1; word < plotParams->numYWords; word++)
            XDrawString(display, drawable, gc, plotParams->xLabelPosition[var],
                        plotParams->yLabelPosition[var] + word * AXES_OFFSET4,
                        plotParams->axisLabel[var] +
			plotParams->yLabelSpace[word-1],
                        plotParams->yLabelSpace[word] -
			plotParams->yLabelSpace[word-1] - 1);
    }
    else
	XDrawString(display, drawable, gc, plotParams->xLabelPosition[var],
		    plotParams->yLabelPosition[var], plotParams->axisLabel[var],
		    plotParams->labelLength[var]);

    XDrawSegments(display, drawable, gc, segments, numSegments);
    XDrawSegments(display, drawable, gc, plotParams->tickMarks[var],
		  plotParams->numTicks[var]);
    XDrawString(display, drawable, gc,
                plotParams->xFirstTickLabelPos[var],
                plotParams->yFirstTickLabelPos[var],
                plotParams->firstTickLabel[var],
                plotParams->firstTickLabelLength[var]);
    XDrawString(display, drawable, gc,
                plotParams->xLastTickLabelPos[var],
                plotParams->yLastTickLabelPos[var],
                plotParams->lastTickLabel[var],
                plotParams->lastTickLabelLength[var]);

} /* drawAxes */


/******************************************************************************/
/* Function : plotDataPoints                                                  */
/* Purpose  : Plots the data points.                                          */
/* Inputs   : Display data, display, drawable and erase on/off flag.          */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
plotDataPoints(displayUpdateData *displayData, Display *display,
	       Drawable drawable, MBool erase)
{
    Int16 x1, x2;				/* x points in line segment   */
    Int16 y1, y2;				/* y points in line segment   */
    Int16 var;					/* loop counter               */
    Int32 count1 = 0;				/* scrolling counters         */
    Int32 count2 = 0;
    Int32 count;				/* loop counters              */
    Int32 xCount, yCount;
    Pixel background;				/* background colour          */

/* get background colour                                                      */
    if (erase)
    {
    	XtVaGetValues(displayData->display, XmNbackground, &background, NULL);
        XSetForeground(display, gc, background);
    }

/* plot the data points                                                       */
    if ((plotStart >= 0) && (pointCount > plotStart) && startDisplay)
    {
    	for (var = 0; var < configParams.numXVariables; var++)
    	{
	    if (!erase)
                XSetForeground(display, gc, displayData->colours[var]);

/* set and draw the first two data points for x and y                         */
	    if (loopNumber == 1)	/* data acquisition not scrolling,    */
	    {				/* first two values are at plot start */
	        if (fabs(dataValues[plotStart][configParams.items[var]] -
			 BAD_DATA_VALUE) <= EPSILON)
		    x1 = NO_PLOT_VALUE;
		else
                    x1 = displayData->xAxisStart + displayData->scales[var] *
	                 (dataValues[plotStart][configParams.items[var]] -
		          displayData->minValues[var]);
	        if (fabs(dataValues[plotStart+1][configParams.items[var]] -
			 BAD_DATA_VALUE) <= EPSILON)
		    x2 = NO_PLOT_VALUE;
		else
                    x2 = displayData->xAxisStart + displayData->scales[var] *
	                 (dataValues[plotStart+1][configParams.items[var]] -
		          displayData->minValues[var]);
	    }
	    else				/* scrolling, first two data  */
	    {					/* points are after scroll    */
						/* count (the last new data   */
						/* point)                     */
		if (pointCount == (numDataPoints - 2))/* second to last count */
		{				      /* in array             */
		    count1 = pointCount + 1;
		    count2 = 0;
		}
		else if (pointCount == (numDataPoints - 1))  /* last count in */
		{					     /* array         */
		    count1 = 0;
		    count2 = 1;
		}
		else
		{
		    count1 = pointCount + 1;
		    count2 = pointCount + 2;
		}
	        if (fabs(dataValues[count1][configParams.items[var]] -
			 BAD_DATA_VALUE) <= EPSILON)
		    x1 = NO_PLOT_VALUE;
		else
                    x1 = displayData->xAxisStart + displayData->scales[var] *
	                 (dataValues[count1][configParams.items[var]] -
		          displayData->minValues[var]);
	        if (fabs(dataValues[count2][configParams.items[var]] -
			 BAD_DATA_VALUE) <= EPSILON)
		    x2 = NO_PLOT_VALUE;
		else
                    x2 = displayData->xAxisStart + displayData->scales[var] *
	                 (dataValues[count2][configParams.items[var]] -
		          displayData->minValues[var]);
	    }
	    if (configParams.items[Y] == TIME)
	    {
	        if (fabs(dataValues[plotStart][configParams.items[Y]] -
			 BAD_DATA_VALUE) <= EPSILON)
		    y1 = NO_PLOT_VALUE;
		else
	    	    y1 = displayData->yAxisStart + displayData->scales[Y] *
	                 (dataValues[plotStart][configParams.items[Y]] -
		          displayData->minValues[Y] * yTimeUnitsScale);
	        if (fabs(dataValues[plotStart+1][configParams.items[Y]] -
			 BAD_DATA_VALUE) <= EPSILON)
		    y2 = NO_PLOT_VALUE;
		else
	    	    y2 = displayData->yAxisStart + displayData->scales[Y] *
	                 (dataValues[plotStart+1][configParams.items[Y]] -
		          displayData->minValues[Y] * yTimeUnitsScale);
	    }
	    else
	    {
	        if (fabs(dataValues[plotStart][configParams.items[Y]] -
			 BAD_DATA_VALUE) <= EPSILON)
		    y1 = NO_PLOT_VALUE;
		else
	    	    y1 = displayData->yAxisStart + displayData->scales[Y] *
	                 (dataValues[plotStart][configParams.items[Y]] -
		          displayData->minValues[Y]);
	        if (fabs(dataValues[plotStart+1][configParams.items[Y]] -
			 BAD_DATA_VALUE) <= EPSILON)
		    y2 = NO_PLOT_VALUE;
		else
	    	    y2 = displayData->yAxisStart + displayData->scales[Y] *
	                 (dataValues[plotStart+1][configParams.items[Y]] -
		          displayData->minValues[Y]);
	    }
	    checkAxisLimits(&x1, &x2, &y1, &y2, displayData);
	    if ( (x1 != NO_PLOT_VALUE) && (y1 != NO_PLOT_VALUE) )
	    {
	        if (configParams.lineDrawing)
		{
	    	    if ( (x2 != NO_PLOT_VALUE) && (y2 != NO_PLOT_VALUE) )
	    	        XDrawLine(display, drawable, gc, x1, y1, x2, y2);
		}
	        else
	    	    XDrawPoint(display, drawable, gc, x1, y1);
	    }

/* set and draw the remaining points in the data array                        */
	    if (loopNumber == 1)	/* data acquisition not scrolling,    */
	    {				/* values are in order up to plot end */
	        for (count = plotStart+2; count <= plotEnd; count++)
	        {
	    	    x1 = x2;
	            if (fabs(dataValues[count][configParams.items[var]] -
			     BAD_DATA_VALUE) <= EPSILON)
		        x2 = NO_PLOT_VALUE;
		    else
            	        x2 = displayData->xAxisStart +
			     displayData->scales[var] *
	                     (dataValues[count][configParams.items[var]] -
		              displayData->minValues[var]);
	    	    y1 = y2;
		    if (configParams.items[Y] == TIME)
		    {
	        	if (fabs(dataValues[count][configParams.items[Y]]
				 - BAD_DATA_VALUE) <= EPSILON)
		    	    y2 = NO_PLOT_VALUE;
			else
	    	    	    y2 = displayData->yAxisStart +
				 displayData->scales[Y] *
				 (dataValues[count][configParams.items[Y]] -
		                  displayData->minValues[Y] * yTimeUnitsScale);
		    }
		    else
		    {
	        	if (fabs(dataValues[count][configParams.items[Y]]
				 - BAD_DATA_VALUE) <= EPSILON)
		    	    y2 = NO_PLOT_VALUE;
			else
	    	    	    y2 = displayData->yAxisStart +
				 displayData->scales[Y] *
				 (dataValues[count][configParams.items[Y]] -
		                  displayData->minValues[Y]);
		    }
	    	    checkAxisLimits(&x1, &x2, &y1, &y2, displayData);
	    	    if ( (x2 != NO_PLOT_VALUE) && (y2 != NO_PLOT_VALUE) )
	    	    {
	    	        if (configParams.lineDrawing)
			{
	    	    	    if ((x1 != NO_PLOT_VALUE) && (y1 != NO_PLOT_VALUE))
	    	                XDrawLine(display, drawable, gc, x1, y1, x2,
					  y2);
			}
		        else
	    	            XDrawPoint(display, drawable, gc, x2, y2);
		    }
	        }
	    }  /* loopNumber == 1 */

	    else				/* scrolling, data points are */
	    {					/* in two groups, scroll count*/
						/* + 1 to end of array (point */
						/* count), and 0 to scroll    */
						/* count                      */
		yCount = 1;

	        for (xCount = count2+1; xCount < pointCount; xCount++)
	        {
						/* second to last count in    */
						/* array, first group drawn   */
						/* loses last point, (already */
						/* drawn as first point)      */
		    if ((count2 == 0) && (xCount == (pointCount - 1)))
			continue;
		    yCount++;
	    	    x1 = x2;
	            if (fabs(dataValues[xCount][configParams.items[var]] -
			     BAD_DATA_VALUE) <= EPSILON)
		        x2 = NO_PLOT_VALUE;
		    else
            	        x2 = displayData->xAxisStart + displayData->scales[var]
			     * (dataValues[xCount][configParams.items[var]] -
		                displayData->minValues[var]);
	    	    y1 = y2;
		    if (configParams.items[Y] == TIME)
		    {
	        	if (fabs(dataValues[yCount][configParams.items[Y]]
				 - BAD_DATA_VALUE) <= EPSILON)
		    	    y2 = NO_PLOT_VALUE;
			else
	    	    	    y2 = displayData->yAxisStart +
				 displayData->scales[Y] *
				 (dataValues[yCount][configParams.items[Y]] -
		                  displayData->minValues[Y] * yTimeUnitsScale);
		    }
		    else
		    {
	        	if (fabs(dataValues[yCount][configParams.items[Y]]
				 - BAD_DATA_VALUE) <= EPSILON)
		    	    y2 = NO_PLOT_VALUE;
			else
	    	    	    y2 = displayData->yAxisStart +
				 displayData->scales[Y] *
				 (dataValues[yCount][configParams.items[Y]] -
		                  displayData->minValues[Y]);
		    }
	    	    checkAxisLimits(&x1, &x2, &y1, &y2, displayData);
	    	    if ( (x2 != NO_PLOT_VALUE) && (y2 != NO_PLOT_VALUE) )
	    	    {
	    	        if (configParams.lineDrawing)
			{
	    	    	    if ((x1 != NO_PLOT_VALUE) && (y1 != NO_PLOT_VALUE))
	    	                XDrawLine(display, drawable, gc, x1, y1, x2,
					  y2);
			}
		        else
	    	            XDrawPoint(display, drawable, gc, x2, y2);
		    }
	        }  /* for xCount */

						/* second to last count and   */
						/* last count in array loses  */
						/* second group, (already     */
						/* drawn in first group)      */
		if ((count2 != 0) && (count2 != 1))
	            for (xCount = 0; xCount <= pointCount; xCount++)
	            {
		        yCount++;
	    	        x1 = x2;
	                if (fabs(dataValues[xCount][configParams.items[var]] -
			         BAD_DATA_VALUE) <= EPSILON)
		            x2 = NO_PLOT_VALUE;
		        else
            	            x2 = displayData->xAxisStart +
			         displayData->scales[var] *
	                         (dataValues[xCount][configParams.items[var]] -
		                  displayData->minValues[var]);
	    	        y1 = y2;
			if (configParams.items[Y] == TIME)
			{
	        	    if (fabs(dataValues[yCount][configParams.items[Y]]
				     - BAD_DATA_VALUE) <= EPSILON)
		    	        y2 = NO_PLOT_VALUE;
			    else
	    	                y2 = displayData->yAxisStart +
				     displayData->scales[Y] *
				     (dataValues[yCount][configParams.items[Y]]
				      - displayData->minValues[Y] *
				      yTimeUnitsScale);
			}
			else
			{
	        	    if (fabs(dataValues[yCount][configParams.items[Y]]
				     - BAD_DATA_VALUE) <= EPSILON)
		    	        y2 = NO_PLOT_VALUE;
			    else
	    	                y2 = displayData->yAxisStart +
				     displayData->scales[Y] *
				     (dataValues[yCount][configParams.items[Y]]
				      - displayData->minValues[Y]);
			}
	    	        checkAxisLimits(&x1, &x2, &y1, &y2, displayData);
	    	        if ( (x2 != NO_PLOT_VALUE) && (y2 != NO_PLOT_VALUE) )
	    	        {
	    	            if (configParams.lineDrawing)
			    {
	    	    	        if ( (x1 != NO_PLOT_VALUE) &&
				     (y1 != NO_PLOT_VALUE) )
	    	                    XDrawLine(display, drawable, gc, x1, y1, x2,
					      y2);
			    }
		            else
	    	                XDrawPoint(display, drawable, gc, x2, y2);
			}
	            }  /* for xCount */
	    }  /* else loopNumber != 1 */
    	}  /* for var */
    }

} /* plotDataPoints */


/******************************************************************************/
/* Function : checkAxisLimits                                                 */
/* Purpose  : Checks that display data is within the drawing axes limits.     */
/* Inputs   : X1, x2, y1, y2, minimum x value, maximum x value, minimum y     */
/*            value and maximum y value.                                      */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
checkAxisLimits(Int16 *x1, Int16 *x2, Int16 *y1, Int16 *y2, 
                displayUpdateData *displayData)
{

    if (*x1 != NO_PLOT_VALUE)
    {
        if (*x1 < displayData->xAxisStart)
	    *x1 = displayData->xAxisStart;
        else if (*x1 > displayData->xAxisEnd)
	    *x1 = displayData->xAxisEnd;
    }
    if (*x2 != NO_PLOT_VALUE)
    {
        if (*x2 < displayData->xAxisStart)
	    *x2 = displayData->xAxisStart;
        else if (*x2 > displayData->xAxisEnd)
	    *x2 = displayData->xAxisEnd;
    }
    if (*y1 != NO_PLOT_VALUE)
    {
        if (*y1 < displayData->yAxisStart)
	    *y1 = displayData->yAxisStart;
        else if (*y1 > displayData->yAxisEnd)
	    *y1 = displayData->yAxisEnd;
    }
    if (*y2 != NO_PLOT_VALUE)
    {
        if (*y2 < displayData->yAxisStart)
	    *y2 = displayData->yAxisStart;
        else if (*y2 > displayData->yAxisEnd)
	    *y2 = displayData->yAxisEnd;
    }

}  /* checkAxesLimits */


/******************************************************************************/
/* Function : plotMarks                                                       */
/* Purpose  : Plots the mark lines.                                           */
/* Inputs   : Plot parameters, display, drawable and erase on/off flag.       */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
plotMarks(plotParameters *plotParams, Display *display, Drawable drawable,
	  MBool erase)
{
    Int16 mark;					/* loop counter               */
    Int16 x1, x2;				/* x points in line segment   */
    Int16 y1, y2;				/* y points in line segment   */
    Pixel background;				/* background colour          */

/* get background colour                                                      */
    if (erase)
    {
    	XtVaGetValues(plotParams->displayData.display, XmNbackground,
		      &background, NULL);
        XSetForeground(display, gc, background);
    }
    else
        XSetForeground(display, gc, plotParams->displayData.colours[Y]);

    x1 = plotParams->displayData.xAxisStart;
    x2 = plotParams->displayData.xAxisEnd;

    for (mark = 0; mark < plotParams->numMarks; mark++)
    {
    	if (configParams.items[Y] == TIME)
            y1 = y2 = plotParams->displayData.yAxisStart +
		      plotParams->displayData.scales[Y] *
		      (plotParams->markValue[mark] -
		       plotParams->displayData.minValues[Y] * yTimeUnitsScale);
    	else
	    y1 = y2 = plotParams->displayData.yAxisStart +
		      plotParams->displayData.scales[Y] *
		      (plotParams->markValue[mark] -
		       plotParams->displayData.minValues[Y]);
    	if ( (y1 > plotParams->displayData.yAxisStart) &&
	     (y1 < plotParams->displayData.yAxisEnd) )
	    XDrawLine(display, drawable, gc, x1, y1, x2, y2);
    }

} /* plotMarks */


/******************************************************************************/
/* Function : resizeCallback                                                  */
/* Purpose  : Resizes the graphics display.                                   */
/* Inputs   : Widget, plotting data and call data.                            */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
resizeCallback(Widget w, XtPointer clientData, XtPointer callData)
{
    plotParameters *plotParams = (plotParameters *) clientData;

    initAxesGeom(plotParams);

    if (XtIsRealized(w))
        XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, TRUE);

/* redraw takes place automatically when redisplayCallback is triggered by an */
/* expose event                                                               */

}


/******************************************************************************/
/* Function : closeDisplayCallback                                            */
/* Purpose  : Closes the graphics display.                                    */
/* Inputs   : Widget, client data and call data.                              */
/* Outputs  : None.                                                           */
/******************************************************************************/
    void
closeDisplayCallback(Widget w, XtPointer clientData, XtPointer callData)
{
    Int32 point;

    printf("exiting CTD display window\n");

    for (point = 0; point < numDataPoints; point++)
	    free(dataValues[point]);

    if (configParams.markFilePtr != NULL)
	fclose(configParams.markFilePtr);

    dm_task_exit(0);
    exit(0);
}
