From: gordon@maxwell.uwaterloo.ca (Gordon R. Strachan)
Subject: XControl program and terminal emulator 1/4
Reply-To: gordon@maxwell.uwaterloo.ca (Gordon R. Strachan)
Organization: University of Waterloo
Date: Sun, 24 Jan 1993 03:48:40 GMT


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Gordon R. Strachan <gordon@maxwell> on Sat Jan 23 22:18:42 1993
#
# This archive contains:
#	GenTerm			Makefile		
#	README			xcontrol		
#	GenTerm/GenTerm.c	GenTerm/GenTerm.h	
#	GenTerm/GenTermEm.h	GenTerm/GenTermEmP.h	
#	GenTerm/GenTermP.h	
#
# Error checking via wc(1) will be performed.

LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH

echo mkdir - GenTerm
mkdir GenTerm

chmod 755 GenTerm

echo x - Makefile
cat >Makefile <<'@EOF'
#  Makefile for whole package

#Directory you want the parser files saved
PARSEDIR=/usr/local/lib/GenTerm

#Directory you want library to be put in
LIBDIR=/usr/local/lib

#Directory you want man pages put in
MANDIR=/usr/local/man

#Directory to install include files
INCDIR=/usr/local/include

#Directory to put executable
BINDIR=/usr/local/bin

DIRS=PARSEDIR=$(PARSEDIR) LIBDIR=$(LIBDIR) MANDIR=$(MANDIR) INCDIR=$(INCDIR) BINDIR=$(BINDIR)

all :
	(cd GenTerm; make $(DIRS) lib)
	(cd xcontrol; make $(DIRS))

install:
	(cd GenTerm; make $(DIRS) install)
	(cd xcontrol; make $(DIRS) install)

installall:
	(cd GenTerm; make $(DIRS) installall)
	(cd xcontrol; make $(DIRS) install)

clean:
	(cd GenTerm; make clean)
	(cd xcontrol; make clean)
@EOF
set `wc -lwc <Makefile`
if test $1$2$3 != 3488741
then
	echo ERROR: wc results of Makefile are $* should be 34 88 741
fi

chmod 644 Makefile

echo x - README
cat >README <<'@EOF'
This package contains all the code necessary to build the XControl program.
XControl is program which provides X window services to programs which where
not written to interact with the X environment.  It provides a terminal
emulator, much like an xterm or hpterm and will also inform the client
program of other X events and allow it to take appropriate actions.  An
example is when the user closes the window, the child program should not simply
be killed (as hpterm would do) but instead should be told to orderly shut
down and save itself.

An example program, called XVi in included.  It provides a simple X interface
to the vi program.  Also, an action database is included to allow the vue
filemanager to call this program whenever the edit action is requested.

The directory xcontrol contains the source code for the XControl program.

The directory GenTerm contains the code for the terminal emulation widget.
This is a stand alone widget which provides a complete terminal emulator
similar to the xterm and hpterm programs.  It can be installed seperately
and used in other programs.

BUILDING THE PROGRAM

First:
    Edit the Makefile in this directory to set the path names of where you
want everything to be put.

Second:
    Type "make"  is this directory to build the widget library and the program.

Third:
    Type "make install" to install the XControl and XVi programs.  All required
programs libraries and application default files will be installed.

Fourth:
    If you want to install the terminal emulator widget library then type
"make installall".


Send any bugs reports or comments to gordon@maxwell.uwaterloo.ca
@EOF
set `wc -lwc <README`
if test $1$2$3 != 392651641
then
	echo ERROR: wc results of README are $* should be 39 265 1641
fi

chmod 644 README

echo mkdir - xcontrol
mkdir xcontrol

chmod 755 xcontrol

echo x - GenTerm/GenTerm.c
cat >GenTerm/GenTerm.c <<'@EOF'
/* GenTerm -- A generalized terminal widget */
/* History:                                 */
/*         Written by G. R. Strachan 1992 */

/*  Copyright Gordon R. Strachan 1992 */
/*  This code is provided as is, neither the University of Waterloo nor */
/*  the author is liable for any damage caused by the use or misuse of this */
/*  code.  */

/* Permission is granted to copy, use and modify this code provided it is */
/* not sold for profit and the above copyright remains intact. */

#include <stdio.h>
#include <ctype.h>
#include <X11/X.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>
#include <X11/Core.h>
#include <X11/CompositeP.h>
#include <X11/Composite.h>
#include <X11/Shell.h>
#include <X11/Xatom.h>
/* sigh... HP doesn't distribute this include file so use it locally */
#include "Xmu.h"
/*#include <X11/Xmu/Xmu.h>*/
#include "GenTermP.h"
#include "GenTerm.h"

#define MIN(a,b) ((a)<(b)?(a):(b))

static XtResource resources[] = {
 {XtNforeground,XtCForeground,XtRPixel,sizeof(Pixel),
   XtOffset(GenTermWidget,genTerm.NormalForeground),XtRString,
   XtDefaultForeground},
 {XtNbackground,XtCBackground,XtRPixel,sizeof(Pixel),
   XtOffset(GenTermWidget,genTerm.NormalBackground),XtRString,
   XtDefaultBackground},
 {XtNkbdCallback,XtCKbdCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(GenTermWidget,genTerm.kbdcallback),XtRCallback,NULL},
 {XtNtopCallback,XtCTopCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(GenTermWidget,genTerm.topcallback),XtRCallback,NULL},
 {XtNresizeCallback,XtCResizeCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(GenTermWidget,genTerm.resizecallback),XtRCallback,NULL},
 {XtNlockCallback,XtCLockCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(GenTermWidget,genTerm.lockcallback),XtRCallback,NULL},
 {XtNwidth,XtCWidth,XtRDimension,sizeof(Dimension),
   XtOffset(GenTermWidget,core.width),XtRImmediate,(caddr_t)(7*80)},
 {XtNheight,XtCHeight,XtRDimension,sizeof(Dimension),
   XtOffset(GenTermWidget,core.height),XtRImmediate,(caddr_t)(13*24)},
 {XtNbottomMargin,XtCBottomMargin,XtRDimension,sizeof(Dimension),
   XtOffset(GenTermWidget,genTerm.BottomMargin),XtRImmediate,(caddr_t)0},
 {XtNrows,XtCRows,XtRInt,sizeof(int),XtOffset(GenTermWidget,genTerm.rows),
   XtRImmediate,(caddr_t)24},
 {XtNcolumns,XtCColumns,XtRInt,sizeof(int),
   XtOffset(GenTermWidget,genTerm.columns),XtRImmediate,(caddr_t)80},
 {XtNbaseFont,XtCBaseFont,XtRString,sizeof(char *),
   XtOffset(GenTermWidget,genTerm.Font),XtRString,"7x13"},
 {XtNalternateFont,XtCAlternateFont,XtRString,sizeof(char *),
   XtOffset(GenTermWidget,genTerm.AlternateFont),XtRString,"7x13bold"},
 {XtNcharacterWidth,XtCCharacterWidth,XtRInt,sizeof(int),
   XtOffset(GenTermWidget,genTerm.CharWidth),XtRImmediate,(caddr_t)7},
 {XtNcharacterHeight,XtCCharacterHeight,XtRInt,sizeof(int),
   XtOffset(GenTermWidget,genTerm.CharHeight),XtRImmediate,(caddr_t)13},
 {XtNautoLineWrap,XtCAutoLineWrap,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.AutoWrap),XtRImmediate,FALSE},
 {XtNliteralMode,XtCLiteralMode,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.LiteralMode),XtRImmediate,(caddr_t)FALSE},
 {XtNcursorColor,XtCCursorColor,XtRPixel,sizeof(Pixel),
   XtOffset(GenTermWidget,genTerm.CursorColour),XtRString,"orange"},
 {XtNshowCursor,XtCShowCursor,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.ShowCursor),XtRImmediate,(caddr_t)True},
 {XtNsaveLines,XtCSaveLines,XtRInt,sizeof(int),
   XtOffset(GenTermWidget,genTerm.SaveLines),XtRImmediate,(caddr_t)512},
 {XtNcursorFloats,XtCCursorFloats,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.CursorFloats),XtRImmediate,(caddr_t)TRUE},
 {XtNfieldAttributes,XtCFieldAttributes,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.FieldAttributes),XtRImmediate,
   (caddr_t)FALSE},
 {XtNscrollDownClear,XtCScrollDownClear,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.ScrollDownClear),XtRImmediate,
   (caddr_t)FALSE},
 {XtNfullScroll,XtCFullScroll,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.FullScroll),XtRImmediate,(caddr_t)FALSE},
 {XtNinsertMode,XtCInsertMode,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.InsertMode),XtRImmediate,(caddr_t)FALSE},
 {XtNsaveScrollRegion,XtCSaveScrollRegion,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.SaveScrollRegion),XtRImmediate,
   (caddr_t)FALSE},
 {XtNblinkRate,XtCBlinkRate,XtRInt,sizeof(int),
   XtOffset(GenTermWidget,genTerm.BlinkRate),XtRImmediate,(caddr_t)500},
 {XtNnumberColors,XtCNumberColors,XtRInt,sizeof(int),
   XtOffset(GenTermWidget,genTerm.NumberColours),XtRImmediate,(caddr_t)8},
 {XtNpenColors,XtCPenColors,XtRString,sizeof(char *),
   XtOffset(GenTermWidget,genTerm.PenColours),XtRString,"Default:Default"},
 {XtNdefineColor,XtCDefineColor,XtRInt,sizeof(int),
   XtOffset(GenTermWidget,genTerm.DefineColour),XtRImmediate,(caddr_t)GTRGB},
 {XtNscrollOnOutput,XtCScrollOnOutput,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.ScrollOnOutput),XtRImmediate,(caddr_t)FALSE},
 {XtNcursorKeyScrollRegion,XtCCursorKeyScrollRegion,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.CursorKeyScrollRegion),XtRImmediate,
   (caddr_t)FALSE},
 {XtNmarginBell,XtCMarginBell,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.MarginBell),XtRImmediate,(caddr_t)False},
 {XtNmargin,XtCMargin,XtRInt,sizeof(int),
   XtOffset(GenTermWidget,genTerm.Margin),XtRImmediate,(caddr_t)8},
 {XtNeolStick,XtCEolStick,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.EOLStick),XtRImmediate,(caddr_t)False},
 {XtNlockScreen,XtCLockScreen,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.Locked),XtRImmediate,(caddr_t)False},
 {XtNignoreNull,XtCIgnoreNull,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermWidget,genTerm.IgnoreNull),XtRImmediate,(caddr_t)False},
};

static void GtInput();
int GtOutput();
static void GtOutputAction();
static void GtExpose();
static void GtNoExpose();
static void GtInitialize();
static void GtRealize();
static void GtDestroy();
static void GtResize();
static void GtRedisplay();
static void GtUpdateRegion();
static Boolean GtSetValues();
static void GtAllocateScreen();
static void GtStoreString();
static void GtShowLine();
static void GtShowCursor();
static void GtUnShowCursor();
static void GtCheckPosition();
static void GtNextLine();
static void GtScrollScreen();
static void GtDoTopCallback();
static void GtSetFonts();
static void GtCreatePens();
static void GtSetupPenColours();
static void GtMoveScreen();
static int GtCheckValidPosition();
static int GtScrollRegionScroll();
static int GtScrollRegionScrollScreen();
static void GtBlinkCallBack();
static void GtDefinePen();
static void GtDefineHalfBrightPen();
static void GtHSLtoRGB();
static void GtRGBtoHSL();
static void GtReallocScreen();
static void GtStartSelection();
static void GtExtendSelection();
static void GtMakeSelection();
static void GtSortStartEnd();
static char *GtCopySection();
static Boolean GtConvertProc();
static void GtLoseSelection();
static void GtInsertSelection();
static void GtInsertCallback();
static void GtHighLightSection();
static void GtDoTopCallback();
static void GtDoLockCallback();
static void GtUnHighLightSection();
static void GtChangeFonts();
static void GtChangeCursorColour();
static void GtChangeColour();
static void GtChangePen();
static void GtDestroyPenColours();

static XtActionsRec actions[] = {
 {"input",GtInput},
 {"expose",GtExpose},
 {"noexpose",GtNoExpose},
 {"output",GtOutputAction},
 {"StartSelection",GtStartSelection},
 {"ExtendSelection",GtExtendSelection},
 {"MakeSelection",GtMakeSelection},
 {"InsertSelection",GtInsertSelection},
};

static char translations[] =
"\
<KeyPress>:input()\n\
<Expose>:expose()\n\
<GraphicsExpose>:expose()\n\
<NoExpose>:noexpose()\n\
<Btn1Down>:StartSelection()\n\
<Btn1Motion>:ExtendSelection()\n\
<Btn1Up>:MakeSelection(PRIMARY,CUT_BUFFER0)\n\
<Btn2Up>:InsertSelection(PRIMARY)\n\
";

GenTermClassRec genTermClassRec =
{
{  /* core fields */
/* superclass               */      (WidgetClass) &compositeClassRec,
/* class_name               */      "GenTerm",
/* widget_size              */      sizeof(GenTermRec),
/* class_initialize         */      NULL,
/* class_part_initialize    */      NULL,
/* class_inited             */      FALSE,
/* initialize               */      GtInitialize,
/* initialize_hook          */      NULL,
/* realize                  */      GtRealize,
/* actions                  */      actions,
/* num_actions              */      XtNumber(actions),
/* resources                */      resources,
/* num_resources            */      XtNumber(resources),
/* xrm_class                */      NULLQUARK,
/* compress_motion          */      TRUE,
/* compress_exposure        */      FALSE,
/* compress_enterleave      */      TRUE,
/* visible_interest         */      FALSE,
/* destroy                  */      GtDestroy,
/* resize                   */      GtResize,
/* expose                   */      GtRedisplay,
/* set_values               */      GtSetValues,
/* set_values_hook          */      NULL,
/* set_values_almost        */      XtInheritSetValuesAlmost,
/* get_values_hook          */      NULL,
/* accept_focus             */      XtInheritAcceptFocus,
/* version                  */      XtVersion,
/* callback_private         */      NULL,
/* tm_table                 */      translations,
/* query_geometry           */      XtInheritQueryGeometry,
/* display_accelerator      */      XtInheritDisplayAccelerator,
/* extension                */      NULL
},
{ /* composite_class fields */
/* geometry_manager   */   XtInheritGeometryManager,
/* change_managed     */   XtInheritChangeManaged,
/* insert_child       */   XtInheritInsertChild,
/* delete_child       */   XtInheritDeleteChild,
/* extension          */   NULL
},
{ 0}
};


WidgetClass genTermWidgetClass = (WidgetClass) &genTermClassRec;

/* GtInitialize:  This is the initialization method for the widget instances */
/* it basically just loads the fonts.  Most of the real work is done in the */
/* realize method    */

static void GtInitialize(request,new)

GenTermWidget request,new;

{
 int val;

 val = GtLoadFonts(new);
 if(val == 0)
  XtAppError(XtWidgetToApplicationContext(new),
	     "GenTerm Widget: Can't load fonts!");
 else if(val == 2)
  XtAppError(XtWidgetToApplicationContext(new),
	     "GenTerm Widget: Alternate font is different size than base font");

 if(new->genTerm.SaveLines < new->genTerm.rows)
  XtAppError(XtWidgetToApplicationContext(new),
	     "GenTerm Widget: Savelines can not be less than rows");
 new->genTerm.BlinkOn = -1;
 new->genTerm.ColourMap = DefaultColormap(XtDisplay(new),
					  DefaultScreen(XtDisplay(new)));
 new->genTerm.ExposureCount = 0;
 new->genTerm.Locked = False;
 XmuInternAtom(XtDisplay(new),XmuMakeAtom("NULL"));
}

/* GtLoadFonts:  This function loads the required fonts for the widget */

static int GtLoadFonts(new)

GenTermWidget new;

{ 
 if((new->genTerm.CurrentFont = XLoadQueryFont(XtDisplay(new),
					       new->genTerm.Font)) != NULL)
  {
   new->genTerm.CharHeight = new->genTerm.CurrentFont->ascent +
    new->genTerm.CurrentFont->descent;
   new->genTerm.CharWidth = XTextWidth(new->genTerm.CurrentFont,"M",1);
  }
 else
  return(0);
 if((new->genTerm.AltFont = XLoadQueryFont(XtDisplay(new),
					   new->genTerm.AlternateFont)) != NULL)
  {
   if((new->genTerm.AltFont->ascent + new->genTerm.AltFont->descent 
       != new->genTerm.CharHeight) ||
      (XTextWidth(new->genTerm.AltFont,"M",1) != new->genTerm.CharWidth))
    return(2);
  }
 else
  return(0);
 return(1);
}

/* GtRealize:  This is the realization method for the widget instance. */
/*   It calculates the screen size, initializes the screen data structure */
/*   sets up the default attributes and initializes all private variables */

static void GtRealize(w,valueMask,attributes)

GenTermWidget w;
XtValueMask *valueMask;
XSetWindowAttributes *attributes;

{
 Arg args[20];
 int n = 0;
 WidgetClass superclass;
 int npens;
 int i;

 superclass = (WidgetClass) NULL;
 superclass = (WidgetClass)compositeWidgetClass;
 (*superclass->core_class.realize)(w,valueMask,attributes);

 n = 0;
 XtSetArg(args[n],XtNwidthInc,w->genTerm.CharWidth); n++;
 XtSetArg(args[n],XtNheightInc,w->genTerm.CharHeight); n++;
 XtSetValues(w,args,n);

 GtSetupPenColours(w);
 GtDefinePen(w,0);

 w->genTerm.foreground = w->genTerm.CurrentForeground =
  w->genTerm.Colours[0].Foreground;
 w->genTerm.background = w->genTerm.CurrentBackground =
  w->genTerm.Colours[0].Background;
 w->genTerm.DefaultSettings.Font = w->genTerm.CurrentFont;
 w->genTerm.DefaultSettings.type = 0;
 memcpy(&(w->genTerm.CurrentSettings),&(w->genTerm.DefaultSettings),
	sizeof(struct Attribute));

 npens = w->genTerm.NumberColours << NUMATTRIBUTES;

 w->genTerm.Pens = (struct GraphicsContexts **) 
  XtMalloc(sizeof(struct GraphicsContexts *) * npens);
 for(i = 0; i < npens; i++)
  w->genTerm.Pens[i] = NULL;

 GtCreatePens(w,0);
 GtAllocateScreen(w);

 w->genTerm.CursorOn = FALSE;

 w->genTerm.CurrentRow = 0;
 w->genTerm.CurrentColumn = 0;
 w->genTerm.ScreenTop = 0;
 w->genTerm.VScreenTop = 0;
 w->genTerm.VirtualTop = 0;
 w->genTerm.MaxVirtualTop = 0;
 w->genTerm.CursorOffset = 0;
 w->genTerm.CurrentNumRows = w->genTerm.rows;
 w->genTerm.CurrentNumColumns = w->genTerm.columns;
 w->genTerm.CurrentSaveLines = w->genTerm.SaveLines;
 w->genTerm.CursorIsStuck = False;
 w->genTerm.SelectionStarted = False;
 w->genTerm.CurrentSelection = NULL;

 /* setup the default mapping table */

 for(i = 0; i < ' '; i++)
  w->genTerm.MapTable[i] = ' ';
 for(i = ' ' + 1; i < 128; i++)
  w->genTerm.MapTable[i] = i;
 for(i = 128; i < NMAP; i++)
  w->genTerm.MapTable[i] = ' ';
}

/* GtCreatePens:  This function builds the graphics contexts needed to */
/*   implement the current attributes.  The graphics contexts are stored */
/*   in the lookup table at position num */

static void GtCreatePens(w,num)

GenTermWidget w;
int num;

