v02i028: gnu chess for X, Part01/06

Mike Wexler mikew at wyse.wyse.com
Tue Dec 6 12:35:33 AEST 1988


Submitted-by: aperez at blazer.prime.com (Arturo Perez Ext.)
Posting-number: Volume 2, Issue 28
Archive-name: xchess/part01

[I had to uuencode message.c and record.c, so uudecode them before 
trying to compile this.]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 6)."
# Contents:  scrollText.c std.h
# Wrapped by mikew at wyse on Mon Dec  5 18:32:46 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'scrollText.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'scrollText.c'\"
else
echo shar: Extracting \"'scrollText.c'\" \(57716 characters\)
sed "s/^X//" >'scrollText.c' <<'END_OF_FILE'
X/*
X * A Scrollable Text Output Window
X *
X * David Harrison 
X * University of California,  Berkeley
X * 1986
X *
X * The following is an implementation for a scrollable text output
X * system.  It handles exposure events only (other interactions are
X * under user control).  For scrolling,  a always present scroll bar
X * is implemented.  It detects size changes and compensates accordingly.
X */
X
X#include <X11/X.h>
X#include <X11/Xlib.h>
X#include <X11/X10.h>
X#include <sys/types.h>
X#include "scrollText.h"
X
Xextern char *malloc();
Xextern char *realloc();
X#define alloc(type)		(type *) malloc(sizeof(type))
X#define numalloc(type, num)	(type *) malloc((unsigned) (num * sizeof(type)))
X#define MAXINT		2147483647
X
Xextern XAssocTable *XCreateAssocTable();
Xextern caddr_t XLookUpAssoc();
X
Xstatic XAssocTable *textWindows = (XAssocTable *) 0;
X
X#define NOOPTION	-1	/* Option hasn't been set yet                */
X#define NORMSCROLL	0	/* Smooth scroll on LineToTop and TopToHere  */
X#define JUMPSCROLL	1	/* Jump scrolling on LineToTop and TopToHere */
X
Xstatic int ScrollOption = NOOPTION;
X
Xtypedef char *Generic;
X
X#define DEFAULT_GC textInfo->fontGC[textInfo->curFont]
X
X#define BARSIZE		15
X#define BARBORDER	1
X#define MAXFONTS	8
X#define INITBUFSIZE	1024
X#define INITLINES	50
X#define INITEXPARY	50
X#define XPADDING	2
X#define YPADDING	2
X#define INTERLINE	5
X#define INTERSPACE	1
X#define CURSORWIDTH	2
X#define EXPANDPERCENT	40
X#define BUFSIZE		1024
X#define CUROFFSET	1
X#define MAXFOREIGN	250
X#define NOINDEX		-1
X
X/* The wrap line indicator */
X#define WRAPINDSIZE	7
X#define STEMOFFSET	5
X#define arrow_width 7
X#define arrow_height 5
Xstatic char arrow_bits[] = {
X   0x24, 0x26, 0x3f, 0x06, 0x04};
X
X#define NEWLINE		'\n'
X#define BACKSPACE	'\010'
X#define NEWFONT		'\006'
X#define LOWCHAR		'\040'
X#define HIGHCHAR	'\176'
X
X#define CHARMASK	0x00ff	/* Character mask */
X#define FONTMASK	0x0700	/* Character font */
X#define FONTSHIFT	8	/* Shift amount   */
X
X#define WRAPFLAG	0x01	/* Line wrap flag */
X
X/*
X * Lines are represented by a pointer into the overall array of
X * 16-bit characters.  The lower eight bits is used to indicate the character
X * (in ASCII),  and the next two bits are used to indicate the font
X * the character should be drawn in.
X */
X
Xtypedef struct txtLine {
X    int lineLength;		/* Current line length               */
X    int lineHeight;		/* Full height of line in pixels     */
X    int lineBaseLine;		/* Current baseline of the line      */
X    int lineWidth;		/* Drawing position at end of line   */
X    int lineText;		/* Offset into master buffer         */
X    int lineFlags;		/* Line wrap flag is here            */
X};
X
X
X/*
X * For ExposeCopy events,  we queue up the redraw requests collapsing
X * them into line redraw requests until the CopyExpose event arrives.
X * The queue is represented as a dynamic array of the following
X * structure:
X */
X
Xtypedef struct expEvent {
X    int lineIndex;		/* Index of line to redraw  */
X    int ypos;			/* Drawing position of line */
X};
X
X
X/*
X * The text buffer is represented using a dynamic counted array
X * of 16-bit quantities. This array expands as needed.
X * For the screen representation,  a dynamic counted array
X * of line structures is used.  This array points into the
X * text buffer to denote the start of each line and its parameters.
X * The windows are configured as one overall window which contains
X * the scroll bar as a sub-window along its right edge.  Thus,
X * the text drawing space is actually w-BARSIZE.
X */
X
X#define NOTATBOTTOM	0x01	/* Need to scroll to bottom before appending */
X#define FONTNUMWAIT	0x02	/* Waiting for font number                   */
X#define COPYEXPOSE	0x04	/* Need to process a copy expose event       */
X#define SCREENWRONG	0x08	/* TxtJamStr has invalidated screen contents */
X
Xtypedef struct txtWin {
X    /* Basic text buffer */
X    int bufAlloc;		/* Allocated size of buffer           */
X    int bufSpot;		/* Current writing position in buffer */
X    short *mainBuffer;		/* Main buffer of text                */
X
X    /* Line information */
X    int numLines;		/* Number of display lines in buffer */
X    int allocLines;		/* Number of lines allocated 	     */
X    struct txtLine **txtBuffer;	/* Dynamic array of lines    	     */
X
X    /* Current Window display information */
X    Window mainWindow;		/* Text display window       */
X    Window scrollBar;		/* Subwindow for scroll bar  */
X    Pixmap arrowMap;		/* line wrap indicator       */
X    int bgPix, fgPix;		/* Background and cursor     */
X    GC CursorGC;		/* gc for the cursor         */
X    GC bgGC;			/* gc for erasing things     */
X    GC fontGC[MAXFONTS];	/* gc for doing fonts        */
X    XFontStruct theFonts[MAXFONTS];/* Display fonts          */
X    int  theColors[MAXFONTS];	/* foregrounds of the fonts  */
X    int  curFont;		/* current font for tracking */
X    int w, h;			/* Current size              */
X    int startLine;		/* Top line in display       */
X    int endLine;		/* Bottom line in display    */
X    int bottomSpace;		/* Space at bottom of screen */
X    int flagWord;		/* If non-zero,  not at end  */
X
X    /* For handling ExposeCopy events */
X    int exposeSize;		/* Current size of array      */
X    int exposeAlloc;		/* Allocated size             */
X    struct expEvent **exposeAry;/* Array of line indices      */
X
X    /* Drawing position information */
X    int curLine;		/* Current line in buffer    */
X    int curX;			/* Current horizontal positi */
X    int curY;			/* Current vertical drawing  */
X};
X
X/* Flags for the various basic character handling functions */
X
X#define DODISP		0x01	/* Update the display  */
X#define NONEWLINE	0x02	/* Dont append newline */
X
X
X
Xstatic int InitLine(newLine)
Xstruct txtLine *newLine;	/* Newly created line structure */
X/*
X * This routine initializes a newly created line structure.
X */
X{
X    newLine->lineLength = 0;
X    newLine->lineHeight = 0;
X    newLine->lineBaseLine = 0;
X    newLine->lineWidth = XPADDING;
X    newLine->lineText = NOINDEX;
X    newLine->lineFlags = 0;
X    return 1;
X}
X
X
X
X
Xint TxtGrab(display, txtWin, program, mainFont, bg, fg, cur)
XDisplay *display;		/* display window is on  */
XWindow txtWin;			/* Window to take over as scrollable text    */
Xchar *program;			/* Program name for Xdefaults                */
XXFontStruct *mainFont;		/* Primary text font                         */
Xint bg, fg, cur;		/* Background, foreground, and cursor colors */
X/*
X * This routine takes control of 'txtWin' and makes it into a scrollable
X * text output window.  It will create a sub-window for the scroll bar
X * with a background of 'bg' and an bar with color 'fg'.  Both fixed width
X * and variable width fonts are supported.  Additional fonts can be loaded
X * using 'TxtAddFont'.  Returns 0 if there were problems,  non-zero if
X * everything went ok.
X */
X{
X    struct txtWin *newWin;	/* Text package specific information */
X    XWindowAttributes winInfo;	/* Window information                */
X    int index;
X    XGCValues gc_val;
X    
X    if (textWindows == (XAssocTable *) 0) {
X	textWindows = XCreateAssocTable(32);
X	if (textWindows == (XAssocTable *) 0) return(0);
X    }
X    if (XGetWindowAttributes(display, txtWin, &winInfo) == 0) return 0;
X
X    if (ScrollOption == NOOPTION) {
X	/* Read to see if the user wants jump scrolling or not */
X	if (XGetDefault(display, program, "JumpScroll")) {
X	    ScrollOption = JUMPSCROLL;
X	} else {
X	    ScrollOption = NORMSCROLL;
X	}
X    }
X
X    /* Initialize local structure */
X    newWin = alloc(struct txtWin);
X
X    /* Initialize arrow pixmap */
X    newWin->arrowMap = XCreatePixmapFromBitmapData(display, txtWin,
X						   arrow_bits,
X						   arrow_width, arrow_height,
X						   cur, bg,
X						   DisplayPlanes(display, 0));
X
X    newWin->bufAlloc = INITBUFSIZE;
X    newWin->bufSpot = 0;
X    newWin->mainBuffer = numalloc(short, INITBUFSIZE);
X
X    newWin->numLines = 1;
X    newWin->allocLines = INITLINES;
X    newWin->txtBuffer = numalloc(struct txtLine *, INITLINES);
X    for (index = 0;  index < INITLINES;  index++) {
X	newWin->txtBuffer[index] = alloc(struct txtLine);
X	InitLine(newWin->txtBuffer[index]);
X    }
X
X    /* Window display information */
X    newWin->mainWindow = txtWin;
X    newWin->w = winInfo.width;
X    newWin->h = winInfo.height;
X    newWin->startLine = 0;
X    newWin->endLine = 0;
X    newWin->bottomSpace = winInfo.height
X      - YPADDING - mainFont->ascent - mainFont->descent - INTERLINE;
X    newWin->flagWord = 0;
X    newWin->bgPix = bg;
X    newWin->fgPix = fg;
X
X    /* Scroll Bar Creation */
X    newWin->scrollBar = XCreateSimpleWindow(display, txtWin,
X				      winInfo.width - BARSIZE,
X				      0, BARSIZE - (2*BARBORDER),
X				      winInfo.height - (2*BARBORDER),
X				      BARBORDER, 
X				      fg, bg);
X    XSelectInput(display, newWin->scrollBar, ExposureMask|ButtonReleaseMask);
X    XMapRaised(display, newWin->scrollBar);
X
X    /* Font and Color Initialization */
X    newWin->theFonts[0] = *mainFont;
X    newWin->theColors[0] = fg;
X    gc_val.function = GXcopy;
X    gc_val.plane_mask = AllPlanes;
X    gc_val.foreground = fg;
X    gc_val.background = bg;
X    gc_val.graphics_exposures = 1;
X    gc_val.font = mainFont->fid;
X    gc_val.line_width = 1;
X    gc_val.line_style = LineSolid;
X
X    newWin->fontGC[0] = XCreateGC(display, txtWin,
X				  GCFunction | GCPlaneMask |
X				  GCForeground | GCBackground |
X				  GCGraphicsExposures | GCFont,
X				  &gc_val);
X
X    gc_val.foreground = cur;
X    newWin->CursorGC = XCreateGC(display, txtWin,
X				 GCFunction | GCPlaneMask |
X				  GCForeground | GCBackground |
X				  GCLineStyle | GCLineWidth,
X				  &gc_val);
X
X    gc_val.foreground = bg;
X    newWin->bgGC = XCreateGC(display, txtWin,
X				  GCFunction | GCPlaneMask |
X				  GCForeground | GCBackground |
X				  GCGraphicsExposures | GCFont,
X				  &gc_val);
X
X
X    for (index = 1;  index < MAXFONTS;  index++) {
X	newWin->theFonts[index].fid = 0;
X	newWin->fontGC[index] = 0;
X    }
X
X    
X    /* Initialize size of first line */
X    newWin->txtBuffer[0]->lineHeight = newWin->theFonts[0].ascent +
X	newWin->theFonts[0].descent;
X    newWin->txtBuffer[0]->lineText = 0;
X
X    /* ExposeCopy array initialization */
X    newWin->exposeSize = 0;
X    newWin->exposeAlloc = INITEXPARY;
X    newWin->exposeAry = numalloc(struct expEvent *, INITEXPARY);
X    for (index = 0;  index < newWin->exposeAlloc;  index++)
X      newWin->exposeAry[index] = alloc(struct expEvent);
X    /* Put plus infinity in last slot for sorting purposes */
X    newWin->exposeAry[0]->lineIndex = MAXINT;
X
X    /* Drawing Position Information */
X    newWin->curLine = 0;
X    newWin->curX = 0;
X    newWin->curY = YPADDING + mainFont->ascent + mainFont->descent;
X
X    /* Attach it to both windows */
X    XMakeAssoc(display, textWindows, (XID) txtWin, (caddr_t) newWin);
X    XMakeAssoc(display, textWindows, (XID) newWin->scrollBar, (caddr_t) newWin);
X    return 1;
X}
X
X
Xint TxtRelease(display, w)
XDisplay *display;
XWindow w;			/* Window to release */
X/*
X * This routine releases all resources associated with the
X * specified window which are consumed by the text
X * window package. This includes the entire text buffer,  line start
X * array,  and the scroll bar window.  However,  the window
X * itself is NOT destroyed.  The routine will return zero if
X * the window is not owned by the text window package.
X */
X{
X    struct txtWin *textInfo;
X    int index;
X
X    if ((textInfo = (struct txtWin *) XLookUpAssoc(display,
X						 textWindows, (XID) w)) == 0)
X      return 0;
X
X    for (index = 0; index < MAXFONTS; index++)
X	if (textInfo->fontGC[index] != 0)
X	    XFreeGC(display, textInfo->fontGC[index]);
X
X    free((Generic) textInfo->mainBuffer);
X    for (index = 0;  index < textInfo->numLines;  index++) {
X	free((Generic) textInfo->txtBuffer[index]);
X    }
X    free((Generic) textInfo->txtBuffer);
X    XDestroyWindow(display, textInfo->scrollBar);
X    for (index = 0;  index < textInfo->exposeSize;  index++) {
X	free((Generic) textInfo->exposeAry[index]);
X    }
X    free((Generic) textInfo->exposeAry);
X    XDeleteAssoc(display, textWindows, (XID) w);
X    free((Generic) textInfo);
X    return 1;
X}
X
X
X
Xstatic int RecompBuffer(textInfo)
Xstruct txtWin *textInfo;	/* Text window information */
X/*
X * This routine recomputes all line breaks in a buffer after
X * a change in window size or font.  This is done by throwing
X * away the old line start array and recomputing it.  Although
X * a lot of this work is also done elsewhere,  it has been included
X * inline here for efficiency.
X */
X{
X    int startPos, endSize, linenum;
X    register int index, chsize, curfont;
X    register short *bufptr;
X    register XFontStruct *fontptr;
X    register struct txtLine *lineptr;
X    char theChar;
X
X    /* Record the old position so we can come back to it */
X    for (startPos = textInfo->txtBuffer[textInfo->startLine]->lineText;
X	 (startPos > 0) && (textInfo->mainBuffer[startPos] != '\n');
X	 startPos--)
X      /* null loop body */;
X    
X    /* Clear out the old line start array */
X    for (index = 0;  index < textInfo->numLines;  index++) {
X	InitLine(textInfo->txtBuffer[index]);
X    }
X
X    /* Initialize first line */
X    textInfo->txtBuffer[0]->lineHeight =
X	textInfo->theFonts[0].ascent + textInfo->theFonts[0].descent;
X    textInfo->txtBuffer[0]->lineText = 0;
X
X    /* Process the text back into lines */
X    endSize = textInfo->w - BARSIZE - WRAPINDSIZE;
X    bufptr = textInfo->mainBuffer;
X    lineptr = textInfo->txtBuffer[0];
X    linenum = 0;
X    fontptr = &(textInfo->theFonts[0]);
X    curfont = 0;
X    for (index = 0;  index < textInfo->bufSpot;  index++) {
X	theChar = bufptr[index] & CHARMASK;
X	
X	if ((bufptr[index] & FONTMASK) != curfont) {
X	    int newFontNum, heightDiff;
X
X	    /* Switch fonts */
X	    newFontNum = (bufptr[index] & FONTMASK) >> FONTSHIFT;
X	    if (textInfo->theFonts[newFontNum].fid != 0) {
X		/* Valid font */
X		curfont = bufptr[index] & FONTMASK;
X		fontptr = &(textInfo->theFonts[newFontNum]);
X		heightDiff = (fontptr->ascent + fontptr->descent) -
X		    lineptr->lineHeight;
X		if (heightDiff < 0) heightDiff = 0;
X		lineptr->lineHeight += heightDiff;
X	    }
X	}
X	if (theChar == '\n') {
X	    /* Handle new line */
X	    if (linenum >= textInfo->allocLines-1)
X	      /* Expand number of lines */
X	      ExpandLines(textInfo);
X	    linenum++;
X	    lineptr = textInfo->txtBuffer[linenum];
X	    /* Initialize next line */
X	    lineptr->lineHeight = fontptr->ascent + fontptr->descent;
X	    lineptr->lineText = index+1;
X	    /* Check to see if its the starting line */
X	    if (index == startPos) textInfo->startLine = linenum;
X	} else {
X	    /* Handle normal character */
X	    chsize = CharSize(textInfo, linenum, index);
X	    if (lineptr->lineWidth + chsize > endSize) {
X		/* Handle line wrap */
X		lineptr->lineFlags |= WRAPFLAG;
X		if (linenum >= textInfo->allocLines-1)
X		  /* Expand number of lines */
X		  ExpandLines(textInfo);
X		linenum++;
X		lineptr = textInfo->txtBuffer[linenum];
X		/* Initialize next line */
X		lineptr->lineHeight = fontptr->ascent + fontptr->descent;
X		lineptr->lineText = index;
X		lineptr->lineLength = 1;
X		lineptr->lineWidth += chsize;
X	    } else {
X		/* Handle normal addition of character */
X		lineptr->lineLength += 1;
X		lineptr->lineWidth += chsize;
X	    }
X	}
X    }
X    /* We now have a valid line array.  Let's clean up some other fields. */
X    textInfo->numLines = linenum+1;
X    if (startPos == 0) {
X	textInfo->startLine = 0;
X    }
X    textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
X    textInfo->curLine = linenum;
X    /* Check to see if we are at the bottom */
X    if (textInfo->endLine >= textInfo->numLines-1) {
X	textInfo->curY = textInfo->h - textInfo->bottomSpace -
X	  lineptr->lineHeight;
X	textInfo->flagWord &= (~NOTATBOTTOM);
X    } else {
X	textInfo->flagWord |= NOTATBOTTOM;
X    }
X    return 1;
X}
X
X
X
X
Xint TxtAddFont(display, textWin, fontNumber, newFont, newColor)
XDisplay *display;
XWindow textWin;			/* Scrollable text window  */
Xint fontNumber;			/* Place to add font (0-7) */
XXFontStruct *newFont;		/* Font to add             */
Xint newColor;			/* Color of font           */
X/*
X * This routine loads a new font so that it can be used in a previously
X * created text window.  There are eight font slots numbered 0 through 7.
X * If there is already a font in the specified slot,  it will be replaced
X * and an automatic redraw of the window will take place.  See TxtWriteStr
X * for details on using alternate fonts.  The color specifies the foreground
X * color of the text.  The default foreground color is used if this
X * parameter is TXT_NO_COLOR.  Returns a non-zero value if
X * everything went well.
X */
X{
X    struct txtWin *textInfo;
X    int redrawFlag;
X    XGCValues gc_val;
X    
X    if ((fontNumber < 0) || (fontNumber >= MAXFONTS)) return 0;
X    if ((textInfo = (struct txtWin *)
X	 XLookUpAssoc(display, textWindows, (XID) textWin)) == 0)
X      return 0;
X    if (newColor == TXT_NO_COLOR) {
X	newColor = textInfo->fgPix;
X    }
X
X    gc_val.font = newFont->fid;
X    gc_val.foreground = newColor;
X    gc_val.background = textInfo->bgPix;
X    gc_val.plane_mask = AllPlanes;
X    gc_val.graphics_exposures = 1;
X    gc_val.function = GXcopy;
X    
X    if (textInfo->fontGC[fontNumber] != 0)
X    {
X	XChangeGC(display, textInfo->fontGC[fontNumber],
X		  GCFont | GCForeground, &gc_val);
X    }
X    else
X	textInfo->fontGC[fontNumber] = XCreateGC(display, textWin,
X						 GCFont |
X						 GCForeground |
X						 GCBackground |
X						 GCFunction |
X						 GCPlaneMask |
X						 GCGraphicsExposures,
X						 &gc_val); 
X
X
X    redrawFlag = (textInfo->theFonts[fontNumber].fid != 0) &&
X      (((newFont) && (newFont->fid != textInfo->theFonts[fontNumber].fid)) ||
X       (newColor != textInfo->theColors[fontNumber]));
X    if (newFont) {
X	textInfo->theFonts[fontNumber] = *newFont;
X    }
X    textInfo->theColors[fontNumber] = newColor;
X
X    if (redrawFlag) {
X	RecompBuffer(textInfo);
X	XClearWindow(display, textWin);
X	TxtRepaint(display, textWin);
X    }
X    return 1;
X}
X
X
X
Xint TxtWinP(display, w)
XDisplay *display;
XWindow w;
X/*
X * Returns a non-zero value if the window has been previously grabbed
X * using TxtGrab and 0 if it has not.
X */
X{
X    if (XLookUpAssoc(display, textWindows, (XID) w))
X      return(1);
X    else return(0);
X}
X
X
X
Xstatic int FindEndLine(textInfo, botSpace)
Xstruct txtWin *textInfo;
Xint *botSpace;
X/*
X * Given the starting line in 'textInfo->startLine',  this routine
X * determines the index of the last line that can be drawn given the
X * current size of the screen.  If there are not enough lines to
X * fill the screen,  the index of the last line will be returned.
X * The amount of empty bottom space is returned in 'botSpace'.
X */
X{
X    int index, height, lineHeight;
X
X    height = YPADDING;
X    index = textInfo->startLine;
X    while (index < textInfo->numLines) {
X	lineHeight = textInfo->txtBuffer[index]->lineHeight + INTERLINE;
X	if (height + lineHeight > textInfo->h) break;
X	height += lineHeight;
X	index++;
X    }
X    if (botSpace) {
X	*botSpace = textInfo->h - height;
X    }
X    return index - 1;
X}
X
X
X
Xstatic int UpdateScroll(display, textInfo)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text window information */
X/*
X * This routine computes the current extent of the scroll bar
X * indicator and repaints the bar with the correct information.
X */
X{
X    int top, bottom;
X
X    if (textInfo->numLines > 1) {
X	top = textInfo->startLine * (textInfo->h - 2*BARBORDER) /
X	  (textInfo->numLines - 1);
X	bottom = textInfo->endLine * (textInfo->h - 2*BARBORDER) /
X	  (textInfo->numLines - 1);
X    } else {
X	top = 0;
X	bottom = textInfo->h - (2*BARBORDER);
X    }
X
X    /* Draw it - make sure there is a little padding */
X    if (top == 0) top++;
X    if (bottom == textInfo->h-(2*BARBORDER)) bottom--;
X
X    XFillRectangle(display, textInfo->scrollBar,
X		   textInfo->bgGC, 
X		   0, 0, BARSIZE, top-1);
X    XFillRectangle(display, textInfo->scrollBar,
X		   DEFAULT_GC, top, BARSIZE - (2*BARBORDER) - 2,
X		   bottom - top);
X    XFillRectangle(display, textInfo->scrollBar, DEFAULT_GC,
X		   0, bottom+1, BARSIZE,
X		   textInfo->h - (2 * BARBORDER) - bottom);
X
X    return 1;
X}
X
X
X
Xint TxtClear(display, w)
XDisplay *display;
XWindow w;
X/*
X * This routine clears a scrollable text window.  It resets the current
X * writing position to the upper left hand corner of the screen. 
X * NOTE:  THIS ALSO CLEARS THE CONTENTS OF THE TEXT WINDOW BUFFER AND
X * RESETS THE SCROLL BAR.  Returns 0 if the window is not a text window.
X * This should be used *instead* of XClear.
X */
X{
X    struct txtWin *textInfo;
X    int index;
X
X    if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)) == 0)
X      return 0;
X
X    /* Zero out the arrays */
X    textInfo->bufSpot = 0;
X    for (index = 0;  index < textInfo->numLines;  index++) {
X	InitLine(textInfo->txtBuffer[index]);
X    }
X    textInfo->txtBuffer[0]->lineHeight =
X      textInfo->theFonts[textInfo->curFont].ascent +
X	  textInfo->theFonts[textInfo->curFont].descent;
X
X    textInfo->numLines = 1;
X    textInfo->startLine = 0;
X    textInfo->endLine = 0;
X    textInfo->curLine = 0;
X    textInfo->curX = 0;
X    textInfo->curY = YPADDING + textInfo->theFonts[textInfo->curFont].ascent 
X	+ textInfo->theFonts[textInfo->curFont].descent;
X
X    textInfo->bottomSpace = textInfo->h - YPADDING -
X      textInfo->theFonts[textInfo->curFont].ascent - INTERLINE -
X	  textInfo->theFonts[textInfo->curFont].descent;
X    /* Actually clear the window */
X    XClearWindow(display, w);
X
X    /* Draw the current cursor */
X    XFillRectangle(display, w, textInfo->CursorGC,
X		   XPADDING + CUROFFSET, textInfo->curY,
X		   CURSORWIDTH,
X		   textInfo->theFonts[textInfo->curFont].ascent +
X		   textInfo->theFonts[textInfo->curFont].descent);
X
X    /* Update the scroll bar */
X    UpdateScroll(display, textInfo);
X    return 1;
X}
X
X
Xstatic int WarpToBottom(display, textInfo)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text Information */
X/*
X * This routine causes the specified text window to display its
X * last screen of information.   It updates the scroll bar
X * to the appropriate spot.  The implementation scans backward
X * through the buffer to find an appropriate starting spot for
X * the window.
X */
X{
X    int index, height, lineHeight;
X
X    index = textInfo->numLines-1;
X    height = 0;
X    while (index >= 0) {
X	lineHeight = textInfo->txtBuffer[index]->lineHeight + INTERLINE;
X	if (height + lineHeight > textInfo->h) break;
X	height += lineHeight;
X	index--;
X    }
X    textInfo->startLine = index + 1;
X    textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
X    textInfo->curY = textInfo->h - textInfo->bottomSpace -
X      textInfo->txtBuffer[textInfo->endLine]->lineHeight;
X    XClearWindow(display, textInfo->mainWindow);
X    TxtRepaint(display, textInfo->mainWindow);
X    return 1;
X}
X
X
X
Xstatic int UpdateExposures(display, textInfo)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text window information */
X/*
X * Before a new scrolling action occurs,  the text window package
X * must handle all COPYEXPOSE events generated by the last scrolling
X * action.  This routine is called to do this.  Foreign events (those
X * not handled by TxtFilter) are queued up and replaced on the queue
X * after the processing of the exposure events is complete.
X */
X{
X#if 0
X    XEvent foreignQueue[MAXFOREIGN];
X    int index, lastItem = 0;
X
X    while (textInfo->flagWord & COPYEXPOSE) {
X	XNextEvent(display, &(foreignQueue[lastItem]));
X	if (!TxtFilter(display, &(foreignQueue[lastItem])))
X	  lastItem++;
X	if (lastItem >= MAXFOREIGN) {
X	    printf("Too many foreign events to queue!\n");
X	    textInfo->flagWord &= (~COPYEXPOSE);
X	}
X    }
X    for (index = 0;  index < lastItem;  index++) {
X	XPutBackEvent(display, &(foreignQueue[index]));
X    }
X#endif
X    return 1;
X}
X
X
Xstatic int ScrollDown(display,textInfo)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text window information */
X/*
X * This routine scrolls the indicated text window down by one
X * line.  The line below the current line must exist.  The window
X * is scrolled so that the line below the last line is fully
X * displayed.  This may cause many lines to scroll off the top.
X * Scrolling is done using XCopyArea.  The exposure events should
X * be caught using ExposeCopy.
X */
X{
X    int lineSum, index, targetSpace, freeSpace, updateFlag;
X
X    lineSum = 0;
X    if (textInfo->endLine + 1 >= textInfo->numLines) return 0;
X    targetSpace = textInfo->txtBuffer[textInfo->endLine+1]->lineHeight +
X      INTERLINE;
X    if (textInfo->bottomSpace < targetSpace) {
X	index = textInfo->startLine;
X	while (index < textInfo->endLine) {
X	    lineSum += (textInfo->txtBuffer[index]->lineHeight + INTERLINE);
X	    if (textInfo->bottomSpace + lineSum >= targetSpace) break;
X	    index++;
X	}
X
X	/* Must move upward by 'lineSum' pixels */
X	XCopyArea(display, textInfo->mainWindow, textInfo->mainWindow,
X		  DEFAULT_GC, 0, lineSum,
X		  textInfo->w - BARSIZE, textInfo->h,
X		  0, 0);
X
X	textInfo->flagWord |= COPYEXPOSE;
X	/* Repair the damage to the structures */
X	textInfo->startLine = index + 1;
X	updateFlag = 1;
X    } else {
X	updateFlag = 0;
X    }
X    /* More lines might be able to fit.  Let's check. */
X    freeSpace = textInfo->bottomSpace + lineSum - targetSpace;
X    index = textInfo->endLine + 1;
X    while (index < textInfo->numLines-1) {
X	if (freeSpace - textInfo->txtBuffer[index+1]->lineHeight - INTERLINE < 0)
X	  break;
X	freeSpace -= (textInfo->txtBuffer[index+1]->lineHeight + INTERLINE);
X	index++;
X    }
X    textInfo->endLine = index;
X    textInfo->bottomSpace = freeSpace;
X    if (updateFlag) {
X	UpdateExposures(display, textInfo);
X    }
X    UpdateScroll(display, textInfo);
X    return 1;
X}
X
X
X
X
Xstatic int ExpandLines(textInfo)
Xstruct txtWin *textInfo;	/* Text Information */
X/*
X * This routine allocates and initializes additional space in
X * the line start array (txtBuffer).  The new space
X * is allocated using realloc.  The expansion factor is a percentage
X * given by EXPANDPERCENT.
X */
X{
X    int newSize, index;
X
X    newSize = textInfo->allocLines;
X    newSize += (newSize * EXPANDPERCENT) / 100;
X
X    textInfo->txtBuffer = (struct txtLine **)
X      realloc((char *) textInfo->txtBuffer,
X	      (unsigned) (newSize * sizeof(struct txtLine *)));
X    for (index = textInfo->allocLines;  index < newSize;  index++) {
X	textInfo->txtBuffer[index] = alloc(struct txtLine);
X	InitLine(textInfo->txtBuffer[index]);
X    }
X    textInfo->allocLines = newSize;
X    return 1;
X}
X
Xstatic int ExpandBuffer(textInfo)
Xstruct txtWin *textInfo;	/* Text information */
X/*
X * Expands the basic character buffer using realloc.  The expansion
X * factor is a percentage given by EXPANDPERCENT.
X */
X{
X    int newSize;
X
X    newSize = textInfo->bufAlloc + (textInfo->bufAlloc * EXPANDPERCENT) / 100;
X    textInfo->mainBuffer = (short *)
X      realloc((char *) textInfo->mainBuffer, (unsigned) newSize * sizeof(short));
X    textInfo->bufAlloc = newSize;
X    return 1;
X}
X
X
X
Xstatic int HandleNewLine(display, textInfo, flagWord)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text Information            */
Xint flagWord;			/* DODISP or NONEWLINE or both */
X/*
X * This routine initializes the next line for drawing by setting
X * its height to the current font height,  scrolls the screen down
X * one line,  and updates the current drawing position to the
X * left edge of the newly cleared line.  If DODISP is specified,
X * the screen will be updated (otherwise not).  If NONEWLINE is
X * specified,  no newline character will be added to the text buffer
X * (this is for line wrap).
X */
X{
X    struct txtLine *curLine, *nextLine;
X
X    /* Check to see if a new line must be allocated */
X    if (textInfo->curLine >= textInfo->allocLines-1)
X      /* Expand the number of lines */
X      ExpandLines(textInfo);
X    textInfo->numLines += 1;
X
X    /* Then we initialize the next line */
X    nextLine = textInfo->txtBuffer[textInfo->numLines-1];
X    nextLine->lineHeight =
X	textInfo->theFonts[textInfo->curFont].ascent +
X	    textInfo->theFonts[textInfo->curFont].descent;
X
X    curLine = textInfo->txtBuffer[textInfo->curLine];
X    if (flagWord & DODISP) {
X	/* Scroll down a line if required */
X	if ((textInfo->curY + curLine->lineHeight +
X	     nextLine->lineHeight + (INTERLINE * 2)) > textInfo->h)
X	  {
X	      ScrollDown(display, textInfo);
X	  }
X	else
X	  {
X	      /* Update the bottom space appropriately */
X	      textInfo->bottomSpace -= (nextLine->lineHeight + INTERLINE);
X	      textInfo->endLine += 1;
X	  }
X	/* Update drawing position */
X	textInfo->curY = textInfo->h -
X	  (textInfo->bottomSpace  + nextLine->lineHeight);
X    }
X
X    /* Move down a line */
X    textInfo->curLine += 1;
X    if (!(flagWord & NONEWLINE)) {
X	/* Append end-of-line to text buffer */
X	if (textInfo->bufSpot >= textInfo->bufAlloc) {
X	    /* Allocate more space in main text buffer */
X	    ExpandBuffer(textInfo);
X	}
X	textInfo->mainBuffer[(textInfo->bufSpot)++] =
X	  (textInfo->curFont << FONTSHIFT) | '\n';
X    }
X    nextLine->lineText = textInfo->bufSpot;
X    textInfo->curX = 0;
X    return 1;
X}
X
X
X
Xstatic int CharSize(textInfo, lineNum, charNum)
Xstruct txtWin *textInfo;	/* Current Text Information */
Xint lineNum;			/* Line in buffer           */
Xint charNum;			/* Character in line        */
X/*
X * This routine determines the size of the specified character.
X * It takes in account the font of the character and whether its
X * fixed or variable.  The size includes INTERSPACE spacing between
X * the characters.
X */
X{
X    register XFontStruct *charFont;
X    register short *theLine;
X    register short theChar;
X
X    theLine = &(textInfo->mainBuffer[textInfo->txtBuffer[lineNum]->lineText]);
X    theChar = theLine[charNum] & CHARMASK;
X    charFont = &(textInfo->theFonts[(theChar & FONTMASK) >> FONTSHIFT]);
X    if (theChar <= charFont->min_char_or_byte2 ||
X	theChar >= charFont->max_char_or_byte2 ||
X	charFont->per_char == 0)
X	return  charFont->max_bounds.width + 1;
X    else
X	return charFont->per_char[theChar].width + 1;
X}
X
X
X
X
X
Xstatic int HandleBackspace(display, textInfo, flagWord)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text Information  */
Xint flagWord;			/* DODISP or nothing */
X/*
X * This routine handles a backspace found in the input stream.  The
X * character before the current writing position will be erased and
X * the drawing position will move back one character.  If the writing
X * position is at the left margin,  the drawing position will move
X * up to the previous line.  If it is a line that has been wrapped,
X * the character at the end of the previous line will be erased.
X */
X{
X    struct txtLine *thisLine, *prevLine;
X    int chSize;
X
X    thisLine = textInfo->txtBuffer[textInfo->curLine];
X    /* First,  determine whether we need to go back a line */
X    if (thisLine->lineLength == 0) {
X	/* Bleep if at top of buffer */
X	if (textInfo->curLine == 0) {
X	    XBell(display, 50);
X	    return 0;
X	}
X
X	/* See if we have to scroll in the other direction */
X	if ((flagWord & DODISP) && (textInfo->curY <= YPADDING)) {
X	    /* This will display the last lines of the buffer */
X	    WarpToBottom(display, textInfo);
X	}
X
X	/* Set drawing position at end of previous line */
X	textInfo->curLine -= 1;
X	prevLine = textInfo->txtBuffer[textInfo->curLine];
X	textInfo->numLines -= 1;
X	if (flagWord & DODISP) {
X	    textInfo->curY -= (prevLine->lineHeight + INTERLINE);
X	    textInfo->bottomSpace += (thisLine->lineHeight + INTERLINE);
X	    textInfo->endLine -= 1;
X	}
X
X	/* We are unlinewrapping if the previous line has flag set */
X	if (prevLine->lineFlags & WRAPFLAG) {
X	    /* Get rid of line wrap indicator */
X	    if (flagWord & DODISP) {
X		XFillRectangle(display, textInfo->mainWindow,
X			       textInfo->bgGC,
X			       textInfo->w - BARSIZE - WRAPINDSIZE,
X			       textInfo->curY,  WRAPINDSIZE,
X			       prevLine->lineHeight);
X	    }
X	    prevLine->lineFlags &= (~WRAPFLAG);
X	    /* Call recursively to wipe out the ending character */
X	    HandleBackspace(display, textInfo, flagWord);
X	} else {
X	    /* Delete the end-of-line in the primary buffer */
X	    textInfo->bufSpot -= 1;
X	}
X    } else {
X	/* Normal deletion of character */
X	chSize =
X	  CharSize(textInfo, textInfo->curLine,
X		   textInfo->txtBuffer[textInfo->curLine]->lineLength - 1);
X	/* Move back appropriate amount and wipe it out */
X	thisLine->lineWidth -= chSize;
X	if (flagWord & DODISP) {
X	    XFillRectangle(display, textInfo->mainWindow,
X			   textInfo->bgGC,
X			   thisLine->lineWidth, textInfo->curY,
X			   chSize, thisLine->lineHeight);
X	}
X	/* Delete from buffer */
X	textInfo->txtBuffer[textInfo->curLine]->lineLength -= 1;
X	textInfo->bufSpot -= 1;
X    }
X    return 1;
X}
X
X
X
Xstatic int DrawLineWrap(display, win, x, y, h, col)
XDisplay *display;
XWindow win;			/* What window to draw it in     */
Xint x, y;			/* Position of upper left corner */
Xint h;				/* Height of indicator           */
Xint col;			/* Color of indicator            */
X/*
X * This routine draws a line wrap indicator at the end of a line.
X * Visually,  it is an arrow of the specified height directly against
X * the scroll bar border.  The bitmap used for the arrow is stored
X * in 'arrowMap' with size 'arrow_width' and 'arrow_height'.
X */
X{
X    struct txtWin *textInfo;
X
X    textInfo = (struct txtWin *)XLookUpAssoc(display, textWindows,
X					     (XID) win);
X
X    /* First,  draw the arrow */
X    XCopyArea(display, textInfo->arrowMap, textInfo->mainWindow,
X	       textInfo->CursorGC,
X	       0, 0, arrow_width, arrow_height,
X	       x, y + h - arrow_height, 1);
X
X    /* Then draw the stem */
X    XDrawLine(display, textInfo->mainWindow, textInfo->CursorGC,
X	      x + STEMOFFSET, y,
X	      x + STEMOFFSET, y + h - arrow_height);
X    return 1;
X}
X
X
X
X
Xstatic int DrawLine(display, textInfo, lineIndex, ypos)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text window information   */
Xint lineIndex;			/* Index of line to draw     */
Xint ypos;			/* Y position for line       */
X/*
X * This routine destructively draws the indicated line in the
X * indicated window at the indicated position.  It does not
X * clear to end of line however.  It draws a line wrap indicator
X * if needed but does not draw a cursor.
X */
X{
X    int index, startPos, curFont, theColor, curX, saveX, fontIndex;
X    struct txtLine *someLine;
X    char lineBuffer[BUFSIZE], *glyph;
X    short *linePointer;
X    XFontStruct *theFont;
X    XGCValues gc;
X
X    /* First,  we draw the text */
X    index = 0;
X    curX = XPADDING;
X    someLine = textInfo->txtBuffer[lineIndex];
X    linePointer = &(textInfo->mainBuffer[someLine->lineText]);
X    while (index < someLine->lineLength) {
X	startPos = index;
X	saveX = curX;
X	curFont = linePointer[index] & FONTMASK;
X	fontIndex = curFont >> FONTSHIFT;
X	theFont = &(textInfo->theFonts[fontIndex]);
X	theColor = textInfo->theColors[fontIndex];
X	glyph = &(lineBuffer[0]);
X	while ((index < someLine->lineLength) &&
X	       ((linePointer[index] & FONTMASK) == curFont))
X	{
X	    *glyph = linePointer[index] & CHARMASK;
X	    index++;
X	    curX += CharSize(textInfo, lineIndex, index);
X	    glyph++;
X	}
X	
X	/* Flush out the glyphs */
X	XFillRectangle(display, textInfo->mainWindow,
X		       textInfo->bgGC,
X		       saveX, ypos,
X		   textInfo->w - BARSIZE,
X		   someLine->lineHeight + YPADDING + INTERLINE);
X
X	XDrawString(display, textInfo->mainWindow,
X		    textInfo->fontGC[fontIndex],
X		    saveX, ypos,
X		    lineBuffer, someLine->lineLength);
X    }
X    /* Then the line wrap indicator (if needed) */
X    if (someLine->lineFlags & WRAPFLAG) {
X	DrawLineWrap(display, textInfo->mainWindow,
X		     textInfo->w - BARSIZE - WRAPINDSIZE,
X		     ypos, someLine->lineHeight,
X		     textInfo->fgPix);
X    }
X    return 1;
X}
X
X
X
X
Xstatic int HandleNewFont(display, fontNum, textInfo, flagWord)
XDisplay *display;
Xint fontNum;			/* Font number       */
Xstruct txtWin *textInfo;	/* Text information  */
Xint flagWord;			/* DODISP or nothing */
X/*
X * This routine handles a new font request.  These requests take
X * the form "^F<digit>".  The parsing is done in TxtWriteStr.
X * This routine is called only if the form is valid.  It may return
X * a failure (0 status) if the requested font is not loaded.
X * If the new font is larger than any of the current
X * fonts on the line,  it will change the line height and redisplay
X * the line.
X */
X{
X    struct txtLine *thisLine;
X    int heightDiff, baseDiff, redrawFlag;
X
X    if (textInfo->theFonts[fontNum].fid == 0) {
X	return 0;
X    } else {
X	thisLine = textInfo->txtBuffer[textInfo->curLine];
X	textInfo->curFont = fontNum;
X	redrawFlag = 0;
X	heightDiff = textInfo->theFonts[fontNum].ascent +
X	    textInfo->theFonts[fontNum].descent -
X		thisLine->lineHeight;
X
X	if (heightDiff > 0) {
X	    redrawFlag = 1;
X	} else {
X	    heightDiff = 0;
X	}
X
X	if (redrawFlag) {
X	    if (flagWord & DODISP) {
X		/* Clear current line */
X		XFillRectangle(display, textInfo->mainWindow,
X			       textInfo->bgGC,
X			       0, textInfo->curY, textInfo->w,
X			       thisLine->lineHeight);
X
X		/* Check to see if it requires scrolling */
X		if ((textInfo->curY + thisLine->lineHeight + heightDiff +
X		     INTERLINE) > textInfo->h)
X		  {
X		      /* 
X		       * General approach:  "unscroll" the last line up
X		       * and then call ScrollDown to do the right thing.
X		       */
X		      textInfo->endLine -= 1;
X		      textInfo->bottomSpace += thisLine->lineHeight +
X			  INTERLINE;
X
X		      XFillRectangle(display, textInfo->mainWindow,
X				     textInfo->bgGC,
X				     0, textInfo->h - textInfo->bottomSpace,
X				     textInfo->w, textInfo->bottomSpace);
X
X		      thisLine->lineHeight += heightDiff;
X		      ScrollDown(display, textInfo);
X		      textInfo->curY = textInfo->h -
X			(textInfo->bottomSpace + INTERLINE +
X			 thisLine->lineHeight);
X		  }
X		else 
X		  {
X		      /* Just update bottom space */
X		      textInfo->bottomSpace -= heightDiff;
X		      thisLine->lineHeight += heightDiff;
X		  }
X		/* Redraw the current line */
X		DrawLine(display, textInfo, textInfo->curLine, textInfo->curY);
X	    } else {
X		/* Just update line height */
X		thisLine->lineHeight += heightDiff;
X	    }
X	}
X	return 1;
X    }
X}
X
X
X
Xint TxtWriteStr(display, w, str)
XDisplay *display;
XWindow w;			/* Text window            */
Xregister char *str;		/* 0 terminated string */
X/*
X * This routine writes a string to the specified text window.
X * The following notes apply:
X *   - Text is always appended to the end of the text buffer.
X *   - If the scroll bar is positioned such that the end of the
X *     text is not visible,  an automatic scroll to the bottom
X *     will be done before the appending of text.
X *   - Non-printable ASCII characters are not displayed.
X *   - The '\n' character causes the current text position to
X *     advance one line and start at the left.
X *   - Tabs are not supported.
X *   - Lines too long for the screen will be wrapped and a line wrap
X *     indication will be drawn.
X *   - Backspace clears the previous character.  It will do the right
X *     thing if asked to backspace past a wrapped line.
X *   - A new font can be chosen using the sequence '^F<digit>' where
X *     <digit> is 0-7.  The directive will be ignored if
X *     there is no font in the specified slot.
X * Returns 0 if something went wrong.  
X */
X{
X    register int fontIndex;
X    register struct txtWin *textInfo;
X    register struct txtLine *thisLine;
X
X    if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)) == 0)
X      return 0;
X    
X    /* See if screen needs to be updated */
X    if (textInfo->flagWord & SCREENWRONG) {
X	TxtRepaint(display, textInfo->mainWindow);
X    }
X
X    /* See if we have to scroll down to the bottom */
X    if (textInfo->flagWord & NOTATBOTTOM) {
X	WarpToBottom(display, textInfo);
X	textInfo->flagWord &= (~NOTATBOTTOM);
X    }
X
X    /* Undraw the current cursor */
X    thisLine = textInfo->txtBuffer[textInfo->curLine];
X
X    XFillRectangle(display, w, textInfo->bgGC,
X	    thisLine->lineWidth + CUROFFSET,
X	    textInfo->curY,
X	    CURSORWIDTH,
X	    thisLine->lineHeight);
X
X    for ( /* str is ok */ ; (*str != 0) ; str++) {
X	/* Check to see if we are waiting on a font */
X	if (textInfo->flagWord & FONTNUMWAIT) {
X	    textInfo->flagWord &= (~FONTNUMWAIT);
X	    fontIndex = *str - '0';
X	    if ((fontIndex >= 0) && (fontIndex < MAXFONTS)) {
X		/* Handle font -- go get next character */
X		if (HandleNewFont(display, fontIndex, textInfo, DODISP))
X		    continue;
X	    }
X	}
X	
X	/* Inline code for handling normal character case */
X	if ((*str >= LOWCHAR) && (*str <= HIGHCHAR)) {
X	    register XFontStruct *thisFont;
X	    register struct txtLine *thisLine;
X	    register int charWidth;
X	    int thisColor;
X
X	    /* Determine size of character */
X	    thisFont = &(textInfo->theFonts[textInfo->curFont]);
X	    thisColor = textInfo->theColors[textInfo->curFont];
X	    if (*str <= thisFont->min_char_or_byte2 ||
X		*str >= thisFont->max_char_or_byte2 ||
X		thisFont->per_char == 0)
X		charWidth = thisFont->max_bounds.width + 1;
X	    else
X		charWidth = thisFont->per_char[*str].width + 1;
X
X	    /* Check to see if line wrap is required */
X	    thisLine = textInfo->txtBuffer[textInfo->curLine];
X	    if (thisLine->lineWidth + charWidth >
X		(textInfo->w-BARSIZE-WRAPINDSIZE))
X	      {
X		  DrawLineWrap(display, textInfo->mainWindow,
X			       textInfo->w-BARSIZE-WRAPINDSIZE,
X			       textInfo->curY, thisLine->lineHeight,
X			       textInfo->fgPix);
X		  thisLine->lineFlags |= WRAPFLAG;
X		  /* Handle the spacing problem the same way as a newline */
X		  HandleNewLine(display, textInfo, DODISP | NONEWLINE);
X		  thisLine = textInfo->txtBuffer[textInfo->curLine];
X	      }
X	    
X	    /* Ready to draw character */
X	    XDrawString(display, textInfo->mainWindow,
X			DEFAULT_GC, 
X			textInfo->curX += charWidth,
X			textInfo->curY + thisLine->lineHeight, 
X			str, 1);
X	    
X	    /* Append character onto main buffer */
X	    if (textInfo->bufSpot >= textInfo->bufAlloc)
X	      /* Make room for more characters */
X	      ExpandBuffer(textInfo);
X	    textInfo->mainBuffer[(textInfo->bufSpot)++] =
X	      (textInfo->curFont << FONTSHIFT) | (*str);
X	    
X	    /* Update the line start array */
X	    thisLine->lineLength += 1;
X	    thisLine->lineWidth += charWidth;
X	} else if (*str == NEWLINE) {
X	    HandleNewLine(display, textInfo, DODISP);
X	} else if (*str == NEWFONT) {
X	    /* Go into waiting for font number mode */
X	    textInfo->flagWord |= FONTNUMWAIT;
X	} else if (*str == BACKSPACE) {
X	    HandleBackspace(display, textInfo, DODISP);
X	} else {
X	    /* Ignore all others */
X	}
X    }
X    /* Draw the cursor in its new position */
X    thisLine = textInfo->txtBuffer[textInfo->curLine];
X
X    XFillRectangle(display, w, textInfo->CursorGC,
X	    thisLine->lineWidth + CUROFFSET,
X	    textInfo->curY /* + thisLine->lineHeight */,
X	    CURSORWIDTH, thisLine->lineHeight);
X
X    return 1;
X}
X
X
X
Xint TxtJamStr(display, w, str)
XDisplay *display;
XWindow w;			/* Text window            */
Xregister char *str;		/* NULL terminated string */
X/*
X * This is the same as TxtWriteStr except the screen is NOT updated.
X * After a call to this routine,  TxtRepaint should be called to
X * update the screen.  This routine is meant to be used to load
X * a text buffer with information and then allow the user to
X * scroll through it at will.
X */
X{
X    register int fontIndex;
X    register struct txtWin *textInfo;
X
X    if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)
X	 ) == 0)
X      return 0;
X    
X    for ( /* str is ok */ ; (*str != 0) ; str++) {
X	/* Check to see if we are waiting on a font */
X	if (textInfo->flagWord & FONTNUMWAIT) {
X	    textInfo->flagWord &= (~FONTNUMWAIT);
X	    fontIndex = *str - '0';
X	    if ((fontIndex >= 0) && (fontIndex < MAXFONTS)) {
X		if (HandleNewFont(display, fontIndex, textInfo, 0)) {
X		    /* Handled font -- go get next character */
X		    continue;
X		}
X	    }
X	}
X	/* Inline code for handling normal character case */
X	if ((*str >= LOWCHAR) && (*str <= HIGHCHAR)) {
X	    register XFontStruct *thisFont;
X	    register struct txtLine *thisLine;
X	    register int charWidth;
X	    
X	    /* Determine size of character */
X	    thisFont = &(textInfo->theFonts[textInfo->curFont]);
X
X	    if (*str <= thisFont->min_char_or_byte2 ||
X		*str >= thisFont->max_char_or_byte2 ||
X		thisFont->per_char == 0)
X		charWidth = thisFont->max_bounds.width + 1;
X	    else
X		charWidth = thisFont->per_char[*str].width + 1;
X
X	    /* Check to see if line wrap is required */
X	    thisLine = textInfo->txtBuffer[textInfo->curLine];
X	    if (thisLine->lineWidth + charWidth >
X		(textInfo->w-BARSIZE-WRAPINDSIZE))
X	      {
X		  thisLine->lineFlags |= WRAPFLAG;
X		  /* Handle the spacing problem the same way as a newline */
X		  HandleNewLine(display, textInfo, NONEWLINE);
X		  thisLine = textInfo->txtBuffer[textInfo->curLine];
X	      }
X	    /* Append character onto main buffer */
X	    if (textInfo->bufSpot >= textInfo->bufAlloc)
X	      /* Make room for more characters */
X	      ExpandBuffer(textInfo);
X	    textInfo->mainBuffer[(textInfo->bufSpot)++] =
X	      (textInfo->curFont << FONTSHIFT) | (*str);
X	    
X	    /* Update the line start array */
X	    thisLine->lineLength += 1;
X	    thisLine->lineWidth += charWidth;
X	} else if (*str == NEWLINE) {
X	    HandleNewLine(display, textInfo, 0);
X	} else if (*str == NEWFONT) {
X	    /* Go into waiting for font number mode */
X	    textInfo->flagWord |= FONTNUMWAIT;
X	} else if (*str == BACKSPACE) {
X	    HandleBackspace(display, textInfo, 0);
X	} else {
X	    /* Ignore all others */
X	}
X    }
X    textInfo->flagWord |= SCREENWRONG;
X    return 1;
X}
X
X
X
Xint TxtRepaint(display,w)
XDisplay *display;
XWindow w;
X/*
X * Repaints the given scrollable text window.  The routine repaints
X * the entire window.  For handling exposure events,  the TxtFilter 
X * routine should be used.
X */
X{
X    struct txtWin *textInfo;
X    int index, ypos;
X
X    if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)
X	 ) == 0)
X      return 0;
X
X    /* Check to see if the screen is up to date */
X    if (textInfo->flagWord & SCREENWRONG) {
X	textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
X	textInfo->flagWord &= (~SCREENWRONG);
X    }
X
X    ypos = YPADDING;
X    index = textInfo->startLine;
X    for (;;) {
X	DrawLine(display, textInfo, index, ypos);
X	if (index >= textInfo->endLine) break;
X	ypos += (textInfo->txtBuffer[index]->lineHeight + INTERLINE);
X	index++;
X    }
X    /* Draw the cursor (if on screen) */
X    if (textInfo->endLine == textInfo->curLine) {
X	XFillRectangle(display, w, textInfo->CursorGC,
X		       textInfo->txtBuffer[index]->lineWidth + CUROFFSET,
X		       ypos /* + textInfo->txtBuffer[index]->lineHeight */,
X		       CURSORWIDTH, textInfo->txtBuffer[index]->lineHeight);
X
X    }
X    /* Update the scroll bar */
X    UpdateScroll(display, textInfo);
X    return 1;
X}
X
X
X
Xstatic int InsertIndex(textInfo, thisIndex, ypos)
Xstruct txtWin *textInfo;	/* Text Window Information    */
Xint thisIndex;			/* Line index of exposed line */
Xint ypos;			/* Drawing position of line   */
X/*
X * This routine inserts the supplied line index into the copy
X * exposure array for 'textInfo'.  The array is kept sorted
X * from lowest to highest using insertion sort.  The array
X * is dynamically expanded if needed.
X */
X{
X    struct expEvent *newItem;
X    int newSize, index, downIndex;
X
X    /* Check to see if we need to expand it */
X    if ((textInfo->exposeSize + 3) >= textInfo->exposeAlloc) {
X	newSize = textInfo->exposeAlloc +
X	  (textInfo->exposeAlloc * EXPANDPERCENT / 100);
X	textInfo->exposeAry = (struct expEvent **)
X	  realloc((char *) textInfo->exposeAry,
X		  (unsigned) (newSize * sizeof(struct expEvent *)));
X	for (index = textInfo->exposeAlloc;  index < newSize;  index++)
X	  textInfo->exposeAry[index] = alloc(struct expEvent);
X	textInfo->exposeAlloc = newSize;
X    }
X    /* Find spot for insertion.  NOTE: last spot has big number */
X    for (index = 0;  index <= textInfo->exposeSize;  index++) {
X	if (textInfo->exposeAry[index]->lineIndex >= thisIndex) {
X	    if (textInfo->exposeAry[index]->lineIndex > thisIndex) {
X		/* Insert before this entry */
X		newItem = textInfo->exposeAry[textInfo->exposeSize+1];
X		for (downIndex = textInfo->exposeSize;
X		     downIndex >= index;
X		     downIndex--)
X		  {
X		      textInfo->exposeAry[downIndex+1] =
X			textInfo->exposeAry[downIndex];
X		  }
X		/* Put a free structure at this spot */
X		textInfo->exposeAry[index] = newItem;
X		/* Fill it in */
X		textInfo->exposeAry[index]->lineIndex = thisIndex;
X		textInfo->exposeAry[index]->ypos = ypos;
X		/* Break out of loop */
X		textInfo->exposeSize += 1;
X	    }
X	    break;
X	}
X    }
X    return 1;
X}
X
X
X
Xstatic int ScrollUp(display, textInfo)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text window information   */
X/*
X * This routine scrolls the indicated text window up by one
X * line.  The line above the current line must exist.  The
X * window is scrolled so that the line above the start line
X * is displayed at the top of the screen.  This may cause
X * many lines to scroll off the bottom.  The scrolling is
X * done using XCopyArea.  The exposure events should be caught
X * by ExposeCopy.
X */
X{
X    int targetSpace;
X
X    /* Make sure all exposures have been handled by now */
X    if (textInfo->startLine == 0) return 0;
X    targetSpace = textInfo->txtBuffer[textInfo->startLine-1]->lineHeight +
X      INTERLINE;
X    /* Move the area downward by the target amount */
X    XCopyArea(display, textInfo->mainWindow, textInfo->mainWindow,
X	      DEFAULT_GC,
X	      0, YPADDING, textInfo->w - BARSIZE,
X	      textInfo->h, 0, targetSpace);
X
X    textInfo->flagWord |= COPYEXPOSE;
X    /* Update the text window parameters */
X    textInfo->startLine -= 1;
X    textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
X
X    /* Clear out bottom space region */
X    XClearArea(display, textInfo->mainWindow,
X	       0, textInfo->h - textInfo->bottomSpace,
X	       textInfo->w, textInfo->bottomSpace);
X    
X    UpdateExposures(display, textInfo);
X    UpdateScroll(display, textInfo);
X
X    return 1;
X}
X
X
Xstatic int ScrollToSpot(display, textInfo, ySpot)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text window information          */
Xint ySpot;			/* Button position in scroll window */
X/*
X * This routine scrolls the specified text window relative to the
X * position of the mouse in the scroll bar.  The center of the screen
X * will be positioned to correspond to the mouse position.
X */
X{
X    int targetLine, aboveLines;
X
X    targetLine = textInfo->numLines * ySpot / textInfo->h;
X    textInfo->startLine = targetLine;
X    textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
X    aboveLines = 0;
X    /* Make the target line the *center* of the window */
X    while ((textInfo->startLine > 0) &&
X	   (aboveLines < textInfo->endLine - targetLine))
X      {
X	  textInfo->startLine -= 1;
X	  textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
X	  aboveLines++;
X      }
X    if (textInfo->endLine == textInfo->numLines-1) {
X	WarpToBottom(display, textInfo);
X    } else {
X	XClearWindow(display, textInfo->mainWindow);
X	TxtRepaint(display, textInfo->mainWindow);
X    }
X    return 1;
X}
X
X
X
Xstatic int LineToTop(display, textInfo, pos)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text window information */
Xint pos;			/* Y position of mouse     */
X/*
X * This routine scrolls the screen down until the line at the
X * mouse position is at the top of the screen.  It stops
X * if it can't scroll the buffer down that far.  If the
X * global 'ScrollOption' is NORMSCROLL,  a smooth scroll
X * is used.  Otherwise,  it jumps to the right position
X * and repaints the screen.
X */
X{
X    int index, sum;
X
X    /* First,  we find the current line */
X    sum = 0;
X    for (index = textInfo->startLine;  index <= textInfo->endLine;  index++) {
X	if (sum + textInfo->txtBuffer[index]->lineHeight + INTERLINE> pos) break;
X	sum += textInfo->txtBuffer[index]->lineHeight + INTERLINE;
X    }
X    /* We always want to scroll down at least one line */
X    if (index == textInfo->startLine) index++;
X    if (ScrollOption == NORMSCROLL) {
X	/* Scroll down until 'index' is the starting line */
X	while ((textInfo->startLine < index) && ScrollDown(display, textInfo))
X	{
X	    /* Empty Loop Body */
X	}
X    } else {
X	/* Immediately jump to correct spot */
X	textInfo->startLine = index;
X	textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
X	if (textInfo->endLine == textInfo->numLines-1) {
X	    WarpToBottom(display, textInfo);
X	} else {
X	    XClearWindow(display, textInfo->mainWindow);
X	    TxtRepaint(display, textInfo->mainWindow);
X	}
X    }
X    /* Check to see if at end of buffer */
X    if (textInfo->endLine >= textInfo->numLines-1) {
X	textInfo->flagWord &= (~NOTATBOTTOM);
X    }
X    return 1;
X}
X
X
X
Xstatic int TopToHere(display, textInfo, pos)
XDisplay *display;
Xstruct txtWin *textInfo;	/* Text window information */
Xint pos;			/* Y position of mouse     */
X/*
X * This routine scrolls the screen up until the top line of
X * the screen is at the current Y position of the mouse.  Again,
X * it will stop if it can't scroll that far.  If the global
X * 'ScrollOption' is NORMSCROLL,  a smooth scroll is used.
X * If it's not,  it will simply redraw the screen at the
X * correct spot.
X */
X{
X    int sum, target, linesup, index;
X
X    target = pos - textInfo->txtBuffer[textInfo->startLine]->lineHeight;
X    /* We always want to scroll up at least one line */
X    if (target <= 0) target = 1;
X    sum = 0;
X    linesup = 0;
X    /* Check to see if we are at the top anyway */
X    if (textInfo->startLine == 0) return 0;
X    if (ScrollOption == NORMSCROLL) {
X	/* Scroll up until sum of new top lines greater than target */
X	while ((sum < target) && ScrollUp(display, textInfo)) {
X	    sum += textInfo->txtBuffer[textInfo->startLine]->lineHeight;
X	    linesup++;
X	}
X    } else {
X	/* Search backward to find index */
X	index = textInfo->startLine - 1;
X	while ((index > 0) && (sum < target)) {
X	    sum += textInfo->txtBuffer[index]->lineHeight;
X	    linesup++;
X	    index--;
X	}
X	/* Go directly to the index */
X	textInfo->startLine = index;
X	textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
X	XClearWindow(display, textInfo->mainWindow);
X	TxtRepaint(display, textInfo->mainWindow);
X    }
X    /* If we scrolled,  assert we are not at bottom of buffer */
X    if (linesup > 0) {
X	textInfo->flagWord |= NOTATBOTTOM;
X    }
X    return 1;
X}
X
X
X
Xint TxtFilter(display, evt)
XDisplay *display;
XXEvent *evt;
X/*
X * This routine handles events associated with scrollable text windows.
X * It will handle all exposure events and any button released events
X * in the scroll bar of a text window.  It does NOT handle any other
X * events.  If it cannot handle the event,  it will return 0.
X */
X{
X    XExposeEvent *expose = &evt->xexpose;
X    XButtonEvent *btEvt = &evt->xbutton;
X    XGraphicsExposeEvent *gexpose = &evt->xgraphicsexpose;
X    XNoExposeEvent *noexpose = &evt->xnoexpose;
X    struct txtWin *textInfo;
X    int index, ypos;
X    Window w, sw;
X
X    if (textWindows == (XAssocTable *) 0) {
X	textWindows = XCreateAssocTable(32);
X	if (textWindows == (XAssocTable *) 0) return(0);
X    }
X    if (evt->type == Expose) {
X	w = expose->window;
X	sw = 0;
X    }
X    else if (evt->type == GraphicsExpose) {
X	w = gexpose->drawable;
X	sw = 0;
X    }
X    else if (evt->type == NoExpose) {
X	w = noexpose->drawable;
X	sw = 0;
X    }
X    else if (evt->type == ButtonRelease) {
X	w = btEvt->window;
X	sw = btEvt->subwindow;
X    }
X    else
X	return 0;
X
X    if ((textInfo = (struct txtWin *)
X	 XLookUpAssoc(display, textWindows, (XID) w)) == 0)	
X	return 0;
X
X    /* Determine whether it's main window or not */
X    if ((w == textInfo->mainWindow) && (sw == 0)) {
X	/* Main Window - handle exposures */
X	switch (evt->type) {
X	case Expose:
X	    ypos = 0 /*YPADDING*/;
X	    for (index = textInfo->startLine;
X		 index <= textInfo->endLine;
X		 index++)
X	      {
X		  int lh = textInfo->txtBuffer[index]->lineHeight;
X
X		  if (((ypos + lh) >= expose->y) &&
X		      (ypos <= (expose->y + expose->height)))
X		    {
X			/* Intersection region */
X			/* Draw line immediately */
X			DrawLine(display, textInfo, index, ypos);
X			/* And possibly draw cursor */
X			if (textInfo->curLine == index) {
X			    XFillRectangle(display, w, textInfo->CursorGC,
X				       textInfo->txtBuffer[index]->lineWidth +
X					   CUROFFSET,
X					   ypos,
X					   CURSORWIDTH,
X					   lh);
X			}
X		    }
X		  ypos += lh + INTERLINE;
X	      }
X	    break;
X	case GraphicsExpose:
X	    ypos = 0 /*YPADDING*/;
X	    for (index = textInfo->startLine;
X		 index <= textInfo->endLine;
X		 index++)
X	      {
X		  int lh = textInfo->txtBuffer[index]->lineHeight;
X
X		  if (((ypos + lh) >= gexpose->y) &&
X		      (ypos <= (gexpose->y + gexpose->height)))
X		    {
X			/* Intersection region */
X			/* Draw line immediately */
X			DrawLine(display, textInfo, index, ypos);
X			/* And possibly draw cursor */
X			if (textInfo->curLine == index) {
X			    XFillRectangle(display, w, textInfo->CursorGC,
X				    textInfo->txtBuffer[index]->lineWidth +
X				    CUROFFSET,
X				    ypos,
X				    CURSORWIDTH,
X				    lh);
X			}
X		    }
X		  ypos += lh + INTERLINE;
X	      }
X	    break;
X	case NoExpose:
X	    break;
X	default:
X	    /* Not one of our events */
X	    return 0;
X	}
X    } else {
X	switch (evt->type) {
X	case Expose:
X	    UpdateScroll(display, textInfo);
X	    break;
X	case ButtonRelease:
X	    /* Find out which button */
X	    switch (btEvt->button) {
X	    case Button1:
X		/* Scroll up until top line is at mouse position */
X		TopToHere(display, textInfo, btEvt->y);
X		break;
X	    case Button2:
X		/* Scroll to spot relative to position */
X		ScrollToSpot(display, textInfo, btEvt->y);
X		if (textInfo->endLine >= textInfo->numLines-1) {
X		    textInfo->flagWord &= (~NOTATBOTTOM);
X		} else {
X		    textInfo->flagWord |= NOTATBOTTOM;
X		}
X		break;
X	    case Button3:
X		/* Scroll down until pointed line is at top */
X		LineToTop(display, textInfo, btEvt->y);
X		break;
X	    }
X	    break;
X	default:
X	    /* Not one of our events */
X	    return 0;
X	}
X    }
X    return 1;
X}
END_OF_FILE
if test 57716 -ne `wc -c <'scrollText.c'`; then
    echo shar: \"'scrollText.c'\" unpacked with wrong size!
