/************************************************************************/
/* Copyright 1994 MBARI							*/
/************************************************************************/
/* $Header: /usr/tiburon/unix/gui/proto/RCS/dmcall.c,v 1.1 1998/01/28 16:17:12 oreilly Exp $			*/
/* Summary  : Callbacks for Data Manager module of ROV User Interface	*/
/* Filename : dmcall.c							*/
/* Author   : Bob Herlien (rah)						*/
/* Project  : Tiburon ROV						*/
/* $Revision: 1.1 $							*/
/* Created  : 02/01/94 by splitting graphcall.c into two modules	*/
/************************************************************************/
/* Modification History:						*/
/* $Log: dmcall.c,v $
 * Revision 1.1  1998/01/28 16:17:12  oreilly
 * Initial revision
 *
 * Revision 2.2  96/05/15  11:15:37  11:15:37  bobh (Bob Herlien)
 * Still supporting proto during final vehicle build
 * 
 * Revision 2.0  95/09/20  14:23:05  14:23:05  hebo (Bob Herlien)
 * Support for final vehicle integration.  AC, PDU micros.
 * 
 * Revision 1.8  94/08/19  17:20:25  17:20:25  hebo (Bob Herlien)
 * Interface to Unix version of Data Manager
 * 
 * Revision 1.7  94/03/21  14:15:19  14:15:19  hebo (Bob Herlien)
 * Misc bug fixes and enhancements
 * 
*/
/************************************************************************/

#include <mbari/types.h>
#include <mbari/const.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include <sys/stat.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <Xm/Xm.h>
#include <Xm/SelectioB.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/TextF.h>
#include <Xm/MessageB.h>
#include <Xm/PushB.h>
#include "rov.h"
#include <datamgr.h>
#include "rdmif.h"
#include "graph.h"
/* #include "/usr/tiburon/vw/recorder/recorder.h" */

#define MAX_ENTRIES	MAX_ITM_SIZE	/* Max number of type entry fields*/
#define ITEM_WIDTH	400		/* Width of form containing item  */
#define TEXTF_RT_POS	60		/* Right Position of Textf in Form*/
#define LABEL_LFT_POS	62		/* Left Position of label in Form */
#define OK_BUTTON_POS	75		/* Position of OK Button in Form  */
#define CANCEL_BUTTON_POS 85		/* Position of Cancel Button in Form*/
#define LOG_DIR		"/usr/tiburon/logs/"


/********************************/
/*	External Functions	*/
/********************************/

Extern Widget	rovError( Widget parent, char *msg );
Extern char 	*rovMalloc( Nat32 size );
Extern Void	rovFree( char *p );
Extern Int32	printType( DM_Type dtype, DM_Size size, char *dat, char *buff );


/********************************/
/*	External Data		*/
/********************************/

Extern XtAppContext	appcontext;	/* The application context	*/
Extern AppData		appdata;	/* Application-wide resources	*/
Extern Widget		dmFormW;	/* Form containing DM screen	*/
Extern char		buff[];		/* Misc buffer used application-wide*/
Extern Widget		dmItemTextField, dmScrolledWindow;
Extern Widget		graphFreqText;


/********************************/
/*	Global Data		*/
/********************************/

Global Widget	logWidgets[NLOGWIDGETS]; /* Widgets in LogFile dialog	*/

Global Nat32		typeSizes[] =
{ 0, 0, sizeof(char), sizeof(char), sizeof(Int16), sizeof(Nat16), 
  sizeof(Int32), sizeof(Nat32), sizeof(MBool), sizeof(Flt32), sizeof(Flt64),
  sizeof(void *), sizeof(int) };

Global GraphList	*curItem = GL_NULL;
Global LogItem		*loglist = LI_NULL;

Global char	 *data_types[] = 
{"", "event", "string", "string", "Int16", "Nat16", "Int32", "Nat32", "MBool", 
 "Flt32", "Flt64", "Pointer", "enum", "array", "struct"
};


/********************************/
/*	Module Local Data	*/
/********************************/

MLocal Widget		dmSelectionBox, dmItemDialog, dmItemDialogTextF;
MLocal Widget		dmWorkingDialog, stopLogDialog, fltRecorderDialog;
MLocal StsList		*sLst = SL_NULL;
MLocal StsList		*oldSLst = SL_NULL;
MLocal Nat32		lastSelLen = 0;
MLocal MBool		graphUpdate = FALSE;
MLocal XtWorkProcId	stsListWorkProcId = (XtWorkProcId)0;
MLocal TypeEntry	typeEntries[MAX_ENTRIES];
MLocal Nat32		loglstcnt = 0;

MLocal Nat32		type_align[] =
{ 0, 0, sizeof(char), sizeof(char), sizeof(Int16), sizeof(Nat16), 
  sizeof(Int32), sizeof(Nat32), sizeof(MBool), sizeof(Flt32), sizeof(Flt64),
  sizeof(char *), sizeof(DM_Type), sizeof(int), sizeof(int) };


/************************************************************************/
/* Function    : readTextF						*/
/* Purpose     : Read DM item into array of TextFields			*/
/* Inputs      : GraphList ptr, XtIntervalId				*/
/* Outputs     : None							*/
/************************************************************************/
     Void
readTextF( GraphList *gp, XtIntervalId *id )
{
    Reg TypeEntry	*tp;
    Reg Nat32		i;
    XmTextPosition	pos;

    if ( gp == GL_NULL )
	return;

    graphUpdate = TRUE;
    rdm_read( gp->gl_item, gp->gl_data, gp->gl_sts.is_size );

    for ( i = 0, tp = gp->gl_types; i < gp->gl_ntypes; i++, tp++ )
	if ( !tp->te_changed )
	{
	    pos = XmTextFieldGetInsertionPosition( tp->te_widget );
	    printType( tp->te_type, tp->te_size, 
		       gp->gl_data + tp->te_offset, buff );
	    XmTextFieldSetString( tp->te_widget, buff );
	    XmTextFieldSetInsertionPosition( tp->te_widget, pos );
	}

    graphUpdate = FALSE;
    /*printf("gp->gl_interval in dmcall = %d\n",gp->gl_interval);*/
    gp->gl_tmoutid = XtAppAddTimeOut( appcontext, gp->gl_interval, 
				     (XtTimerCallbackProc)readTextF, gp );

} /* readTextF() */