{
 XGCValues values;
 int HighLight = num | HIGHLIGHT;

 w->genTerm.Pens[num] = (struct GraphicsContexts *)
  XtMalloc(sizeof(struct GraphicsContexts));

 w->genTerm.Pens[HighLight] = (struct GraphicsContexts *)
  XtMalloc(sizeof(struct GraphicsContexts));

 values.graphics_exposures = TRUE;
 values.foreground = w->genTerm.foreground;
 values.background = w->genTerm.background;
 w->genTerm.Pens[num]->draw_gc = XCreateGC(XtDisplay(w),XtWindow(w),
					   GCBackground | GCForeground | 
					   GCGraphicsExposures,&values);
 XSetFont(XtDisplay(w),w->genTerm.Pens[num]->draw_gc,
	  w->genTerm.CurrentSettings.Font->fid);

 values.graphics_exposures = TRUE;
 values.foreground = w->genTerm.background;
 values.background = w->genTerm.foreground;
 w->genTerm.Pens[HighLight]->draw_gc = XCreateGC(XtDisplay(w),XtWindow(w),
						 GCBackground | GCForeground |
						 GCGraphicsExposures,&values);
 XSetFont(XtDisplay(w),w->genTerm.Pens[HighLight]->draw_gc,
	  w->genTerm.CurrentSettings.Font->fid);

 values.graphics_exposures = FALSE;
 values.foreground = w->genTerm.foreground;
 values.background = w->genTerm.CursorColour;
 w->genTerm.Pens[num]->cursor_gc = XCreateGC(XtDisplay(w),XtWindow(w),
					     GCBackground | GCForeground |
					     GCGraphicsExposures,&values);
 XSetFont(XtDisplay(w),w->genTerm.Pens[num]->cursor_gc,
	  w->genTerm.CurrentSettings.Font->fid);

 values.graphics_exposures = FALSE;
 values.foreground = w->genTerm.background;
 values.background = w->genTerm.CursorColour;
 w->genTerm.Pens[HighLight]->cursor_gc = XCreateGC(XtDisplay(w),XtWindow(w),
						   GCBackground | GCForeground |
						   GCGraphicsExposures,&values);
 XSetFont(XtDisplay(w),w->genTerm.Pens[HighLight]->cursor_gc,
	  w->genTerm.CurrentSettings.Font->fid);

 values.graphics_exposures = FALSE;
 values.foreground = w->genTerm.background;
 values.background = w->genTerm.background;
 w->genTerm.Pens[num]->blink_gc = XCreateGC(XtDisplay(w),XtWindow(w),
					    GCBackground | GCForeground |
					    GCGraphicsExposures,&values);
 XSetFont(XtDisplay(w),w->genTerm.Pens[num]->blink_gc,
	  w->genTerm.CurrentSettings.Font->fid);

 values.graphics_exposures = FALSE;
 values.foreground = w->genTerm.foreground;
 values.background = w->genTerm.background;
 w->genTerm.Pens[HighLight]->blink_gc = XCreateGC(XtDisplay(w),XtWindow(w),
						  GCBackground | GCForeground |
						  GCGraphicsExposures,&values);
 XSetFont(XtDisplay(w),w->genTerm.Pens[HighLight]->blink_gc,
	  w->genTerm.CurrentSettings.Font->fid);
}

/* GtSetupPenColours(w):  This function allocates and initializes the pen */
/*  colours structure.  */

static void GtSetupPenColours(w)

GenTermWidget w;

{
 int i,j,k;
 char *Colours = w->genTerm.PenColours;
 char ColourName[100];

 w->genTerm.Colours = (struct PenColour *) XtMalloc(sizeof(struct PenColour) *
						    w->genTerm.NumberColours);

 for(i = 0; i < w->genTerm.NumberColours; i++)
  {
   w->genTerm.Colours[i].defined = 0;
   w->genTerm.Colours[i].ForegroundName = XtMalloc(sizeof(char) * 8);
   w->genTerm.Colours[i].BackgroundName = XtMalloc(sizeof(char) * 8);
   strcpy(w->genTerm.Colours[i].ForegroundName,"Default");
   strcpy(w->genTerm.Colours[i].BackgroundName,"Default");
  }

 /* we now parse the colour list we were given */

 i = j = 0;
 while(*Colours != NULL)
  {
   if(i >= w->genTerm.NumberColours)
    break;
   k = 0;
   while((Colours[k] != ':') && (Colours[k] != NULL))
    ColourName[k++] = Colours[k];
   ColourName[k] = NULL;
   if(j == 0)
    {
     XtFree(w->genTerm.Colours[i].ForegroundName);
     w->genTerm.Colours[i].ForegroundName = XtMalloc(sizeof(char) * 
						     strlen(ColourName) + 1);
     strcpy(w->genTerm.Colours[i].ForegroundName,ColourName);
     j = 1;
    }
   else
    {
     XtFree(w->genTerm.Colours[i].BackgroundName);
     w->genTerm.Colours[i].BackgroundName = XtMalloc(sizeof(char) *
						     strlen(ColourName) + 1);
     strcpy(w->genTerm.Colours[i].BackgroundName,ColourName);
     j = 0;
     i++;
    }
   if(Colours[k] != NULL)
    Colours = &(Colours[++k]);
  }
}

/* GtDestroyPenColours:  This function deallocates the Pen colour structure */

static void GtDestroyPenColours(w)

GenTermWidget w;

{
 int i;

 for(i = 0; i < w->genTerm.NumberColours; i++)
  {
   XtFree(w->genTerm.Colours[i].ForegroundName);
   XtFree(w->genTerm.Colours[i].BackgroundName);
  }
 XtFree(w->genTerm.Colours);
}

/* GtDefinePen:  This function defines the colour information for the given */
/* pen number. */

static void GtDefinePen(w,pen)

GenTermWidget w;
int pen;

{
 XColor Colour;
 char string[1024];

 if(w->genTerm.Colours[pen].defined == 0)
  {
   if(strcmp(w->genTerm.Colours[pen].ForegroundName,"Default") == 0)
    w->genTerm.Colours[pen].Foreground = w->genTerm.NormalForeground;
   else
    {
     if(!XParseColor(XtDisplay(w),
		     w->genTerm.ColourMap,
		     w->genTerm.Colours[pen].ForegroundName,&Colour))
      {
       sprintf(string,"Foreground color %s can't be located for pen %d",
	       w->genTerm.Colours[pen].ForegroundName,pen);
       XtAppWarning(XtWidgetToApplicationContext(w),string);
       w->genTerm.Colours[pen].Foreground = w->genTerm.NormalForeground;
      }
     else
      {
       if(!XAllocColor(XtDisplay(w),w->genTerm.ColourMap,&Colour))
	{
	 sprintf(string,"Foreground color %s can not be allocated for pen %d",
		 w->genTerm.Colours[pen].ForegroundName,pen);
	 XtAppWarning(XtWidgetToApplicationContext(w),string);
	 w->genTerm.Colours[pen].Foreground = w->genTerm.NormalForeground;
	}
       else
	w->genTerm.Colours[pen].Foreground = Colour.pixel;
      }
    }
   if(strcmp(w->genTerm.Colours[pen].BackgroundName,"Default") == 0)
    w->genTerm.Colours[pen].Background = w->genTerm.NormalBackground;
   else
    {
     if(!XParseColor(XtDisplay(w),
		     w->genTerm.ColourMap,w->genTerm.Colours[pen].BackgroundName,
		     &Colour))
      {
       sprintf(string,"Background color %s can't be located for pen %d",
	       w->genTerm.Colours[pen].BackgroundName,pen);
       XtAppWarning(XtWidgetToApplicationContext(w),string);
       w->genTerm.Colours[pen].Background = w->genTerm.NormalBackground;
      }
     else
      {
       if(!XAllocColor(XtDisplay(w),w->genTerm.ColourMap,&Colour))
	{
	 sprintf(string,"Background color %s can not be allocated for pen %d",
		 w->genTerm.Colours[pen].BackgroundName,pen);
	 XtAppWarning(XtWidgetToApplicationContext(w),string);
	 w->genTerm.Colours[pen].Background = w->genTerm.NormalBackground;
	}
       else
	w->genTerm.Colours[pen].Background = Colour.pixel;
      }
    }
   w->genTerm.Colours[pen].defined = 1;
  }
}

/* GtDefinePenColour:  This function allows a pen colour to be defined */
/*  by either the rgb or hsl values of the foreground and the background. */
/*  This routine should probably try to free the previous colours used for */
/*  this pen but I have no way of telling if the colours are used in another */
/*  pen so I might accidently free a colour I still need. */

GtDefinePenColour(w,pen,fr,fg,fb,br,bg,bb)

GenTermWidget w;
int pen;
float fr,fg,fb;
float br,bg,bb;

{
 int Fr,Fg,Fb;
 int Br,Bg,Bb;
 int red,green,blue;
 XColor Foreground;
 XColor Background;
 int GotForeground = 0;

#define GtFixColour(a)  ((a)<0.0?0.0:((a)>1.0?1.0:(a)))

 /* first make sure we received sane values */

 if(pen < 0)
  pen = 0;
 if(pen >= w->genTerm.NumberColours)
  pen = w->genTerm.NumberColours - 1;

 Fr = GtFixColour(fr) * MAXCOLOUR;
 Fg = GtFixColour(fg) * MAXCOLOUR;
 Fb = GtFixColour(fb) * MAXCOLOUR;
 Br = GtFixColour(br) * MAXCOLOUR;
 Bg = GtFixColour(bg) * MAXCOLOUR;
 Bb = GtFixColour(bb) * MAXCOLOUR;

 if(w->genTerm.DefineColour == GTRGB)
  {
   Foreground.red = Fr;
   Foreground.green = Fg;
   Foreground.blue = Fb;

   Background.red = Br;
   Background.green = Bg;
   Background.blue = Bb;
  }
 else
  {
   GtHSLtoRGB(&red,&green,&blue,Fr,Fg,Fb);
   Foreground.red = red;
   Foreground.green = green;
   Foreground.blue = blue;
   GtHSLtoRGB(&red,&green,&blue,Br,Bg,Bb);
   Background.red = red;
   Background.green = green;
   Background.blue = blue;
  }
 if(XAllocColor(XtDisplay(w),w->genTerm.ColourMap,&Foreground))
  {
   w->genTerm.Colours[pen].Foreground = Foreground.pixel;
   GotForeground = 1;
  }
 if(XAllocColor(XtDisplay(w),w->genTerm.ColourMap,&Background))
  w->genTerm.Colours[pen].Background = Background.pixel;
 else
  if((w->genTerm.Colours[pen].defined == 0) && (GotForeground == 1))
   {				/* managed to allocate foreground colour only, fall back on default */
    w->genTerm.Colours[pen].Background = w->genTerm.NormalBackground;
   }

 w->genTerm.Colours[pen].defined = 1;
 return(GTGOOD);
}

/* GtDefineHalfBrightPen : This function defines the halfbright colour for */
/*  the given pen. The algorithm first calculates the rgb values of the */
/*  foreground and background colours of the pen.  These are then converted */
/*  to hue saturation and luminance.  The difference in the luminance vales */
/*  is calculated.  A new colour is then built such that it has the same hue */
/*  and saturation as the foreground pen.  The luminance is calculated as */
/*  the luminance of the foreground colour minus 3/4 of the luminance */
/*  difference.  The 3/4 factor was determined empiracally. */

static void GtDefineHalfBrightPen(w,pen)

GenTermWidget w;
int pen;

{
 int r,g,b,h,s,l;
 int l1,ldiff;
 XColor ForegroundColour;
 XColor BackgroundColour;
 XrmValue from,to;

 switch(w->genTerm.Colours[pen].defined)
  {
 case 0:
   GtDefinePen(w,pen);
 case 1:
   from.size = sizeof(Pixel);
   from.addr = (caddr_t) &(w->genTerm.Colours[pen].Background);
   to.size = sizeof(XColor);
   to.addr = (caddr_t) &(BackgroundColour);
   XtConvertAndStore(w,XtRPixel,&from,XtRColor,&to);

   from.size = sizeof(Pixel);
   from.addr = (caddr_t) &(w->genTerm.Colours[pen].Foreground);
   to.size = sizeof(XColor);
   to.addr = (caddr_t) &ForegroundColour;
   XtConvertAndStore(w,XtRPixel,&from,XtRColor,&to);

   r = BackgroundColour.red;
   g = BackgroundColour.green;
   b = BackgroundColour.blue;
   GtRGBtoHSL(r,g,b,&h,&s,&l);

   l1 = l;

   r = ForegroundColour.red;
   g = ForegroundColour.green;
   b = ForegroundColour.blue;
   GtRGBtoHSL(r,g,b,&h,&s,&l);

   ldiff = l - l1;
   l = l - ldiff * 0.75;
   GtHSLtoRGB(&r,&g,&b,h,s,l);

   ForegroundColour.red = r;
   ForegroundColour.green = g;
   ForegroundColour.blue = b;

   if(!XAllocColor(XtDisplay(w),w->genTerm.ColourMap,&ForegroundColour))
    {
     w->genTerm.Colours[pen].HalfBright = w->genTerm.Colours[pen].Foreground;
     w->genTerm.Colours[pen].defined = 2;
     return;
    }
   w->genTerm.Colours[pen].HalfBright = ForegroundColour.pixel;
   w->genTerm.Colours[pen].defined = 2;
   break;
 case 2:
   break;
  }
}
/* GtDestroy:  This is the destroy method for the widget instance.  It frees */
/*   up all allocated memory */

static void GtDestroy(w)

GenTermWidget w;

{
 int i;
 int npen;

 /* first delete all the graphics contexts */

 npen = w->genTerm.NumberColours <<NUMATTRIBUTES;
 for(i = 0; i < npen; i++)
  if(w->genTerm.Pens[i] != NULL)
   {
    XFreeGC(XtDisplay(w),w->genTerm.Pens[i]->draw_gc);
    XFreeGC(XtDisplay(w),w->genTerm.Pens[i]->cursor_gc);
    XFreeGC(XtDisplay(w),w->genTerm.Pens[i]->blink_gc);
    XtFree(w->genTerm.Pens[i]);
   }
 XtFree(w->genTerm.Pens);

 /* now free our colours */

 for(i = 0; i < w->genTerm.NumberColours; i++)
  if(w->genTerm.Colours[i].defined != 0)
   {
    if(strcmp(w->genTerm.Colours[i].ForegroundName,"Default") != 0)
     XFreeColors(XtDisplay(w),w->genTerm.ColourMap,
		 &(w->genTerm.Colours[i].Foreground),1,0);
    if(strcmp(w->genTerm.Colours[i].BackgroundName,"Default") != 0)
     XFreeColors(XtDisplay(w),w->genTerm.ColourMap,
		 &(w->genTerm.Colours[i].Background),1,0);
    if(w->genTerm.Colours[i].defined == 2)
     XFreeColors(XtDisplay(w),w->genTerm.ColourMap,
		 &(w->genTerm.Colours[i].HalfBright),1,0);
   }
 GtDestroyPenColours(w);

 if(w->genTerm.CurrentSelection != NULL)
  XtFree(w->genTerm.CurrentSelection);

 for(i = 0; i < w->genTerm.SaveLines; i++)
  {
   XtFree(w->genTerm.VScreen[i]->Characters);
   XtFree(w->genTerm.VScreen[i]->Attributes);
   XtFree(w->genTerm.VScreen[i]->Fields);
   XtFree(w->genTerm.VScreen[i]);
  }
 XtFree(w->genTerm.VScreen);
 XtFree(w->genTerm.Screen);
}

/* GtBlinkCallBack:  This is the timer callback which is used to implement */
/*  blinking text.  Everytime it is called it checks to see which state it */
/*  in, whether the blinking text is shown or not.  It then searches the */
/*  screen for text with the blinking mode inabled and redraws it with the */
/*  appropriate graphics context.  If, it doesn't find any text on the */
/*  screen which has a blinking attribute then it searches the save memory */
/*  to see if there is any there.  If it doesn't find end then it does not */
/*  reset the timeout callback. */

static void GtBlinkCallBack(client_data,Id)

XtPointer client_data;
XtIntervalId *Id;

{
 GenTermWidget w = (GenTermWidget) client_data;
 int i,j,k;
 GC gc;
 int found = 0;
 int start;
 int xpos,ypos;
 int len;
 int type;

 for(i = 0; i < w->genTerm.rows; i++)
  {
   j = 0;
   while(j < w->genTerm.columns)
    {
     if(w->genTerm.Screen[i]->Attributes[j].type & SETBLINK)
      {
       type = w->genTerm.Screen[i]->Attributes[j].type;
       start = j;
       found = 1;
       while((++j < w->genTerm.columns) && 
	     (w->genTerm.Screen[i]->Attributes[j].type == type));

       len = j - start;
       if(j == w->genTerm.columns)
	{		/* don't blink the tail end of field (looks better) */
	 k = j - 1;
	 while((k >= start) && (w->genTerm.Screen[i]->Characters[k] == ' '))
	  {
	   k--;
	   len--;
	  }
	}
       if(w->genTerm.BlinkOn == 0)
	gc = w->genTerm.Pens[type]->blink_gc;
       else
	gc = w->genTerm.Pens[type]->draw_gc;

       ypos = i * w->genTerm.CharHeight + w->genTerm.CurrentFont->ascent;
       xpos = start * w->genTerm.CharWidth;
       XDrawImageString(XtDisplay(w),XtWindow(w),gc,xpos,ypos,
			&(w->genTerm.Screen[i]->Characters[start]),len);
       if(type & SETUNDERLINE)	/* is this an underline font? */
	{
	 ypos += w->genTerm.CurrentFont->descent - 1;
	 XDrawLine(XtDisplay(w),XtWindow(w),gc,xpos,ypos,
		   xpos + len * w->genTerm.CharWidth,ypos);
	}
      }
     else
      j++;
    }
  }

 /* check if we destroyed the cursor and fix it if we did */
 if(w->genTerm.Screen[w->genTerm.CurrentRow]->
    Attributes[w->genTerm.CurrentColumn].type & SETBLINK)
  GtShowCursor(w);
 w->genTerm.BlinkOn = (w->genTerm.BlinkOn + 1) % 2;

 /* if we are still in a blink mode keep the  callback alive since we may get */
 /* more output to blink. */

 if(w->genTerm.CurrentSettings.type & SETBLINK)
  found = 1;

 if(found == 0)		/* if didn't find a blink on screen, check memory */
  {
   for(i = 0; i < w->genTerm.SaveLines; i++)
    for(j = 0; j < w->genTerm.columns; j++)
     if(w->genTerm.VScreen[i]->Attributes[j].type & SETBLINK)
      {
       found = 1;
       break;
      }
  }
 if(found == 0)
  w->genTerm.BlinkOn = -1;
 else
  w->genTerm.BlinkTimeOut =
   XtAppAddTimeOut(XtWidgetToApplicationContext(w),
		   (unsigned long) w->genTerm.BlinkRate,GtBlinkCallBack,w);
}

/* GtInput:  This is the input action callback.  It is called anytime an */
/*   input action occures.  It simply passes the X event on to the input */
/*   callback routine */

static void GtInput(w,event,x,y)

GenTermWidget w;
XEvent *event;
String *x;
Cardinal *y;

{
 GenTermCallback reason;

 GtMarginBell(w);

 reason.reason = GT_INPUT;
 reason.event = event;
 XtCallCallbacks(w,XtNkbdCallback,(caddr_t)&reason);
}

/* GtMarginBell:  This function tests whether the margin bell should be */
/*  sounded or not and sounds it if it should.  */

int GtMarginBell(w)

GenTermWidget w;

{
 if((w->genTerm.MarginBell) && 
    (w->genTerm.CurrentColumn == (w->genTerm.columns - w->genTerm.Margin)))
  XBell(XtDisplay(w),50);
 return(GTGOOD);
}

/* GtOutputAction:  This is the output action handler for the widget.  It */
/*  will send the given strings to the widget to be displayed on the screen */

static void GtOutputAction(w,event,strings,num)

GenTermWidget w;
XEvent *event;
char *strings[];
Cardinal *num;

{
 int i;

 for(i = 0; i < *num; i++)
  {
   GtOutput(w,strings[i],strlen(strings[i]));
  }
}

/* GtOutput:  This is the main user input routine.  The calling process */
/*   passes the function a character string and the length of the string. */
/*   The string is first filtered to make sure all the characters are */
/*   displayable.  If the LiteralMode resource is set, control characters */
/*   are proceeded with a ^ sign and mapped down into the legal range. The */
/*   string is stored in the screen array at the current cursor position */
/*   which is then updated.  */

int GtOutput(w,string,len)

GenTermWidget w;
char *string;
int len;

{
 char Buffer[1024];
 int BufferSize = 1024;
 int i,j;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 /* first filter input to ensure there is nothing nasty in it */

 for(i = 0, j = 0; i < len; i++)
  {
   if(j >= BufferSize-3)
    {
     GtStoreString(w,Buffer,j);
     j = 0;
    }
   if(w->genTerm.LiteralMode == TRUE)
    {
     if(!iscntrl(string[i]))
      Buffer[j++] = string[i];
     else
      {
       Buffer[j++] = '^';
       Buffer[j++] = 0100 | string[i];
      }
    }
   else
    if((w->genTerm.IgnoreNull == False) || (string[i] != NULL))
     Buffer[j++] = w->genTerm.MapTable[string[i]];
  }
 len = j;

 GtStoreString(w,Buffer,len);	/* now output the string */
 return(GTGOOD);
}

/* GtRedisplay:  This is the Redisplay method for the widget instance.  It */
/*   determines the size of the screen that must be redrawn and calls the */
/*   appropriate function to do it. */

static void GtRedisplay(w,event)

GenTermWidget w;
XExposeEvent *event;

{
 int StartRow,EndRow;
 int StartColumn,EndColumn;
 int temp;

 GtPositionToRowColumn(w,event->x,event->y,&StartRow,&StartColumn);
 GtPositionToRowColumn(w,event->x + event->width,event->y + event->height,
		       &EndRow,&EndColumn);
 if(EndRow >= w->genTerm.rows)
  EndRow = w->genTerm.rows - 1;
 if(EndColumn >= w->genTerm.columns)
  EndColumn = w->genTerm.columns - 1;

 GtUpdateRegion(w,StartRow,StartColumn,EndRow,EndColumn,TRUE);
}