fi
# end of 'scrollText.c'
fi
if test -f 'std.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'std.h'\"
else
echo shar: Extracting \"'std.h'\" \(2535 characters\)
sed "s/^X//" >'std.h' <<'END_OF_FILE'
X/* This file contains code for X-CHESS.
X   Copyright (C) 1986 Free Software Foundation, Inc.
X
XThis file is part of X-CHESS.
X
XX-CHESS is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY.  No author or distributor
Xaccepts responsibility to anyone for the consequences of using it
Xor for whether it serves any particular purpose or works at all,
Xunless he says so in writing.  Refer to the X-CHESS General Public
XLicense for full details.
X
XEveryone is granted permission to copy, modify and redistribute
XX-CHESS, but only under the conditions described in the
XX-CHESS General Public License.   A copy of this license is
Xsupposed to have been given to you along with X-CHESS so you
Xcan know your rights and responsibilities.  It should be in a
Xfile named COPYING.  Among other things, the copyright notice
Xand this notice must be preserved on all copies.  */
X
X
X/* RCS Info: $Revision: 1.2 $ on $Date: 86/11/23 17:18:32 $
X *		   $Source: /users/faustus/xchess/RCS/std.h,v $
X * Copyright (c) 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
X *
X * Standard definitions.
X */
X
X#define UNIX
X#define BSD
X
X#ifndef FILE
X#include <stdio.h>
X#endif
X#ifndef isalpha
X#include <ctype.h>
X#endif
X#ifndef HUGE
X#include <math.h>
X#endif
X#include <strings.h>
X
Xtypedef int bool;
X
X#define false 0
X#define true 1
X
X/* Externs defined in std.c */
X
Xextern char *tmalloc();
Xextern char *trealloc();
Xextern char *copy();
Xextern char *datestring();
Xextern char *getusername();
Xextern char *gethome();
Xextern char *gettok();
Xextern char *tildexpand();
Xextern void fatal();
Xextern void setenv();
Xextern void appendc();
Xextern int scannum();
Xextern int seconds();
Xextern bool prefix();
Xextern bool ciprefix();
Xextern bool cieq();
Xextern bool substring();
X
X/* Externs from libc */
X
Xextern char *getenv();
Xextern int errno;
Xextern char *sys_errlist[];
X
X/* Should use BSIZE instead of BUFSIZ... */
X
X#define BSIZE	   512
X
X/* Some standard macros. */
X
X#define eq(a,b)	 (!strcmp((a), (b)))
X#define isalphanum(c)   (isalpha(c) || isdigit(c))
X#define alloc(strname)  ((struct strname *) tmalloc(sizeof(struct strname)))
X#define tfree(ptr)  { if (ptr) free((char *) ptr); ptr = 0; }
X#define hexnum(c) ((((c) >= '0') && ((c) <= '9')) ? ((c) - '0') : ((((c) >= \
X		'a') && ((c) <= 'f')) ? ((c) - 'a' + 10) : ((((c) >= 'A') && \
X		((c) <= 'F')) ? ((c) - 'A' + 10) : 0)))
X
X#ifndef BSD
X#define random rand
X#define srandom srand
X#endif BSD
X
X#ifdef VMS
X
X#define EXIT_NORMAL	1
X#define EXIT_BAD	0
X
X#else VMS
X
X#define EXIT_NORMAL	0
X#define EXIT_BAD	1
X
X#endif VMS
X
END_OF_FILE
if test 2535 -ne `wc -c <'std.h'`; then
    echo shar: \"'std.h'\" unpacked with wrong size!
fi
# end of 'std.h'
fi
echo shar: End of archive 1 \(of 6\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mike Wexler(wyse!mikew)    Phone: (408)433-1000 x1330
Moderator of comp.sources.x



More information about the Comp.sources.x mailing list