/************************************************************************/
/* Function    : modifyTextF						*/
/* Purpose     : Enable OK and Cancel buttons for Text Field		*/
/* Inputs      : Widget, TypeEntry ptr, callback struct			*/
/* Outputs     : None							*/
/************************************************************************/
     Void
modifyTextF( Widget w, TypeEntry *tp, XmTextVerifyCallbackStruct *tvp )
{
    if ( !graphUpdate && (!XtIsManaged(tp->te_auxwid1)) )
    {
	tp->te_changed = TRUE;
	XtManageChild( tp->te_auxwid1 );
	XtManageChild( tp->te_auxwid2 );
    }

} /* modifyTextF() */


/************************************************************************/
/* Function    : cancelTextF						*/
/* Purpose     : Disable OK and Cancel buttons for Text Field		*/
/* Inputs      : Widget, TypeEntry ptr, callback struct			*/
/* Outputs     : None							*/
/************************************************************************/
     Void
cancelTextF( Widget w, TypeEntry *tp, XmAnyCallbackStruct *cbs )
{
    tp->te_changed = FALSE;
    XtUnmanageChild( tp->te_auxwid1 );
    XtUnmanageChild( tp->te_auxwid2 );

} /* cancelTextF() */


/************************************************************************/
/* Function    : writeTextF						*/
/* Purpose     : Write selected item					*/
/* Inputs      : Widget, GraphList ptr, callback struct			*/
/* Outputs     : None							*/
/************************************************************************/
     Void
writeTextF( Widget w, GraphList *gp, XmAnyCallbackStruct *cbs )
{
    Reg Nat32		i;
    Reg TypeEntry	*tp;
    Reg char		*p, *str;
    TypeUnion		udat;

    if ( gp == GL_NULL )
	return;

    for ( i = 0, tp = gp->gl_types; i < gp->gl_ntypes; i++, tp++ )
    {
	tp->te_changed = FALSE;
	XtUnmanageChild( tp->te_auxwid1 );
	XtUnmanageChild( tp->te_auxwid2 );

	str = XmTextFieldGetString( tp->te_widget );
	p = gp->gl_data + tp->te_offset;

	switch( tp->te_type )
	{
	  case DM_CHAR:
	  case DM_UCHAR:
	    strncpy( p, str, tp->te_size );
	    break;

	  case DM_INT16:
	  case DM_MBOOL:
	  case DM_NAT16:
	    sscanf( str, "%hi", &udat.nat16 );
	    bcopy( &udat, p, sizeof(Nat16) );
	    break;
	    
	  case DM_INT32:
	  case DM_NAT32:
	  case DM_ENUM:
	  case DM_PTR:
	    sscanf( str, "%i", &udat.nat32 );
	    bcopy( &udat, p, sizeof(Nat32) );
	    break;

	  case DM_FLT32:
	    sscanf( str, "%g", &udat.flt32 );
	    bcopy( &udat, p, sizeof(Flt32) );
	    break;

	  case DM_FLT64:
	    sscanf( str, "%lg", &udat.flt64 );
	    bcopy( &udat, p, sizeof(Flt64) );
	    break;

	} /* switch */

	XtFree( str );
    }

    rdm_write_once( gp->gl_item, gp->gl_data, gp->gl_sts.is_size );

} /* writeTextF() */


/************************************************************************/
/* Function    : graphUpdateRate					*/
/* Purpose     : Get the update rate for graph				*/
/* Inputs      : None							*/
/* Outputs     : Update period in milliseconds (suitable for XtAddTimeOut)*/
/************************************************************************/
     Nat32
graphUpdateRate( Void )
{
    char	*p;
    Flt64	x;
    Nat32	i;

    p = XmTextFieldGetString( graphFreqText );
    i = sscanf( p, "%lg", &x );
    XtFree( p );
    
    if ( (i == 1) && (x <= ULONG_MAX/1000) )
	return( (Nat32)(x * 1000.) );
    else
	return( appdata.graph_update );

} /* graphUpdateRate() */


/************************************************************************/
/* Function    : graphUpdateCallback					*/
/* Purpose     : Callback when user changes update rate			*/
/* Inputs      : Widget, unused ptr, callback struct			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
graphUpdateCallback(Widget w, XtPointer unused, XmAnyCallbackStruct *cbs)
{
    if ( curItem != GL_NULL )
    {
	curItem->gl_interval = graphUpdateRate();
	rdm_start_cnsmr( curItem->gl_item, curItem->gl_interval * 1000, NULL );
    }

} /* graphUpdateCallback() */


/************************************************************************/
/* Function    : getGraphList						*/
/* Purpose     : Allocate a new GraphList item				*/
/* Inputs      : DM_Item, Size of DM_Item, Number of TypeEntries	*/
/* Outputs     : GraphList ptr						*/
/************************************************************************/
     GraphList *
getGraphList( DM_Item item, DM_Size size, Nat32 ntypes )
{
    Reg GraphList	*gp;

    gp = (GraphList *)rovMalloc( sizeof(GraphList) + 
				 (ntypes * sizeof(TypeEntry)) + size );
    if ( gp == GL_NULL )
	return( GL_NULL );
    
    gp->gl_item = item;
    gp->gl_types = (TypeEntry *)(gp + 1);
    bcopy( typeEntries, gp->gl_types, ntypes * sizeof(TypeEntry) );
    gp->gl_ntypes = ntypes;
    gp->gl_shell = NULLW;
    gp->gl_widget = NULLW;
    gp->gl_data = (char *)(gp->gl_types + ntypes);
    gp->gl_interval = graphUpdateRate();
    gp->gl_tmoutid = (XtIntervalId)0;
    rdm_item_status( item, &gp->gl_sts );

    return( gp );

} /* getGraphList() */


/************************************************************************/
/* Function    : restoreConsumer					*/
/* Purpose     : Restore old Consumer rate if no longer in use		*/
/* Inputs      : Item, old period					*/
/* Outputs     : None							*/
/************************************************************************/
     Void