/* GtUpdateRegion:  This function redraws the rectangular section of the */
/*   screen specified by the starting and ending row-column position. */
/*   If the cursor is within this region, the function will also redraw */
/*   the cursor.  */

static void GtUpdateRegion(w,StartRow,StartColumn,EndRow,EndColumn,CursorFlag)

GenTermWidget w;
int StartRow,StartColumn;
int EndRow,EndColumn;
Boolean CursorFlag;

{
 int i,len;

 if(EndRow >= w->genTerm.rows)
  EndRow = w->genTerm.rows - 1;

 for(i = StartRow; i <= EndRow; i++)
  {
   if(w->genTerm.Screen[i]->NumChars < EndColumn)
    len = w->genTerm.Screen[i]->NumChars - StartColumn;
   else
    len = EndColumn - StartColumn;
   if(len == 0)
    len = 1;
   GtShowLine(w,i,StartColumn,len);
  }

 if((StartRow <= w->genTerm.CurrentRow) && (w->genTerm.CurrentRow <= EndRow + 1)
    && (StartColumn <= w->genTerm.CurrentColumn) && 
    (w->genTerm.CurrentColumn <= EndColumn + 1) && (CursorFlag == TRUE))
  GtShowCursor(w);
}

/* GtPositionToRowColumn: This function takes a window coordinate and */
/*   converts it into a row and column number */

int GtPositionToRowColumn(w,x,y,row,column)

GenTermWidget w;
Dimension x,y;
int *row,*column;

{
 *row = y / w->genTerm.CharHeight;
 *column = x / w->genTerm.CharWidth;

 if(*row > w->genTerm.rows)
  *row = w->genTerm.rows;
 if(*column > w->genTerm.columns)
  *column = w->genTerm.columns;
 return(GTGOOD);
}

/* GtExpose:  This is the expose method for the widget instance. */

static void GtExpose(w,event)

GenTermWidget w;
XEvent *event;

{
 if(event->type == GraphicsExpose)
  {
   w->genTerm.ExposureCount--;
   if(w->genTerm.ExposureCount < 0) /* sanity check, should never happen */
    w->genTerm.ExposureCount = 0;
  }
 if(!XtIsRealized(w))
  return;
 GtRedisplay(w,event);
}

/* GtNoExpose: This is the noexpose event handler for the widget */

static void GtNoExpose(w,event)

GenTermWidget w;
XEvent *event;
{
w->genTerm.ExposureCount--;
if(w->genTerm.ExposureCount < 0)
w->genTerm.ExposureCount = 0;
}

/* GtResize:  This is the resize method for the widget instance. */

static void GtResize(w)

GenTermWidget w;

{
 GenTermCallback reason;

 w->genTerm.rows = (w->core.height - w->genTerm.BottomMargin) /
  w->genTerm.CharHeight;
 w->genTerm.columns = w->core.width / w->genTerm.CharWidth;
 if((w->genTerm.CurrentNumRows != w->genTerm.rows) || 
    (w->genTerm.CurrentNumColumns != w->genTerm.columns) ||
    (w->genTerm.SaveLines != w->genTerm.CurrentSaveLines))
  {
   if(w->genTerm.rows >= w->genTerm.SaveLines)
    w->genTerm.SaveLines = w->genTerm.rows * 2;
   GtReallocScreen(w);
   if(w->genTerm.CurrentRow >= w->genTerm.rows)
    w->genTerm.CurrentRow = w->genTerm.rows - 1;
   reason.reason = GT_RESIZE;
   reason.event = NULL;
   reason.Rows = w->genTerm.rows;
   reason.Columns = w->genTerm.columns;
   reason.Save = w->genTerm.SaveLines;
   XtCallCallbacks(w,XtNresizeCallback,(caddr_t)&reason);
   GtCheckPosition(w);
   GtUpdateRegion(w,0,0,w->genTerm.rows-1,w->genTerm.columns-1,True);
  }
}

/* GtReallocScreen:  This function reallocates the internal screen structure.*/
/*  It is called when ever the widget is resized. */

static void GtReallocScreen(w)

GenTermWidget w;

{
 struct Line **OldScreen = w->genTerm.VScreen;
 int i,j,k;
 int Row,Column,Save;
 int NewScreenTop;

 XtFree(w->genTerm.Screen);
 GtAllocateScreen(w);
 Row = MIN(w->genTerm.CurrentNumRows,w->genTerm.rows);
 Column = MIN(w->genTerm.CurrentNumColumns,w->genTerm.columns);
 Save = MIN(w->genTerm.SaveLines,w->genTerm.CurrentSaveLines);
 for(i = 0; i < w->genTerm.CurrentSaveLines; i++)
  {
   k = i % w->genTerm.SaveLines;
   for(j = 0; j < Column; j++)
    {
     w->genTerm.VScreen[k]->Characters[j] = OldScreen[i]->Characters[j];
     memcpy(&(w->genTerm.VScreen[k]->Attributes[j]),
	    &(OldScreen[i]->Attributes[j]),sizeof(struct Attribute));
    }
   XtFree(w->genTerm.VScreen[k]->Fields);
   w->genTerm.VScreen[k]->Fields = (struct Field *)
    XtMalloc(sizeof(struct Field) * OldScreen[i]->NumFields);
   memcpy(w->genTerm.VScreen[k]->Fields,OldScreen[i]->Fields,
	  sizeof(struct Field) * OldScreen[i]->NumFields);
   w->genTerm.VScreen[k]->ScrollRegion = OldScreen[i]->ScrollRegion;
   w->genTerm.VScreen[k]->NumChars = MIN(Column,OldScreen[i]->NumChars);
   w->genTerm.VScreen[k]->NumFields = OldScreen[i]->NumFields;
   if((w->genTerm.ScreenTop % w->genTerm.CurrentSaveLines) == i)
    NewScreenTop = k;
  }

 for(i = 0; i < w->genTerm.rows; i++)
  w->genTerm.Screen[i] = w->genTerm.VScreen[(NewScreenTop + i) %
					    w->genTerm.SaveLines];

 w->genTerm.ScreenTop = NewScreenTop;
 for(i = 0; i < w->genTerm.CurrentSaveLines; i++)
  {
   XtFree(OldScreen[i]->Characters);
   XtFree(OldScreen[i]->Attributes);
   XtFree(OldScreen[i]->Fields);
   XtFree(OldScreen[i]);
  }
 XtFree(OldScreen);

 w->genTerm.CurrentNumRows = w->genTerm.rows;
 w->genTerm.CurrentNumColumns = w->genTerm.columns;
 w->genTerm.CurrentSaveLines = w->genTerm.SaveLines;
}

/* GtSetValues:  This is the setvalue method for the widget instance. */

static Boolean GtSetValues(current,request,new)

GenTermWidget current,request,new;

{
 Arg args[10];
 int n = 0;
 int Redraw = False;
 int npen;

 if((current->genTerm.ShowCursor != new->genTerm.ShowCursor) && 
    (XtIsRealized(new)))
  {
   if((new->genTerm.ShowCursor == True) && (current->genTerm.CursorOn == False))
    GtShowCursor(new);
   if((new->genTerm.ShowCursor == False) && (current->genTerm.CursorOn == True))
    GtUnShowCursor(new);
  }
 if(current->genTerm.columns != new->genTerm.columns)
  {
   XtSetArg(args[n],XtNwidth,new->genTerm.columns * new->genTerm.CharWidth);n++;
  }
 if(current->genTerm.rows != new->genTerm.rows)
  {
   if(new->genTerm.SaveLines < new->genTerm.rows)
    {
     XtAppError(XtWidgetToApplicationContext(new),
		"GenTerm Widget: Savelines can not be less than rows");
     new->genTerm.rows = current->genTerm.rows;
    }
   else
    {
     XtSetArg(args[n],XtNheight,
	      new->genTerm.BottomMargin + new->genTerm.rows *
	      new->genTerm.CharHeight);n++;
    }
  }
 if(current->genTerm.BottomMargin != new->genTerm.BottomMargin)
  {
   XtSetArg(args[n],XtNheight,
	    new->genTerm.BottomMargin + new->genTerm.rows *
	    new->genTerm.CharHeight); n++;
  }
 if(current->genTerm.SaveLines != new->genTerm.SaveLines)
  { 
   if(new->genTerm.SaveLines < new->genTerm.rows)
    {
     XtAppError(XtWidgetToApplicationContext(new),
		"GenTerm Widget: Savelines can not be less than rows");
     new->genTerm.SaveLines = current->genTerm.SaveLines;
    }
   else
    if(XtIsRealized(new))
     GtResize(new);
  }
 if(current->genTerm.Locked != new->genTerm.Locked)
  {
   GtDoLockCallback(new);
  }

 if(current->genTerm.CharHeight != new->genTerm.CharHeight)
  new->genTerm.CharHeight = current->genTerm.CharHeight;
 if(current->genTerm.CharWidth != new->genTerm.CharWidth)
  new->genTerm.CharWidth = current->genTerm.CharWidth;

 if((current->genTerm.NumberColours != new->genTerm.NumberColours) &&
    (XtIsRealized(new)))
  {
   XtAppWarning(XtWidgetToApplicationContext(new),
		"GenTerm Widget: Resource Number Colours can only be set prior to realization");
   new->genTerm.NumberColours = current->genTerm.NumberColours;
  }

 if((current->genTerm.PenColours != new->genTerm.PenColours) &&
    (strcmp(current->genTerm.PenColours,new->genTerm.PenColours) != 0) &&
    (XtIsRealized(new)))
  {
   Redraw = True;
   GtChangePen(new,current);
  }

 if(((current->genTerm.Font != new->genTerm.Font) && 
     (strcmp(current->genTerm.Font,new->genTerm.Font) != 0)) ||
    ((current->genTerm.AlternateFont != new->genTerm.AlternateFont) &&
     (strcmp(current->genTerm.AlternateFont,new->genTerm.AlternateFont) != 0)))
  {
   if(GtLoadFonts(new) != 1)
    {
     new->genTerm.CurrentFont = current->genTerm.CurrentFont;
     new->genTerm.AltFont = current->genTerm.AltFont;
    }
   if(XtIsRealized(new))
    GtChangeFonts(new);
   XtSetArg(args[n],XtNwidthInc,new->genTerm.CharWidth); n++;
   XtSetArg(args[n],XtNheightInc,new->genTerm.CharHeight); n++;
   XtSetArg(args[n],XtNheight,	    
	    new->genTerm.BottomMargin + new->genTerm.rows *
	    new->genTerm.CharHeight); n++;
   XtSetArg(args[n],XtNwidth,new->genTerm.columns * new->genTerm.CharWidth);n++;
  }

 if((current->genTerm.CursorColour != new->genTerm.CursorColour) &&
    (XtIsRealized(new)))
  {
   GtChangeCursorColour(new);
   Redraw = True;
  }

 if((current->genTerm.NormalForeground != new->genTerm.NormalForeground) &&
    XtIsRealized(new))
  {
   Redraw = True;
   npen = new->genTerm.NumberColours << NUMATTRIBUTES;
   GtChangeColour(new,new->genTerm.NormalForeground,
		  current->genTerm.NormalForeground,0,npen);
   if(new->genTerm.foreground == current->genTerm.NormalForeground)
    new->genTerm.foreground = new->genTerm.NormalForeground;
   if(new->genTerm.CurrentForeground = current->genTerm.NormalForeground)
    new->genTerm.CurrentForeground = new->genTerm.NormalForeground;
   if(new->genTerm.background == current->genTerm.NormalForeground)
    new->genTerm.background = new->genTerm.NormalForeground;
   if(new->genTerm.CurrentBackground == current->genTerm.NormalForeground)
    new->genTerm.CurrentBackground = new->genTerm.NormalForeground;
  }

 if((current->genTerm.NormalBackground != new->genTerm.NormalBackground) &&
    XtIsRealized(new))
  {
   Redraw = True;
   npen = new->genTerm.NumberColours << NUMATTRIBUTES;
   GtChangeColour(new,new->genTerm.NormalBackground,
		  current->genTerm.NormalBackground,0,npen);
   if(new->genTerm.foreground == current->genTerm.NormalBackground)
    new->genTerm.foreground = new->genTerm.NormalBackground;
   if(new->genTerm.CurrentForeground == current->genTerm.NormalBackground)
    new->genTerm.CurrentForeground = new->genTerm.NormalBackground;
   if(new->genTerm.background == current->genTerm.NormalBackground)
    new->genTerm.background = new->genTerm.NormalBackground;
   if(new->genTerm.CurrentBackground == current->genTerm.NormalBackground)
    new->genTerm.CurrentBackground = new->genTerm.NormalBackground;
  }

 if(n != 0)
  XtSetValues(new,args,n);
 return(Redraw);
}

/* GtAllocateScreen:  This function allocates the datastructures for the */
/*  terminal screen.  It allocates both the screen and the virtual screen.  */
/*  After allocating the memory, it initializes all the fields. */

static void GtAllocateScreen(widget)

GenTermWidget widget;

{
 int i,j;
 int size = widget->genTerm.columns;
 widget->genTerm.VScreen = (struct Line**) XtMalloc(sizeof(struct Line *) *
						    widget->genTerm.SaveLines);
 widget->genTerm.Screen = (struct Line **) XtMalloc(sizeof(struct Line *) *
						    widget->genTerm.rows);
 for(i = 0; i < widget->genTerm.SaveLines; i++)
  {
   widget->genTerm.VScreen[i] = (struct Line *) XtMalloc(sizeof(struct Line));
   widget->genTerm.VScreen[i]->Characters = (char *) XtMalloc(sizeof(char) *
							      size);
   widget->genTerm.VScreen[i]->Attributes = (struct Attribute *) 
    XtMalloc(sizeof(struct Attribute) * size); 
   for(j = 0; j < widget->genTerm.columns; j++)
    {
     widget->genTerm.VScreen[i]->Characters[j] = ' ';
    }
   memrep(widget->genTerm.VScreen[i]->Attributes,
	  &(widget->genTerm.DefaultSettings),sizeof(struct Attribute),
	  widget->genTerm.columns);

   widget->genTerm.VScreen[i]->Fields = (struct Field *)
    XtMalloc(sizeof(struct Field));
   widget->genTerm.VScreen[i]->Fields[0].Start = 0;
   widget->genTerm.VScreen[i]->Fields[0].End = widget->genTerm.columns - 1;

   widget->genTerm.VScreen[i]->ScrollRegion = 0;
   widget->genTerm.VScreen[i]->NumChars = 0;
   widget->genTerm.VScreen[i]->NumFields = 1;
  }
 for(i = 0; i < widget->genTerm.rows; i++)
  widget->genTerm.Screen[i] = widget->genTerm.VScreen[i];
}

/* GtStoreString:  This function stores a string in the screen data */
/*  structure. It is the main input routine.  It simply puts the string into */
/*  the screen structure at the current cursor position.  If there isn't */
/*  enough room on the line it will either truncate the string or wrap to */
/*  the next line depending on the resource settings.  If the data wraps to */
/*  the next line, this function may force a scroll to ensure there is */
/*  enough room on the screen to display the string.  After storing the data,*/
/*  Showline is called to display it and the current cursor position is */
/*  updated. */

static void GtStoreString(w,buffer,len)

GenTermWidget w;
char buffer[];
int len;

{
 int newlen;
 int OldColumn = w->genTerm.CurrentColumn;
 int Column = w->genTerm.CurrentColumn;
 int Row;
 int i,end,to;
 Boolean Stuck = w->genTerm.CursorIsStuck;

 GtCheckPosition(w);
 Row = w->genTerm.CurrentRow;
 GtUnShowCursor(w);

 if(Stuck)			/* if cursor is currently stuck move it */
  {
   GtNextLine(w);
   Row = w->genTerm.CurrentRow;
   Column = w->genTerm.CurrentColumn;
   OldColumn = Column;
   w->genTerm.CursorIsStuck = False;
  }

 if(w->genTerm.InsertMode == True) /* if in insert mode move chars first */
  {
   end = w->genTerm.Screen[Row]->NumChars + len;
   if(end > w->genTerm.columns)
    end = w->genTerm.columns;
   for(i = end - 1; i >= Column; i--)
    {
     to = i + len;
     if(to >= w->genTerm.columns)
      to = w->genTerm.columns - 1;
     w->genTerm.Screen[Row]->Characters[to] = 
      w->genTerm.Screen[Row]->Characters[i];
     memcpy(&(w->genTerm.Screen[Row]->Attributes[to]),
	    &(w->genTerm.Screen[Row]->Attributes[i]),sizeof(struct Attribute));
    }
   w->genTerm.Screen[Row]->NumChars = end;
   newlen = end - Column - len;
   GtShowLine(w,Row,Column + len,newlen);
  }
 if((len + OldColumn) < w->genTerm.columns) /* enough space on the line? */
  {
   memcpy(&(w->genTerm.Screen[Row]->Characters[Column]),buffer,len);
   if(w->genTerm.FieldAttributes == FALSE)
    memrep(&(w->genTerm.Screen[Row]->Attributes[Column]),
	   &(w->genTerm.CurrentSettings),sizeof(struct Attribute),len);

   GtShowLine(w,w->genTerm.CurrentRow,OldColumn,len);
   w->genTerm.CurrentColumn += len;
   if(w->genTerm.Screen[Row]->NumChars < w->genTerm.CurrentColumn)
    w->genTerm.Screen[Row]->NumChars = w->genTerm.CurrentColumn;
  }
 else if(((len + OldColumn) == w->genTerm.columns) && (w->genTerm.EOLStick))
  {
   memcpy(&(w->genTerm.Screen[Row]->Characters[Column]),buffer,len);
   if(w->genTerm.FieldAttributes == FALSE)
    memrep(&(w->genTerm.Screen[Row]->Attributes[Column]),
	   &(w->genTerm.CurrentSettings),sizeof(struct Attribute),len);

   GtShowLine(w,w->genTerm.CurrentRow,OldColumn,len);
   w->genTerm.CurrentColumn = w->genTerm.columns - 1;
   w->genTerm.CursorIsStuck = True;
   if(w->genTerm.Screen[Row]->NumChars < w->genTerm.CurrentColumn)
    w->genTerm.Screen[Row]->NumChars = w->genTerm.CurrentColumn;
  }
 else if(w->genTerm.AutoWrap == FALSE)
  {
   newlen = w->genTerm.columns - OldColumn;
   buffer[newlen-1] = buffer[len-1]; /* simulate cusor stuck at end of screen */
   memcpy(&(w->genTerm.Screen[Row]->Characters[Column]),buffer,newlen);
   if(w->genTerm.FieldAttributes == FALSE)
    memrep(&(w->genTerm.Screen[Row]->Attributes[Column]),
	   &(w->genTerm.CurrentSettings),sizeof(struct Attribute),newlen);
   GtShowLine(w,w->genTerm.CurrentRow,OldColumn,newlen);
   w->genTerm.CurrentColumn += newlen - 1;
   if(w->genTerm.Screen[Row]->NumChars < w->genTerm.CurrentColumn)
    w->genTerm.Screen[Row]->NumChars = w->genTerm.CurrentColumn;
  }
 else				/* must do a line wrap possibly scrolling up */
  {
   newlen = w->genTerm.columns - OldColumn;
   memcpy(&(w->genTerm.Screen[Row]->Characters[Column]),buffer,newlen);
   if(w->genTerm.FieldAttributes == FALSE)
    memrep(&(w->genTerm.Screen[Row]->Attributes[Column]),
	   &(w->genTerm.CurrentSettings),sizeof(struct Attribute),newlen);
   GtShowLine(w,w->genTerm.CurrentRow,OldColumn,newlen);
   if(w->genTerm.Screen[Row]->NumChars < (w->genTerm.CurrentColumn + newlen))
    w->genTerm.Screen[Row]->NumChars = w->genTerm.CurrentColumn + newlen;
   GtNextLine(w);		/* goto next line */
   GtStoreString(w,&(buffer[newlen]),len - newlen); /* put out rest of line */
  }

 GtShowCursor(w);

}

/* GtShowLine:  This is the display routine for the widget.  It displays the */
/*  next len characters starting at position row,col.  Each character is */
/*  displayed according to the attributes assigned to it. */

static void GtShowLine(w,row,col,len)

GenTermWidget w;
int row;
int col;
int len;

{
 int xpos,ypos;
 int i,end,npen;

 if((row < 0) || (row >= w->genTerm.rows) || (col < 0) || 
    (col >= w->genTerm.columns))
  return;

 ypos = row * w->genTerm.CharHeight + w->genTerm.CurrentFont->ascent;
 xpos = col * w->genTerm.CharWidth;
 end = col + len;

 while(col < end)
  {
   for(i = col; i < end; i++)
    if(w->genTerm.Screen[row]->Attributes[i].type != 
       w->genTerm.Screen[row]->Attributes[col].type)
     break;
   npen = w->genTerm.Screen[row]->Attributes[col].type;
   xpos = col * w->genTerm.CharWidth;
   len = i-col;
   XDrawImageString(XtDisplay(w),XtWindow(w),w->genTerm.Pens[npen]->draw_gc,
		    xpos,ypos,&(w->genTerm.Screen[row]->Characters[col]),len);
   if(npen & SETUNDERLINE)	/* is this an underline font? */
    {
     ypos += w->genTerm.CurrentFont->descent - 1;
     XDrawLine(XtDisplay(w),XtWindow(w),w->genTerm.Pens[npen]->draw_gc,xpos,
	       ypos,xpos + len * w->genTerm.CharWidth,ypos);
    }
   col = i;
  }
}

