games-request@tekred.TEK.COM (01/19/88)
Submitted by: faustus@ic.berkeley.edu (Wayne A. Christopher) Comp.sources.games: Volume 3, Issue 43 Archive-name: xchess/Part02 #! /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 2 (of 6)." # Contents: scrollText/scrollText.c xchess.cur # Wrapped by billr@tekred on Mon Jan 18 08:48:07 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f scrollText/scrollText.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"scrollText/scrollText.c\" else echo shar: Extracting \"scrollText/scrollText.c\" \(55874 characters\) sed "s/^X//" >scrollText/scrollText.c <<'END_OF_scrollText/scrollText.c' 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 <X/Xlib.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 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 1 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 short arrow_bits[] = { X 0x0024, 0x0026, 0x003f, 0x0006, X 0x0004}; Xstatic Pixmap arrowMap; 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 int bgPix, fgPix, curPix; /* Background and cursor */ X FontInfo theFonts[MAXFONTS];/* Display fonts */ X int theColors[MAXFONTS]; /* Display colors */ X int curFont; /* Which font is in use */ X int curColor; /* Current drawing color */ 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 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 Xstatic int FindBaseLine(someFont) XFontInfo *someFont; X/* X * Due to inconsistencies in the font information, the baseline X * must be computed for each new font. The baseline here is X * defined as the number of pixels from the bottom of the font X * to the bottom of a non-decending character. Some fonts the X * original baseline info is opposite this (from the top down). X * For certain well known fonts, a table is used. X */ X{ X if (someFont->baseline == 0) { X if ((someFont->height == 10) || (someFont->height == 13)) X return 2; X if (someFont->height == 15) X return 3; X } X if (someFont->baseline > someFont->height / 2) X return someFont->height - someFont->baseline; X else return someFont->baseline; X} 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(txtWin, program, mainFont, bg, fg, cur) XWindow txtWin; /* Window to take over as scrollable text */ Xchar *program; /* Program name for Xdefaults */ XFontInfo *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 WindowInfo winInfo; /* Window information */ X Pixmap bdrMap, bgndMap; X Bitmap arrowBM, scrollBM; X int index; X X if (textWindows == (XAssocTable *) 0) { X textWindows = XCreateAssocTable(32); X if (textWindows == (XAssocTable *) 0) return(0); X } X if (XQueryWindow(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(program, "JumpScroll")) { X ScrollOption = JUMPSCROLL; X } else { X ScrollOption = NORMSCROLL; X } X } X X /* Initialize arrow pixmap */ X arrowBM = XStoreBitmap(arrow_width, arrow_height, arrow_bits); X arrowMap = XMakePixmap(arrowBM, fg, bg); X XFreeBitmap(arrowBM); X X /* Initialize local structure */ X newWin = alloc(struct txtWin); 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->height - INTERLINE; X newWin->flagWord = 0; X newWin->bgPix = bg; X newWin->fgPix = fg; X newWin->curPix = cur; X X /* Scroll Bar Creation */ X bdrMap = XMakeTile(fg); X bgndMap = XMakeTile(bg); X newWin->scrollBar = XCreateWindow(txtWin, X winInfo.width - BARSIZE, X 0, BARSIZE - (2*BARBORDER), X winInfo.height - (2*BARBORDER), BARBORDER, X bdrMap, bgndMap); X XSelectInput(newWin->scrollBar, ExposeWindow|ButtonReleased); X XMapWindow(newWin->scrollBar); X XFreePixmap(bdrMap); X XFreePixmap(bgndMap); X X /* Font and Color Initialization */ X newWin->theFonts[0] = *mainFont; X newWin->theFonts[0].baseline = FindBaseLine(mainFont); X newWin->theColors[0] = fg; X for (index = 1; index < MAXFONTS; index++) { X newWin->theFonts[index].id = 0; X newWin->theColors[index] = TXT_NO_COLOR; X } X newWin->curFont = 0; X X /* Initialize size of first line */ X newWin->txtBuffer[0]->lineHeight = newWin->theFonts[0].height; X newWin->txtBuffer[0]->lineBaseLine = newWin->theFonts[0].baseline; 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->curY = YPADDING; X X /* Attach it to both windows */ X XMakeAssoc(textWindows, (XId) txtWin, (caddr_t) newWin); X XMakeAssoc(textWindows, (XId) newWin->scrollBar, (caddr_t) newWin); X return 1; X} X X Xint TxtRelease(w) 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(textWindows, (XId) w)) == 0) X return 0; 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(textInfo->scrollBar); X for (index = 0; index < textInfo->exposeSize; index++) { X free((Generic) textInfo->exposeAry[index]); X } X free((Generic) textInfo->exposeAry); X XDeleteAssoc(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 FontInfo *fontptr; X register struct txtLine *lineptr; 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 = textInfo->theFonts[0].height; X textInfo->txtBuffer[0]->lineBaseLine = textInfo->theFonts[0].baseline; 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 if ((bufptr[index] & FONTMASK) != curfont) { X int newFontNum, heightDiff, baseDiff; X X /* Switch fonts */ X newFontNum = (bufptr[index] & FONTMASK) >> FONTSHIFT; X if (textInfo->theFonts[newFontNum].id != 0) { X /* Valid font */ X curfont = bufptr[index] & FONTMASK; X fontptr = &(textInfo->theFonts[newFontNum]); X heightDiff = (fontptr->height - fontptr->baseline) - X (lineptr->lineHeight - lineptr->lineBaseLine); X if (heightDiff < 0) heightDiff = 0; X baseDiff = fontptr->baseline - lineptr->lineBaseLine; X if (baseDiff > 0) { X heightDiff += baseDiff; X lineptr->lineBaseLine += baseDiff; X } X lineptr->lineHeight += heightDiff; X } X } X if ((bufptr[index] & CHARMASK) == '\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->height; X lineptr->lineBaseLine = fontptr->baseline; 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 = (fontptr->fixedwidth ? X fontptr->width : X fontptr->widths[(bufptr[index] & CHARMASK) - X fontptr->firstchar] + 1); 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->height; X lineptr->lineBaseLine = fontptr->baseline; 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(textWin, fontNumber, newFont, newColor) XWindow textWin; /* Scrollable text window */ Xint fontNumber; /* Place to add font (0-7) */ XFontInfo *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 X if ((fontNumber < 0) || (fontNumber >= MAXFONTS)) return 0; X if ((textInfo = (struct txtWin *) X XLookUpAssoc(textWindows, (XId) textWin)) == 0) X return 0; X if (newColor == TXT_NO_COLOR) { X newColor = textInfo->fgPix; X } X redrawFlag = (textInfo->theFonts[fontNumber].id != 0) && X (((newFont) && (newFont->id != textInfo->theFonts[fontNumber].id)) || X (newColor != textInfo->theColors[fontNumber])); X if (newFont) { X textInfo->theFonts[fontNumber] = *newFont; X textInfo->theFonts[fontNumber].baseline = FindBaseLine(newFont); X } X textInfo->theColors[fontNumber] = newColor; X X if (redrawFlag) { X RecompBuffer(textInfo); X XClear(textWin); X TxtRepaint(textWin); X } X return 1; X} X X X Xint TxtWinP(w) 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(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(textInfo) 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 XPixSet(textInfo->scrollBar, 0, 0, BARSIZE, top-1, textInfo->bgPix); X XPixSet(textInfo->scrollBar, 1, top, BARSIZE - (2*BARBORDER) - 2, X bottom - top, textInfo->fgPix); X XPixSet(textInfo->scrollBar, 0, bottom+1, BARSIZE, X textInfo->h - (2 * BARBORDER) - bottom, X textInfo->bgPix); X return 1; X} X X X X Xint TxtClear(w) 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(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].height; X textInfo->txtBuffer[0]->lineBaseLine = X textInfo->theFonts[textInfo->curFont].baseline; X X textInfo->numLines = 1; X textInfo->startLine = 0; X textInfo->endLine = 0; X textInfo->curLine = 0; X textInfo->curY = YPADDING; X textInfo->bottomSpace = textInfo->h - YPADDING - X textInfo->theFonts[textInfo->curFont].height - INTERLINE; X /* Actually clear the window */ X XClear(w); X /* Draw the current cursor */ X XPixSet(w, XPADDING + CUROFFSET, YPADDING, X CURSORWIDTH, textInfo->theFonts[textInfo->curFont].height, X textInfo->curPix); X /* Update the scroll bar */ X UpdateScroll(textInfo); X return 1; X} X X Xstatic int WarpToBottom(textInfo) 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 XClear(textInfo->mainWindow); X TxtRepaint(textInfo->mainWindow); X return 1; X} X X X Xstatic int UpdateExposures(textInfo) 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 XEvent foreignQueue[MAXFOREIGN]; X int index, lastItem = 0; X X while (textInfo->flagWord & COPYEXPOSE) { X XNextEvent(&(foreignQueue[lastItem])); X if (!TxtFilter(&(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(&(foreignQueue[index])); X } X return 1; X} X X Xstatic int ScrollDown(textInfo) 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 /* Must move upward by 'lineSum' pixels */ X XMoveArea(textInfo->mainWindow, 0, lineSum + YPADDING, X 0, YPADDING, textInfo->w - BARSIZE, textInfo->h); 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(textInfo); X } X UpdateScroll(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(textInfo, flagWord) 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 = textInfo->theFonts[textInfo->curFont].height; X nextLine->lineBaseLine = textInfo->theFonts[textInfo->curFont].baseline; 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(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 + INTERLINE + 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 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 FontInfo *charFont; X register short *theLine; X register short theChar; X X theLine = &(textInfo->mainBuffer[textInfo->txtBuffer[lineNum]->lineText]); X theChar = theLine[charNum]; X charFont = &(textInfo->theFonts[(theChar & FONTMASK) >> FONTSHIFT]); X if (charFont->fixedwidth) { X return charFont->width; X } else { X theChar &= CHARMASK; X return charFont->widths[theChar - charFont->firstchar] + 1; X } X} X X X X X Xstatic int HandleBackspace(textInfo, flagWord) 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 XFeep(0); 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(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 XPixSet(textInfo->mainWindow, X textInfo->w - BARSIZE - WRAPINDSIZE, X textInfo->curY, WRAPINDSIZE, X prevLine->lineHeight, X textInfo->bgPix); X } X prevLine->lineFlags &= (~WRAPFLAG); X /* Call recursively to wipe out the ending character */ X HandleBackspace(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 XPixSet(textInfo->mainWindow, thisLine->lineWidth, textInfo->curY, X chSize, thisLine->lineHeight, textInfo->bgPix); 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(win, x, y, h, col) 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 /* First, draw the arrow */ X XPixmapPut(win, 0, 0, x, y + h - arrow_height, arrow_width, X arrow_height, arrowMap, GXcopy, AllPlanes); X /* Then draw the stem */ X XLine(win, x + STEMOFFSET, y, x + STEMOFFSET, y + h - arrow_height, X 1, 1, col, GXcopy, AllPlanes); X return 1; X} X X X X Xstatic int DrawLine(textInfo, lineIndex, ypos) 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; X struct txtLine *someLine; X char lineBuffer[BUFSIZE], *glyph; X short *linePointer; X FontInfo *theFont; 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 theFont = &(textInfo->theFonts[curFont >> FONTSHIFT]); X theColor = textInfo->theColors[curFont >> FONTSHIFT]; X if (theFont->fixedwidth) { X glyph = &(lineBuffer[0]); X while ((index < someLine->lineLength) && X ((linePointer[index] & FONTMASK) == curFont)) X { X *glyph = linePointer[index] & CHARMASK; X index++; X glyph++; X curX += theFont->width; X } X } else { X glyph = &(lineBuffer[0]); X while ((index < someLine->lineLength) && X ((linePointer[index] & FONTMASK) == curFont)) X { X *glyph = linePointer[index] & CHARMASK; X index++; X curX += (theFont->widths[*glyph - theFont->firstchar] + 1); X glyph++; X } X } X /* Flush out the glyphs */ X if (theFont->fixedwidth) { X XText(textInfo->mainWindow, saveX, X ypos + (someLine->lineHeight - theFont->height) - X (someLine->lineBaseLine - theFont->baseline), X lineBuffer, X index - startPos, X theFont->id, theColor, textInfo->bgPix); X } else { X XTextPad(textInfo->mainWindow, saveX, X ypos + (someLine->lineHeight - theFont->height) - X (someLine->lineBaseLine - theFont->baseline), X lineBuffer, X index - startPos, X theFont->id, 1, 1, theColor, textInfo->bgPix, X GXcopy, AllPlanes); X } X } X /* Then the line wrap indicator (if needed) */ X if (someLine->lineFlags & WRAPFLAG) { X DrawLineWrap(textInfo->mainWindow, textInfo->w - BARSIZE - WRAPINDSIZE, X ypos, someLine->lineHeight, X textInfo->fgPix); X } X return 1; X} X X X X Xstatic int HandleNewFont(fontNum, textInfo, flagWord) 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].id == 0) { X return 0; X } else { X thisLine = textInfo->txtBuffer[textInfo->curLine]; X textInfo->curFont = fontNum; X redrawFlag = 0; X heightDiff = (textInfo->theFonts[fontNum].height - X textInfo->theFonts[fontNum].baseline) - X (thisLine->lineHeight - thisLine->lineBaseLine); X if (heightDiff > 0) { X redrawFlag = 1; X } else { X heightDiff = 0; X } X baseDiff = textInfo->theFonts[fontNum].baseline - X thisLine->lineBaseLine; X if (baseDiff > 0) { X heightDiff += baseDiff; X thisLine->lineBaseLine += baseDiff; X redrawFlag = 1; X } X if (redrawFlag) { X if (flagWord & DODISP) { X /* Clear current line */ X XPixSet(textInfo->mainWindow, 0, textInfo->curY, textInfo->w, X thisLine->lineHeight, textInfo->bgPix); 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 + INTERLINE; X XPixSet(textInfo->mainWindow, 0, X textInfo->h - textInfo->bottomSpace, X textInfo->w, textInfo->bottomSpace, X textInfo->bgPix); X thisLine->lineHeight += heightDiff; X ScrollDown(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(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(w, str) XWindow w; /* Text window */ Xregister char *str; /* NULL 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(textWindows, (XId) w)) == 0) X return 0; X X /* See if screen needs to be updated */ X if (textInfo->flagWord & SCREENWRONG) { X TxtRepaint(textInfo->mainWindow); X } X X /* See if we have to scroll down to the bottom */ X if (textInfo->flagWord & NOTATBOTTOM) { X WarpToBottom(textInfo); X textInfo->flagWord &= (~NOTATBOTTOM); X } X X /* Undraw the current cursor */ X thisLine = textInfo->txtBuffer[textInfo->curLine]; X XPixSet(w, X thisLine->lineWidth + CUROFFSET, X textInfo->curY, X CURSORWIDTH, X thisLine->lineHeight, X textInfo->bgPix); 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(fontIndex, textInfo, DODISP)) { 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 FontInfo *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 (thisFont->fixedwidth) { X charWidth = thisFont->width; X } else { X charWidth = thisFont->widths[(*str) - thisFont->firstchar] + 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(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(textInfo, DODISP | NONEWLINE); X thisLine = textInfo->txtBuffer[textInfo->curLine]; X } X X /* Ready to draw character */ X XText(textInfo->mainWindow, thisLine->lineWidth, X textInfo->curY + (thisLine->lineHeight - thisFont->height)- X (thisLine->lineBaseLine - thisFont->baseline), X str, 1, thisFont->id, thisColor, textInfo->bgPix); 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(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(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 XPixSet(w, thisLine->lineWidth + CUROFFSET, textInfo->curY, CURSORWIDTH, X thisLine->lineHeight, textInfo->curPix); X return 1; X} X X X Xint TxtJamStr(w, str) 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(textWindows, (XId) w)) == 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(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 FontInfo *thisFont; X register struct txtLine *thisLine; X register int charWidth; X X /* Determine size of character */ X thisFont = &(textInfo->theFonts[textInfo->curFont]); X if (thisFont->fixedwidth) { X charWidth = thisFont->width; X } else { X charWidth = thisFont->widths[(*str) - thisFont->firstchar] + 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(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(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(textInfo, 0); X } else { X /* Ignore all others */ X } X } X textInfo->flagWord |= SCREENWRONG; X return 1; X} X X X Xint TxtRepaint(w) 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(textWindows, (XId) w)) == 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(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 XPixSet(w, textInfo->txtBuffer[index]->lineWidth + CUROFFSET, X ypos, CURSORWIDTH, X textInfo->txtBuffer[index]->lineHeight, X textInfo->curPix); X } X /* Update the scroll bar */ X UpdateScroll(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(textInfo) 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 XMoveArea(textInfo->mainWindow, 0, YPADDING-targetSpace, 0, YPADDING, X textInfo->w - BARSIZE, textInfo->h); X textInfo->flagWord |= COPYEXPOSE; X /* Update the text window parameters */ X textInfo->startLine -= 1; X textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace)); X /* Clear out bottom space region */ X XPixSet(textInfo->mainWindow, 0, textInfo->h - textInfo->bottomSpace, X textInfo->w, textInfo->bottomSpace, textInfo->bgPix); X UpdateExposures(textInfo); X UpdateScroll(textInfo); X return 1; X} X X Xstatic int ScrollToSpot(textInfo, ySpot) 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(textInfo); X } else { X XClear(textInfo->mainWindow); X TxtRepaint(textInfo->mainWindow); X } X return 1; X} X X X Xstatic int LineToTop(textInfo, pos) 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(textInfo)) { 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(textInfo); X } else { X XClear(textInfo->mainWindow); X TxtRepaint(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(textInfo, pos) 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(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 XClear(textInfo->mainWindow); X TxtRepaint(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(evt) 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 = (XExposeEvent *) evt; X XButtonEvent *btEvt = (XButtonEvent *) evt; X struct txtWin *textInfo; X struct txtLine *thisLine; X int index, ypos; X X if (textWindows == (XAssocTable *) 0) { X textWindows = XCreateAssocTable(32); X if (textWindows == (XAssocTable *) 0) return(0); X } X if ((textInfo = (struct txtWin *) X XLookUpAssoc(textWindows, (XId) evt->window)) == 0) X return 0; X X /* Determine whether it's main window or not */ X if ((evt->window == textInfo->mainWindow) && (evt->subwindow == 0)) { X /* Main Window - handle exposures */ X switch (evt->type) { X case ExposeWindow: X if ((expose->width != textInfo->w) || X (expose->height != textInfo->h)) X { X /* Window changed size */ X textInfo->w = expose->width; X textInfo->h = expose->height; X /* Reconfigure scroll bar */ X XConfigureWindow(textInfo->scrollBar, X textInfo->w - BARSIZE, X 0, BARSIZE - (2 * BARBORDER), X textInfo->h - (2 * BARBORDER)); X /* Recompute line breaks */ X RecompBuffer(textInfo); X } X TxtRepaint(evt->window); X break; X case ExposeRegion: X ypos = 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 if (expose->detail == ExposeCopy) { X /* Queue up line to be redrawn */ X InsertIndex(textInfo, index, ypos); X } else { X /* Draw line immediately */ X DrawLine(textInfo, index, ypos); X /* And possibly draw cursor */ X if (textInfo->curLine == index) { X XPixSet(evt->window, X textInfo->txtBuffer[index]->lineWidth + X CUROFFSET, X ypos, CURSORWIDTH, X textInfo->txtBuffer[index]->lineHeight, X textInfo->curPix); X } X } X } X ypos += lh + INTERLINE; X } X break; X case ExposeCopy: X /* Expose queued up lines */ X for (index = 0; index < textInfo->exposeSize; index++) { X DrawLine(textInfo, textInfo->exposeAry[index]->lineIndex, X textInfo->exposeAry[index]->ypos); X /* And possibly draw cursor */ X thisLine= X textInfo->txtBuffer[textInfo->exposeAry[index]->lineIndex]; X if (textInfo->numLines==textInfo->exposeAry[index]->lineIndex) { X XPixSet(evt->window, thisLine->lineWidth + CUROFFSET, X ypos, CURSORWIDTH, thisLine->lineHeight, X textInfo->curPix); X } X } X textInfo->exposeSize = 0; X textInfo->exposeAry[0]->lineIndex = MAXINT; X textInfo->flagWord &= (~COPYEXPOSE); X break; X default: X /* Not one of our events */ X return 0; X } X } else { X switch (evt->type) { X case ExposeWindow: X UpdateScroll(textInfo); X break; X case ButtonReleased: X /* Find out which button */ X switch (btEvt->detail & ValueMask) { X case RightButton: X /* Scroll up until top line is at mouse position */ X TopToHere(textInfo, btEvt->y); X break; X case MiddleButton: X /* Scroll to spot relative to position */ X ScrollToSpot(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 LeftButton: X /* Scroll down until pointed line is at top */ X LineToTop(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_scrollText/scrollText.c if test 55874 -ne `wc -c <scrollText/scrollText.c`; then echo shar: \"scrollText/scrollText.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f xchess.cur -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"xchess.cur\" else echo shar: Extracting \"xchess.cur\" \(267 characters\) sed "s/^X//" >xchess.cur <<'END_OF_xchess.cur' X#define xchess_width 16 X#define xchess_height 16 X#define xchess_x_hot 9 X#define xchess_y_hot 8 Xstatic short xchess_bits[] = { X 0x0000, 0x0000, 0x7000, 0xf800, X 0xfe00, 0xff80, 0xffc0, 0xff60, X 0xfdb0, 0x66d8, 0x3b6c, 0x1d76, X 0x1d98, 0x0ccc, 0x0060, 0x0000}; END_OF_xchess.cur if test 267 -ne `wc -c <xchess.cur`; then echo shar: \"xchess.cur\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 2 \(of 6\). cp /dev/null ark2isdone 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