restoreConsumer( DM_Item item, Nat32 period )
{
    if ( graphItemInUse(item) )
	return;

    if ( period == NO_PERIOD )
	rdm_stop_consumer( item );
    else
	rdm_set_period( item, period );

} /* restoreConsumer() */


/************************************************************************/
/* Function    : freeGraphList						*/
/* Purpose     : Free a GraphList entry					*/
/* Inputs      : GraphList to free					*/
/* Outputs     : None							*/
/************************************************************************/
     Void
freeGraphList( GraphList *gp )
{
    if ( gp != GL_NULL )
    {
	if ( gp->gl_tmoutid != (XtIntervalId)0 )
	    XtRemoveTimeOut( gp->gl_tmoutid );
	if ( gp->gl_shell != NULLW )
	    XtDestroyWidget( gp->gl_shell );
	rdm_item_status_free( &gp->gl_sts );
	restoreConsumer( gp->gl_item, gp->gl_gui_period );
	rovFree( (char *)gp );
    }

} /* freeGraphList() */


/************************************************************************/
/* Function    : createDisplayItem					*/
/* Purpose     : Create TextF widgets and GraphList item to display a DM Item*/
/* Inputs      : StsList for item to display, DM_Item number		*/
/* Outputs     : GraphList Item created					*/
/************************************************************************/
     GraphList *
createDisplayItem( StsList *sp, DM_Num itmNum )
{
    Reg Nat32		i, j, k, n, nentries, offset, size;
    Reg DM_Element	*ep;
    Reg TypeEntry	*tp;
    DM_Item		item;
    DM_Type		type;
    Widget		rc, form, label;
    Nat32		period;
    XmString		str;
    Reg GraphList	*gp;

    gp = curItem;
    curItem = GL_NULL;

    if ( gp != GL_NULL )
	freeGraphList( gp );

    if ( sp->sl_nitems > 1 )
    {
	if ( (item = rdm_lookup(sp->sl_sts.is_name, itmNum)) == NO_ITEM )
	    return( GL_NULL );

	sprintf( buff, "%s[%d]", sp->sl_sts.is_name, itmNum );
	XmTextFieldSetString( dmItemTextField, buff );
    }
    else
    {
	item = sp->sl_item;
	XmTextFieldSetString( dmItemTextField, sp->sl_sts.is_name );
    }

    rc = XtVaCreateWidget("dmValueRowColumn", xmRowColumnWidgetClass, 
			  dmScrolledWindow, XmNorientation, XmVERTICAL, NULL);

    tp = typeEntries;
    for ( i = offset = n = 0; i < sp->sl_sts.is_num_compounds; i++ )
    {
	type = sp->sl_sts.is_compound[i].elt_type;
	size = typeSizes[type];
	nentries = sp->sl_sts.is_compound[i].elt_num;

	switch( type )
	{
	  case DM_EMPTY:
	  case DM_CHAR:
	  case DM_UCHAR:
	    size *= nentries;
	    nentries = 1;
	}

	for ( j = 0; j < nentries; j++, n++, tp++ )
	{
	    form = XtVaCreateManagedWidget("itemForm", xmFormWidgetClass, rc,
					   XmNwidth, ITEM_WIDTH, NULL);

	    tp->te_widget = 
		XtVaCreateWidget("itemTextF", xmTextFieldWidgetClass, form,
				 XmNtopAttachment, XmATTACH_FORM,
				 XmNbottomAttachment, XmATTACH_FORM,
				 XmNleftAttachment, XmATTACH_FORM,
				 XmNrightAttachment, XmATTACH_POSITION,
				 XmNrightPosition, TEXTF_RT_POS, NULL);

	    XtManageChild( tp->te_widget );

	    str = XmStringCreateSimple( data_types[type] );
	    label = XtVaCreateManagedWidget("itemType", xmLabelWidgetClass, 
					    form,
					    XmNtopAttachment, XmATTACH_FORM,
					    XmNbottomAttachment, XmATTACH_FORM,
					    XmNleftAttachment,XmATTACH_POSITION,
					    XmNleftPosition, LABEL_LFT_POS,
					    XmNlabelString, str, NULL );
	    XmStringFree( str );

	    tp->te_type = type;			/* Save entry type	    */
	    tp->te_size = size;			/* Save entry size	    */
	    k = type_align[type] - 1;		/* Calc alignment mask	    */
	    offset = (offset + k) & ~k;		/* Add padding for alignment*/
	    tp->te_offset = offset;		/* Save current offset	    */
	    offset += size;			/* Add size for next offset */
	    tp->te_changed = FALSE;

	    str = XmStringCreateSimple("OK");
	    tp->te_auxwid1 = 
		XtVaCreateWidget("graphOKButton", xmPushButtonWidgetClass,
				 form, XmNtopAttachment, XmATTACH_FORM,
				 XmNbottomAttachment, XmATTACH_FORM,
				 XmNleftAttachment, XmATTACH_POSITION,
				 XmNleftPosition, OK_BUTTON_POS,
				 XmNlabelString, str, NULL);
	    XmStringFree(str);

	    str = XmStringCreateSimple("Cancel");
	    tp->te_auxwid2 = 
		XtVaCreateWidget("graphCancelButton", xmPushButtonWidgetClass,
				 form, XmNtopAttachment, XmATTACH_FORM,
				 XmNbottomAttachment, XmATTACH_FORM,
				 XmNleftAttachment, XmATTACH_POSITION,
				 XmNleftPosition, CANCEL_BUTTON_POS,
				 XmNlabelString, str, NULL);
	    XmStringFree(str);
	}
    }

    period = sp->sl_sts.is_cnsmr_period;
    if ( (period == NO_PERIOD) || (period > 1000 * appdata.graph_update) )
	period = 1000 * appdata.graph_update;

    sprintf( buff, "%g", (double)period / 1000000. ); 
    XmTextFieldSetString( graphFreqText, buff );

    gp = getGraphList( item, sp->sl_sts.is_size, n );
    gp->gl_shell = rc;
    gp->gl_gui_period = sp->sl_sts.is_cnsmr_period;
    rdm_start_cnsmr( gp->gl_item, period, NULL );

    for ( i = 0, tp = gp->gl_types; i < n; i++, tp++ )
    {
	tp->te_graph = gp;
	XtAddCallback( tp->te_widget, XmNvalueChangedCallback, 
		       (XtCallbackProc)modifyTextF, tp );
	XtAddCallback( tp->te_widget, XmNactivateCallback,
		       (XtCallbackProc)writeTextF, gp );
	XtAddCallback( tp->te_auxwid1, XmNactivateCallback,
		       (XtCallbackProc)writeTextF, gp );
	XtAddCallback( tp->te_auxwid2, XmNactivateCallback,
		       (XtCallbackProc)cancelTextF, tp );
    }

    XtManageChild( rc );
    readTextF( gp, (XtIntervalId *)NULL );
    return( gp );

} /* createDisplayItem() */