/* GtShowCursor:  This function will display the cursor at the current cursor*/
/*  position if the cursor is being displayed and is currently on the screen */

static void GtShowCursor(w)

GenTermWidget w;

{
 int row = w->genTerm.CurrentRow;
 int col = w->genTerm.CurrentColumn;
 int ypos = w->genTerm.CharHeight * row + w->genTerm.CurrentFont->ascent;
 int xpos = w->genTerm.CharWidth * col;
 int npen;

 if((w->genTerm.ShowCursor) && (row >= 0) && ( row < w->genTerm.rows))
  {
   npen = w->genTerm.Screen[row]->Attributes[col].type;
   XDrawImageString(XtDisplay(w),XtWindow(w),w->genTerm.Pens[npen]->cursor_gc,
		    xpos,ypos,&(w->genTerm.Screen[row]->Characters[col]),1);
   w->genTerm.CursorOn = TRUE;
  }
}

/* GtUnShowCursor:  This function turns off the cursor */

static void GtUnShowCursor(w)

GenTermWidget w;

{
 int row = w->genTerm.CurrentRow;
 int col = w->genTerm.CurrentColumn;
 int ypos = w->genTerm.CharHeight * row + w->genTerm.CurrentFont->ascent;
 int xpos = w->genTerm.CharWidth * col;
 int npen;

 if((w->genTerm.CursorOn == TRUE) && (row >= 0) && (row < w->genTerm.rows))
  {
   npen = w->genTerm.Screen[row]->Attributes[col].type;
   XDrawImageString(XtDisplay(w),XtWindow(w),w->genTerm.Pens[npen]->draw_gc,
		    xpos,ypos,&(w->genTerm.Screen[row]->Characters[col]),1);
   if(npen & SETUNDERLINE)
    {
     ypos += w->genTerm.CurrentFont->descent - 1;
     XDrawLine(XtDisplay(w),XtWindow(w),w->genTerm.Pens[npen]->draw_gc,xpos,
	       ypos,xpos + w->genTerm.CharWidth,ypos);
    }
   w->genTerm.CursorOn = FALSE;
  }
}

/* GtCheckPosition:  This function checks to make sure the current cursor */
/*  position is within the visible screen boundaries.  If it isn't, it sets */
/*  the top of screen to make sure that it is. In addition if the */
/*  ScrollOnOutput resource is true then the function makes sure the screen */
/*  is at the bottom of the scroll bar. */

static void GtCheckPosition(w)

GenTermWidget w;

{
 if((w->genTerm.ScrollOnOutput == TRUE) &&
    (w->genTerm.VirtualTop < w->genTerm.MaxVirtualTop))
  GtSetTopOfScreen(w,w->genTerm.MaxVirtualTop);

 /* if the cursor can roll of the screen and it is not visible, move screen */
 /* so that it becomes visible */

 if((w->genTerm.CursorFloats == FALSE) &&
    ((w->genTerm.CurrentRow < 0) || (w->genTerm.CurrentRow >= w->genTerm.rows)))
  GtSetTopOfScreen(w,w->genTerm.VirtualTop - w->genTerm.CursorOffset);
 w->genTerm.CursorIsStuck = False; /* convenient place to reset this flag */
}

/* GtNextLine:  This function moves the cursor to the next line.  It is */
/* called by StoreString when it needs to wrap to the next line */

static void GtNextLine(w)

GenTermWidget w;

{
 if(w->genTerm.CurrentRow >= w->genTerm.rows-1)
  {
   GtScrollUp(w,1);
   w->genTerm.CurrentColumn = 0;
  }
 else if((w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion !=
	  w->genTerm.Screen[w->genTerm.CurrentRow+1]->ScrollRegion) &&
	 (w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion != 0))
  {
   GtScrollUp(w,1);
   w->genTerm.CurrentColumn = 0;
   w->genTerm.CurrentRow += 1;
  }
 else
  {
   w->genTerm.CurrentRow += 1;
   w->genTerm.CurrentColumn = 0;
  }
}

/* GtNewLine:  This function implements a newline function.  The current */
/*   position is moved dist lines down from the current line.  If this would */
/*   move the cursor off the bottom of the screen, a scroll up is performed. */

int GtNewLine(w,dist)

GenTermWidget w;
int dist;

{
 int NewRow = w->genTerm.CurrentRow + dist;
 int ScrollDist;
 int i;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);
 if((NewRow >= w->genTerm.rows) ||
    ((w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion !=
      w->genTerm.Screen[NewRow]->ScrollRegion) &&
     (w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion != 0)))
  {
   for(i = w->genTerm.CurrentRow; i < w->genTerm.rows; i++)
    if(w->genTerm.Screen[i]->ScrollRegion != 
       w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
     break;
   ScrollDist = dist - (i - w->genTerm.CurrentRow) + 1;
   GtScrollUp(w,ScrollDist);
   w->genTerm.CurrentRow = w->genTerm.rows - 1;
  }
 else
  w->genTerm.CurrentRow += dist;
 if(w->genTerm.CurrentRow >= w->genTerm.rows)
  w->genTerm.CurrentRow = w->genTerm.rows - 1;

 GtShowCursor(w);
 return(GTGOOD);
}

/* GtCursorDown:  This function moves the cursor down dist lines.  If this */
/*  would move the cursor outside of the screen and wrap=0 then the screen */
/*  is rolled up but the required number of lines.  If wrap=1, then the */
/*  cursor wraps around to the top of the screen.  If wrap=2, then the cursor*/
/*  stays at the bottom of the screen */

int GtCursorDown(w,dist,wrap)

GenTermWidget w;
int dist;
int wrap;