/************************************************************************/
/* Function    : itemNumCallback					*/
/* Purpose     : Callback to prompt user for Item number of DM_Item arrays*/
/* Inputs      : Widget ID, client_data, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
itemNumCallback(Widget w, StsList *sp, XmSelectionBoxCallbackStruct *cbs)
{
    Nat32	num;
    char	*p;

    XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &p );

    if ( (sscanf(p, "%d", &num) < 1) || (num >= sp->sl_nitems) )
    {
	XtManageChild( w );
	rovError(w, "Item Number out of range");
	num = 0;
    }

    XtFree( p );

    curItem = createDisplayItem( sp, num );

} /* itemNumCallback() */


/************************************************************************/
/* Function    : itemNumModifyCallback					*/
/* Purpose     : Callback when user modifies Item Num TextField		*/
/* Inputs      : Widget ID, client_data, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
itemNumModifyCallback(Widget w, XtPointer unused,
		      XmTextVerifyCallbackStruct *tvp )
{
    Nat32	len;

    if ( tvp->text->ptr == NULL )
	return;

    for ( len = 0; len < tvp->text->length; len++ )
	if ( !isdigit(tvp->text->ptr[len]) )
	    tvp->doit = False;

} /* itemNumModifyCallback() */


/************************************************************************/
/* Function    : displayListFree					*/
/* Purpose     : Free the DisplayList					*/
/* Inputs      : DisplayList ptr					*/
/* Outputs     : None							*/
/************************************************************************/
    Void
displayListFree( DisplayList *dp )
{
    DisplayList	*ndp;

    while( dp != DL_NULL )
    {
	ndp = dp->dl_next;
	free( dp );
	dp = ndp;
    }

} /* displayListFree() */


/************************************************************************/
/* Function    : displayNames						*/
/* Purpose     : Display DM Names in SelectionBox that match given name	*/
/* Inputs      : Name to match						*/
/* Outputs     : None							*/
/************************************************************************/
     Void
displayNames( char *name )
{
    Reg DisplayList	*dp, *curdp;
    Reg StsList		*sp;
    Reg char		*p, *q;
    Reg Nat32		nmlen, matchlen, nstrs;
    Reg Int32		i;
    XmString		str, *strp;
    Reg DisplayList	*dp1, *dp2;

    str = XmStringCreateSimple( name );	/* Show name we're matching	*/
    XtVaSetValues( dmSelectionBox, XmNtextString, str, NULL );
    XmStringFree( str );

    nmlen = strlen( name );		/* Get length of match string	*/
    nstrs = 0;				/* Init number of matches to 0	*/
    dp = DL_NULL;			/* Init list of matching names to null*/
    for ( sp = sLst; sp != SL_NULL; sp = sp->sl_next )
    {					/* Scan entire status list of items*/
	p = sp->sl_sts.is_name;		/* Point to current name on sLst */

	if ( (strcmp(p, name) == 0) &&  (p != NULL) && (*p != '\0') )
	{				/* If name matches EXACTLY (non-NULL)*/
	    displayListFree( dp );	/* Free list of partial matches	*/

	    if ( sp->sl_nitems > 1 )	/* If array of DM items, ask user*/
	    {				/*   which item he wants	 */
		sprintf( buff, "Item Number (0 - %d)\n", sp->sl_nitems - 1 );
		str = XmStringCreateSimple( buff );
		XtVaSetValues( dmItemDialog, 
			       XmNselectionLabelString, str, NULL );
		XmTextFieldSetString( dmItemDialogTextF, "0" );
		XmStringFree( str );

		XtRemoveAllCallbacks( dmItemDialog, XmNokCallback );
		XtAddCallback( dmItemDialog, XmNokCallback,
			       (XtCallbackProc)itemNumCallback, sp );
		XtManageChild( dmItemDialog );
	    }
	    else			/* If single DM item, we're there! */
		curItem = createDisplayItem( sp, 0 );	/* Display it	   */
	    return;
	}
					/* Don't have exact match	*/
	if ( strncmp(p, name, nmlen) != 0 )
	    continue;

	if ( (q = strchr(p + nmlen, '.')) == NULL )
	    matchlen = strlen(p) + 1;	/* Try to match to next '.'	*/
	else
	    matchlen = q - p + 1;
				/* See if we already have DisplayList item */
				/*   with this partial (up to '.') match   */
	for ( curdp = dp; curdp != DL_NULL; curdp = curdp->dl_next )
	    if ( strncmp(p, curdp->dl_name, matchlen) == 0 )
		break;

	if ( curdp == DL_NULL )	/* If this is a new partial match	*/
	{			/*  create a new DisplayList item	*/
	    curdp = (DisplayList *)rovMalloc(sizeof(DisplayList)+matchlen+1);
	    if ( curdp == DL_NULL )		/* If no space, stop	*/
		break;
	    curdp->dl_name = (char *)(curdp + 1); /* Remember name	*/
	    bcopy( p, curdp->dl_name, matchlen );
	    curdp->dl_name[matchlen] = '\0';
	    curdp->dl_sts = sp;			  /* Remember sts ptr	*/
					/* Put on DisplayList in alpha order*/
	    if ( (dp == DL_NULL) || 
		 (strcmp(curdp->dl_name, dp->dl_name) < 0) )
	    {				/* If lower than first, put first*/
		curdp->dl_next = dp;
		dp = curdp;
	    }
	    else			/* Scan list, insert in alpha order*/
	    {
		for ( dp1 = dp; (dp2 = dp1->dl_next) != DL_NULL; dp1 = dp2 )
		    if ( strcmp(curdp->dl_name, dp2->dl_name) < 0 )
			break;
		dp1->dl_next = curdp;
		curdp->dl_next = dp2;
	    }
	    nstrs++;				  /* Incr # found names	*/
	}
    }

    switch ( nstrs )		/* Done.  How many matching strings found?*/
    {
      case 0:			/* No matching display strings	*/
	rovError(XtParent(dmSelectionBox), 
		 "Data Manager Item doesn't exist!\n");
	break;

      case 1:			/* Found exactly 1 match.  Display next level*/
	displayNames( dp->dl_name );
	break;

      default:			/* Found multiple matches.  Show all matches*/
	strp = (XmString *)rovMalloc( nstrs * sizeof(XmString) );
	bzero( (char *)strp, nstrs * sizeof(XmString) );

				/* Create the XmStrings		*/
	for ( i = 0, curdp = dp; curdp != DL_NULL; i++, curdp = curdp->dl_next )
	    strp[i] = XmStringCreateSimple( curdp->dl_name );

	XtVaSetValues( dmSelectionBox, XmNlistItems, strp, 
		       XmNlistItemCount, nstrs, NULL );

	while ( --i >= 0 )
	    XmStringFree( strp[i] );

	rovFree( (char *)strp );
	break;

    } /* switch() */

    displayListFree( dp );

} /* displayNames() */


/************************************************************************/
/* Function    : freeStsList						*/
/* Purpose     : Free a StsList						*/
/* Inputs      : Ptr to StsList 					*/
/* Outputs     : None							*/
/************************************************************************/
     Void
freeStsList( StsList **spp )
{
    Reg StsList	*sp;

    while( (sp = *spp) != SL_NULL )
    {
	rdm_item_status_free( &sp->sl_sts );
	*spp = sp->sl_next;
	rovFree( (char *)sp );
    }

} /* freeStsList() */


/************************************************************************/
/* Function    : stsListWorkProc					*/
/* Purpose     : XtWorkProc to create a StsList				*/
/* Inputs      : Place to put new StsList				*/
/* Outputs     : True if done, False to continue			*/
/************************************************************************/
    Boolean
stsListWorkProc( StsList **spp )
{
    DM_Item		item;
    Reg StsList		*sp;
    DM_Num		nitems;

    item = (*spp == SL_NULL) ? NO_ITEM : (*spp)->sl_item;

    if ( ((item = rdm_search("*", item, &nitems)) != NO_ITEM) &&
	 ((sp = (StsList *)rovMalloc(sizeof(StsList))) != SL_NULL) )
    {
	if ( rdm_item_status(item, &sp->sl_sts) == SUCCESS )
	{
	    sp->sl_next = *spp;
	    sp->sl_item = item;
	    sp->sl_nitems = nitems;
	    *spp = sp;
	}
	else
	{
	    fprintf( stderr, "DM Error in name lookup\n" );
	    rovFree( (char *)sp );
	}
	return( False );
    }

	/* Done.  Free the old StsList and display all the new names	*/
    freeStsList( &oldSLst );

    if ( curItem == GL_NULL )
	displayNames("");
    else
	displayNames( curItem->gl_sts.is_name );

    stsListWorkProcId = (XtWorkProcId)0;

	/* Note - we should be able to Unmanage the Working Dialog directly,*/
	/*	  but for some reason, we get a bus error if we do so.	    */
	/*	  So, we add a timeout to unmanage it later		    */
    if ( XtIsManaged(dmWorkingDialog) )
	XtAppAddTimeOut( appcontext, 10, (XtTimerCallbackProc)XtUnmanageChild,
			 dmWorkingDialog );

    return( True );

} /* stsListWorkProc() */


/************************************************************************/
/* Function    : cancelStsList						*/
/* Purpose     : Callback to cancel stsListWorkProc			*/
/* Inputs      : Widget ID, client_data, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
cancelStsList( Widget w, XtPointer unused, XmSelectionBoxCallbackStruct *cbs)
{

    if ( stsListWorkProcId != (XtWorkProcId)0 )
	XtRemoveWorkProc( stsListWorkProcId );
    stsListWorkProcId = (XtWorkProcId)0;
    freeStsList( &sLst );
    sLst = oldSLst;
    oldSLst = SL_NULL;
    displayNames("");

    if ( XtIsManaged(dmWorkingDialog) )
	XtUnmanageChild( dmWorkingDialog );

} /* cancelStsList() */


/************************************************************************/
/* Function    : dmSelectOkCallback					*/
/* Purpose     : Callback when user hits "OK" in DM Selection Box	*/
/* Inputs      : Widget ID, client_data, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
dmSelectOkCallback(Widget w, XtPointer unused,
		   XmSelectionBoxCallbackStruct *cbs)
{
    char	*p;

    XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &p );
    lastSelLen = strlen( p );
    displayNames( p );
    XtFree( p );

} /* dmSelectOkCallback() */


/************************************************************************/
/* Function    : dmSelectNewCallback					*/
/* Purpose     : Callback when user hits "New" in DM Selection Box	*/
/* Inputs      : Widget ID, client_data, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
dmSelectNewCallback(Widget w, XtPointer unused,
		    XmSelectionBoxCallbackStruct *cbs)
{
    Reg StsList		*sp;
    Reg GraphList	*gp;

    gp = curItem;
    curItem = GL_NULL;
    freeGraphList( gp );
    XmTextFieldSetString( dmItemTextField, NULL );
    lastSelLen = 0;
    oldSLst = sLst;				/* Save sLst in case of	*/
    sLst = SL_NULL;				/*   cancel		*/

    XtVaSetValues( dmSelectionBox, XmNlistItemCount, 0, NULL );
    XtManageChild( dmWorkingDialog );

    stsListWorkProcId = 
	XtAppAddWorkProc( appcontext, (XtWorkProc)stsListWorkProc, &sLst );

} /* dmSelectNewCallback() */


/************************************************************************/
/* Function    : dmSelectBackCallback					*/
/* Purpose     : Callback when user hits "Back" in DM Selection Box	*/
/* Inputs      : Widget ID, client_data, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
dmSelectBackCallback(Widget w, XtPointer unused,
		    XmSelectionBoxCallbackStruct *cbs)
{
    char	*p, *q;

    XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &p );
    if ( p[lastSelLen-1] == '.' )
	p[lastSelLen-1] = '\0';
    if ( (q = strrchr(p, '.')) == NULL )
	lastSelLen = 0;
    else
	lastSelLen = q - p + 1;
    p[lastSelLen] = '\0';

    displayNames( p );
    XtFree( p );

} /* dmSelectBackCallback() */