{
 int NewRow = w->genTerm.CurrentRow + dist;
 int move,i;
 int TopOfScroll, ScrollSize;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);
 if((NewRow >= w->genTerm.rows) && (wrap == 0))
  {
   move = w->genTerm.rows - NewRow + 1;
   GtScrollScreen(w,move);
   w->genTerm.CurrentRow = w->genTerm.rows - 1;
  }
 else if((NewRow >= w->genTerm.rows) && (wrap == 1))
  {
   while(NewRow >= w->genTerm.rows)
    NewRow -= w->genTerm.rows;
   w->genTerm.CurrentRow = NewRow;
  }
 else if((NewRow >= w->genTerm.rows) && (wrap == 2))
  w->genTerm.CurrentRow = w->genTerm.rows - 1;
 else if((w->genTerm.CursorKeyScrollRegion) &&
	 ((w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion !=
	   w->genTerm.Screen[NewRow]->ScrollRegion) &&
	  (w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion != 0)))
  {
   if(wrap == 0)
    {
     for(i = w->genTerm.CurrentRow; i < w->genTerm.rows; i++)
      if(w->genTerm.Screen[i]->ScrollRegion != 
	 w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
       break;
     move = dist - (i - w->genTerm.CurrentRow) + 1;
     GtScrollUp(w,move);
    }
   else if (wrap == 1)
    {
     TopOfScroll = -1;
     ScrollSize = 0;
     for(i = 0; i < w->genTerm.rows; i++)
      if(w->genTerm.Screen[i]->ScrollRegion == 
	 w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
       {
	if(TopOfScroll == -1)
	 TopOfScroll = i;
	ScrollSize++;
       }
     while(w->genTerm.Screen[NewRow]->ScrollRegion !=
	   w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
      {
       NewRow = NewRow - ScrollSize;
      }
     w->genTerm.CurrentRow = NewRow;
    }
   else if (wrap == 2)
    {
     for(i = w->genTerm.CurrentRow; i < w->genTerm.rows; i++)
      if(w->genTerm.Screen[i]->ScrollRegion !=
	 w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
       {
	i--;
	break;
       }
     w->genTerm.CurrentRow = i;
    }   
  }
 else
  w->genTerm.CurrentRow = NewRow;

 GtShowCursor(w);
 return(GTGOOD);
}

/* GtCursorUp: This function moves the current position up dist lines.  If */
/*  this would move the cursor off of the screen and wrap=0, then the screen */
/*  is rolled down the required number of lines and the cursor is placed on */
/*  the top line.  If wrap=1 then the cursor wraps around to the bottom of */
/*  the screen.  If wrap=2 then the cursor sticks at the top of the screen. */

int GtCursorUp(w,dist,wrap)

GenTermWidget w;
int dist;
int wrap;

{
 int NewRow = w->genTerm.CurrentRow - dist;
 int move,i;
 int TopOfScroll;
 int ScrollSize;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);
 if((NewRow < 0) && (wrap == 0))
  {
   move = NewRow;
   GtScrollScreen(w,move);
   w->genTerm.CurrentRow = 0;
  }
 else if((NewRow < 0) && (wrap == 1))
  {
   while(NewRow < 0)
    NewRow += w->genTerm.rows;
   w->genTerm.CurrentRow = NewRow;
  }
 else if((NewRow < 0) && (wrap == 2))
  w->genTerm.CurrentRow = 0;
 else if((w->genTerm.CursorKeyScrollRegion) &&
	 ((w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion !=
	   w->genTerm.Screen[NewRow]->ScrollRegion) &&
	  (w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion != 0)))
  {
   if(wrap == 0)
    {
     for(i = w->genTerm.CurrentRow; i >= 0; i--)
      if(w->genTerm.Screen[i]->ScrollRegion != 
	 w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
       break;
     move = dist - (w->genTerm.CurrentRow - i) + 1;
     move = -move;
     GtScrollUp(w,move);
    }
   else if (wrap == 1)
    {
     TopOfScroll = -1;
     ScrollSize = 0;
     for(i = 0; i < w->genTerm.rows; i++)
      if(w->genTerm.Screen[i]->ScrollRegion == 
	 w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
       {
	if(TopOfScroll == -1)
	 TopOfScroll = i;
	ScrollSize++;
       }
     while(w->genTerm.Screen[NewRow]->ScrollRegion !=
	   w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
      {
       NewRow = NewRow + ScrollSize;
      }
     w->genTerm.CurrentRow = NewRow;
    }
   else if (wrap == 2)
    {
     for(i = w->genTerm.CurrentRow; i >= 0; i--)
      if(w->genTerm.Screen[i]->ScrollRegion !=
	 w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion)
       {
	i++;
	break;
       }
     w->genTerm.CurrentRow = i;
    }  
  }
 else
  w->genTerm.CurrentRow = NewRow;

 GtShowCursor(w);
 return(GTGOOD);
}

/* GtCursorRight:  This function moves the cursor dist columns to the left. */
/*  If wrap=0, then the cursor will stick at the rightmost column, otherwise */
/*  it will wrap around to the left side.  If roll=0 then the cursor will */
/*  wrap from the bottom right corner to the top left otherwise the screen */
/*  will be rolled up */

int GtCursorRight(w,dist,wrap,roll)

GenTermWidget w;
int dist;
int wrap;
int roll;

{
 int NewColumn = w->genTerm.CurrentColumn + dist;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);
 if(NewColumn >= w->genTerm.columns)
  {
   if(wrap == 0)
    w->genTerm.CurrentColumn = w->genTerm.columns - 1;
   else
    {
     while(NewColumn >= w->genTerm.columns)
      {
       w->genTerm.CurrentRow += 1;
       if(w->genTerm.CurrentRow >= w->genTerm.rows)
	{
	 if(roll == 0)
	  w->genTerm.CurrentRow = 0;
	 else
	  {
	   w->genTerm.CurrentRow = w->genTerm.rows - 1;
	   GtScrollScreen(w,1);
	  }
	}
       NewColumn = NewColumn - w->genTerm.columns;
      }
     w->genTerm.CurrentColumn = NewColumn;
    }
  }
 else
  {
   w->genTerm.CurrentColumn = NewColumn;
  }

 GtShowCursor(w);
 return(GTGOOD);
}

/* GtCursorLeft:  This function moves the current position dist columns to */
/*  the left.  If wrap==0 then the cursor will stick at the leftmost column */
/*  otherwise it will wrap around to the right. If roll==0 then at the top */
/*  left corner the cursor will wrap down to the bottom right, otherwise the */
/*  screen is rolled up if possible. */

int GtCursorLeft(w,dist,wrap,roll)

GenTermWidget w;
int dist;
int wrap;
int roll;

{
 int NewColumn = w->genTerm.CurrentColumn - dist;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);
 if(NewColumn < 0)
  {
   if(wrap == 0)
    NewColumn = 0;
   else
    {
     while(NewColumn < 0)
      {
       NewColumn = w->genTerm.columns + NewColumn;
       w->genTerm.CurrentRow -= 1;
       if(w->genTerm.CurrentRow < 0)
	if(roll == 0)
	 w->genTerm.CurrentRow = w->genTerm.rows - 1;
	else
	 {
	  w->genTerm.CurrentRow = 0;
	  if(w->genTerm.VirtualTop == 0)
	   NewColumn = 0;
	  else
	   GtScrollScreen(w,-1);
	 }
      }
    }
  }      
 w->genTerm.CurrentColumn = NewColumn;
 GtShowCursor(w);
 return(GTGOOD);
}

/* GtGetCursorPosition:  This function returns the row and column of the */
/*  current position */

int GtGetCursorPosition(w,r,c)

GenTermWidget w;
int *c;
int *r;

{
 *r = w->genTerm.CurrentRow;
 *c = w->genTerm.CurrentColumn;
 return(GTGOOD);
}

/* GtCursorReturn:  This function moves the current position to the leftmost */
/*  column on the current row */ 

int GtCursorReturn(w)

GenTermWidget w;

{
 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);
 w->genTerm.CurrentColumn = 0;
 GtShowCursor(w);
 return(GTGOOD);
}

/* GtSetCursorPosition:  This function moves the current position to the */
/*  specified row and column.  If the given position is outside of the */
/*  screen, the current position is set to the closest point that is still */
/*  within the screen. */

int GtSetCursorPosition(w,row,column)

GenTermWidget w;
int row;
int column;

{
 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);
 GtCheckValidPosition(w,&row,&column,1);

 w->genTerm.CurrentRow = row;
 w->genTerm.CurrentColumn = column;

 GtShowCursor(w);
 return(GTGOOD);
}

/* GtScrollUp:  This function is called when there is not enough space in */
/*  the current scroll region to output a new line.  It will scroll the */
/*  region up by the required amount and move the current position to */
/*  correspond to the new screen. */

int GtScrollUp(w,dist)

GenTermWidget w;
int dist;

{
 int Top;
 int NewTop;
 int NewCurrent;
 int OldCurrent;
 int CurrentRegion = w->genTerm.Screen[w->genTerm.CurrentRow]->ScrollRegion;
 int i = w->genTerm.CurrentRow;
 int DestY;
 int SrcY;
 int Height;
 int Width;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 /* first go find top of scrolling region */

 while((i >= 0) && (w->genTerm.Screen[i]->ScrollRegion == CurrentRegion))
  i--;
 i++;

 if(i < 0)
  i = 0;
 Top = i;
 NewTop = Top + dist;
 if(NewTop < w->genTerm.CurrentRow) /* make sure scroll region large enough */
  {
   DestY = Top * w->genTerm.CharHeight;
   SrcY = NewTop * w->genTerm.CharHeight;
   Width = w->genTerm.columns * w->genTerm.CharWidth;
   Height = (w->genTerm.CurrentRow - NewTop + 1) * w->genTerm.CharHeight;

   XCopyArea(XtDisplay(w),XtWindow(w),XtWindow(w),w->genTerm.Pens[0]->draw_gc,
	     0,SrcY,Width,Height,0,DestY);
   w->genTerm.ExposureCount++;

   Height = dist * w->genTerm.CharHeight;
   /*SrcY = w->genTerm.CurrentRow * w->genTerm.CharHeight;*/
   SrcY = (w->genTerm.CurrentRow - dist + 1) * w->genTerm.CharHeight;
   XClearArea(XtDisplay(w),XtWindow(w),0,SrcY,Width,Height,False);

   if((Top == 0) && (w->genTerm.CurrentRow + dist >= w->genTerm.rows))
    {
     if(w->genTerm.VirtualTop < (w->genTerm.SaveLines - w->genTerm.rows))
      GtMoveScreen(w,dist,w->genTerm.ScrollDownClear);
     else
      GtMoveScreen(w,dist,True);
     w->genTerm.CurrentRow -= (dist - 1);
     for(i = 0; i < dist; i++)
      w->genTerm.Screen[i + w->genTerm.CurrentRow]->ScrollRegion = CurrentRegion;
    }
   else
    {		/* perform an internal screen scroll inside a scroll region */
     GtScrollRegionScroll(w,dist,Top,CurrentRegion);
    }
   GtUpdateRegion(w,w->genTerm.CurrentRow,0,w->genTerm.CurrentRow+dist,
		  w->genTerm.columns,FALSE);
  }
 else				/* our new top of screen is below our current line */
  {
   SrcY = Top * w->genTerm.CharHeight;   
   Height = w->genTerm.CharHeight * w->genTerm.rows;
   Width = w->genTerm.CharWidth * w->genTerm.columns;
   XClearArea(XtDisplay(w),XtWindow(w),0,0,Width,Height,False);

   if((Top == 0) && (w->genTerm.CurrentRow + dist >= w->genTerm.rows))
    GtMoveScreen(w,dist,FALSE);
   else
    GtScrollRegionScroll(w,dist,Top,CurrentRegion);
   GtUpdateRegion(w,0,0,w->genTerm.rows,w->genTerm.columns,FALSE);
  }
 return(GTGOOD);
}

/* GtScrollRegionScroll:  This function handles the scrolling from within */
/*  a scroll region */

static int GtScrollRegionScroll(w,dist,Top,CurrentRegion)

GenTermWidget w;
int dist;
int Top;
int CurrentRegion;

{
 struct Line **Store;
 int i;
 int NewCurrent;

 Store = (struct Line **) XtMalloc(sizeof(struct Line *) * dist);
 for(i = 0; i < dist; i++)
  {
   Store[i] = w->genTerm.Screen[Top + i];
  }
 if(w->genTerm.SaveScrollRegion == True)
  {
   for(i = Top - 1; i >= 0; i--)
    w->genTerm.Screen[i + dist] = w->genTerm.Screen[i];

   for(i = 0; i < dist; i++)
    w->genTerm.Screen[i] = Store[i];

   for(i = 0; i < w->genTerm.rows; i++)
    w->genTerm.VScreen[(w->genTerm.ScreenTop + i) % w->genTerm.SaveLines]
     = w->genTerm.Screen[i];

   for(i = 0; i < dist; i++)
    Store[i] = w->genTerm.VScreen[(w->genTerm.ScreenTop + w->genTerm.rows + i)
				  % w->genTerm.SaveLines];

   for(i = w->genTerm.rows; i > w->genTerm.CurrentRow + dist; i--)
    w->genTerm.VScreen[(w->genTerm.ScreenTop + i) % w->genTerm.SaveLines] =
     w->genTerm.VScreen[(w->genTerm.ScreenTop + i - dist) % w->genTerm.SaveLines];

   for(i = 0; i < dist; i++)
    {
     w->genTerm.VScreen[(w->genTerm.ScreenTop + w->genTerm.CurrentRow + 1 +
			 i) % w->genTerm.SaveLines] = Store[i];
     if((w->genTerm.VirtualTop >= (w->genTerm.SaveLines - w->genTerm.rows)) ||
	(w->genTerm.ScrollDownClear == 0))
      GtClearLine(w,Store[i]);
    }  

   if(w->genTerm.VirtualTop < (w->genTerm.SaveLines - w->genTerm.rows))
    GtMoveScreen(w,dist,w->genTerm.ScrollDownClear);
   else
    GtMoveScreen(w,dist,True);
   NewCurrent = w->genTerm.CurrentRow - dist + 1;
   for(i = 0; i < dist; i++)
    w->genTerm.Screen[i + NewCurrent]->ScrollRegion = CurrentRegion;
  }
 else
  {
   NewCurrent = w->genTerm.CurrentRow - dist + 1;
   for(i = Top; i < NewCurrent; i++)
    w->genTerm.Screen[i] = w->genTerm.Screen[i+dist];
   for(i = 0; i < dist; i++)
    {
     w->genTerm.Screen[NewCurrent + i] = Store[i];
     GtClearLine(w,w->genTerm.Screen[NewCurrent + i]);
     w->genTerm.Screen[NewCurrent + i]->ScrollRegion = CurrentRegion;
    }
  }
 w->genTerm.CurrentRow = w->genTerm.CurrentRow - dist + 1;
 XtFree(Store);
}

/* GtClearLine:  This function removes all data and attributes from the */
/*  current line. */

static int GtClearLine(w,row)

GenTermWidget w;
struct Line *row;

{
 int i;

 for(i = 0; i < w->genTerm.columns; i++)
  {
   row->Characters[i] = ' ';
   memcpy(&(row->Attributes[i]),&(w->genTerm.DefaultSettings),
	  sizeof(struct Attribute));
  }

 row->NumChars = 0;
 row->NumFields = 1;
 row->Fields[0].Start = 0;
 row->Fields[0].End = w->genTerm.columns - 1;
}

/* GtMoveScreen: This function moves the physical screen data by a distance  */
/*  dist within the virtual screen.  If clear=TRUE, the new lines that are */
/*  moved onto the screen are cleared.  This function will cause TopCallbacks*/
/*  to  be executed.  */

static void GtMoveScreen(w,dist,clear)

GenTermWidget w;
int dist;
int clear;

{
 int NewTop = w->genTerm.ScreenTop + dist;
 int i;

 for(i = 0; i < w->genTerm.rows; i++)
  {
   w->genTerm.Screen[i] = w->genTerm.VScreen[(NewTop + i) % w->genTerm.SaveLines];
   if((i >= w->genTerm.rows - dist) && (clear == TRUE))
    {
     GtClearLine(w,w->genTerm.Screen[i]);
    }
  }
 w->genTerm.ScreenTop = NewTop;
 if(w->genTerm.ScreenTop > w->genTerm.VScreenTop)
  w->genTerm.VScreenTop += dist;
 w->genTerm.VirtualTop = w->genTerm.VirtualTop + dist;
 if(w->genTerm.VirtualTop > w->genTerm.SaveLines - w->genTerm.rows)
  w->genTerm.VirtualTop = w->genTerm.SaveLines - w->genTerm.rows;
 if(w->genTerm.VirtualTop > w->genTerm.MaxVirtualTop)
  w->genTerm.MaxVirtualTop = w->genTerm.VirtualTop;
 GtDoTopCallback(w);
}

/* DoLockCallback:  This function will execute the LockCallbacks that are */
/* defined for the widget instance */

static void GtDoLockCallback(w)

GenTermWidget w;

{
 GenTermCallback reason;

 reason.reason = GT_LOCK;
 reason.event = NULL;
 reason.Value = w->genTerm.Locked;
 XtCallCallbacks(w,XtNlockCallback,(caddr_t)&reason);
}

/* GtDoTopCallback:  This function will execute the TopCallbacks that are */
/*  defined for the widget instance */

static void GtDoTopCallback(w)

GenTermWidget w;

{
 GenTermCallback reason;

 reason.reason = GT_TOP;
 reason.event = NULL;
 reason.TopLine = w->genTerm.VirtualTop;
 XtCallCallbacks(w,XtNtopCallback,(caddr_t)&reason);
}

/* GtSetTopOfScreen:  This function allows the caller to set the top line of */
/*  the physical screen to a certain point within the virtual screen. */

int GtSetTopOfScreen(w,line)

GenTermWidget w;
int line;

{
 int dist;

 if(w->genTerm.Locked)
  return(GTLOCKED);
 if (line < 0)
  line = 0;
 if(w->genTerm.FullScroll == True)
  {
   if(line > (w->genTerm.SaveLines - w->genTerm.rows))
    line = w->genTerm.SaveLines - w->genTerm.rows;
  }
 else
  {
   if(line > w->genTerm.MaxVirtualTop)
    line = w->genTerm.MaxVirtualTop;
  }

 GtUnShowCursor(w);
 dist = line - w->genTerm.VirtualTop;
 GtScrollScreen(w,dist);
 if(dist == 0)			/* if dist is zero we won't scroll but do callback anyway */
  {				/* incase user is moving a scroll bar */
   GtDoTopCallback(w);
  }
 GtShowCursor(w);
 return(GTGOOD);
}

/* GtScrollScreen:  This function moves the screen up or down in the virtual */
/*  screen by a distance dist.  It copies the data that is on the screen */
/*  to its new location, clears the screen that will be updated, calls */
/*  MoveScreen to move the data around and finally calls update region to */
/*  output the new information.  */

static void GtScrollScreen(w,dist)

GenTermWidget w;
int dist;

{
 int DestY,SrcY,Width,Height;
 int NewTop = dist + w->genTerm.VirtualTop;
 int offset;
 int i;
 int FromScroll = 0;
 int maxdist = w->genTerm.rows;

 if(dist == 0)
  return;

 offset = w->genTerm.MaxVirtualTop - NewTop;
 if(NewTop < 0)			/* make sure we can scroll to that point */
  dist -= NewTop;
 else if(offset > w->genTerm.SaveLines - w->genTerm.rows)
  {
   dist = w->genTerm.MaxVirtualTop - w->genTerm.VirtualTop - 
    w->genTerm.SaveLines + w->genTerm.rows;
  }
 if(w->genTerm.SaveScrollRegion == True)
  {
   for(i = 0; i < w->genTerm.rows; i++)
    if(w->genTerm.Screen[i]->ScrollRegion != 0)
     FromScroll = 1;
  }

 /* if we are going to scroll the screen with a scroll region then perform */
 /* the required row swapping in the virtual screen before we update the */
 /* screen. */

 if(FromScroll == 1)
  maxdist = GtScrollRegionScrollScreen(w,dist);
 else
  {
   if((dist > 0) && ( dist < maxdist))
    {
     DestY = 0;
     SrcY = dist * w->genTerm.CharHeight;
     Width = w->genTerm.columns * w->genTerm.CharWidth;
     Height = (w->genTerm.rows - dist) * w->genTerm.CharHeight;

     XCopyArea(XtDisplay(w),XtWindow(w),XtWindow(w),w->genTerm.Pens[0]->draw_gc,
	       0,SrcY,Width,Height,0,DestY);
     w->genTerm.ExposureCount++;

     Height = dist * w->genTerm.CharHeight;
     SrcY = (w->genTerm.rows - dist) * w->genTerm.CharHeight;
     XClearArea(XtDisplay(w),XtWindow(w),0,SrcY,Width,Height,False);

     GtMoveScreen(w,dist,FALSE);
     GtUpdateRegion(w,w->genTerm.rows - dist,0,w->genTerm.rows,w->genTerm.columns,
		    FALSE);
    }
   else if((dist < 0) && (-dist < maxdist))
    {
     DestY =- dist * w->genTerm.CharHeight;
     SrcY = 0;
     Width = w->genTerm.columns * w->genTerm.CharWidth;
     Height = (w->genTerm.rows + dist) * w->genTerm.CharHeight;

     XCopyArea(XtDisplay(w),XtWindow(w),XtWindow(w),w->genTerm.Pens[0]->draw_gc,
	       0,SrcY,Width,Height,0,DestY);
     w->genTerm.ExposureCount++;

     Height = -dist * w->genTerm.CharHeight;
     SrcY = 0;
     XClearArea(XtDisplay(w),XtWindow(w),0,SrcY,Width,Height,False);

     GtMoveScreen(w,dist,FALSE);
     GtUpdateRegion(w,0,0,-dist,w->genTerm.columns,FALSE);
    }
   else
    {
     Width = w->genTerm.columns * w->genTerm.CharWidth;
     Height = w->genTerm.rows * w->genTerm.CharHeight;
     XClearArea(XtDisplay(w),XtWindow(w),0,0,Width,Height,False);
     GtMoveScreen(w,dist,FALSE);
     GtUpdateRegion(w,0,0,w->genTerm.rows,w->genTerm.columns,FALSE);
    }
  }
 if(w->genTerm.CursorFloats == FALSE)
  {
   w->genTerm.CursorOffset += dist;
   w->genTerm.CurrentRow -= dist;
  }
}

/* GtGetTopOfScreen:  This function returns to the calling program the */
/*  current position of the screen within the virtual screen. */

int GtGetTopOfScreen(w)

GenTermWidget w;

{
 return(w->genTerm.VirtualTop);
}

/* GtScrollRegionScrollScreen:  This function handles the row movement that */
/*  is required to perform a screen scroll when scroll regions are involved */

static int GtScrollRegionScrollScreen(w,dist)

GenTermWidget w;
int dist;

{
 int Top;
 int Bottom;
 int maxdist;
 int i;
 int ScreenTop = w->genTerm.ScreenTop;
 int Size = w->genTerm.SaveLines;
 int CurrentRegion;
 int Ypos,Width,Height;
 struct Line **Store;

 Store = (struct Line **) XtMalloc(sizeof(struct Line *) * abs(dist));

 if(dist > 0)
  {
   for(i = 0; i < w->genTerm.rows; i++)
    if(w->genTerm.Screen[i]->ScrollRegion != 0)
     {
      Top = i;
      break;
     }
   CurrentRegion = w->genTerm.Screen[Top]->ScrollRegion;
   for(i = Top; i < w->genTerm.rows; i++)
    if(w->genTerm.Screen[i]->ScrollRegion!=w->genTerm.Screen[Top]->ScrollRegion)
     break;
   Bottom = i - 1;
   if(Bottom >= w->genTerm.rows)
    Bottom = w->genTerm.rows - 1;
   maxdist = Bottom - Top;

   for(i = 0; i < dist; i++)
    Store[i] = w->genTerm.VScreen[(Top + i + ScreenTop) % Size];

   for(i = Top - 1; i >= 0; i--)
    w->genTerm.VScreen[(ScreenTop + i + dist) % Size] =
     w->genTerm.VScreen[(ScreenTop + i) % Size];

   for(i = 0; i < dist; i++)
    w->genTerm.VScreen[(ScreenTop + i) % Size] = Store[i];

   for(i = 0; i < dist; i++)
    Store[i] = w->genTerm.VScreen[(ScreenTop + w->genTerm.rows + i) % Size];

   for(i = w->genTerm.rows; i >= Bottom + dist; i--)
    w->genTerm.VScreen[(ScreenTop + i) % Size] =
     w->genTerm.VScreen[(ScreenTop + i - dist ) % Size];

   for(i = 0; i < dist; i++)
    {
     w->genTerm.VScreen[(ScreenTop + Bottom + 1 + i) % Size] =
      Store[i];
     w->genTerm.VScreen[(ScreenTop + Bottom + 1 + i) % 
			Size]->ScrollRegion = 
			 w->genTerm.Screen[Top]->ScrollRegion;
    }
  }
 else
  {
   dist = abs(dist);
   for(i = w->genTerm.rows - 1; i >= 0; i--)
    if(w->genTerm.Screen[i]->ScrollRegion != 0)
     {
      Bottom = i;
      break;
     }
   CurrentRegion = w->genTerm.Screen[Bottom]->ScrollRegion;
   for(i = Bottom; i >= 0; i--)
    if(w->genTerm.Screen[i]->ScrollRegion != CurrentRegion)
     break;
   Top = i + 1;
   maxdist = Bottom - Top;

   for(i = 0; i < dist; i++)
    Store[i] = w->genTerm.VScreen[(ScreenTop - dist + i) % Size];

   for(i = 0; i < Top; i++)
    {
     w->genTerm.VScreen[(ScreenTop + i - dist) % Size] =
      w->genTerm.VScreen[(ScreenTop + i) % Size];
    }

   for(i = 0; i < dist; i++)
    {
     w->genTerm.VScreen[(ScreenTop + i + Top - dist) % Size] = Store[i];
     w->genTerm.VScreen[(ScreenTop + i + Top - dist) % Size]->ScrollRegion = 
      CurrentRegion;
    }
   if(Bottom < w->genTerm.rows - 1)
    {
     for(i = 0; i < dist; i++)
      Store[i] = w->genTerm.VScreen[(ScreenTop + Bottom - dist + 1 + i) % Size];

     for(i = Bottom; i < w->genTerm.rows; i++)
      w->genTerm.VScreen[(ScreenTop + 1 + i - dist) % Size] =
       w->genTerm.VScreen[(ScreenTop + 1 + i) % Size];

     for(i = 0; i < dist; i++)
      w->genTerm.VScreen[(ScreenTop + w->genTerm.rows + 1 + i) % Size] = Store[i];
    }
   dist = -dist;
  }
 Ypos = Top * w->genTerm.CharHeight;
 Width = w->genTerm.columns * w->genTerm.CharWidth;
 Height = (Bottom - Top + 1) * w->genTerm.CharHeight;
 XClearArea(XtDisplay(w),XtWindow(w),0,Ypos,Width,Height,False);
 GtMoveScreen(w,dist,False);
 GtUpdateRegion(w,Top,0,Bottom,w->genTerm.columns,False);
 XtFree(Store);
 return(maxdist);
}

/* GtGetLine:  This funtion returns to the calling program the data on the */
/*  current line.  The calling function must ensure that there is enough */
/*  space in string to store the data and the string is not null terminated. */

int GtGetLine(w,row,string,len)

GenTermWidget w;
int row;
char *string;
int *len;

{
 *len = 0;
 if((row >= 0) && (row < w->genTerm.rows))
  {
   *len = w->genTerm.Screen[row]->NumChars;
   strncpy(string,w->genTerm.Screen[row]->Characters,*len);
   return(GTGOOD);
  }
 return(GTBAD);
}

/* GtSetAttribute:  This function sets the attribute specified by which to */
/*  the value specified by flag. */

int GtSetAttribute(w,which,flag)

GenTermWidget w;
int which;
int flag;

{
 int row,col;
 int pen;

 /* a bit a kludge here.  GtLoadAttribute can be used to reset the current */
 /* settings on us.  Before we go and change attributes we check here if */
 /* the attributes were changed and if so make foreground and background */
 /* colors agree */

 if(w->genTerm.CurrentSettings.type == 0)
  {
   w->genTerm.foreground = w->genTerm.CurrentForeground = 
    w->genTerm.Colours[0].Foreground;
   w->genTerm.background = w->genTerm.CurrentBackground =
    w->genTerm.Colours[0].Background;
  }

 switch(which)
  {
 case GTFONT:
   if(flag == GTBASE)
    {
     w->genTerm.CurrentSettings.Font = w->genTerm.CurrentFont;
     w->genTerm.CurrentSettings.type &= ~SETALTFONT;
    }
   else if(flag == GTALTERNATE)
    {
     w->genTerm.CurrentSettings.Font = w->genTerm.AltFont;
     w->genTerm.CurrentSettings.type |= SETALTFONT;
    }
   else
    XtAppWarning(XtWidgetToApplicationContext(w),
		 "Invalid argument for setting font");
   break;
 case GTINVERSEVIDEO:
   if(flag == GTNORMAL)
    {
     w->genTerm.foreground = w->genTerm.CurrentForeground;
     w->genTerm.background = w->genTerm.CurrentBackground;
     w->genTerm.CurrentSettings.type &= ~SETINVERSE;
    }
   else if(flag == GTINVERSE)
    {
     w->genTerm.foreground = w->genTerm.CurrentBackground;
     w->genTerm.background = w->genTerm.CurrentForeground;
     w->genTerm.CurrentSettings.type |= SETINVERSE;
    }
   else
    XtAppWarning(XtWidgetToApplicationContext(w),
		 "Invalid argument for setting inverse video in GtSetAttribute");
   break;
 case GTUNDERLINE:
   if(flag == GTON)
    w->genTerm.CurrentSettings.type |= SETUNDERLINE;
   else if(flag == GTOFF)
    w->genTerm.CurrentSettings.type &= ~SETUNDERLINE;
   else
    XtAppWarning(XtWidgetToApplicationContext(w),
		 "Invalid argument for setting underline mode in GtSetAttribute");
   break;
 case GTHALFBRIGHT:
   pen = w->genTerm.CurrentSettings.type >> NUMATTRIBUTES;
   if(flag == GTON)
    {
     GtDefineHalfBrightPen(w,pen);
     w->genTerm.foreground = w->genTerm.CurrentForeground =
      w->genTerm.Colours[pen].HalfBright;
     w->genTerm.CurrentSettings.type |= SETHALFBRIGHT;
    }
   else if(flag == GTOFF)
    {
     w->genTerm.foreground = w->genTerm.CurrentForeground =
      w->genTerm.Colours[pen].Foreground;
     w->genTerm.CurrentSettings.type &= ~SETHALFBRIGHT;
    }
   else
    XtAppWarning(XtWidgetToApplicationContext(w),
		 "Invalid argument for setting halfbright mode in GtSetAttribute");
   break;
 case GTBLINKMODE:
   if(flag == GTON)
    {
     w->genTerm.CurrentSettings.type |= SETBLINK;
     if(w->genTerm.BlinkOn == -1) /* if first time set the timeout */
      {
       w->genTerm.BlinkTimeOut = 
	XtAppAddTimeOut(XtWidgetToApplicationContext(w),
			(unsigned long)w->genTerm.BlinkRate,GtBlinkCallBack,w);
       w->genTerm.BlinkOn = 0;
      }
    }
   else if(flag == GTOFF)
    w->genTerm.CurrentSettings.type &= ~SETBLINK;
   else
    XtAppWarning(XtWidgetToApplicationContext(w),
		 "Invalid argument for setting blink mode in GtSetAttribute");
   break;
 case GTPEN:
   if((flag < 0 ) || (flag >= w->genTerm.NumberColours))
    XtAppWarning(XtWidgetToApplicationContext(w),
		 "Invalid pen number in GtSetAttribute");
   else
    {
     GtDefinePen(w,flag);
     w->genTerm.foreground = w->genTerm.CurrentForeground = 
      w->genTerm.Colours[flag].Foreground;
     w->genTerm.background = w->genTerm.CurrentBackground = 
      w->genTerm.Colours[flag].Background;

     /* must now check other attributes to make sure we put the colour in the */
     /* correct spot */

     if(w->genTerm.CurrentSettings.type & SETHALFBRIGHT)
      {
       GtDefineHalfBrightPen(w,flag);
       w->genTerm.foreground = w->genTerm.CurrentForeground =
	w->genTerm.Colours[flag].HalfBright;
      }
     if(w->genTerm.CurrentSettings.type & SETINVERSE)
      {
       w->genTerm.foreground = w->genTerm.CurrentBackground;
       w->genTerm.background = w->genTerm.CurrentForeground;
      }
     w->genTerm.CurrentSettings.type &= BASEATTRIBUTES;
     w->genTerm.CurrentSettings.type |= (flag << NUMATTRIBUTES);
    }
   break;
 default:
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid attribute specified in GtSetAttribute");
  }
 if(w->genTerm.Pens[w->genTerm.CurrentSettings.type] == NULL)
  GtCreatePens(w,w->genTerm.CurrentSettings.type);
 return(GTGOOD);
}

/* GtGetAttribute: This function returns the current value of the requested */
/*  attribute */

int GtGetAttribute(w,which,flag)

GenTermWidget w;
int which;
int *flag;

{
 switch(which)
  {
 case GTFONT:
   if(w->genTerm.CurrentSettings.type & SETALTFONT)
    *flag = 1;
   else
    *flag = 0;
   break;
 case GTINVERSEVIDEO:
   if(w->genTerm.CurrentSettings.type & SETINVERSE)
    *flag = 1;
   else
    *flag = 0;
   break;
 case GTUNDERLINE:
   if(w->genTerm.CurrentSettings.type & SETUNDERLINE)
    *flag = 1;
   else
    *flag = 0;
   break;
 case GTHALFBRIGHT:
   if(w->genTerm.CurrentSettings.type & SETHALFBRIGHT)
    *flag = 1;
   else
    *flag = 0;
   break;
 case GTBLINKMODE:
   if(w->genTerm.CurrentSettings.type & SETBLINK)
    *flag = 1;
   else
    *flag = 0;
   break;
 case GTPEN:
   *flag = w->genTerm.CurrentSettings.type >> NUMATTRIBUTES;
   break;
 default:
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid attribute specified in GtGetAttribute");
  }
 return(GTGOOD);
}

/* GtSetFieldAttribute:  This function copies the current attribute through */
/*  out the current field.  The end of the field is defined by the type */
/*  Argument.  If type = 0 then the field extends to the end of the line. */
/*  If type=1 then the field extends to the end of the line or the next */
/*  non blank character.  If type=2 then the field extends to the end of the */
/*  line or the next non-blank character which does not have a field */
/*  attribute set. If type=3 then the field extends to the end of the line */
/*  or until the next charater which does not have a field attribute set. */

int GtSetFieldAttribute(w,type)

GenTermWidget w;
int type;

{
 int row,col;
 int i,j;
 int start,end;
 struct Field *NewFields;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 if(w->genTerm.FieldAttributes == TRUE)	/* is nop if not in field mode */
  {
   GtCheckPosition(w);
   row = w->genTerm.CurrentRow;
   i = col = w->genTerm.CurrentColumn;
   for(i = 0; i < w->genTerm.Screen[row]->NumFields; i++)
    if((w->genTerm.Screen[row]->Fields[i].Start <= col) &&
       (w->genTerm.Screen[row]->Fields[i].End >= col))
     {
      if(col == w->genTerm.Screen[row]->Fields[i].Start)
       {
	start = w->genTerm.Screen[row]->Fields[i].Start;
	end = w->genTerm.Screen[row]->Fields[i].End;
       }
      else
       {
	NewFields = (struct Field *) XtMalloc(sizeof(struct Field) * 
					      (w->genTerm.Screen[row]->NumFields
					       + 1));
	for(j = 0; j <= i; j++)
	 {
	  NewFields[j].Start = w->genTerm.Screen[row]->Fields[j].Start;
	  NewFields[j].End = w->genTerm.Screen[row]->Fields[j].End;
	 }
	start = col;
	end = NewFields[i].End;
	NewFields[i].End = start - 1;
	NewFields[i+1].Start = start;
	NewFields[i+1].End = end;
	for(j = i+1; j < w->genTerm.Screen[row]->NumFields; j++)
	 {
	  NewFields[j+1].Start = w->genTerm.Screen[row]->Fields[j].Start;
	  NewFields[j+1].End = w->genTerm.Screen[row]->Fields[j].End;
	 }
	XtFree(w->genTerm.Screen[row]->Fields);
	w->genTerm.Screen[row]->Fields = NewFields;
	w->genTerm.Screen[row]->NumFields += 1;
       }
      break;
     }
   if(end >= w->genTerm.columns)
    end = w->genTerm.columns - 1;

   for(i = start; i <= end; i++)
    {
     memcpy(&(w->genTerm.Screen[row]->Attributes[i]),
	    &(w->genTerm.CurrentSettings),sizeof(struct Attribute));
    }
   w->genTerm.Screen[row]->NumChars = w->genTerm.columns;
   GtUpdateRegion(w,row,col,row,w->genTerm.columns,True);
  }
 else
  return(GTBAD);
 return(GTGOOD);
}

/* GtLoadAttribute:  This function sets the current attribute to be the */
/*  attribute of the character at position row,col.  If that position is */
/*  invalid, the default attribute is loaded. */

int GtLoadAttribute(w,row,col)

GenTermWidget w;
int row,col;

{
 if(GtCheckValidPosition(w,&row,&col,0) == 0)
  memcpy(&(w->genTerm.CurrentSettings),&(w->genTerm.DefaultSettings),
	 sizeof(struct Attribute));
 else
  memcpy(&(w->genTerm.CurrentSettings),
	 &(w->genTerm.Screen[row]->Attributes[col]),sizeof(struct Attribute));
 return(GTGOOD);
}

/* GtClearRegion:  This function clears the region of the screen specified */
/*  by the starting and ending row,column pair. */

int GtClearRegion(w,startrow,startcolumn,endrow,endcolumn)

GenTermWidget w;
int startrow,startcolumn,endrow,endcolumn;

{
 int i,j,k;
 int end;
 int xpos,ypos,height,width;
 int type;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);

 GtCheckValidPosition(w,&startrow,&startcolumn,1);
 GtCheckValidPosition(w,&endrow,&endcolumn,1);

 for(i = startrow; i <= endrow; i++)
  {
   end = endcolumn;
   if(w->genTerm.Screen[i]->NumChars < end)
    end = w->genTerm.Screen[i]->NumChars;
   for(j = startcolumn; j <= end; j++)
    {
     w->genTerm.Screen[i]->Characters[j] = ' ';
     memcpy(&(w->genTerm.Screen[i]->Attributes[j]),&(w->genTerm.DefaultSettings),
	    sizeof(struct Attribute));
    }

   /* we now have to update the attribute fields, if they are being used */
   if(w->genTerm.FieldAttributes)
    {
     k = 0;
     w->genTerm.Screen[i]->Fields[k].Start = 0;
     type = w->genTerm.Screen[i]->Attributes[0].type;
     for(j = 0; j < end; j++)
      if(type != w->genTerm.Screen[i]->Attributes[j].type)
       {
	w->genTerm.Screen[i]->Fields[k++].End = j - 1;
	w->genTerm.Screen[i]->Fields[k].Start = j;
	type = w->genTerm.Screen[i]->Attributes[j].type;
       }
     w->genTerm.Screen[i]->Fields[k].End = w->genTerm.columns - 1;
     w->genTerm.Screen[i]->NumFields = k + 1;
    }
   /*   w->genTerm.Screen[i]->NumFields = 1;
	w->genTerm.Screen[i]->Fields[0].Start = 0;
	w->genTerm.Screen[i]->Fields[0].End = w->genTerm.columns - 1;*/
   if(w->genTerm.Screen[i]->NumChars > startcolumn)
    w->genTerm.Screen[i]->NumChars = startcolumn;
  }
 xpos = startcolumn * w->genTerm.CharWidth;
 ypos = startrow * w->genTerm.CharHeight;
 height = (endrow - startrow + 1) * w->genTerm.CharHeight;
 width = (endcolumn - startcolumn + 1) * w->genTerm.CharWidth;
 XClearArea(XtDisplay(w),XtWindow(w),xpos,ypos,width,height,False);

 GtShowCursor(w);
 return(GTGOOD);
}