/************************************************************************/
/* Function    : createDmSelectionBox					*/
/* Purpose     : Callback for creating the DM Selection box		*/
/* Inputs      : Widget ID, client_data, call_data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
createDmSelectionBox(Widget w, XtPointer unused, XmAnyCallbackStruct *call_data)
{
    dmSelectionBox = w;
    XtAddCallback( w, XmNokCallback, (XtCallbackProc)dmSelectOkCallback, NULL );
    XtAddCallback( w, XmNcancelCallback, 
		  (XtCallbackProc)dmSelectBackCallback, NULL );
    XtAddCallback( w, XmNhelpCallback, 
		  (XtCallbackProc)dmSelectNewCallback, NULL );
    XtAddCallback( w, XmNnoMatchCallback, 
		  (XtCallbackProc)dmSelectOkCallback, NULL );

    dmItemDialog = XmCreatePromptDialog( w, "itemNumDialog", (ArgList)NULL, 0 );
    XtUnmanageChild(XmSelectionBoxGetChild(dmItemDialog, XmDIALOG_HELP_BUTTON));

    dmItemDialogTextF = XmSelectionBoxGetChild(dmItemDialog, XmDIALOG_TEXT);
    XtAddCallback( dmItemDialogTextF, XmNmodifyVerifyCallback,
		   (XtCallbackProc)itemNumModifyCallback, NULL );

} /* createDmSelectionBox() */


/************************************************************************/
/* Function    : initRate						*/
/* Purpose     : Initialize the displayed Update Rate from app-default	*/
/* Inputs      : Widget, unused, callback struct			*/
/* Outputs     : None							*/
/************************************************************************/
     Void
initRate( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    sprintf( buff, "%g", (double)appdata.graph_update/1000. );
    XmTextFieldSetString( graphFreqText, buff );

} /* initRate() */


/************************************************************************/
/* Function    : logItem						*/
/* Purpose     : XtTimeOut proc to log item to file			*/
/* Inputs      : LogItem ptr, XtIntervalId				*/
/* Outputs     : None							*/
/************************************************************************/
     Void
logItem( LogItem *lp, XtIntervalId *id )
{
    Reg Nat32		i, j, k, n;
    Reg DM_Element	*ep;
    Reg char		*p;
    MBool		comma;
    double		x;

    if ( --(lp->log_flushcnt) == 0 )
    {
	fflush( lp->log_fp );
	lp->log_flushcnt = lp->log_flush;
    }

    rdm_readtm( lp->log_dmitem, lp->log_data, lp->log_sts.is_size, 
	        &lp->log_time );

    if ( lp->log_fields & LOG_NAME )
	fprintf(lp->log_fp, "%s ", lp->log_sts.is_name);
    comma = FALSE;
    ep = lp->log_sts.is_compound;

    if ( lp->log_fields & LOG_DATA )
	for ( i = n = 0; i < lp->log_sts.is_num_compounds; i++, ep++ )
	{
	    for ( j = 0; j < ep->elt_num; j++ )
	    {
		if ( comma )
		    fprintf(lp->log_fp, ", ");
		comma = TRUE;

		k = type_align[ep->elt_type] - 1;
		n = (n + k) & ~k;
		p = lp->log_data + n;

		switch( ep->elt_type )
		{
		  case DM_EMPTY:
		    break;

		  case DM_CHAR:
		  case DM_UCHAR:
		    if ( isascii(*p) )
			fprintf(lp->log_fp, "%c", *p);
		    else
			fprintf(lp->log_fp, "\\%d", (Nat32)*p);
		    comma = FALSE;
		    break;
		
		  case DM_INT16:
		  case DM_NAT16:
		  case DM_MBOOL:
		    fprintf(lp->log_fp, "%hd", *(Int16 *)p);
		    break;

		  case DM_INT32:
		  case DM_NAT32:
		  case DM_ENUM:
		    fprintf(lp->log_fp, "%d", *(Int32 *)p);
		    break;
			    
		  case DM_FLT32:
		    x = *(Flt32 *)p;
		    fprintf(lp->log_fp, "%f", x);
		    break;

		  case DM_FLT64:
		    x = *(Flt64 *)p;
		    fprintf(lp->log_fp, "%f", x);
		    break;

		  case DM_PTR:
		    fprintf(lp->log_fp, "%#x", *(Nat32 *)p);
		    break;

		  default:
		    fprintf(lp->log_fp, "Unknown type %d\n", ep->elt_type );
		}

		n += typeSizes[ep->elt_type];
	    }
	    comma = TRUE;
	}

    if ( lp->log_fields & LOG_TIME )
	fprintf(lp->log_fp, "  %d.%06d", 
		lp->log_time.tv_sec, lp->log_time.tv_usec);

    fprintf(lp->log_fp, "\n");

    lp->log_tmoutid = XtAppAddTimeOut(appcontext, lp->log_period,
				     (XtTimerCallbackProc)logItem, lp);

} /* logItem() */


/************************************************************************/
/* Function    : logItemCallback					*/
/* Purpose     : OK Callback to start logging DM Item to a file		*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
logItemCallback( Widget w, LogItem *lp, XmAnyCallbackStruct *cbs )
{
    char	*p, *fname;
    Flt64	x;
    LogItem	*nlp;
    struct stat	sbuff;

    lp->log_fp = (FILE *)NULL;
    fname = XmTextFieldGetString( logWidgets[LOG_FNAMETEXTF] );
    bzero( &sbuff, sizeof(sbuff) );
    stat( fname, &sbuff );

    lp->log_fields = 0;
    if ( XmToggleButtonGetState(logWidgets[LOG_NAMETOGGLE]) )
	lp->log_fields |= LOG_NAME;
    if ( XmToggleButtonGetState(logWidgets[LOG_DATATOGGLE]) )
	lp->log_fields |= LOG_DATA;
    if ( XmToggleButtonGetState(logWidgets[LOG_TIMETOGGLE]) )
	lp->log_fields |= LOG_TIME;

    if ( ((p = XmTextFieldGetString(logWidgets[LOG_RATETEXTF])) != NULL) &&
	 (sscanf(p, "%lg", &x) > 0) )
    {
	lp->log_period = (Nat32)(1000. * x);
	XtFree( p );
	rdm_start_cnsmr( lp->log_dmitem, 1000 * lp->log_period, NULL );
    }

    if ( ((p = XmTextFieldGetString(logWidgets[LOG_FLUSHTEXTF])) != NULL) &&
	 (sscanf(p, "%lg", &x) > 0) )
    {
	lp->log_flush = (Nat32)((1000. * x) / lp->log_period);
	XtFree( p );
	lp->log_flushcnt = lp->log_flush;
    }

    for ( nlp = loglist; nlp != LI_NULL; nlp = nlp->log_link )
	if ((nlp->log_dev == sbuff.st_dev) && (nlp->log_inode == sbuff.st_ino))
	{
	    lp->log_fp = nlp->log_fp;
	    break;
	}

    if ( lp->log_fp == (FILE *)NULL )
    {
	lp->log_fp = fopen(fname, "w");
	if ( stat(fname, &sbuff) != 0 )
	{
	    fclose( lp->log_fp );
	    lp->log_fp = (FILE *)NULL;
	}
	lp->log_dev = sbuff.st_dev;
	lp->log_inode = sbuff.st_ino;
    }

    if ( lp->log_fp == (FILE *)NULL )
    {
	rdm_item_status_free( &lp->log_sts );
	free( lp );
	rovError( logWidgets[LOG_FORM], "Cannot open log file" );
    }
    else
    {
	lp->log_link = loglist;
	loglist = lp;
	loglstcnt++;
    }

    XtFree( fname );
    lp->log_tmoutid = XtAppAddTimeOut(appcontext, lp->log_period,
				     (XtTimerCallbackProc)logItem, lp);

    XtUnmanageChild( logWidgets[LOG_FORM] );

} /* logItemCallback() */


/************************************************************************/
/* Function    : logItemPopup						*/
/* Purpose     : Callback for PushButton to Log Item to File		*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
logItemPopup( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    LogItem	*lp;
    
    if ( curItem == GL_NULL )
	return;

    sprintf( buff, "%f", (Flt64)graphUpdateRate()/1000.0 );
    XmTextFieldSetString( logWidgets[LOG_RATETEXTF], buff );

    if ( (lp = (LogItem *)malloc(sizeof(LogItem) + curItem->gl_sts.is_size))
	== LI_NULL )
	rovError( logWidgets[LOG_FORM], "Out of Space" );

    if ( rdm_item_status(curItem->gl_item, &lp->log_sts) != SUCCESS )
	rovError(logWidgets[LOG_FORM], "Failed to get DM Item status");

    lp->log_dmitem = curItem->gl_item;
    lp->log_gui_period = curItem->gl_gui_period;
    lp->log_data = (char *)(lp + 1);

    sprintf( buff, "%s%s", LOG_DIR, lp->log_sts.is_name );
    XmTextFieldSetString( logWidgets[LOG_FNAMETEXTF], buff );
    XtRemoveAllCallbacks( logWidgets[LOG_OKBUTTON], XmNactivateCallback );
    XtAddCallback( logWidgets[LOG_OKBUTTON], XmNactivateCallback,
		   (XtCallbackProc)logItemCallback, lp );

    XtManageChild( logWidgets[LOG_FORM] );

} /* logItemPopup() */


/************************************************************************/
/* Function    : storeLogWidget						*/
/* Purpose     : Creation Callback to store widgets used for LogFile Dialog*/
/* Inputs      : Widget, array index, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
storeLogWidget( Widget w, int index, XmAnyCallbackStruct *cbs )
{
    logWidgets[index] = w;

} /* storeLogWidget() */


/************************************************************************/
/* Function    : stopLog						*/
/* Purpose     : Callback to Stop Data Logging a DM Item		*/
/* Inputs      : Widget, Unused pointer, SelectionBox callback struct	*/
/* Outputs     : None							*/
/************************************************************************/
     Void
stopLog( Widget w, XtPointer unused, XmSelectionBoxCallbackStruct *cbs )
{
    char		*s;
    Reg LogItem		*lp, *lp1;

    XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &s );

    for ( lp = loglist; lp != LI_NULL; lp = lp->log_link )
	if ( strcmp(lp->log_sts.is_name, s) == 0 )
	{
	    XtRemoveTimeOut( lp->log_tmoutid );	/* Stop logging		 */

	    /* Look for any other LogItems that are logging to this file */
	    for ( lp1 = loglist; lp1 != LI_NULL; lp1 = lp1->log_link )
		if ( (lp1 != lp) && (lp1->log_fp == lp->log_fp) )
		    break;
	    if ( lp1 == LI_NULL )		/* If nobody else using file*/
		fclose( lp->log_fp );		/*  close it		    */

	    if ( loglist == lp )		/* Take off linked list	*/
		loglist = lp->log_link;
	    else
		for ( lp1 = loglist; lp1 != LI_NULL; lp1 = lp1->log_link )
		    if ( lp1->log_link == lp )
		    {
			lp1->log_link = lp->log_link;
			break;
		    }

	    rdm_item_status_free( &lp->log_sts ); /* Free item sts ptrs	*/
	    restoreConsumer( lp->log_dmitem, lp->log_gui_period );
	    free( lp );				  /* Free LogItem	*/
	    loglstcnt--;
	    break;
	}

    if ( lp == LI_NULL )
    {
	sprintf( buff, "Not found: %s", s );
	rovError( w, buff );
    }

    XtFree( s );

} /* stopLog() */