/* GtCheckValidPosition:  This function takes a row,column pair at checks to */
/*  see if it is valid.  If it is invalid and flag=0 then an error is */
/*  returned.  If flag=1, the position is corrected. */

static int GtCheckValidPosition(w,row,col,flag)

GenTermWidget w;
int *row,*col;
int flag;

{
 if((*row >= 0) && (*row < w->genTerm.rows) && (*col >= 0) && 
    (*col < w->genTerm.columns))
  return(1);
 else
  {
   if(flag == 0)
    return(0);
   else
    {		/* we have an error and caller wants us to correct it */
     if(*row < 0)
      *row = 0;
     if(*row >= w->genTerm.rows)
      *row = w->genTerm.rows - 1;
     if(*col < 0)
      *col = 0;
     if(*col >= w->genTerm.columns)
      *col = w->genTerm.columns - 1;
     return(1);
    }
  }
}

/* GtClearMemory:  This function clears the data in the virtual screen. If */
/*  flag=0, the entire virtual screen is cleared.  If flag=1, the portion */
/*  of the virtual screen, currently below the screen is cleared.  If */
/*  flag=2 then the portion of the virtual screen currently above the screen */
/*  is cleared */

int GtClearMemory(w,flag)

GenTermWidget w;
int flag;

{
 int StartRow,EndRow;
 int i,j;
 int Width,Height;

 if(w->genTerm.Locked)
  return(GTLOCKED);
 switch(flag)
  {
 case 0:
   StartRow = 0;
   EndRow = w->genTerm.SaveLines;
   break;
 case 1:
   StartRow = w->genTerm.VirtualTop + w->genTerm.rows;
   EndRow = w->genTerm.MaxVirtualTop + w->genTerm.rows;
   break;
 case 2:
   StartRow = 0;
   EndRow = w->genTerm.VirtualTop;
   break;
 default:
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Bad value to GtClearMemory");
   return(0);
  }
 for(i = StartRow; i < EndRow; i++)
  {
   for(j = 0; j < w->genTerm.VScreen[i]->NumChars; j++)
    {
     w->genTerm.VScreen[i]->Characters[j] = ' ';
     memcpy(&(w->genTerm.VScreen[i]->Attributes[j]),
	    &(w->genTerm.DefaultSettings),sizeof(struct Attribute));
    }
   w->genTerm.VScreen[i]->NumChars = 0;
   w->genTerm.VScreen[i]->NumFields = 1;
   w->genTerm.VScreen[i]->Fields[0].Start = 0;
   w->genTerm.VScreen[i]->Fields[0].End = w->genTerm.columns - 1;
  }
 if(flag == 0)			/* we also cleared the screen so blank it */
  {
   Width = w->genTerm.columns * w->genTerm.CharWidth;
   Height = w->genTerm.rows * w->genTerm.CharHeight;
   XClearArea(XtDisplay(w),XtWindow(w),0,0,Width,Height,False);
  }  
 return(GTGOOD);
}

/* GtInsertLines:  This function inserts num rows at position row.  The  */
/*  insertion is performed by moving and clearing the last num lines in the */
/*  virtual screen to the current row. */

int GtInsertLines(w,row,num)

GenTermWidget w;
int row;
int num;

{
 int From,To,i;
 int Xpos,Ypos, Hght,Wid;
 int NewYpos,CpyHght;
 struct Line **Hold;

 if((row < 0) || (row >= w->genTerm.rows))
  return(GTBAD);

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);

 /* first calculate where in the virtual screen we are to put the new lines */

 To = w->genTerm.ScreenTop + row;
 From = w->genTerm.VScreenTop + w->genTerm.rows + 1  - num;
 Hold = (struct Line **) XtMalloc(sizeof(struct Line *) * num);
 for(i = 0; i < num; i++)
  {
   Hold[i] = w->genTerm.VScreen[(From + i) % w->genTerm.SaveLines];
  }
 for(i = From; i >= (To + num); i--)
  {
   w->genTerm.VScreen[i % w->genTerm.SaveLines] =
    w->genTerm.VScreen[(i - num) % w->genTerm.SaveLines];
  }
 for(i = 0; i < num; i++)
  {
   w->genTerm.VScreen[(To + i) % w->genTerm.SaveLines] = Hold[i];
   GtClearLine(w,w->genTerm.VScreen[(To + i) % w->genTerm.SaveLines]);
  }
 for(i = 0; i < w->genTerm.rows; i++)
  w->genTerm.Screen[i] =
   w->genTerm.VScreen[(w->genTerm.ScreenTop + i) % w->genTerm.SaveLines];

 Xpos = 0;
 Ypos = row * w->genTerm.CharHeight;
 Hght = num * w->genTerm.CharHeight;
 Wid = w->genTerm.columns * w->genTerm.CharWidth;
 if((row + num) < w->genTerm.rows)
  {
   NewYpos = (row + num) * w->genTerm.CharHeight;
   CpyHght = (w->genTerm.rows - row - num) * w->genTerm.CharHeight;
   XCopyArea(XtDisplay(w),XtWindow(w),XtWindow(w),w->genTerm.Pens[0]->draw_gc,
	     Xpos,Ypos,Wid,CpyHght,Xpos,NewYpos);
   w->genTerm.ExposureCount++;
  }
 XClearArea(XtDisplay(w),XtWindow(w),Xpos,Ypos,Wid,Hght,False);
 XtFree(Hold);

 /* since we might have scrolled down in memory we increase MaxVirtualTop */
 /* to allow us to get there */

 if(w->genTerm.ScrollOnOutput == False)
  {
   w->genTerm.MaxVirtualTop += num;
   if(w->genTerm.MaxVirtualTop > w->genTerm.SaveLines - w->genTerm.rows)
    w->genTerm.MaxVirtualTop = w->genTerm.SaveLines - w->genTerm.rows;
   if(w->genTerm.MaxVirtualTop >= w->genTerm.SaveLines - w->genTerm.rows)
    {
     w->genTerm.VirtualTop -= num;
     if(w->genTerm.VirtualTop < 0)
      w->genTerm.VirtualTop = 0;
     GtDoTopCallback(w);
    }
  }
 GtShowCursor(w);
 return(GTGOOD);
}

/* GtDeleteLines:  This function deletes num rows starting at the current */
/*  postion.  The deletion is performed by moving and clearing the rows to */
/*  the last num lines in the virtual screen to the current row. */

int GtDeleteLines(w,num)

GenTermWidget w;
int num;

{
 int From,To,i;
 int Xpos,Ypos, Hght,Wid;
 int NewYpos,CpyHght;
 struct Line **Hold;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);

 /* first calculate where in the virtual screen we are to put the new lines */

 From = w->genTerm.ScreenTop + w->genTerm.CurrentRow;
 To = w->genTerm.VScreenTop + w->genTerm.rows + 1  - num;
 Hold = (struct Line **) XtMalloc(sizeof(struct Line *) * num);
 for(i = 0; i < num; i++)
  {
   Hold[i] = w->genTerm.VScreen[(From + i) % w->genTerm.SaveLines];
  }
 for(i = From; i < (To + num); i++)
  {
   w->genTerm.VScreen[i % w->genTerm.SaveLines] =
    w->genTerm.VScreen[(i + num) % w->genTerm.SaveLines];
  }
 for(i = 0; i < num; i++)
  {
   w->genTerm.VScreen[(To + i) % w->genTerm.SaveLines] = Hold[i];
   GtClearLine(w,w->genTerm.VScreen[(To + i) % w->genTerm.SaveLines]);
  }
 for(i = 0; i < w->genTerm.rows; i++)
  w->genTerm.Screen[i] =
   w->genTerm.VScreen[(w->genTerm.ScreenTop + i) % w->genTerm.SaveLines];

 Xpos = 0;
 Ypos = (w->genTerm.CurrentRow + num) * w->genTerm.CharHeight;
 Hght = num * w->genTerm.CharHeight;
 Wid = w->genTerm.columns * w->genTerm.CharWidth;
 if((w->genTerm.CurrentRow + num) < w->genTerm.rows)
  {
   NewYpos = (w->genTerm.CurrentRow) * w->genTerm.CharHeight;
   CpyHght = (w->genTerm.rows - w->genTerm.CurrentRow - num) * 
    w->genTerm.CharHeight;
   XCopyArea(XtDisplay(w),XtWindow(w),XtWindow(w),w->genTerm.Pens[0]->draw_gc,
	     Xpos,Ypos,Wid,CpyHght,Xpos,NewYpos);
   w->genTerm.ExposureCount++;
  }
 Ypos = (w->genTerm.rows - num) * w->genTerm.CharHeight;
 XClearArea(XtDisplay(w),XtWindow(w),Xpos,Ypos,Wid,Hght,False);
 GtUpdateRegion(w,w->genTerm.rows - num,0,w->genTerm.rows,w->genTerm.columns,
		False);
 XtFree(Hold);

 GtShowCursor(w);
 return(GTGOOD);
}

/* GtDeleteCharacters:  This function deletes num characters from the current*/
/*  line starting at the current position. */

int GtDeleteCharacters(w,num)

GenTermWidget w;
int num;

{
 int row;
 int max;
 int i;
 int Xpos,Ypos,Width,Height;

 if(w->genTerm.Locked)
  return(GTLOCKED);

 GtCheckPosition(w);
 GtUnShowCursor(w);

 row = w->genTerm.CurrentRow;
 max = w->genTerm.Screen[row]->NumChars;

 for(i = w->genTerm.CurrentColumn + num; i < max; i++)
  {
   w->genTerm.Screen[row]->Characters[i - num] = 
    w->genTerm.Screen[row]->Characters[i];
   memcpy(&(w->genTerm.Screen[row]->Attributes[i - num]),
	  &(w->genTerm.Screen[row]->Attributes[i]),sizeof(struct Attribute));
  }
 for(i = max - num; i < max; i++)
  {
   w->genTerm.Screen[row]->Characters[i] = ' ';
   memcpy(&(w->genTerm.Screen[row]->Attributes[i]),&(w->genTerm.DefaultSettings),
	  sizeof(struct Attribute));
  }
 w->genTerm.Screen[row]->NumChars -= num;
 if(w->genTerm.Screen[row]->NumChars < w->genTerm.CurrentColumn)
  w->genTerm.Screen[row]->NumChars = w->genTerm.CurrentColumn;

 Xpos = w->genTerm.Screen[row]->NumChars * w->genTerm.CharWidth;
 Ypos = row * w->genTerm.CharHeight;
 Width = (w->genTerm.rows - w->genTerm.Screen[row]->NumChars) * 
  w->genTerm.CharWidth;
 Height = w->genTerm.CharHeight;
 XClearArea(XtDisplay(w),XtWindow(w),Xpos,Ypos,Width,Height,False);
 GtUpdateRegion(w,row,w->genTerm.CurrentColumn,row,
		w->genTerm.Screen[row]->NumChars,False);

 GtShowCursor(w);
 return(GTGOOD);
}

/* GtSetScrollRegion:  This function sets a scroll region between the given */
/*  starting and ending rows. */

int GtSetScrollRegion(w,start,end,num)

GenTermWidget w;
int start;
int end;
int num;

{
 int i;

 if((start < 0) || (start >= w->genTerm.rows) || (end < 0) || 
    (end >= w->genTerm.rows))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid starting or ending row in GtSetScrollRegion");
   return(GTBAD);
  }
 else
  {
   for(i = start; i <= end; i++)
    w->genTerm.Screen[i]->ScrollRegion = num;
  }
 return(GTGOOD);
}

/* GtGetScrollRegion: This function returns the bounds on a given scroll */
/*  region. */

int GtGetScrollRegion(w,num,start,end)

GenTermWidget w;
int num;
int *start,*end;

{
 int i;

 *start = -1;
 *end = w->genTerm.rows;

 for(i = 0; i < w->genTerm.rows; i++)
  if(w->genTerm.Screen[i]->ScrollRegion == num)
   {
    *start = i;
    break;
   }
 if(*start != -1)
  {
   *end = w->genTerm.rows - 1;
   for(i = *start; i < w->genTerm.rows; i++)
    if(w->genTerm.Screen[i]->ScrollRegion != num)
     {
      *end = i - 1;
      break;
     }
  }
 return(GTGOOD);
}

/* GtGetMapTable: This function returns a copy of the current output mapping */
/*  table. */

int GtGetMapTable(w,Table)

GenTermWidget w;
char Table[NMAP];

{
 int i;

 for(i = 0; i < NMAP; i++)
  Table[i] = w->genTerm.MapTable[i];
 return(GTGOOD);
}

/* GtSetMapTable:  This function set the values for the current output */
/*  mapping table. */

int GtSetMapTable(w,Table)

GenTermWidget w;
char Table[NMAP];

{
 int i;

 for(i = 0; i < NMAP; i++)
  w->genTerm.MapTable[i] = Table[i];
 return(GTGOOD);
}

static void GtStartSelection(w,event,names,num)

GenTermWidget w;
XEvent *event;
char *names[];
Cardinal *num;

{
 int Row,Col;

 GtUnHighLightSection(w);
 if(w->genTerm.CurrentSelection != NULL)
  {
   XtFree(w->genTerm.CurrentSelection);
   w->genTerm.CurrentSelection = NULL;
  }
 w->genTerm.SelectionStarted = True;
 GtPositionToRowColumn(w,event->xbutton.x,event->xbutton.y,&Row,&Col);
 w->genTerm.SelectionStartRow = Row;
 w->genTerm.SelectionStartCol = Col;
 w->genTerm.SelectionEndRow = Row;
 w->genTerm.SelectionEndCol = Col;
 w->genTerm.Locked = True;
 GtDoLockCallback(w);
}

static void GtExtendSelection(w,event,names,num)

GenTermWidget w;
XEvent *event;
char *names[];
Cardinal *num;

{
 int Row,Col;
 int OldEndRow;

 if(w->genTerm.SelectionStarted == False)
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"GenTerm widget gets extend selection action before start selection!");
  }
 else
  {
   GtPositionToRowColumn(w,event->xbutton.x,event->xbutton.y,&Row,&Col);
   OldEndRow = w->genTerm.SelectionEndRow;
   w->genTerm.SelectionEndRow = Row;
   w->genTerm.SelectionEndCol = Col;
   GtHighLightSection(w,OldEndRow);
  }
}

static void GtHighLightSection(w,OldRow)

GenTermWidget w;
int OldRow;

{
 int StartRow = w->genTerm.SelectionStartRow;
 int EndRow = w->genTerm.SelectionEndRow;
 int StartCol = w->genTerm.SelectionStartCol;
 int EndCol = w->genTerm.SelectionEndCol;
 int EndLine;
 int i,j;
 int First,Last;

 /* first erase old highlight section */

 if(StartRow < OldRow)
  {
   First = StartRow;
   Last = OldRow;
  }
 else
  {
   First = OldRow;
   Last = StartRow;
  }
 for(i = First; i <= Last; i++)
  {
   EndLine = MIN(w->genTerm.Screen[i]->NumChars,w->genTerm.columns-1);
   for(j = 0; j <= EndLine; j++)
    w->genTerm.Screen[i]->Attributes[j].type &= ~HIGHLIGHT;
  }

 GtSortStartEnd(&StartRow,&StartCol,&EndRow,&EndCol);

 EndLine = MIN(w->genTerm.Screen[StartRow]->NumChars,w->genTerm.columns-1);
 if(EndRow == StartRow)
  EndLine = MIN(EndLine,EndCol);
 for(i = StartCol; i <= EndLine; i++)
  w->genTerm.Screen[StartRow]->Attributes[i].type |= HIGHLIGHT;

 if(EndRow != StartRow)
  {
   for(i = StartRow + 1; i < EndRow; i++)
    {
     EndLine = MIN(w->genTerm.Screen[i]->NumChars,w->genTerm.columns-1);
     for(j = 0; j <= EndLine; j++)
      w->genTerm.Screen[i]->Attributes[j].type |= HIGHLIGHT;
    }
   EndLine = MIN(w->genTerm.Screen[i]->NumChars,EndCol);
   for(i = 0; i <= EndLine; i++)
    w->genTerm.Screen[EndRow]->Attributes[i].type |= HIGHLIGHT;
  }
 GtUpdateRegion(w,First,0,Last,w->genTerm.columns,True);
 GtUpdateRegion(w,StartRow,0,EndRow,w->genTerm.columns,True);
}