/************************************************************************/
/* Function    : stopLogItem						*/
/* Purpose     : Callback for PushButton to Stop Data Logging for Item	*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
stopLogItem( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    Reg LogItem		*lp;
    Reg XmString	*strp;
    Reg Int32		i;

    if ( loglstcnt == 0 )
    {
	rovError( w, "No items being logged" );
	return;
    }

    if ( (strp = (XmString *)malloc(loglstcnt * sizeof(XmString *))) ==
	 (XmString *)NULL )
    {
	rovError(w, "Out of malloc space");
	return;
    }

    for ( lp = loglist, i = 0; lp != LI_NULL; lp = lp->log_link, i++ )
	strp[i] = XmStringCreateSimple( lp->log_sts.is_name );

    XtVaSetValues( stopLogDialog, XmNlistItems, strp, 
		   XmNlistItemCount, i, NULL );

    for ( i--; i >= 0; i-- )
	XmStringFree( strp[i] );

    free( strp );

    XtManageChild( stopLogDialog );

} /* stopLogItem() */


/************************************************************************/
/* Function    : restartFltRecorder					*/
/* Purpose     : Callback to Restart Flight Recorder Function		*/
/* Inputs      : Widget, Unused pointer, SelectionBox callback struct	*/
/* Outputs     : None							*/
/************************************************************************/
     Void
restartFltRecorder( Widget w, XtPointer state,
		    XmSelectionBoxCallbackStruct *cbs )
{
#if 0
    char	*s;
    DM_Item	rec_state, rec_file;

    rec_state = rdm_lookup(RECORD_STATE, 0);
    rec_file  = rdm_lookup(RECORD_FILENAME, 0);

    if ( (rec_state == NO_ITEM) || (rec_file == NO_ITEM) )
    {
	rovError(w, "Flight Recorder not present in target system\n\
		You must load it via ld() and initialize it via recordInit()\n\
		before you can restart it via the user interface");
    }
    else
    {
	XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &s );
	XtFree( s );
	rdm_write_once( rec_file, s, strlen(s) );
	rdm_write_once( rec_state, (char *)&state, sizeof(state) );
    }

    XtUnmanageChild( fltRecorderDialog );
#endif

} /* restartFltRecorder() */


/************************************************************************/
/* Function    : fltRecordCallback					*/
/* Purpose     : Callback for PushButton to Restart Flight Recorder	*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
fltRecordCallback( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
#if 0
    XtManageChild( fltRecorderDialog );
#endif

} /* fltRecordCallback() */


/************************************************************************/
/* Function    : createLogDialogs					*/
/* Purpose     : Create the Logging Dialogs				*/
/* Inputs      : Parent Widget						*/
/* Outputs     : None							*/
/************************************************************************/
     Void
createLogDialogs( Widget w )
{
    XmString	str, str1, str2, str3;

    stopLogDialog = XmCreateSelectionDialog(w, "StopLog", (ArgList)NULL, 0);

    str = XmStringCreateSimple( "Choose Item to Stop Logging:" );
    XtVaSetValues( stopLogDialog, XmNlistLabelString, str, NULL );
    XmStringFree( str );

    XtUnmanageChild(XmSelectionBoxGetChild(stopLogDialog, 
					   XmDIALOG_HELP_BUTTON));
    XtUnmanageChild(XmSelectionBoxGetChild(stopLogDialog, 
					   XmDIALOG_APPLY_BUTTON));
    XtAddCallback(stopLogDialog, XmNokCallback, (XtCallbackProc)stopLog, NULL);

    fltRecorderDialog = XmCreatePromptDialog(w, "FltRecord", (ArgList)NULL, 0);
#if 0
    str = XmStringCreateLtoR(
    "Restart Flight Recorder\nfunction using configuration file:",
			     XmSTRING_DEFAULT_CHARSET );

    str1 = XmStringCreateSimple( RECORD_CFGFILE );
    str2 = XmStringCreateLtoR( "Restart\nRecorder", XmSTRING_DEFAULT_CHARSET );
    str3 = XmStringCreateLtoR( "Stop\nRecorder", XmSTRING_DEFAULT_CHARSET );

    XtVaSetValues( fltRecorderDialog, XmNselectionLabelString, str,
		   XmNtextString, str1, XmNokLabelString, str2,
		   XmNhelpLabelString, str3, NULL );

    XmStringFree( str );
    XmStringFree( str1 );
    XmStringFree( str2 );
    XmStringFree( str3 );

    XtAddCallback( fltRecorderDialog, XmNokCallback,
		  (XtCallbackProc)restartFltRecorder,
		  (XtPointer)REC_RESTART );
    XtAddCallback( fltRecorderDialog, XmNhelpCallback,
		  (XtCallbackProc)restartFltRecorder,
		  (XtPointer)REC_PAUSE );
#endif

} /* createLogDialogs() */


/************************************************************************/
/* Function    : selectDM						*/
/* Purpose     : Callback to select the Data Manager screen		*/
/* Inputs      : Select Ptr						*/
/* Outputs     : None							*/
/************************************************************************/
    Void
selectDM( Select *sp )
{
    stsListWorkProcId = 
	XtAppAddWorkProc( appcontext, (XtWorkProc)stsListWorkProc, &sLst );

    XtManageChild( dmWorkingDialog );

} /* selectDM() */


/************************************************************************/
/* Function    : unselectDM						*/
/* Purpose     : Callback when Data Manager screen is unselected	*/
/* Inputs      : Select Ptr						*/
/* Outputs     : None							*/
/************************************************************************/
    Void
unselectDM( Select *sp )
{
    if ( XtIsManaged(dmWorkingDialog) )
	XtUnmanageChild( dmWorkingDialog );

} /* unselectDM() */


/************************************************************************/
/* Function    : initDm							*/
/* Purpose     : Initialize function for DM screen			*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
    Void
initDm( Void )
{
    XmString		str;

    createLogDialogs( dmFormW );

    dmWorkingDialog = XmCreateWorkingDialog( dmFormW, "dmWorkingDialog",
					     (ArgList)NULL, 0 );
    XtUnmanageChild(XmMessageBoxGetChild(dmWorkingDialog, 
					 XmDIALOG_HELP_BUTTON));
    str = XmStringCreateSimple( "Updating Data Manager Items" );
    XtVaSetValues( dmWorkingDialog, XmNmessageString, str, NULL );
    XmStringFree( str );

    XtAddCallback( dmWorkingDialog, XmNcancelCallback,
		   (XtCallbackProc)cancelStsList, NULL );

    stsListWorkProcId = 
	XtAppAddWorkProc( appcontext, (XtWorkProc)stsListWorkProc, &sLst );

} /* initDm() */