/* MyUnHightLightSection:  This function searches throught the entire */
/*  screen searching for characters with the highlight bit set.  If it finds */
/*  any it clears the bit and, if the character was visible, it calls */
/*  GtUpdateRegion to redraw that section of the screen.  Note that we can't */
/*  use the selection row column pointers because they are not valid after */
/*  the selection is completed because they aren't updated during screen */
/*  scrolling.  */

static void GtUnHighLightSection(w)

GenTermWidget w;

{
 int i,j;
 int StartRow = -1;
 int EndRow;

 /* first look in the visible screen */

 for(i = 0; i < w->genTerm.rows; i++)
  {
   for(j = 0; j < w->genTerm.columns; j++)
    if(w->genTerm.Screen[i]->Attributes[j].type & HIGHLIGHT)
     {
      w->genTerm.Screen[i]->Attributes[j].type &= ~HIGHLIGHT;
      if(StartRow == -1)
       StartRow = i;
      EndRow = i;
     }
  }
 /* now update any area that needs doing */

 if(StartRow != -1)
  GtUpdateRegion(w,StartRow,0,EndRow,w->genTerm.columns,True);

 /* finally, look for things that might have scrolled off the screen */

 for(i = 0; i < w->genTerm.SaveLines; i++)
  for(j = 0; j < w->genTerm.columns; j++)
   if(w->genTerm.VScreen[i]->Attributes[j].type & HIGHLIGHT)
    w->genTerm.VScreen[i]->Attributes[j].type &= ~HIGHLIGHT;

}

static void GtMakeSelection(w,event,names,num)

GenTermWidget w;
XEvent *event;
char *names[];
Cardinal *num;

{
 char *selection;
 Atom atom;
 int which = 0;
 int buffer = -1;
 int i;

 for(i = 0; i < *num; i++)
  {
   if(strcmp(names[i],"PRIMARY") == 0)
    which = 0;
   else if(strcmp(names[i],"SECONDARY") == 0)
    which = 1;
   else if(strncmp(names[i],"CUT_BUFFER",strlen("CUT_BUFFER")) == 0)
    {
     buffer = names[i][strlen("CUT_BUFFER")] - '0';
    }
  }

 if(w->genTerm.SelectionStarted == False)
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"GenTerm widget gets make selection action before start selection!");
  }
 else
  {
   GtSortStartEnd(&w->genTerm.SelectionStartRow,&w->genTerm.SelectionStartCol,
		  &w->genTerm.SelectionEndRow,&w->genTerm.SelectionEndCol);
   w->genTerm.SelectionStarted = False;
   if((w->genTerm.SelectionStartRow == w->genTerm.SelectionEndRow) &&
      (w->genTerm.SelectionStartCol == w->genTerm.SelectionEndCol))
    {
     GtUnHighLightSection(w);
     w->genTerm.Locked = False;
     GtDoLockCallback(w);
     return;
    }

   selection = GtCopySection(w,w->genTerm.SelectionStartRow,
			     w->genTerm.SelectionStartCol,
			     w->genTerm.SelectionEndRow,
			     w->genTerm.SelectionEndCol);
   w->genTerm.CurrentSelection = selection;

   if(which == 0)
    atom = XA_PRIMARY;
   else
    atom = XA_SECONDARY;
   if(XtOwnSelection(w,atom,event->xbutton.time,GtConvertProc,GtLoseSelection,
		     NULL) == False)
    {
     XtAppWarning(XtWidgetToApplicationContext(w),
		  "GenTerm Widget failed to own selection");
    }
   if(buffer >= 0)
    XStoreBuffer(XtDisplay(w),selection,strlen(selection),buffer);
  }
 w->genTerm.Locked = False;
 GtDoLockCallback(w);
}

/* GtConvertProc:  This function is the convert procedure for the selections*/
/*  It is copied from page 300 of the X Toolkit Intrinsics Programming */
/*  manual Volume 4. */

static Boolean GtConvertProc(w,selection,target,type_return,value_return,
		     length_return,format_return)

GenTermWidget w;
Atom *selection;
Atom *target;
Atom *type_return;
caddr_t *value_return;
unsigned long *length_return;
int *format_return;

{
 if( *target == XA_TARGETS(XtDisplay(w)))
  {
   Atom *targetP;
   Atom *std_targets;
   unsigned long std_length;

   XmuConvertStandardSelection(w,CurrentTime,selection,target,type_return,
			       (caddr_t *)&std_targets,&std_length,
			       format_return);
   *value_return = XtMalloc(sizeof(Atom)*(std_length + 1));
   targetP = *(Atom **) value_return;
   *length_return = std_length + 1;
   *targetP++ = XA_STRING;
   bcopy((char *)std_targets,(char *)targetP,sizeof(Atom)*std_length);
   XtFree((char *)std_targets);
   *type_return = XA_ATOM;
   *format_return = sizeof(Atom) * 8;
   return(True);
  }
 else if (*target == XA_STRING)
  {
   *type_return = XA_STRING;
   *value_return = (XtPointer) XtNewString(w->genTerm.CurrentSelection);
   *length_return = strlen(*value_return);
   *format_return = 8;
   return(True);
  }
 else
  {
   if(XmuConvertStandardSelection(w,CurrentTime,selection,target,type_return,
				  value_return,length_return,format_return))
    return(True);
   else
    return(False);
  }
}

static void GtLoseSelection(w,selection)

GenTermWidget w;
Atom *selection;

{
 if(w->genTerm.CurrentSelection != NULL)
  XtFree(w->genTerm.CurrentSelection);
 w->genTerm.CurrentSelection = NULL;
 GtUnHighLightSection(w);
}

/* GtSortStartEnd:  This function takes two row column pairs and sorts them */
/*  to determine which comes before the other.  The position which comes */
/*  first is defined to be the one which you would encounter first when */
/*  traversing the screen left to row and top to bottom.  */

static void GtSortStartEnd(StartRow,StartCol,EndRow,EndCol)

int *StartRow;
int *StartCol;
int *EndRow;
int *EndCol;

{
 int row,col;
 Boolean Flip = False;

 if(*EndRow < *StartRow)
  Flip = True;
 else if((*EndRow == *StartRow) && (*EndCol < *StartCol))
  Flip = True;

 if(Flip == True)
  {
   row = *StartRow;
   col = *StartCol;
   *StartRow = *EndRow;
   *StartCol = *EndCol;
   *EndRow = row;
   *EndCol = col;
  }
}

/* GtCopySection:  This function copies a section of the screen */

static char *GtCopySection(w,StartRow,StartCol,EndRow,EndCol)

GenTermWidget w;
int StartRow,StartCol;
int EndRow,EndCol;

{
 char *store;
 int i,j,k = 0;
 int l;
 int size;

 size = (w->genTerm.columns + 1)* (EndRow - StartRow + 1); /* over est. size */
 store = XtMalloc(sizeof(char) * (size + 1));

 i = MIN(w->genTerm.Screen[StartRow]->NumChars,w->genTerm.columns-1);
 if(StartRow == EndRow)
  i = MIN(i,EndCol);
 while((i >= 0) && (w->genTerm.Screen[StartRow]->Characters[i--] == ' '));
 i++;
 for(j = StartCol; j <= i; j++)
  store[k++] = w->genTerm.Screen[StartRow]->Characters[j];

 if(StartRow == EndRow)
  {
   store[k] = NULL;
   return(store);
  }
 else
  store[k++] = '\n';

 for(l = StartRow + 1; l < EndRow; l++)
  {
   i = MIN(w->genTerm.Screen[l]->NumChars,w->genTerm.columns-1);
   while((i >= 0) && (w->genTerm.Screen[l]->Characters[i--] == ' '));
   i++;
   for(j = 0; j <= i; j++)
    store[k++] = w->genTerm.Screen[l]->Characters[j];
   store[k++] = '\n';
  }

 i = MIN(w->genTerm.Screen[EndRow]->NumChars,w->genTerm.columns-1);
 if(EndCol < i)
  i = EndCol;
 while((i >= 0) && (w->genTerm.Screen[EndRow]->Characters[i--] == ' '));
 i++;
 for(j = 0; j <= i; j++)
  store[k++] = w->genTerm.Screen[EndRow]->Characters[j];
 /*store[k++] = '\n';*/

 store[k] = NULL;
 return(store);
}

static void GtInsertSelection(w,event,names,num)

GenTermWidget w;
XEvent *event;
char *names[];
Cardinal *num;

{
 Atom which = XA_PRIMARY;
 int i;

 w->genTerm.CutBuffer = -1;

 for(i = 0; i < *num; i++)
  {
   if(strcmp(names[i],"SECONDARY") == 0)
    which = XA_SECONDARY;
   else if(strncmp(names[i],"CUT_BUFFER",strlen("CUT_BUFFER")) == 0)
    {
     w->genTerm.CutBuffer = names[i][strlen("CUT_BUFFER")] - '0';
    }
  }

 XtGetSelectionValue(w,which,XA_STRING,GtInsertCallback,NULL,
		     event->xbutton.time);
}

static void GtInsertCallback(w,client_data,selection,type,value,length,format)

GenTermWidget w;
XtPointer client_data;
Atom *selection;
Atom *type;
XtPointer *value;
unsigned long *length;
int *format;

{
 GenTermCallback reason;
 int len;

 if((value == NULL) || ((*value == NULL) && (*length == 0)))
  {
   if(w->genTerm.CutBuffer >= 0)
    {
     reason.Selection = XFetchBuffer(XtDisplay(w),&(len),0);
     if(len > 0)
      {
       reason.reason = GT_PASTE;
       reason.event = NULL;
       XtCallCallbacks(w,XtNkbdCallback,(caddr_t)&reason);
      }
    }
  }
 else
  {
   reason.reason = GT_PASTE;
   reason.event = NULL;
   reason.Selection = value;
   XtCallCallbacks(w,XtNkbdCallback,(caddr_t)&reason);
  }
}

/* GtGetScreenSize:  This function returns the current size of the screen */
/*  to the calling program. */

int GtGetScreenSize(w,rows,cols)

GenTermWidget w;
int *rows;
int *cols;

{
 *rows = w->genTerm.rows;
 *cols = w->genTerm.columns;

 return(GTGOOD);
}

/* GtChangeFonts:  This function is called when the user has requested that */
/*  fonts be changed.  The new fonts have already been loaded.  Here we walk */
/*  through all the graphics contexts and attributes and change the */
/*  appropriate font */

static void GtChangeFonts(w)

GenTermWidget w;

{
 int i,j;
 int npen;
 Font font;
 XFontStruct *Temp;

 npen = w->genTerm.NumberColours << NUMATTRIBUTES;

 /* first walk each pen */

 for(i = 0; i < npen; i++)
  if(w->genTerm.Pens[i] != NULL)
   {
    if(i & SETALTFONT)
     font = w->genTerm.AltFont->fid;
    else
     font = w->genTerm.CurrentFont->fid;
    XSetFont(XtDisplay(w),w->genTerm.Pens[i]->draw_gc,font);
    XSetFont(XtDisplay(w),w->genTerm.Pens[i]->cursor_gc,font);
    XSetFont(XtDisplay(w),w->genTerm.Pens[i]->blink_gc,font);
   }
 /* now look at all attribute fields */
 for(i = 0; i < w->genTerm.SaveLines;i++)
  for(j = 0; j < w->genTerm.columns; j++)
   {
    if(w->genTerm.VScreen[i]->Attributes[j].type & SETALTFONT)
     w->genTerm.VScreen[i]->Attributes[j].Font = w->genTerm.AltFont;
    else
     w->genTerm.VScreen[i]->Attributes[j].Font = w->genTerm.CurrentFont;
   }

 if(w->genTerm.CurrentSettings.type & SETALTFONT)
  w->genTerm.CurrentSettings.Font = w->genTerm.AltFont;
}

/* GtChangeCursorColour:  This function is called whent he user has requested*/
/*  to change the cursor colour.  It goes through all the currently defined */
/*  graphics contexts and updates the cursor colour setting. */

static void GtChangeCursorColour(w)

GenTermWidget w;

{
 int i;
 int npen;
 XGCValues values;

 npen = w->genTerm.NumberColours << NUMATTRIBUTES;

 for(i = 0; i < npen; i++)
  if(w->genTerm.Pens[i] != NULL)
   {
    values.background = w->genTerm.CursorColour;
    XChangeGC(XtDisplay(w),w->genTerm.Pens[i]->cursor_gc,GCBackground,
	      &values);
   }
}

/* GtChangeColour:  This function walks through all the graphics contexts */
/*  and changes any reference to the old colour to new colour. */

static void GtChangeColour(w,NewColour,OldColour,start,end)

GenTermWidget w;
Pixel OldColour;
Pixel NewColour;
int start,end;

{
 int i,j;
 XGCValues values;
 GC gc;

 for(i = start; i < end; i++)
  if(w->genTerm.Pens[i] != NULL)
   {
    for(j = 0; j < 3; j++)
     {
      switch(j)
       {
      case 0:
	gc = w->genTerm.Pens[i]->draw_gc;
	break;
      case 1:
	gc = w->genTerm.Pens[i]->cursor_gc;
	break;
      case 2:
	gc = w->genTerm.Pens[i]->blink_gc;
	break;
       }

      XGetGCValues(XtDisplay(w),gc,GCBackground | GCForeground,&values);
      if(values.foreground == OldColour)
       values.foreground = NewColour;
      if(values.background == OldColour)
       values.background = NewColour;
      XChangeGC(XtDisplay(w),gc,GCBackground | GCForeground,&values);
     }
   }
}

/* GtChangePen: This function is called when the user changes one of the */
/*  pen colours.  It rebuilts the pen colour structure and then if a colour */
/*  has been changed, it goes and updates all the graphics contexts that */
/*  might use that colour */

static void GtChangePen(new,old)

GenTermWidget new;
GenTermWidget old;

{
 int i;
 int start;

 GtSetupPenColours(new);	/* first build the new pen table */

 for(i = 0; i < new->genTerm.NumberColours; i++)
  {				/* now compare old and new tables to find pens that changed */
   if(old->genTerm.Colours[i].defined != 0) /* only care about ones we used */
    {
     if((strcmp(new->genTerm.Colours[i].ForegroundName,
		old->genTerm.Colours[i].ForegroundName) != 0) ||
	(strcmp(new->genTerm.Colours[i].BackgroundName,
		old->genTerm.Colours[i].BackgroundName) != 0))
      {
       GtDefinePen(new,i);
       start = i << NUMATTRIBUTES;
       GtChangeColour(new,new->genTerm.Colours[i].Foreground,
		      old->genTerm.Colours[i].Foreground,start,
		      start+BASEATTRIBUTES);
       GtChangeColour(new,new->genTerm.Colours[i].Background,
		      old->genTerm.Colours[i].Background,start,
		      start + BASEATTRIBUTES);
       if(old->genTerm.Colours[i].defined == 2)
	{
	 GtDefineHalfBrightPen(new,i);
	 GtChangeColour(new,new->genTerm.Colours[i].HalfBright,
			old->genTerm.Colours[i].HalfBright,start,
			start + BASEATTRIBUTES);
	}
       if((new->genTerm.CurrentSettings.type >> NUMATTRIBUTES) == i)
	{	/* pen is currently in use so update current colours */
	 if(old->genTerm.foreground == old->genTerm.Colours[i].Foreground)
	  new->genTerm.foreground = new->genTerm.Colours[i].Foreground;
	 if(old->genTerm.foreground == old->genTerm.Colours[i].Background)
	  new->genTerm.foreground = new->genTerm.Colours[i].Background;
	 if(old->genTerm.foreground = old->genTerm.Colours[i].HalfBright)
	  new->genTerm.foreground = new->genTerm.Colours[i].HalfBright;
	 if(old->genTerm.CurrentForeground ==
	    old->genTerm.Colours[i].Foreground)
	  new->genTerm.CurrentForeground = new->genTerm.Colours[i].Foreground;
	 if(old->genTerm.CurrentForeground ==
	    old->genTerm.Colours[i].Background)
	  new->genTerm.CurrentForeground = new->genTerm.Colours[i].Background;
	 if(old->genTerm.CurrentForeground =
	    old->genTerm.Colours[i].HalfBright)
	  new->genTerm.CurrentForeground = new->genTerm.Colours[i].HalfBright;
	 if(old->genTerm.background == old->genTerm.Colours[i].Foreground)
	  new->genTerm.background = new->genTerm.Colours[i].Foreground;
	 if(old->genTerm.background == old->genTerm.Colours[i].Background)
	  new->genTerm.background = new->genTerm.Colours[i].Background;
	 if(old->genTerm.background = old->genTerm.Colours[i].HalfBright)
	  new->genTerm.background = new->genTerm.Colours[i].HalfBright;
	 if(old->genTerm.CurrentBackground ==
	    old->genTerm.Colours[i].Foreground)
	  new->genTerm.CurrentBackground = new->genTerm.Colours[i].Foreground;
	 if(old->genTerm.CurrentBackground ==
	    old->genTerm.Colours[i].Background)
	  new->genTerm.CurrentBackground = new->genTerm.Colours[i].Background;
	 if(old->genTerm.CurrentBackground = old->genTerm.Colours[i].HalfBright)
	  new->genTerm.CurrentBackground = new->genTerm.Colours[i].HalfBright;
	}
      }
     else
      {
       new->genTerm.Colours[i].Foreground = old->genTerm.Colours[i].Foreground;
       new->genTerm.Colours[i].Background = old->genTerm.Colours[i].Background;
       new->genTerm.Colours[i].HalfBright = old->genTerm.Colours[i].HalfBright;
       new->genTerm.Colours[i].defined = old->genTerm.Colours[i].defined;
      }
    }
  }
 GtDestroyPenColours(old);
}

/* GtHSLtoRGB: This utility function converts a colour from RGB to HSL */
/*  Stolen from "Starbase Graphics Techniques, HP-UX Concepts and */
/*  Tutorials" March 1988 Edition 1 */

static void GtHSLtoRGB(r,g,b,h,s,l)

int *r,*g,*b;
int h,s,l;

{
 float red,green,blue;
 float hue,sat,lum;
 float frac,lx,ly,lz;
 float minval;

 hue = ((float)h)/MAXCOLOUR;
 sat = ((float)s)/MAXCOLOUR;
 lum = ((float)l)/MAXCOLOUR;

 hue = 6.0 * hue;
 frac = hue - (int) hue;
 lx = lum * (1.0 - sat);
 ly = lum * (1.0 - sat * frac);
 lz = lum * (1.0 - sat * (1.0 - frac));

 switch((int)hue)
  {
 case 0:
 case 6:
   red = lum;
   green = lz;
   blue = lx;
   break;
 case 1:
   red = ly;
   green = lum;
   blue = lx;
   break;
 case 2:
   red = lx;
   green = lum;
   blue = lz;
   break;
 case 3:
   red = lx;
   green = ly;
   blue = lum;
   break;
 case 4:
   red = lz;
   green = lx;
   blue = lum;
   break;
 case 5:
   red = lum;
   green = lx;
   blue = ly;
   break;
  }


 red *= MAXCOLOUR;
 green *= MAXCOLOUR;
 blue *= MAXCOLOUR;

 *r = (int)red;
 *g = (int)green;
 *b = (int)blue;
}

static void GtRGBtoHSL(r,g,b,h,s,l)

int r,g,b;
int *h,*s,*l;

{
 float red,green,blue;
 float hue,sat,lum;
 float x,tempr,tempg,tempb;

#define MAXCOL(a,b,c) ((a>b?a:b)>c?(a>b?a:b):c)
#define MINCOL(a,b,c) ((a<b?a:b)<c?(a<b?a:b):c)

 red = ((float)r)/MAXCOLOUR;
 green = ((float)g)/MAXCOLOUR;
 blue = ((float)b)/MAXCOLOUR;

 hue = 0.0;
 sat = 1.0;
 lum = MAXCOL(red,green,blue);
 x = MINCOL(red,green,blue);
 if(lum != 0.0)
  {
   sat = (lum - x) / lum;
   if(sat != 0.0)
    {
     tempr = (lum - red) / (lum - x);
     tempg = (lum - green) / (lum - x);
     tempb = (lum - blue) / (lum - x);
     if(red == lum)
      hue = (green == x ? 5.0 + tempb : 1.0 - tempg);
     else if(green = lum)
      hue = (blue == x ? 1.0 + tempr : 3.0 - tempb);
     else
      hue = (red == x ? 3.0 + tempg : 5.0 - tempr);
     
     hue /= 6.0;
    }
  }

 *h = (int)(hue * MAXCOLOUR);
 *s = (int)(sat * MAXCOLOUR);
 *l = (int)(lum * MAXCOLOUR);
}
 
memrep(s1,s2,size,n)

char *s1;
char *s2;
int size;
int n;

{
 int i;

 for(i = 0; i < n; i++)
  {
   memcpy(s1,s2,size);
   s1 += size;
  }
}

@EOF
set `wc -lwc <GenTerm/GenTerm.c`
if test $1$2$3 != 409511685117264
then
	echo ERROR: wc results of GenTerm/GenTerm.c are $* should be 4095 11685 117264
fi

chmod 644 GenTerm/GenTerm.c

echo x - GenTerm/GenTerm.h
cat >GenTerm/GenTerm.h <<'@EOF'
#ifndef _READGenTermh
#define _READGenTermh
/* History:                                 */
/*         Written by G. R. Strachan 1992 */

/*  Copyright Gordon R. Strachan 1992 */
/*  This code is provided as is, neither the University of Waterloo nor */
/*  the author is liable for any damage caused by the use or misuse of this */
/*  code.  */

/* Permission is granted to copy, use and modify this code provided it is */
/* not sold for profit and the above copyright remains intact. */

#include <X11/Core.h>
#include <X11/Composite.h>

extern WidgetClass genTermWidgetClass;

typedef struct _GenTermClassRec *GenTermWidgetClass;
typedef struct _GenTermRec *GenTermWidget;

#define XtNrows                  "rows"
#define XtNcolumns               "columns"
#define XtNbottomMargin          "bottomMargin"
#define XtNbaseFont              "baseFont"
#define XtNalternateFont         "alternateFont"
#define XtNsaveLines             "saveLines"
#define XtNautoLineWrap          "autoLineWrap"
#define XtNliteralMode           "literalMode"
#define XtNcursorColor           "cursorColor"
#define XtNshowCursor            "showCursor"
#define XtNkbdCallback           "kbdCallback"
#define XtNtopCallback           "topCallback"
#define XtNresizeCallback        "resizeCallback"
#define XtNlockCallback          "lockCallback"
#define XtNcursorFloats          "cursorFloats"
#define XtNfieldAttributes       "fieldAttributes"
#define XtNscrollDownClear       "scrollDownClear"
#define XtNfullScroll            "fullScroll"
#define XtNinsertMode            "insertMode"
#define XtNsaveScrollRegion      "saveScrollRegion"
#define XtNcharacterHeight       "characterHeight"
#define XtNcharacterWidth        "characterWidth"
#define XtNblinkRate             "blinkRate"
#define XtNnumberColors          "numberColors"
#define XtNpenColors             "penColors"
#define XtNdefineColor           "defineColor"
#define XtNscrollOnOutput        "scrollOnOutput"
#define XtNcursorKeyScrollRegion "cursorKeyScrollRegion"
#define XtNmarginBell            "marginBell"
#define XtNmargin                "margin"
#define XtNeolStick              "eolStick"
#define XtNlockScreen            "lockScreen"
#define XtNignoreNull            "ignoreNull"

#define XtCRows                  "Rows"
#define XtCColumns               "Columns"
#define XtCBottomMargin          "BottomMargin"
#define XtCBaseFont              "BaseFont"
#define XtCAlternateFont         "AlternateFont"
#define XtCSaveLines             "SaveLines"
#define XtCAutoLineWrap          "AutoLineWrap"
#define XtCLiteralMode           "LiteralMode"
#define XtCCursorColor           "CursorColor"
#define XtCKbdCallback           "KbdCallback"
#define XtCTopCallback           "TopCallback"
#define XtCResizeCallback        "ResizeCallback"
#define XtCLockCallback          "LockCallback"
#define XtCCursorFloats          "CursorFloats"
#define XtCShowCursor            "ShowCursor"
#define XtCFieldAttributes       "Fieldattributes"
#define XtCScrollDownClear       "ScrollDownClear"
#define XtCFullScroll            "FullScroll"
#define XtCInsertMode            "InsertMode"
#define XtCSaveScrollRegion      "SaveScrollRegion"
#define XtCCharacterHeight       "CharacterHeight"
#define XtCCharacterWidth        "CharacterWidth"
#define XtCBlinkRate             "BlinkRate"
#define XtCNumberColors          "NumberColors"
#define XtCPenColors             "PenColors"
#define XtCDefineColor           "DefineColor"
#define XtCScrollOnOutput        "ScrollOnOutput"
#define XtCCursorKeyScrollRegion "CursorKeyScrollRegion"
#define XtCMarginBell            "MarginBell"
#define XtCMargin                "Margin"
#define XtCEolStick              "EolStick"
#define XtCLockScreen            "LockScreen"
#define XtCIgnoreNull            "IgnoreNull"

#define GTFONT 1
#define GTBASE 0
#define GTALTERNATE    1
#define GTINVERSEVIDEO 2
#define GTUNDERLINE    3
#define GTHALFBRIGHT   4
#define GTBLINKMODE    5
#define GTPEN          6

#define GTOFF 0
#define GTON 1
#define GTNORMAL 0
#define GTINVERSE 1

#define GT_INPUT 1
#define GT_TOP 2
#define GT_RESIZE 3
#define GT_PASTE 4
#define GT_LOCK 5

#define GTRGB 0
#define GTHSL 1

#define MAXCOLOUR 65535.0

#define NMAP 255

#define GTGOOD 1
#define GTBAD 0
#define GTLOCKED 2

typedef struct mytermCallback
{
 int reason;
 XEvent *event;
 int TopLine;
 int Rows;
 int Columns;
 int Save;
 char *Selection;
 int Value;
} GenTermCallback;

#endif _READGenTermh

@EOF
set `wc -lwc <GenTerm/GenTerm.h`
if test $1$2$3 != 1343924464
then
	echo ERROR: wc results of GenTerm/GenTerm.h are $* should be 134 392 4464
fi

chmod 644 GenTerm/GenTerm.h

echo x - GenTerm/GenTermEm.h
cat >GenTerm/GenTermEm.h <<'@EOF'
#ifndef _READGenTermEmh
#define _READGenTermEmh
/* History:                                 */
/*         Written by G. R. Strachan 1992 */

/*  Copyright Gordon R. Strachan 1992 */
/*  This code is provided as is, neither the University of Waterloo nor */
/*  the author is liable for any damage caused by the use or misuse of this */
/*  code.  */

/* Permission is granted to copy, use and modify this code provided it is */
/* not sold for profit and the above copyright remains intact. */

#include <X11/Core.h>
#include "GenTerm.h"

extern WidgetClass genTermEmWidgetClass;

typedef struct _GenTermEmClassRec *GenTermEmWidgetClass;
typedef struct _GenTermEmRec *GenTermEmWidget;

#define XtNname                   "name"
#define XtNshowFunction           "showFunction"
#define XtNfunctionSize           "functionSize"
#define XtNfunctionLabelWidth     "functionLabelWidth"
#define XtNnumberFunctionKeys     "numberFunctionKeys"
#define XtNoutputFile             "outputFile"
#define XtNlogging                "logging"
#define XtNlogFile                "logFile"
#define XtNdestructiveTab         "destructiveTab"
#define XtNparseFile              "parseFile"
#define XtNescCallback            "escCallback"
#define XtNwakeUpCallback         "wakeUpCallback"
#define XtNflowCallback           "flowCallback"
#define XtNnumberMapTables        "numberMapTables"
#define XtNnumberStorageArguments "numberStorageArguments"
#define XtNpreScroll              "preScroll"
#define XtNscrollChar             "scrollChar"
#define XtNscrollAbortChar        "scrollAbortChar"

#define XtCName                   "Name"
#define XtCShowFunction           "ShowFunction"
#define XtCFunctionSize           "FunctionSize"
#define XtCFunctionLabelWidth     "FunctionLabelWidth"
#define XtCNumberFunctionKeys     "NumberFunctionKeys"
#define XtCOutputFile             "OutputFile"
#define XtCLogging                "Logging"
#define XtCLogFile                "LogFile"
#define XtCDestructiveTab         "DestructiveTab"
#define XtCParseFile              "ParseFile"
#define XtCEscCallback            "EscCallback"
#define XtCWakeUpCallback         "WakeUpCallback"
#define XtCFlowCallback           "FlowCallback"
#define XtCNumberMapTables        "NumberMapTables"
#define XtCNumberStorageArguments "NumberStorageArguments"
#define XtCPreScroll              "PreScroll"
#define XtCScrollChar             "ScrollChar"
#define XtCScrollAbortChar        "ScrollAbortChar"

#define GTE_INPUT  1
#define GTE_ESCAPE 2
#define GTE_WAKEUP 3
#define GTE_XOFF   4
#define GTE_XON    5

#define GTE_DONE 1
#define GTE_WAIT 2

typedef struct mytermemCallback
{
 int reason;
 XEvent *event;
 char *string;
 int len;
 char **escapes;
} GenTermEmCallback;

#endif _READGenTermEmh
@EOF
set `wc -lwc <GenTerm/GenTermEm.h`
if test $1$2$3 != 782452753
then
	echo ERROR: wc results of GenTerm/GenTermEm.h are $* should be 78 245 2753
fi

chmod 644 GenTerm/GenTermEm.h

echo x - GenTerm/GenTermEmP.h
cat >GenTerm/GenTermEmP.h <<'@EOF'
/* GenTermP.h -- Private definitions for GenTerm widget */
/* History:                                 */
/*         Written by G. R. Strachan 1992 */

/*  Copyright Gordon R. Strachan 1992 */
/*  This code is provided as is, neither the University of Waterloo nor */
/*  the author is liable for any damage caused by the use or misuse of this */
/*  code.  */

/* Permission is granted to copy, use and modify this code provided it is */
/* not sold for profit and the above copyright remains intact. */

#ifndef _ReadGenTermEmP
#define _ReadGenTermEmP

#include <X11/X.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>
#include <Xm/Label.h>

#include "GenTermEm.h"
#include "GenTermP.h"

#define NTABS 20
#define NUMARGS 20

#define NKEYS 8

#define ADEFINED  1
#define AMALLOCED (1 << 1)

/* our internal private data structures */

struct ParseItem
{
 short empty;
 char c;
 struct ParseItem *next;
 struct ParseItem *child;
 struct SpecialItem *special;
 struct Translator *translators;
};

struct InputArgument
{
 char *string;
 int length;
 int valid;
};

struct Arguments
{
 char *string;
 int type;
 int n;
};

struct ArgumentList
{
 int NumArgs;
 struct Arguments *args;
};

struct SpecialItem
{
 int position;
 struct ArgumentList *arglist;
 int (*func)();
};

struct Translator
{
 struct ArgumentList *arglist;
 int (*func)();
 int label;
 struct Translator *next;
};

struct FuncDefs
{
 char *name;
 int (*func)();
};

struct KeyTranslations
{
 KeySym sym;
 int state;
 char type;
 char *string;
 int len;
};

struct GtEList
{
 char Name[80];
 union
  {
   struct KeyTranslations *KeyTable;
   struct ParseItem *ParseTable;
  }Point;
 int Num;
 struct GtEList *Next;
};

struct GtEParseFile

{
 char *Name;
 struct GtEList *ParseTables;
 struct GtEList *KeyTables;
 struct GtEParseFile *Next;
};

struct StateTable
{
 char *Name;
 int Mask;
};

struct SpecialVariables    /* storage for static variable for special parsers*/
{
 int Started;
 union
  {
   int NumToGo;
   struct {
    int IntNumToGo;
    int FracNumToGo;
    int SeenDot;
   } FloatVars;
   struct {
    int NumToGo;
    char Sep[1];
    int Store;
   } DigitsVars;
  } store;
};

struct FunctionKey
{
 Widget FuncKey;
 char *Label;
 char *String;
 int Type;
};

/* Additions to widget class record */

typedef struct {
 struct GtEParseFile *ParseFiles;     /* our loaded parse files */
} GenTermEmClassPart;

/* our full class declaration */

typedef struct _GenTermEmClassRec {
 CoreClassPart core_class;
 CompositeClassPart composite_class;
 GenTermClassPart genTerm_class;
 GenTermEmClassPart genTermEm_class;
} GenTermEmClassRec;

/* new field for our widget record */

typedef struct {
 /* resources */
 char *name;
 char *ParseFile;
 Dimension FuncKeyHeight;
 int FuncLabelWidth;
 int NumberFunctionKeys;
 Boolean ShowKey;
 int OutputDescriptor;
 Boolean Logging;
 int LogFileDescriptor;
 Boolean DestructiveTab;
 int NumMapTables;
 int NumStoreArgs;
 Boolean PreScroll;
 unsigned char ScrollChar;
 unsigned char ScrollAbortChar;
 XtCallbackList KbdCallbacks;
 XtCallbackList EscCallbacks;
 XtCallbackList WakeUpCallbacks;
 XtCallbackList FlowCallbacks;

/* private data parts */

 Widget Menu;
 struct FunctionKey *FKeys;
 Boolean FunctionRealized;
 XtInputId OutputId;
 struct ParseItem *ParseTable;
 struct ParseItem *CurrentPoint;
 struct KeyTranslations *Keys;
 struct GtEList *KeyList;
 struct GtEList *ParseList;
 struct StateTable *Mods;
 int NumKeys;
 char InputStack[1024];
 int TopStack;
 int TabStops[NTABS];
 char **MapTables;
 XComposeStatus ComposeStatus;
 struct SpecialVariables SpecialVars;
 struct InputArgument *InputArgs;
 struct InputArgument *StoreArgs;
 XEvent LastEvent;
 char *Storage;
 int NumInStorage;
 int StorageSize;
 Boolean InputBlocked;
 int CutBuffer;
 Boolean WidgetLocked;
 Boolean NeedWakeUp;
} GenTermEmPart;

/* our full instance record */

typedef struct _GenTermEmRec
{
 CorePart core;
 CompositePart composite;
 GenTermPart genTerm;
 GenTermEmPart genTermEm;
} GenTermEmRec;

#endif _ReadGenTermEmP
@EOF
set `wc -lwc <GenTerm/GenTermEmP.h`
if test $1$2$3 != 2285074033
then
	echo ERROR: wc results of GenTerm/GenTermEmP.h are $* should be 228 507 4033
fi

chmod 644 GenTerm/GenTermEmP.h

echo x - GenTerm/GenTermP.h
cat >GenTerm/GenTermP.h <<'@EOF'
/* GenTermP.h -- Private definitions for GenTerm widget */
/* History:                                 */
/*         Written by G. R. Strachan 1992 */

/*  Copyright Gordon R. Strachan 1992 */
/*  This code is provided as is, neither the University of Waterloo nor */
/*  the author is liable for any damage caused by the use or misuse of this */
/*  code.  */

/* Permission is granted to copy, use and modify this code provided it is */
/* not sold for profit and the above copyright remains intact. */

#ifndef _ReadGenTermP
#define _ReadGenTermP

#include <X11/X.h>
#include <X11/IntrinsicP.h>
#include <X11/Core.h>
#include <X11/CoreP.h>
#include <X11/Composite.h>
#include <X11/CompositeP.h>

#include "GenTerm.h"

#define NPEN 512

#define SETALTFONT     1
#define SETINVERSE     2
#define SETUNDERLINE   4
#define SETHALFBRIGHT  8
#define SETBLINK       16
#define HIGHLIGHT      32
#define BASEATTRIBUTES 63
#define NUMATTRIBUTES  6

struct Attribute
{
 int type;
 XFontStruct *Font;
};

struct GraphicsContexts
{
 GC draw_gc;
 GC cursor_gc;
 GC blink_gc;
};

struct PenColour
{
 char *ForegroundName;
 char *BackgroundName;
 Pixel Foreground;
 Pixel Background;
 Pixel HalfBright;
 int defined;
};

struct Field
{
 int Start;
 int End;
};

struct Line
{
 char *Characters;
 struct Attribute *Attributes;
 struct Field *Fields;
 int ScrollRegion;
 int NumChars;
 int NumFields;
};

/* Additions to widget class record */

typedef struct {
 int dummy;
} GenTermClassPart;

/* our full class declaration */

typedef struct _GenTermClassRec {
 CoreClassPart core_class;
 CompositeClassPart composite_class;
 GenTermClassPart genTerm_class;
} GenTermClassRec;

/* new field for our widget record */

typedef struct _GenTermPart{
 /* resources */
 Pixel NormalForeground;        /* the colors when no attributes set */
 Pixel NormalBackground;
 XtCallbackList kbdcallback;    /* callbacks for when text is entered */
 XtCallbackList topcallback;    /* callbacks for when top of screen changes */
 XtCallbackList resizecallback; /* callbacks for when widget size changes */
 XtCallbackList lockcallback;   /* callbacks for when widget locks itself */
 Dimension width;               /* our width width and height */
 Dimension height;
 Dimension BottomMargin;        /* used distance from bottom */
 int rows;                      /* number of rows and columns to show */
 int columns;
 int SaveLines;                 /* number of lines in the virtual screen */
 char *Font;                    /* the name of the base font */
 char *AlternateFont;           /* the name of the alternate font */
 int CharHeight;                /* the current character height */
 int CharWidth;                 /* the current character width */
 Boolean AutoWrap;              /* flag if text wraps at the end of the line */
 Boolean LiteralMode;           /* flag if to escape undisplayable text */
 Pixel CursorColour;            /* the colour of our cursor */
 Boolean CursorFloats;          /* flag is cursor floats when screen moved */
 Boolean ShowCursor;            /* flag if cursor should be displayed or not */
 Boolean FieldAttributes;       /* flag if text attributes are field oriented*/
 Boolean ScrollDownClear;       /* clear lines when they scroll into page? */
 Boolean FullScroll;            /* scroll through entire virtual screen? */
 Boolean InsertMode;            /* flag if in insert mode or not */
 Boolean SaveScrollRegion;      /* save scroll region lines in virtual screen*/
 Boolean EOLStick;              /* flag if cursor sticks at end of line */
 int NumberColours;             /* number of pen colours allowed */
 int BlinkRate;                 /* the blink rate for blinking text */
 char *PenColours;              /* the pen colours */
 int DefineColour;              /* colours are defined by RGB or HSL */
 Boolean ScrollOnOutput;        /* flag if to scroll to bottom on text output*/
 Boolean CursorKeyScrollRegion; /* cursor keys are sensitive to scrollregion?*/
 Boolean MarginBell;            /* flag if margin bell is activated */
 int Margin;                    /* the size of the margin. */
 Boolean Locked;                /* flag is screen currently locked */
 Boolean IgnoreNull;            /* flag if to ignore null characters */

/* private state info */
 
 XFontStruct *CurrentFont;
 XFontStruct *AltFont;
 Pixel CurrentForeground;    /* currently defined foreground and background */
 Pixel CurrentBackground;
 Pixel foreground;           /* colors in use by the graphics contexts */
 Pixel background;
 char MapTable[NMAP];        /* out key mapping tables */
 struct PenColour *Colours;  /* the pen colour structures */
 int CurrentRow;             /* the current cursor position (row and col) */
 int CurrentColumn;
 int ScreenTop;              /* Top of visible screen in save screen */
 int VScreenTop;             /* Maximimum extent of ScreenTop */
 int VirtualTop;             /* relative position of screen (0-SaveLines) */
 int MaxVirtualTop;          /* Maximum extent of VirtualTop */
 int CursorOffset;           /* distance cursor is from visible screen */
 Boolean CursorOn;           /* flag is cursor is turned on */
 struct Line **VScreen;      /* the virtual screen */
 struct Line **Screen;       /* the visible screen */
 struct GraphicsContexts **Pens;  /* the drawing pens */
 struct Attribute CurrentSettings;     /* our current attribute */
 struct Attribute DefaultSettings;     /* the default attribute */
 XtIntervalId BlinkTimeOut;            /* the blink time out structure */
 int BlinkOn;                /* flag if blinking text is on or off */
 Colormap ColourMap;         /* out colour map */
 int CurrentNumRows;         /* the current number of rows in Screen */
 int CurrentNumColumns;      /* the current number of columns in Screen */
 int CurrentSaveLines;       /* the current number of rows in virtual screen */
 Boolean CursorIsStuck;      /* flag if cursor stuck at end of line */
 int ExposureCount;          /* number of exposure counts pending */
 Boolean SelectionStarted;   /* flag if currently doing a selection */
 int SelectionStartRow;      /* position selection started in */
 int SelectionStartCol;
 int SelectionEndRow;        /* position selection ended in */
 int SelectionEndCol;
 char *CurrentSelection;     /* the currently selected portion of the screen */
 int CutBuffer;              /* the cut buffer we are using */
} GenTermPart;

/* our full instance record */

typedef struct _GenTermRec
{
 CorePart core;
 CompositePart composite;
 GenTermPart genTerm;
} GenTermRec;

#endif _ReadGenTermP

#include "GenTerm.h"
@EOF
set `wc -lwc <GenTerm/GenTermP.h`
if test $1$2$3 != 1829036618
then
	echo ERROR: wc results of GenTerm/GenTermP.h are $* should be 182 903 6618
fi

chmod 644 GenTerm/GenTermP.h

exit 0
From: bobm@hpfcso.FC.HP.COM (Bob Montgomery)
Date: Fri, 22 Jan 1993 22:46:54 GMT
Subject: Re: fortran preprocessor?
Organization: Hewlett-Packard, Fort Collins, CO, USA