Annotation of 43BSDReno/games/chess/Xchess/scrollText/scrollText.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * A Scrollable Text Output Window
        !             3:  *
        !             4:  * David Harrison 
        !             5:  * University of California,  Berkeley
        !             6:  * 1986
        !             7:  *
        !             8:  * The following is an implementation for a scrollable text output
        !             9:  * system.  It handles exposure events only (other interactions are
        !            10:  * under user control).  For scrolling,  a always present scroll bar
        !            11:  * is implemented.  It detects size changes and compensates accordingly.
        !            12:  */
        !            13: 
        !            14: #include <X11/X.h>
        !            15: #include <X11/Xlib.h>
        !            16: #include <X11/X10.h>
        !            17: #include <sys/types.h>
        !            18: #include "scrollText.h"
        !            19: 
        !            20: extern char *malloc();
        !            21: extern char *realloc();
        !            22: #define alloc(type)            (type *) malloc(sizeof(type))
        !            23: #define numalloc(type, num)    (type *) malloc((unsigned) (num * sizeof(type)))
        !            24: #define MAXINT         2147483647
        !            25: 
        !            26: extern XAssocTable *XCreateAssocTable();
        !            27: extern caddr_t XLookUpAssoc();
        !            28: 
        !            29: static XAssocTable *textWindows = (XAssocTable *) 0;
        !            30: 
        !            31: #define NOOPTION       -1      /* Option hasn't been set yet                */
        !            32: #define NORMSCROLL     0       /* Smooth scroll on LineToTop and TopToHere  */
        !            33: #define JUMPSCROLL     1       /* Jump scrolling on LineToTop and TopToHere */
        !            34: 
        !            35: static int ScrollOption = NOOPTION;
        !            36: 
        !            37: typedef char *Generic;
        !            38: 
        !            39: #define DEFAULT_GC textInfo->fontGC[textInfo->curFont]
        !            40: 
        !            41: #define BARSIZE                15
        !            42: #define BARBORDER      1
        !            43: #define MAXFONTS       8
        !            44: #define INITBUFSIZE    1024
        !            45: #define INITLINES      50
        !            46: #define INITEXPARY     50
        !            47: #define XPADDING       2
        !            48: #define YPADDING       2
        !            49: #define INTERLINE      5
        !            50: #define INTERSPACE     1
        !            51: #define CURSORWIDTH    2
        !            52: #define EXPANDPERCENT  40
        !            53: #define BUFSIZE                1024
        !            54: #define CUROFFSET      1
        !            55: #define MAXFOREIGN     250
        !            56: #define NOINDEX                -1
        !            57: 
        !            58: /* The wrap line indicator */
        !            59: #define WRAPINDSIZE    7
        !            60: #define STEMOFFSET     5
        !            61: #define arrow_width 7
        !            62: #define arrow_height 5
        !            63: static char arrow_bits[] = {
        !            64:    0x24, 0x26, 0x3f, 0x06, 0x04};
        !            65: 
        !            66: #define NEWLINE                '\n'
        !            67: #define BACKSPACE      '\010'
        !            68: #define NEWFONT                '\006'
        !            69: #define LOWCHAR                '\040'
        !            70: #define HIGHCHAR       '\176'
        !            71: 
        !            72: #define CHARMASK       0x00ff  /* Character mask */
        !            73: #define FONTMASK       0x0700  /* Character font */
        !            74: #define FONTSHIFT      8       /* Shift amount   */
        !            75: 
        !            76: #define WRAPFLAG       0x01    /* Line wrap flag */
        !            77: 
        !            78: /*
        !            79:  * Lines are represented by a pointer into the overall array of
        !            80:  * 16-bit characters.  The lower eight bits is used to indicate the character
        !            81:  * (in ASCII),  and the next two bits are used to indicate the font
        !            82:  * the character should be drawn in.
        !            83:  */
        !            84: 
        !            85: typedef struct txtLine {
        !            86:     int lineLength;            /* Current line length               */
        !            87:     int lineHeight;            /* Full height of line in pixels     */
        !            88:     int lineBaseLine;          /* Current baseline of the line      */
        !            89:     int lineWidth;             /* Drawing position at end of line   */
        !            90:     int lineText;              /* Offset into master buffer         */
        !            91:     int lineFlags;             /* Line wrap flag is here            */
        !            92: };
        !            93: 
        !            94: 
        !            95: /*
        !            96:  * For ExposeCopy events,  we queue up the redraw requests collapsing
        !            97:  * them into line redraw requests until the CopyExpose event arrives.
        !            98:  * The queue is represented as a dynamic array of the following
        !            99:  * structure:
        !           100:  */
        !           101: 
        !           102: typedef struct expEvent {
        !           103:     int lineIndex;             /* Index of line to redraw  */
        !           104:     int ypos;                  /* Drawing position of line */
        !           105: };
        !           106: 
        !           107: 
        !           108: /*
        !           109:  * The text buffer is represented using a dynamic counted array
        !           110:  * of 16-bit quantities. This array expands as needed.
        !           111:  * For the screen representation,  a dynamic counted array
        !           112:  * of line structures is used.  This array points into the
        !           113:  * text buffer to denote the start of each line and its parameters.
        !           114:  * The windows are configured as one overall window which contains
        !           115:  * the scroll bar as a sub-window along its right edge.  Thus,
        !           116:  * the text drawing space is actually w-BARSIZE.
        !           117:  */
        !           118: 
        !           119: #define NOTATBOTTOM    0x01    /* Need to scroll to bottom before appending */
        !           120: #define FONTNUMWAIT    0x02    /* Waiting for font number                   */
        !           121: #define COPYEXPOSE     0x04    /* Need to process a copy expose event       */
        !           122: #define SCREENWRONG    0x08    /* TxtJamStr has invalidated screen contents */
        !           123: 
        !           124: typedef struct txtWin {
        !           125:     /* Basic text buffer */
        !           126:     int bufAlloc;              /* Allocated size of buffer           */
        !           127:     int bufSpot;               /* Current writing position in buffer */
        !           128:     short *mainBuffer;         /* Main buffer of text                */
        !           129: 
        !           130:     /* Line information */
        !           131:     int numLines;              /* Number of display lines in buffer */
        !           132:     int allocLines;            /* Number of lines allocated         */
        !           133:     struct txtLine **txtBuffer;        /* Dynamic array of lines            */
        !           134: 
        !           135:     /* Current Window display information */
        !           136:     Window mainWindow;         /* Text display window       */
        !           137:     Window scrollBar;          /* Subwindow for scroll bar  */
        !           138:     Pixmap arrowMap;           /* line wrap indicator       */
        !           139:     int bgPix, fgPix;          /* Background and cursor     */
        !           140:     GC CursorGC;               /* gc for the cursor         */
        !           141:     GC bgGC;                   /* gc for erasing things     */
        !           142:     GC fontGC[MAXFONTS];       /* gc for doing fonts        */
        !           143:     XFontStruct theFonts[MAXFONTS];/* Display fonts          */
        !           144:     int  theColors[MAXFONTS];  /* foregrounds of the fonts  */
        !           145:     int  curFont;              /* current font for tracking */
        !           146:     int w, h;                  /* Current size              */
        !           147:     int startLine;             /* Top line in display       */
        !           148:     int endLine;               /* Bottom line in display    */
        !           149:     int bottomSpace;           /* Space at bottom of screen */
        !           150:     int flagWord;              /* If non-zero,  not at end  */
        !           151: 
        !           152:     /* For handling ExposeCopy events */
        !           153:     int exposeSize;            /* Current size of array      */
        !           154:     int exposeAlloc;           /* Allocated size             */
        !           155:     struct expEvent **exposeAry;/* Array of line indices      */
        !           156: 
        !           157:     /* Drawing position information */
        !           158:     int curLine;               /* Current line in buffer    */
        !           159:     int curX;                  /* Current horizontal positi */
        !           160:     int curY;                  /* Current vertical drawing  */
        !           161: };
        !           162: 
        !           163: /* Flags for the various basic character handling functions */
        !           164: 
        !           165: #define DODISP         0x01    /* Update the display  */
        !           166: #define NONEWLINE      0x02    /* Dont append newline */
        !           167: 
        !           168: 
        !           169: 
        !           170: static int InitLine(newLine)
        !           171: struct txtLine *newLine;       /* Newly created line structure */
        !           172: /*
        !           173:  * This routine initializes a newly created line structure.
        !           174:  */
        !           175: {
        !           176:     newLine->lineLength = 0;
        !           177:     newLine->lineHeight = 0;
        !           178:     newLine->lineBaseLine = 0;
        !           179:     newLine->lineWidth = XPADDING;
        !           180:     newLine->lineText = NOINDEX;
        !           181:     newLine->lineFlags = 0;
        !           182:     return 1;
        !           183: }
        !           184: 
        !           185: 
        !           186: 
        !           187: 
        !           188: int TxtGrab(display, txtWin, program, mainFont, bg, fg, cur)
        !           189: Display *display;              /* display window is on  */
        !           190: Window txtWin;                 /* Window to take over as scrollable text    */
        !           191: char *program;                 /* Program name for Xdefaults                */
        !           192: XFontStruct *mainFont;         /* Primary text font                         */
        !           193: int bg, fg, cur;               /* Background, foreground, and cursor colors */
        !           194: /*
        !           195:  * This routine takes control of 'txtWin' and makes it into a scrollable
        !           196:  * text output window.  It will create a sub-window for the scroll bar
        !           197:  * with a background of 'bg' and an bar with color 'fg'.  Both fixed width
        !           198:  * and variable width fonts are supported.  Additional fonts can be loaded
        !           199:  * using 'TxtAddFont'.  Returns 0 if there were problems,  non-zero if
        !           200:  * everything went ok.
        !           201:  */
        !           202: {
        !           203:     struct txtWin *newWin;     /* Text package specific information */
        !           204:     XWindowAttributes winInfo; /* Window information                */
        !           205:     int index;
        !           206:     XGCValues gc_val;
        !           207:     
        !           208:     if (textWindows == (XAssocTable *) 0) {
        !           209:        textWindows = XCreateAssocTable(32);
        !           210:        if (textWindows == (XAssocTable *) 0) return(0);
        !           211:     }
        !           212:     if (XGetWindowAttributes(display, txtWin, &winInfo) == 0) return 0;
        !           213: 
        !           214:     if (ScrollOption == NOOPTION) {
        !           215:        /* Read to see if the user wants jump scrolling or not */
        !           216:        if (XGetDefault(display, program, "JumpScroll")) {
        !           217:            ScrollOption = JUMPSCROLL;
        !           218:        } else {
        !           219:            ScrollOption = NORMSCROLL;
        !           220:        }
        !           221:     }
        !           222: 
        !           223:     /* Initialize local structure */
        !           224:     newWin = alloc(struct txtWin);
        !           225: 
        !           226:     /* Initialize arrow pixmap */
        !           227:     newWin->arrowMap = XCreatePixmapFromBitmapData(display, txtWin,
        !           228:                                                   arrow_bits,
        !           229:                                                   arrow_width, arrow_height,
        !           230:                                                   cur, bg,
        !           231:                                                   DisplayPlanes(display, 0));
        !           232: 
        !           233:     newWin->bufAlloc = INITBUFSIZE;
        !           234:     newWin->bufSpot = 0;
        !           235:     newWin->mainBuffer = numalloc(short, INITBUFSIZE);
        !           236: 
        !           237:     newWin->numLines = 1;
        !           238:     newWin->allocLines = INITLINES;
        !           239:     newWin->txtBuffer = numalloc(struct txtLine *, INITLINES);
        !           240:     for (index = 0;  index < INITLINES;  index++) {
        !           241:        newWin->txtBuffer[index] = alloc(struct txtLine);
        !           242:        InitLine(newWin->txtBuffer[index]);
        !           243:     }
        !           244: 
        !           245:     /* Window display information */
        !           246:     newWin->mainWindow = txtWin;
        !           247:     newWin->w = winInfo.width;
        !           248:     newWin->h = winInfo.height;
        !           249:     newWin->startLine = 0;
        !           250:     newWin->endLine = 0;
        !           251:     newWin->bottomSpace = winInfo.height
        !           252:       - YPADDING - mainFont->ascent - mainFont->descent - INTERLINE;
        !           253:     newWin->flagWord = 0;
        !           254:     newWin->bgPix = bg;
        !           255:     newWin->fgPix = fg;
        !           256: 
        !           257:     /* Scroll Bar Creation */
        !           258:     newWin->scrollBar = XCreateSimpleWindow(display, txtWin,
        !           259:                                      winInfo.width - BARSIZE,
        !           260:                                      0, BARSIZE - (2*BARBORDER),
        !           261:                                      winInfo.height - (2*BARBORDER),
        !           262:                                      BARBORDER, 
        !           263:                                      fg, bg);
        !           264:     XSelectInput(display, newWin->scrollBar, ExposureMask|ButtonReleaseMask);
        !           265:     XMapRaised(display, newWin->scrollBar);
        !           266: 
        !           267:     /* Font and Color Initialization */
        !           268:     newWin->theFonts[0] = *mainFont;
        !           269:     newWin->theColors[0] = fg;
        !           270:     gc_val.function = GXcopy;
        !           271:     gc_val.plane_mask = AllPlanes;
        !           272:     gc_val.foreground = fg;
        !           273:     gc_val.background = bg;
        !           274:     gc_val.graphics_exposures = 1;
        !           275:     gc_val.font = mainFont->fid;
        !           276:     gc_val.line_width = 1;
        !           277:     gc_val.line_style = LineSolid;
        !           278: 
        !           279:     newWin->fontGC[0] = XCreateGC(display, txtWin,
        !           280:                                  GCFunction | GCPlaneMask |
        !           281:                                  GCForeground | GCBackground |
        !           282:                                  GCGraphicsExposures | GCFont,
        !           283:                                  &gc_val);
        !           284: 
        !           285:     gc_val.foreground = cur;
        !           286:     newWin->CursorGC = XCreateGC(display, txtWin,
        !           287:                                 GCFunction | GCPlaneMask |
        !           288:                                  GCForeground | GCBackground |
        !           289:                                  GCLineStyle | GCLineWidth,
        !           290:                                  &gc_val);
        !           291: 
        !           292:     gc_val.foreground = bg;
        !           293:     newWin->bgGC = XCreateGC(display, txtWin,
        !           294:                                  GCFunction | GCPlaneMask |
        !           295:                                  GCForeground | GCBackground |
        !           296:                                  GCGraphicsExposures | GCFont,
        !           297:                                  &gc_val);
        !           298: 
        !           299: 
        !           300:     for (index = 1;  index < MAXFONTS;  index++) {
        !           301:        newWin->theFonts[index].fid = 0;
        !           302:        newWin->fontGC[index] = 0;
        !           303:     }
        !           304: 
        !           305:     
        !           306:     /* Initialize size of first line */
        !           307:     newWin->txtBuffer[0]->lineHeight = newWin->theFonts[0].ascent +
        !           308:        newWin->theFonts[0].descent;
        !           309:     newWin->txtBuffer[0]->lineText = 0;
        !           310: 
        !           311:     /* ExposeCopy array initialization */
        !           312:     newWin->exposeSize = 0;
        !           313:     newWin->exposeAlloc = INITEXPARY;
        !           314:     newWin->exposeAry = numalloc(struct expEvent *, INITEXPARY);
        !           315:     for (index = 0;  index < newWin->exposeAlloc;  index++)
        !           316:       newWin->exposeAry[index] = alloc(struct expEvent);
        !           317:     /* Put plus infinity in last slot for sorting purposes */
        !           318:     newWin->exposeAry[0]->lineIndex = MAXINT;
        !           319: 
        !           320:     /* Drawing Position Information */
        !           321:     newWin->curLine = 0;
        !           322:     newWin->curX = 0;
        !           323:     newWin->curY = YPADDING + mainFont->ascent + mainFont->descent;
        !           324: 
        !           325:     /* Attach it to both windows */
        !           326:     XMakeAssoc(display, textWindows, (XID) txtWin, (caddr_t) newWin);
        !           327:     XMakeAssoc(display, textWindows, (XID) newWin->scrollBar, (caddr_t) newWin);
        !           328:     return 1;
        !           329: }
        !           330: 
        !           331: 
        !           332: int TxtRelease(display, w)
        !           333: Display *display;
        !           334: Window w;                      /* Window to release */
        !           335: /*
        !           336:  * This routine releases all resources associated with the
        !           337:  * specified window which are consumed by the text
        !           338:  * window package. This includes the entire text buffer,  line start
        !           339:  * array,  and the scroll bar window.  However,  the window
        !           340:  * itself is NOT destroyed.  The routine will return zero if
        !           341:  * the window is not owned by the text window package.
        !           342:  */
        !           343: {
        !           344:     struct txtWin *textInfo;
        !           345:     int index;
        !           346: 
        !           347:     if ((textInfo = (struct txtWin *) XLookUpAssoc(display,
        !           348:                                                 textWindows, (XID) w)) == 0)
        !           349:       return 0;
        !           350: 
        !           351:     for (index = 0; index < MAXFONTS; index++)
        !           352:        if (textInfo->fontGC[index] != 0)
        !           353:            XFreeGC(display, textInfo->fontGC[index]);
        !           354: 
        !           355:     free((Generic) textInfo->mainBuffer);
        !           356:     for (index = 0;  index < textInfo->numLines;  index++) {
        !           357:        free((Generic) textInfo->txtBuffer[index]);
        !           358:     }
        !           359:     free((Generic) textInfo->txtBuffer);
        !           360:     XDestroyWindow(display, textInfo->scrollBar);
        !           361:     for (index = 0;  index < textInfo->exposeSize;  index++) {
        !           362:        free((Generic) textInfo->exposeAry[index]);
        !           363:     }
        !           364:     free((Generic) textInfo->exposeAry);
        !           365:     XDeleteAssoc(display, textWindows, (XID) w);
        !           366:     free((Generic) textInfo);
        !           367:     return 1;
        !           368: }
        !           369: 
        !           370: 
        !           371: 
        !           372: static int RecompBuffer(textInfo)
        !           373: struct txtWin *textInfo;       /* Text window information */
        !           374: /*
        !           375:  * This routine recomputes all line breaks in a buffer after
        !           376:  * a change in window size or font.  This is done by throwing
        !           377:  * away the old line start array and recomputing it.  Although
        !           378:  * a lot of this work is also done elsewhere,  it has been included
        !           379:  * inline here for efficiency.
        !           380:  */
        !           381: {
        !           382:     int startPos, endSize, linenum;
        !           383:     register int index, chsize, curfont;
        !           384:     register short *bufptr;
        !           385:     register XFontStruct *fontptr;
        !           386:     register struct txtLine *lineptr;
        !           387:     char theChar;
        !           388: 
        !           389:     /* Record the old position so we can come back to it */
        !           390:     for (startPos = textInfo->txtBuffer[textInfo->startLine]->lineText;
        !           391:         (startPos > 0) && (textInfo->mainBuffer[startPos] != '\n');
        !           392:         startPos--)
        !           393:       /* null loop body */;
        !           394:     
        !           395:     /* Clear out the old line start array */
        !           396:     for (index = 0;  index < textInfo->numLines;  index++) {
        !           397:        InitLine(textInfo->txtBuffer[index]);
        !           398:     }
        !           399: 
        !           400:     /* Initialize first line */
        !           401:     textInfo->txtBuffer[0]->lineHeight =
        !           402:        textInfo->theFonts[0].ascent + textInfo->theFonts[0].descent;
        !           403:     textInfo->txtBuffer[0]->lineText = 0;
        !           404: 
        !           405:     /* Process the text back into lines */
        !           406:     endSize = textInfo->w - BARSIZE - WRAPINDSIZE;
        !           407:     bufptr = textInfo->mainBuffer;
        !           408:     lineptr = textInfo->txtBuffer[0];
        !           409:     linenum = 0;
        !           410:     fontptr = &(textInfo->theFonts[0]);
        !           411:     curfont = 0;
        !           412:     for (index = 0;  index < textInfo->bufSpot;  index++) {
        !           413:        theChar = bufptr[index] & CHARMASK;
        !           414:        
        !           415:        if ((bufptr[index] & FONTMASK) != curfont) {
        !           416:            int newFontNum, heightDiff;
        !           417: 
        !           418:            /* Switch fonts */
        !           419:            newFontNum = (bufptr[index] & FONTMASK) >> FONTSHIFT;
        !           420:            if (textInfo->theFonts[newFontNum].fid != 0) {
        !           421:                /* Valid font */
        !           422:                curfont = bufptr[index] & FONTMASK;
        !           423:                fontptr = &(textInfo->theFonts[newFontNum]);
        !           424:                heightDiff = (fontptr->ascent + fontptr->descent) -
        !           425:                    lineptr->lineHeight;
        !           426:                if (heightDiff < 0) heightDiff = 0;
        !           427:                lineptr->lineHeight += heightDiff;
        !           428:            }
        !           429:        }
        !           430:        if (theChar == '\n') {
        !           431:            /* Handle new line */
        !           432:            if (linenum >= textInfo->allocLines-1)
        !           433:              /* Expand number of lines */
        !           434:              ExpandLines(textInfo);
        !           435:            linenum++;
        !           436:            lineptr = textInfo->txtBuffer[linenum];
        !           437:            /* Initialize next line */
        !           438:            lineptr->lineHeight = fontptr->ascent + fontptr->descent;
        !           439:            lineptr->lineText = index+1;
        !           440:            /* Check to see if its the starting line */
        !           441:            if (index == startPos) textInfo->startLine = linenum;
        !           442:        } else {
        !           443:            /* Handle normal character */
        !           444:            chsize = CharSize(textInfo, linenum, index);
        !           445:            if (lineptr->lineWidth + chsize > endSize) {
        !           446:                /* Handle line wrap */
        !           447:                lineptr->lineFlags |= WRAPFLAG;
        !           448:                if (linenum >= textInfo->allocLines-1)
        !           449:                  /* Expand number of lines */
        !           450:                  ExpandLines(textInfo);
        !           451:                linenum++;
        !           452:                lineptr = textInfo->txtBuffer[linenum];
        !           453:                /* Initialize next line */
        !           454:                lineptr->lineHeight = fontptr->ascent + fontptr->descent;
        !           455:                lineptr->lineText = index;
        !           456:                lineptr->lineLength = 1;
        !           457:                lineptr->lineWidth += chsize;
        !           458:            } else {
        !           459:                /* Handle normal addition of character */
        !           460:                lineptr->lineLength += 1;
        !           461:                lineptr->lineWidth += chsize;
        !           462:            }
        !           463:        }
        !           464:     }
        !           465:     /* We now have a valid line array.  Let's clean up some other fields. */
        !           466:     textInfo->numLines = linenum+1;
        !           467:     if (startPos == 0) {
        !           468:        textInfo->startLine = 0;
        !           469:     }
        !           470:     textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
        !           471:     textInfo->curLine = linenum;
        !           472:     /* Check to see if we are at the bottom */
        !           473:     if (textInfo->endLine >= textInfo->numLines-1) {
        !           474:        textInfo->curY = textInfo->h - textInfo->bottomSpace -
        !           475:          lineptr->lineHeight;
        !           476:        textInfo->flagWord &= (~NOTATBOTTOM);
        !           477:     } else {
        !           478:        textInfo->flagWord |= NOTATBOTTOM;
        !           479:     }
        !           480:     return 1;
        !           481: }
        !           482: 
        !           483: 
        !           484: 
        !           485: 
        !           486: int TxtAddFont(display, textWin, fontNumber, newFont, newColor)
        !           487: Display *display;
        !           488: Window textWin;                        /* Scrollable text window  */
        !           489: int fontNumber;                        /* Place to add font (0-7) */
        !           490: XFontStruct *newFont;          /* Font to add             */
        !           491: int newColor;                  /* Color of font           */
        !           492: /*
        !           493:  * This routine loads a new font so that it can be used in a previously
        !           494:  * created text window.  There are eight font slots numbered 0 through 7.
        !           495:  * If there is already a font in the specified slot,  it will be replaced
        !           496:  * and an automatic redraw of the window will take place.  See TxtWriteStr
        !           497:  * for details on using alternate fonts.  The color specifies the foreground
        !           498:  * color of the text.  The default foreground color is used if this
        !           499:  * parameter is TXT_NO_COLOR.  Returns a non-zero value if
        !           500:  * everything went well.
        !           501:  */
        !           502: {
        !           503:     struct txtWin *textInfo;
        !           504:     int redrawFlag;
        !           505:     XGCValues gc_val;
        !           506:     
        !           507:     if ((fontNumber < 0) || (fontNumber >= MAXFONTS)) return 0;
        !           508:     if ((textInfo = (struct txtWin *)
        !           509:         XLookUpAssoc(display, textWindows, (XID) textWin)) == 0)
        !           510:       return 0;
        !           511:     if (newColor == TXT_NO_COLOR) {
        !           512:        newColor = textInfo->fgPix;
        !           513:     }
        !           514: 
        !           515:     gc_val.font = newFont->fid;
        !           516:     gc_val.foreground = newColor;
        !           517:     gc_val.background = textInfo->bgPix;
        !           518:     gc_val.plane_mask = AllPlanes;
        !           519:     gc_val.graphics_exposures = 1;
        !           520:     gc_val.function = GXcopy;
        !           521:     
        !           522:     if (textInfo->fontGC[fontNumber] != 0)
        !           523:     {
        !           524:        XChangeGC(display, textInfo->fontGC[fontNumber],
        !           525:                  GCFont | GCForeground, &gc_val);
        !           526:     }
        !           527:     else
        !           528:        textInfo->fontGC[fontNumber] = XCreateGC(display, textWin,
        !           529:                                                 GCFont |
        !           530:                                                 GCForeground |
        !           531:                                                 GCBackground |
        !           532:                                                 GCFunction |
        !           533:                                                 GCPlaneMask |
        !           534:                                                 GCGraphicsExposures,
        !           535:                                                 &gc_val); 
        !           536: 
        !           537: 
        !           538:     redrawFlag = (textInfo->theFonts[fontNumber].fid != 0) &&
        !           539:       (((newFont) && (newFont->fid != textInfo->theFonts[fontNumber].fid)) ||
        !           540:        (newColor != textInfo->theColors[fontNumber]));
        !           541:     if (newFont) {
        !           542:        textInfo->theFonts[fontNumber] = *newFont;
        !           543:     }
        !           544:     textInfo->theColors[fontNumber] = newColor;
        !           545: 
        !           546:     if (redrawFlag) {
        !           547:        RecompBuffer(textInfo);
        !           548:        XClearWindow(display, textWin);
        !           549:        TxtRepaint(display, textWin);
        !           550:     }
        !           551:     return 1;
        !           552: }
        !           553: 
        !           554: 
        !           555: 
        !           556: int TxtWinP(display, w)
        !           557: Display *display;
        !           558: Window w;
        !           559: /*
        !           560:  * Returns a non-zero value if the window has been previously grabbed
        !           561:  * using TxtGrab and 0 if it has not.
        !           562:  */
        !           563: {
        !           564:     if (XLookUpAssoc(display, textWindows, (XID) w))
        !           565:       return(1);
        !           566:     else return(0);
        !           567: }
        !           568: 
        !           569: 
        !           570: 
        !           571: static int FindEndLine(textInfo, botSpace)
        !           572: struct txtWin *textInfo;
        !           573: int *botSpace;
        !           574: /*
        !           575:  * Given the starting line in 'textInfo->startLine',  this routine
        !           576:  * determines the index of the last line that can be drawn given the
        !           577:  * current size of the screen.  If there are not enough lines to
        !           578:  * fill the screen,  the index of the last line will be returned.
        !           579:  * The amount of empty bottom space is returned in 'botSpace'.
        !           580:  */
        !           581: {
        !           582:     int index, height, lineHeight;
        !           583: 
        !           584:     height = YPADDING;
        !           585:     index = textInfo->startLine;
        !           586:     while (index < textInfo->numLines) {
        !           587:        lineHeight = textInfo->txtBuffer[index]->lineHeight + INTERLINE;
        !           588:        if (height + lineHeight > textInfo->h) break;
        !           589:        height += lineHeight;
        !           590:        index++;
        !           591:     }
        !           592:     if (botSpace) {
        !           593:        *botSpace = textInfo->h - height;
        !           594:     }
        !           595:     return index - 1;
        !           596: }
        !           597: 
        !           598: 
        !           599: 
        !           600: static int UpdateScroll(display, textInfo)
        !           601: Display *display;
        !           602: struct txtWin *textInfo;       /* Text window information */
        !           603: /*
        !           604:  * This routine computes the current extent of the scroll bar
        !           605:  * indicator and repaints the bar with the correct information.
        !           606:  */
        !           607: {
        !           608:     int top, bottom;
        !           609: 
        !           610:     if (textInfo->numLines > 1) {
        !           611:        top = textInfo->startLine * (textInfo->h - 2*BARBORDER) /
        !           612:          (textInfo->numLines - 1);
        !           613:        bottom = textInfo->endLine * (textInfo->h - 2*BARBORDER) /
        !           614:          (textInfo->numLines - 1);
        !           615:     } else {
        !           616:        top = 0;
        !           617:        bottom = textInfo->h - (2*BARBORDER);
        !           618:     }
        !           619: 
        !           620:     /* Draw it - make sure there is a little padding */
        !           621:     if (top == 0) top++;
        !           622:     if (bottom == textInfo->h-(2*BARBORDER)) bottom--;
        !           623: 
        !           624:     XFillRectangle(display, textInfo->scrollBar,
        !           625:                   textInfo->bgGC, 
        !           626:                   0, 0, BARSIZE, top-1);
        !           627:     XFillRectangle(display, textInfo->scrollBar,
        !           628:                   DEFAULT_GC, top, BARSIZE - (2*BARBORDER) - 2,
        !           629:                   bottom - top);
        !           630:     XFillRectangle(display, textInfo->scrollBar, DEFAULT_GC,
        !           631:                   0, bottom+1, BARSIZE,
        !           632:                   textInfo->h - (2 * BARBORDER) - bottom);
        !           633: 
        !           634:     return 1;
        !           635: }
        !           636: 
        !           637: 
        !           638: 
        !           639: 
        !           640: int TxtClear(display, w)
        !           641: Display *display;
        !           642: Window w;
        !           643: /*
        !           644:  * This routine clears a scrollable text window.  It resets the current
        !           645:  * writing position to the upper left hand corner of the screen. 
        !           646:  * NOTE:  THIS ALSO CLEARS THE CONTENTS OF THE TEXT WINDOW BUFFER AND
        !           647:  * RESETS THE SCROLL BAR.  Returns 0 if the window is not a text window.
        !           648:  * This should be used *instead* of XClear.
        !           649:  */
        !           650: {
        !           651:     struct txtWin *textInfo;
        !           652:     int index;
        !           653: 
        !           654:     if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)) == 0)
        !           655:       return 0;
        !           656: 
        !           657:     /* Zero out the arrays */
        !           658:     textInfo->bufSpot = 0;
        !           659:     for (index = 0;  index < textInfo->numLines;  index++) {
        !           660:        InitLine(textInfo->txtBuffer[index]);
        !           661:     }
        !           662:     textInfo->txtBuffer[0]->lineHeight =
        !           663:       textInfo->theFonts[textInfo->curFont].ascent +
        !           664:          textInfo->theFonts[textInfo->curFont].descent;
        !           665: 
        !           666:     textInfo->numLines = 1;
        !           667:     textInfo->startLine = 0;
        !           668:     textInfo->endLine = 0;
        !           669:     textInfo->curLine = 0;
        !           670:     textInfo->curX = 0;
        !           671:     textInfo->curY = YPADDING + textInfo->theFonts[textInfo->curFont].ascent 
        !           672:        + textInfo->theFonts[textInfo->curFont].descent;
        !           673: 
        !           674:     textInfo->bottomSpace = textInfo->h - YPADDING -
        !           675:       textInfo->theFonts[textInfo->curFont].ascent - INTERLINE -
        !           676:          textInfo->theFonts[textInfo->curFont].descent;
        !           677:     /* Actually clear the window */
        !           678:     XClearWindow(display, w);
        !           679: 
        !           680:     /* Draw the current cursor */
        !           681:     XFillRectangle(display, w, textInfo->CursorGC,
        !           682:                   XPADDING + CUROFFSET, textInfo->curY,
        !           683:                   CURSORWIDTH,
        !           684:                   textInfo->theFonts[textInfo->curFont].ascent +
        !           685:                   textInfo->theFonts[textInfo->curFont].descent);
        !           686: 
        !           687:     /* Update the scroll bar */
        !           688:     UpdateScroll(display, textInfo);
        !           689:     return 1;
        !           690: }
        !           691: 
        !           692: 
        !           693: static int WarpToBottom(display, textInfo)
        !           694: Display *display;
        !           695: struct txtWin *textInfo;       /* Text Information */
        !           696: /*
        !           697:  * This routine causes the specified text window to display its
        !           698:  * last screen of information.   It updates the scroll bar
        !           699:  * to the appropriate spot.  The implementation scans backward
        !           700:  * through the buffer to find an appropriate starting spot for
        !           701:  * the window.
        !           702:  */
        !           703: {
        !           704:     int index, height, lineHeight;
        !           705: 
        !           706:     index = textInfo->numLines-1;
        !           707:     height = 0;
        !           708:     while (index >= 0) {
        !           709:        lineHeight = textInfo->txtBuffer[index]->lineHeight + INTERLINE;
        !           710:        if (height + lineHeight > textInfo->h) break;
        !           711:        height += lineHeight;
        !           712:        index--;
        !           713:     }
        !           714:     textInfo->startLine = index + 1;
        !           715:     textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
        !           716:     textInfo->curY = textInfo->h - textInfo->bottomSpace -
        !           717:       textInfo->txtBuffer[textInfo->endLine]->lineHeight;
        !           718:     XClearWindow(display, textInfo->mainWindow);
        !           719:     TxtRepaint(display, textInfo->mainWindow);
        !           720:     return 1;
        !           721: }
        !           722: 
        !           723: 
        !           724: 
        !           725: static int UpdateExposures(display, textInfo)
        !           726: Display *display;
        !           727: struct txtWin *textInfo;       /* Text window information */
        !           728: /*
        !           729:  * Before a new scrolling action occurs,  the text window package
        !           730:  * must handle all COPYEXPOSE events generated by the last scrolling
        !           731:  * action.  This routine is called to do this.  Foreign events (those
        !           732:  * not handled by TxtFilter) are queued up and replaced on the queue
        !           733:  * after the processing of the exposure events is complete.
        !           734:  */
        !           735: {
        !           736: #if 0
        !           737:     XEvent foreignQueue[MAXFOREIGN];
        !           738:     int index, lastItem = 0;
        !           739: 
        !           740:     while (textInfo->flagWord & COPYEXPOSE) {
        !           741:        XNextEvent(display, &(foreignQueue[lastItem]));
        !           742:        if (!TxtFilter(display, &(foreignQueue[lastItem])))
        !           743:          lastItem++;
        !           744:        if (lastItem >= MAXFOREIGN) {
        !           745:            printf("Too many foreign events to queue!\n");
        !           746:            textInfo->flagWord &= (~COPYEXPOSE);
        !           747:        }
        !           748:     }
        !           749:     for (index = 0;  index < lastItem;  index++) {
        !           750:        XPutBackEvent(display, &(foreignQueue[index]));
        !           751:     }
        !           752: #endif
        !           753:     return 1;
        !           754: }
        !           755: 
        !           756: 
        !           757: static int ScrollDown(display,textInfo)
        !           758: Display *display;
        !           759: struct txtWin *textInfo;       /* Text window information */
        !           760: /*
        !           761:  * This routine scrolls the indicated text window down by one
        !           762:  * line.  The line below the current line must exist.  The window
        !           763:  * is scrolled so that the line below the last line is fully
        !           764:  * displayed.  This may cause many lines to scroll off the top.
        !           765:  * Scrolling is done using XCopyArea.  The exposure events should
        !           766:  * be caught using ExposeCopy.
        !           767:  */
        !           768: {
        !           769:     int lineSum, index, targetSpace, freeSpace, updateFlag;
        !           770: 
        !           771:     lineSum = 0;
        !           772:     if (textInfo->endLine + 1 >= textInfo->numLines) return 0;
        !           773:     targetSpace = textInfo->txtBuffer[textInfo->endLine+1]->lineHeight +
        !           774:       INTERLINE;
        !           775:     if (textInfo->bottomSpace < targetSpace) {
        !           776:        index = textInfo->startLine;
        !           777:        while (index < textInfo->endLine) {
        !           778:            lineSum += (textInfo->txtBuffer[index]->lineHeight + INTERLINE);
        !           779:            if (textInfo->bottomSpace + lineSum >= targetSpace) break;
        !           780:            index++;
        !           781:        }
        !           782: 
        !           783:        /* Must move upward by 'lineSum' pixels */
        !           784:        XCopyArea(display, textInfo->mainWindow, textInfo->mainWindow,
        !           785:                  DEFAULT_GC, 0, lineSum,
        !           786:                  textInfo->w - BARSIZE, textInfo->h,
        !           787:                  0, 0);
        !           788: 
        !           789:        textInfo->flagWord |= COPYEXPOSE;
        !           790:        /* Repair the damage to the structures */
        !           791:        textInfo->startLine = index + 1;
        !           792:        updateFlag = 1;
        !           793:     } else {
        !           794:        updateFlag = 0;
        !           795:     }
        !           796:     /* More lines might be able to fit.  Let's check. */
        !           797:     freeSpace = textInfo->bottomSpace + lineSum - targetSpace;
        !           798:     index = textInfo->endLine + 1;
        !           799:     while (index < textInfo->numLines-1) {
        !           800:        if (freeSpace - textInfo->txtBuffer[index+1]->lineHeight - INTERLINE < 0)
        !           801:          break;
        !           802:        freeSpace -= (textInfo->txtBuffer[index+1]->lineHeight + INTERLINE);
        !           803:        index++;
        !           804:     }
        !           805:     textInfo->endLine = index;
        !           806:     textInfo->bottomSpace = freeSpace;
        !           807:     if (updateFlag) {
        !           808:        UpdateExposures(display, textInfo);
        !           809:     }
        !           810:     UpdateScroll(display, textInfo);
        !           811:     return 1;
        !           812: }
        !           813: 
        !           814: 
        !           815: 
        !           816: 
        !           817: static int ExpandLines(textInfo)
        !           818: struct txtWin *textInfo;       /* Text Information */
        !           819: /*
        !           820:  * This routine allocates and initializes additional space in
        !           821:  * the line start array (txtBuffer).  The new space
        !           822:  * is allocated using realloc.  The expansion factor is a percentage
        !           823:  * given by EXPANDPERCENT.
        !           824:  */
        !           825: {
        !           826:     int newSize, index;
        !           827: 
        !           828:     newSize = textInfo->allocLines;
        !           829:     newSize += (newSize * EXPANDPERCENT) / 100;
        !           830: 
        !           831:     textInfo->txtBuffer = (struct txtLine **)
        !           832:       realloc((char *) textInfo->txtBuffer,
        !           833:              (unsigned) (newSize * sizeof(struct txtLine *)));
        !           834:     for (index = textInfo->allocLines;  index < newSize;  index++) {
        !           835:        textInfo->txtBuffer[index] = alloc(struct txtLine);
        !           836:        InitLine(textInfo->txtBuffer[index]);
        !           837:     }
        !           838:     textInfo->allocLines = newSize;
        !           839:     return 1;
        !           840: }
        !           841: 
        !           842: static int ExpandBuffer(textInfo)
        !           843: struct txtWin *textInfo;       /* Text information */
        !           844: /*
        !           845:  * Expands the basic character buffer using realloc.  The expansion
        !           846:  * factor is a percentage given by EXPANDPERCENT.
        !           847:  */
        !           848: {
        !           849:     int newSize;
        !           850: 
        !           851:     newSize = textInfo->bufAlloc + (textInfo->bufAlloc * EXPANDPERCENT) / 100;
        !           852:     textInfo->mainBuffer = (short *)
        !           853:       realloc((char *) textInfo->mainBuffer, (unsigned) newSize * sizeof(short));
        !           854:     textInfo->bufAlloc = newSize;
        !           855:     return 1;
        !           856: }
        !           857: 
        !           858: 
        !           859: 
        !           860: static int HandleNewLine(display, textInfo, flagWord)
        !           861: Display *display;
        !           862: struct txtWin *textInfo;       /* Text Information            */
        !           863: int flagWord;                  /* DODISP or NONEWLINE or both */
        !           864: /*
        !           865:  * This routine initializes the next line for drawing by setting
        !           866:  * its height to the current font height,  scrolls the screen down
        !           867:  * one line,  and updates the current drawing position to the
        !           868:  * left edge of the newly cleared line.  If DODISP is specified,
        !           869:  * the screen will be updated (otherwise not).  If NONEWLINE is
        !           870:  * specified,  no newline character will be added to the text buffer
        !           871:  * (this is for line wrap).
        !           872:  */
        !           873: {
        !           874:     struct txtLine *curLine, *nextLine;
        !           875: 
        !           876:     /* Check to see if a new line must be allocated */
        !           877:     if (textInfo->curLine >= textInfo->allocLines-1)
        !           878:       /* Expand the number of lines */
        !           879:       ExpandLines(textInfo);
        !           880:     textInfo->numLines += 1;
        !           881: 
        !           882:     /* Then we initialize the next line */
        !           883:     nextLine = textInfo->txtBuffer[textInfo->numLines-1];
        !           884:     nextLine->lineHeight =
        !           885:        textInfo->theFonts[textInfo->curFont].ascent +
        !           886:            textInfo->theFonts[textInfo->curFont].descent;
        !           887: 
        !           888:     curLine = textInfo->txtBuffer[textInfo->curLine];
        !           889:     if (flagWord & DODISP) {
        !           890:        /* Scroll down a line if required */
        !           891:        if ((textInfo->curY + curLine->lineHeight +
        !           892:             nextLine->lineHeight + (INTERLINE * 2)) > textInfo->h)
        !           893:          {
        !           894:              ScrollDown(display, textInfo);
        !           895:          }
        !           896:        else
        !           897:          {
        !           898:              /* Update the bottom space appropriately */
        !           899:              textInfo->bottomSpace -= (nextLine->lineHeight + INTERLINE);
        !           900:              textInfo->endLine += 1;
        !           901:          }
        !           902:        /* Update drawing position */
        !           903:        textInfo->curY = textInfo->h -
        !           904:          (textInfo->bottomSpace  + nextLine->lineHeight);
        !           905:     }
        !           906: 
        !           907:     /* Move down a line */
        !           908:     textInfo->curLine += 1;
        !           909:     if (!(flagWord & NONEWLINE)) {
        !           910:        /* Append end-of-line to text buffer */
        !           911:        if (textInfo->bufSpot >= textInfo->bufAlloc) {
        !           912:            /* Allocate more space in main text buffer */
        !           913:            ExpandBuffer(textInfo);
        !           914:        }
        !           915:        textInfo->mainBuffer[(textInfo->bufSpot)++] =
        !           916:          (textInfo->curFont << FONTSHIFT) | '\n';
        !           917:     }
        !           918:     nextLine->lineText = textInfo->bufSpot;
        !           919:     textInfo->curX = 0;
        !           920:     return 1;
        !           921: }
        !           922: 
        !           923: 
        !           924: 
        !           925: static int CharSize(textInfo, lineNum, charNum)
        !           926: struct txtWin *textInfo;       /* Current Text Information */
        !           927: int lineNum;                   /* Line in buffer           */
        !           928: int charNum;                   /* Character in line        */
        !           929: /*
        !           930:  * This routine determines the size of the specified character.
        !           931:  * It takes in account the font of the character and whether its
        !           932:  * fixed or variable.  The size includes INTERSPACE spacing between
        !           933:  * the characters.
        !           934:  */
        !           935: {
        !           936:     register XFontStruct *charFont;
        !           937:     register short *theLine;
        !           938:     register short theChar;
        !           939: 
        !           940:     theLine = &(textInfo->mainBuffer[textInfo->txtBuffer[lineNum]->lineText]);
        !           941:     theChar = theLine[charNum] & CHARMASK;
        !           942:     charFont = &(textInfo->theFonts[(theChar & FONTMASK) >> FONTSHIFT]);
        !           943:     if (theChar <= charFont->min_char_or_byte2 ||
        !           944:        theChar >= charFont->max_char_or_byte2 ||
        !           945:        charFont->per_char == 0)
        !           946:        return  charFont->max_bounds.width + 1;
        !           947:     else
        !           948:        return charFont->per_char[theChar].width + 1;
        !           949: }
        !           950: 
        !           951: 
        !           952: 
        !           953: 
        !           954: 
        !           955: static int HandleBackspace(display, textInfo, flagWord)
        !           956: Display *display;
        !           957: struct txtWin *textInfo;       /* Text Information  */
        !           958: int flagWord;                  /* DODISP or nothing */
        !           959: /*
        !           960:  * This routine handles a backspace found in the input stream.  The
        !           961:  * character before the current writing position will be erased and
        !           962:  * the drawing position will move back one character.  If the writing
        !           963:  * position is at the left margin,  the drawing position will move
        !           964:  * up to the previous line.  If it is a line that has been wrapped,
        !           965:  * the character at the end of the previous line will be erased.
        !           966:  */
        !           967: {
        !           968:     struct txtLine *thisLine, *prevLine;
        !           969:     int chSize;
        !           970: 
        !           971:     thisLine = textInfo->txtBuffer[textInfo->curLine];
        !           972:     /* First,  determine whether we need to go back a line */
        !           973:     if (thisLine->lineLength == 0) {
        !           974:        /* Bleep if at top of buffer */
        !           975:        if (textInfo->curLine == 0) {
        !           976:            XBell(display, 50);
        !           977:            return 0;
        !           978:        }
        !           979: 
        !           980:        /* See if we have to scroll in the other direction */
        !           981:        if ((flagWord & DODISP) && (textInfo->curY <= YPADDING)) {
        !           982:            /* This will display the last lines of the buffer */
        !           983:            WarpToBottom(display, textInfo);
        !           984:        }
        !           985: 
        !           986:        /* Set drawing position at end of previous line */
        !           987:        textInfo->curLine -= 1;
        !           988:        prevLine = textInfo->txtBuffer[textInfo->curLine];
        !           989:        textInfo->numLines -= 1;
        !           990:        if (flagWord & DODISP) {
        !           991:            textInfo->curY -= (prevLine->lineHeight + INTERLINE);
        !           992:            textInfo->bottomSpace += (thisLine->lineHeight + INTERLINE);
        !           993:            textInfo->endLine -= 1;
        !           994:        }
        !           995: 
        !           996:        /* We are unlinewrapping if the previous line has flag set */
        !           997:        if (prevLine->lineFlags & WRAPFLAG) {
        !           998:            /* Get rid of line wrap indicator */
        !           999:            if (flagWord & DODISP) {
        !          1000:                XFillRectangle(display, textInfo->mainWindow,
        !          1001:                               textInfo->bgGC,
        !          1002:                               textInfo->w - BARSIZE - WRAPINDSIZE,
        !          1003:                               textInfo->curY,  WRAPINDSIZE,
        !          1004:                               prevLine->lineHeight);
        !          1005:            }
        !          1006:            prevLine->lineFlags &= (~WRAPFLAG);
        !          1007:            /* Call recursively to wipe out the ending character */
        !          1008:            HandleBackspace(display, textInfo, flagWord);
        !          1009:        } else {
        !          1010:            /* Delete the end-of-line in the primary buffer */
        !          1011:            textInfo->bufSpot -= 1;
        !          1012:        }
        !          1013:     } else {
        !          1014:        /* Normal deletion of character */
        !          1015:        chSize =
        !          1016:          CharSize(textInfo, textInfo->curLine,
        !          1017:                   textInfo->txtBuffer[textInfo->curLine]->lineLength - 1);
        !          1018:        /* Move back appropriate amount and wipe it out */
        !          1019:        thisLine->lineWidth -= chSize;
        !          1020:        if (flagWord & DODISP) {
        !          1021:            XFillRectangle(display, textInfo->mainWindow,
        !          1022:                           textInfo->bgGC,
        !          1023:                           thisLine->lineWidth, textInfo->curY,
        !          1024:                           chSize, thisLine->lineHeight);
        !          1025:        }
        !          1026:        /* Delete from buffer */
        !          1027:        textInfo->txtBuffer[textInfo->curLine]->lineLength -= 1;
        !          1028:        textInfo->bufSpot -= 1;
        !          1029:     }
        !          1030:     return 1;
        !          1031: }
        !          1032: 
        !          1033: 
        !          1034: 
        !          1035: static int DrawLineWrap(display, win, x, y, h, col)
        !          1036: Display *display;
        !          1037: Window win;                    /* What window to draw it in     */
        !          1038: int x, y;                      /* Position of upper left corner */
        !          1039: int h;                         /* Height of indicator           */
        !          1040: int col;                       /* Color of indicator            */
        !          1041: /*
        !          1042:  * This routine draws a line wrap indicator at the end of a line.
        !          1043:  * Visually,  it is an arrow of the specified height directly against
        !          1044:  * the scroll bar border.  The bitmap used for the arrow is stored
        !          1045:  * in 'arrowMap' with size 'arrow_width' and 'arrow_height'.
        !          1046:  */
        !          1047: {
        !          1048:     struct txtWin *textInfo;
        !          1049: 
        !          1050:     textInfo = (struct txtWin *)XLookUpAssoc(display, textWindows,
        !          1051:                                             (XID) win);
        !          1052: 
        !          1053:     /* First,  draw the arrow */
        !          1054:     XCopyArea(display, textInfo->arrowMap, textInfo->mainWindow,
        !          1055:               textInfo->CursorGC,
        !          1056:               0, 0, arrow_width, arrow_height,
        !          1057:               x, y + h - arrow_height, 1);
        !          1058: 
        !          1059:     /* Then draw the stem */
        !          1060:     XDrawLine(display, textInfo->mainWindow, textInfo->CursorGC,
        !          1061:              x + STEMOFFSET, y,
        !          1062:              x + STEMOFFSET, y + h - arrow_height);
        !          1063:     return 1;
        !          1064: }
        !          1065: 
        !          1066: 
        !          1067: 
        !          1068: 
        !          1069: static int DrawLine(display, textInfo, lineIndex, ypos)
        !          1070: Display *display;
        !          1071: struct txtWin *textInfo;       /* Text window information   */
        !          1072: int lineIndex;                 /* Index of line to draw     */
        !          1073: int ypos;                      /* Y position for line       */
        !          1074: /*
        !          1075:  * This routine destructively draws the indicated line in the
        !          1076:  * indicated window at the indicated position.  It does not
        !          1077:  * clear to end of line however.  It draws a line wrap indicator
        !          1078:  * if needed but does not draw a cursor.
        !          1079:  */
        !          1080: {
        !          1081:     int index, startPos, curFont, theColor, curX, saveX, fontIndex;
        !          1082:     struct txtLine *someLine;
        !          1083:     char lineBuffer[BUFSIZE], *glyph;
        !          1084:     short *linePointer;
        !          1085:     XFontStruct *theFont;
        !          1086:     XGCValues gc;
        !          1087: 
        !          1088:     /* First,  we draw the text */
        !          1089:     index = 0;
        !          1090:     curX = XPADDING;
        !          1091:     someLine = textInfo->txtBuffer[lineIndex];
        !          1092:     linePointer = &(textInfo->mainBuffer[someLine->lineText]);
        !          1093:     while (index < someLine->lineLength) {
        !          1094:        startPos = index;
        !          1095:        saveX = curX;
        !          1096:        curFont = linePointer[index] & FONTMASK;
        !          1097:        fontIndex = curFont >> FONTSHIFT;
        !          1098:        theFont = &(textInfo->theFonts[fontIndex]);
        !          1099:        theColor = textInfo->theColors[fontIndex];
        !          1100:        glyph = &(lineBuffer[0]);
        !          1101:        while ((index < someLine->lineLength) &&
        !          1102:               ((linePointer[index] & FONTMASK) == curFont))
        !          1103:        {
        !          1104:            *glyph = linePointer[index] & CHARMASK;
        !          1105:            index++;
        !          1106:            curX += CharSize(textInfo, lineIndex, index);
        !          1107:            glyph++;
        !          1108:        }
        !          1109:        
        !          1110:        /* Flush out the glyphs */
        !          1111:        XFillRectangle(display, textInfo->mainWindow,
        !          1112:                       textInfo->bgGC,
        !          1113:                       saveX, ypos,
        !          1114:                   textInfo->w - BARSIZE,
        !          1115:                   someLine->lineHeight + YPADDING + INTERLINE);
        !          1116: 
        !          1117:        XDrawString(display, textInfo->mainWindow,
        !          1118:                    textInfo->fontGC[fontIndex],
        !          1119:                    saveX, ypos,
        !          1120:                    lineBuffer, someLine->lineLength);
        !          1121:     }
        !          1122:     /* Then the line wrap indicator (if needed) */
        !          1123:     if (someLine->lineFlags & WRAPFLAG) {
        !          1124:        DrawLineWrap(display, textInfo->mainWindow,
        !          1125:                     textInfo->w - BARSIZE - WRAPINDSIZE,
        !          1126:                     ypos, someLine->lineHeight,
        !          1127:                     textInfo->fgPix);
        !          1128:     }
        !          1129:     return 1;
        !          1130: }
        !          1131: 
        !          1132: 
        !          1133: 
        !          1134: 
        !          1135: static int HandleNewFont(display, fontNum, textInfo, flagWord)
        !          1136: Display *display;
        !          1137: int fontNum;                   /* Font number       */
        !          1138: struct txtWin *textInfo;       /* Text information  */
        !          1139: int flagWord;                  /* DODISP or nothing */
        !          1140: /*
        !          1141:  * This routine handles a new font request.  These requests take
        !          1142:  * the form "^F<digit>".  The parsing is done in TxtWriteStr.
        !          1143:  * This routine is called only if the form is valid.  It may return
        !          1144:  * a failure (0 status) if the requested font is not loaded.
        !          1145:  * If the new font is larger than any of the current
        !          1146:  * fonts on the line,  it will change the line height and redisplay
        !          1147:  * the line.
        !          1148:  */
        !          1149: {
        !          1150:     struct txtLine *thisLine;
        !          1151:     int heightDiff, baseDiff, redrawFlag;
        !          1152: 
        !          1153:     if (textInfo->theFonts[fontNum].fid == 0) {
        !          1154:        return 0;
        !          1155:     } else {
        !          1156:        thisLine = textInfo->txtBuffer[textInfo->curLine];
        !          1157:        textInfo->curFont = fontNum;
        !          1158:        redrawFlag = 0;
        !          1159:        heightDiff = textInfo->theFonts[fontNum].ascent +
        !          1160:            textInfo->theFonts[fontNum].descent -
        !          1161:                thisLine->lineHeight;
        !          1162: 
        !          1163:        if (heightDiff > 0) {
        !          1164:            redrawFlag = 1;
        !          1165:        } else {
        !          1166:            heightDiff = 0;
        !          1167:        }
        !          1168: 
        !          1169:        if (redrawFlag) {
        !          1170:            if (flagWord & DODISP) {
        !          1171:                /* Clear current line */
        !          1172:                XFillRectangle(display, textInfo->mainWindow,
        !          1173:                               textInfo->bgGC,
        !          1174:                               0, textInfo->curY, textInfo->w,
        !          1175:                               thisLine->lineHeight);
        !          1176: 
        !          1177:                /* Check to see if it requires scrolling */
        !          1178:                if ((textInfo->curY + thisLine->lineHeight + heightDiff +
        !          1179:                     INTERLINE) > textInfo->h)
        !          1180:                  {
        !          1181:                      /* 
        !          1182:                       * General approach:  "unscroll" the last line up
        !          1183:                       * and then call ScrollDown to do the right thing.
        !          1184:                       */
        !          1185:                      textInfo->endLine -= 1;
        !          1186:                      textInfo->bottomSpace += thisLine->lineHeight +
        !          1187:                          INTERLINE;
        !          1188: 
        !          1189:                      XFillRectangle(display, textInfo->mainWindow,
        !          1190:                                     textInfo->bgGC,
        !          1191:                                     0, textInfo->h - textInfo->bottomSpace,
        !          1192:                                     textInfo->w, textInfo->bottomSpace);
        !          1193: 
        !          1194:                      thisLine->lineHeight += heightDiff;
        !          1195:                      ScrollDown(display, textInfo);
        !          1196:                      textInfo->curY = textInfo->h -
        !          1197:                        (textInfo->bottomSpace + INTERLINE +
        !          1198:                         thisLine->lineHeight);
        !          1199:                  }
        !          1200:                else 
        !          1201:                  {
        !          1202:                      /* Just update bottom space */
        !          1203:                      textInfo->bottomSpace -= heightDiff;
        !          1204:                      thisLine->lineHeight += heightDiff;
        !          1205:                  }
        !          1206:                /* Redraw the current line */
        !          1207:                DrawLine(display, textInfo, textInfo->curLine, textInfo->curY);
        !          1208:            } else {
        !          1209:                /* Just update line height */
        !          1210:                thisLine->lineHeight += heightDiff;
        !          1211:            }
        !          1212:        }
        !          1213:        return 1;
        !          1214:     }
        !          1215: }
        !          1216: 
        !          1217: 
        !          1218: 
        !          1219: int TxtWriteStr(display, w, str)
        !          1220: Display *display;
        !          1221: Window w;                      /* Text window            */
        !          1222: register char *str;            /* 0 terminated string */
        !          1223: /*
        !          1224:  * This routine writes a string to the specified text window.
        !          1225:  * The following notes apply:
        !          1226:  *   - Text is always appended to the end of the text buffer.
        !          1227:  *   - If the scroll bar is positioned such that the end of the
        !          1228:  *     text is not visible,  an automatic scroll to the bottom
        !          1229:  *     will be done before the appending of text.
        !          1230:  *   - Non-printable ASCII characters are not displayed.
        !          1231:  *   - The '\n' character causes the current text position to
        !          1232:  *     advance one line and start at the left.
        !          1233:  *   - Tabs are not supported.
        !          1234:  *   - Lines too long for the screen will be wrapped and a line wrap
        !          1235:  *     indication will be drawn.
        !          1236:  *   - Backspace clears the previous character.  It will do the right
        !          1237:  *     thing if asked to backspace past a wrapped line.
        !          1238:  *   - A new font can be chosen using the sequence '^F<digit>' where
        !          1239:  *     <digit> is 0-7.  The directive will be ignored if
        !          1240:  *     there is no font in the specified slot.
        !          1241:  * Returns 0 if something went wrong.  
        !          1242:  */
        !          1243: {
        !          1244:     register int fontIndex;
        !          1245:     register struct txtWin *textInfo;
        !          1246:     register struct txtLine *thisLine;
        !          1247: 
        !          1248:     if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)) == 0)
        !          1249:       return 0;
        !          1250:     
        !          1251:     /* See if screen needs to be updated */
        !          1252:     if (textInfo->flagWord & SCREENWRONG) {
        !          1253:        TxtRepaint(display, textInfo->mainWindow);
        !          1254:     }
        !          1255: 
        !          1256:     /* See if we have to scroll down to the bottom */
        !          1257:     if (textInfo->flagWord & NOTATBOTTOM) {
        !          1258:        WarpToBottom(display, textInfo);
        !          1259:        textInfo->flagWord &= (~NOTATBOTTOM);
        !          1260:     }
        !          1261: 
        !          1262:     /* Undraw the current cursor */
        !          1263:     thisLine = textInfo->txtBuffer[textInfo->curLine];
        !          1264: 
        !          1265:     XFillRectangle(display, w, textInfo->bgGC,
        !          1266:            thisLine->lineWidth + CUROFFSET,
        !          1267:            textInfo->curY,
        !          1268:            CURSORWIDTH,
        !          1269:            thisLine->lineHeight);
        !          1270: 
        !          1271:     for ( /* str is ok */ ; (*str != 0) ; str++) {
        !          1272:        /* Check to see if we are waiting on a font */
        !          1273:        if (textInfo->flagWord & FONTNUMWAIT) {
        !          1274:            textInfo->flagWord &= (~FONTNUMWAIT);
        !          1275:            fontIndex = *str - '0';
        !          1276:            if ((fontIndex >= 0) && (fontIndex < MAXFONTS)) {
        !          1277:                /* Handle font -- go get next character */
        !          1278:                if (HandleNewFont(display, fontIndex, textInfo, DODISP))
        !          1279:                    continue;
        !          1280:            }
        !          1281:        }
        !          1282:        
        !          1283:        /* Inline code for handling normal character case */
        !          1284:        if ((*str >= LOWCHAR) && (*str <= HIGHCHAR)) {
        !          1285:            register XFontStruct *thisFont;
        !          1286:            register struct txtLine *thisLine;
        !          1287:            register int charWidth;
        !          1288:            int thisColor;
        !          1289: 
        !          1290:            /* Determine size of character */
        !          1291:            thisFont = &(textInfo->theFonts[textInfo->curFont]);
        !          1292:            thisColor = textInfo->theColors[textInfo->curFont];
        !          1293:            if (*str <= thisFont->min_char_or_byte2 ||
        !          1294:                *str >= thisFont->max_char_or_byte2 ||
        !          1295:                thisFont->per_char == 0)
        !          1296:                charWidth = thisFont->max_bounds.width + 1;
        !          1297:            else
        !          1298:                charWidth = thisFont->per_char[*str].width + 1;
        !          1299: 
        !          1300:            /* Check to see if line wrap is required */
        !          1301:            thisLine = textInfo->txtBuffer[textInfo->curLine];
        !          1302:            if (thisLine->lineWidth + charWidth >
        !          1303:                (textInfo->w-BARSIZE-WRAPINDSIZE))
        !          1304:              {
        !          1305:                  DrawLineWrap(display, textInfo->mainWindow,
        !          1306:                               textInfo->w-BARSIZE-WRAPINDSIZE,
        !          1307:                               textInfo->curY, thisLine->lineHeight,
        !          1308:                               textInfo->fgPix);
        !          1309:                  thisLine->lineFlags |= WRAPFLAG;
        !          1310:                  /* Handle the spacing problem the same way as a newline */
        !          1311:                  HandleNewLine(display, textInfo, DODISP | NONEWLINE);
        !          1312:                  thisLine = textInfo->txtBuffer[textInfo->curLine];
        !          1313:              }
        !          1314:            
        !          1315:            /* Ready to draw character */
        !          1316:            XDrawString(display, textInfo->mainWindow,
        !          1317:                        DEFAULT_GC, 
        !          1318:                        textInfo->curX += charWidth,
        !          1319:                        textInfo->curY + thisLine->lineHeight, 
        !          1320:                        str, 1);
        !          1321:            
        !          1322:            /* Append character onto main buffer */
        !          1323:            if (textInfo->bufSpot >= textInfo->bufAlloc)
        !          1324:              /* Make room for more characters */
        !          1325:              ExpandBuffer(textInfo);
        !          1326:            textInfo->mainBuffer[(textInfo->bufSpot)++] =
        !          1327:              (textInfo->curFont << FONTSHIFT) | (*str);
        !          1328:            
        !          1329:            /* Update the line start array */
        !          1330:            thisLine->lineLength += 1;
        !          1331:            thisLine->lineWidth += charWidth;
        !          1332:        } else if (*str == NEWLINE) {
        !          1333:            HandleNewLine(display, textInfo, DODISP);
        !          1334:        } else if (*str == NEWFONT) {
        !          1335:            /* Go into waiting for font number mode */
        !          1336:            textInfo->flagWord |= FONTNUMWAIT;
        !          1337:        } else if (*str == BACKSPACE) {
        !          1338:            HandleBackspace(display, textInfo, DODISP);
        !          1339:        } else {
        !          1340:            /* Ignore all others */
        !          1341:        }
        !          1342:     }
        !          1343:     /* Draw the cursor in its new position */
        !          1344:     thisLine = textInfo->txtBuffer[textInfo->curLine];
        !          1345: 
        !          1346:     XFillRectangle(display, w, textInfo->CursorGC,
        !          1347:            thisLine->lineWidth + CUROFFSET,
        !          1348:            textInfo->curY /* + thisLine->lineHeight */,
        !          1349:            CURSORWIDTH, thisLine->lineHeight);
        !          1350: 
        !          1351:     return 1;
        !          1352: }
        !          1353: 
        !          1354: 
        !          1355: 
        !          1356: int TxtJamStr(display, w, str)
        !          1357: Display *display;
        !          1358: Window w;                      /* Text window            */
        !          1359: register char *str;            /* NULL terminated string */
        !          1360: /*
        !          1361:  * This is the same as TxtWriteStr except the screen is NOT updated.
        !          1362:  * After a call to this routine,  TxtRepaint should be called to
        !          1363:  * update the screen.  This routine is meant to be used to load
        !          1364:  * a text buffer with information and then allow the user to
        !          1365:  * scroll through it at will.
        !          1366:  */
        !          1367: {
        !          1368:     register int fontIndex;
        !          1369:     register struct txtWin *textInfo;
        !          1370: 
        !          1371:     if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)
        !          1372:         ) == 0)
        !          1373:       return 0;
        !          1374:     
        !          1375:     for ( /* str is ok */ ; (*str != 0) ; str++) {
        !          1376:        /* Check to see if we are waiting on a font */
        !          1377:        if (textInfo->flagWord & FONTNUMWAIT) {
        !          1378:            textInfo->flagWord &= (~FONTNUMWAIT);
        !          1379:            fontIndex = *str - '0';
        !          1380:            if ((fontIndex >= 0) && (fontIndex < MAXFONTS)) {
        !          1381:                if (HandleNewFont(display, fontIndex, textInfo, 0)) {
        !          1382:                    /* Handled font -- go get next character */
        !          1383:                    continue;
        !          1384:                }
        !          1385:            }
        !          1386:        }
        !          1387:        /* Inline code for handling normal character case */
        !          1388:        if ((*str >= LOWCHAR) && (*str <= HIGHCHAR)) {
        !          1389:            register XFontStruct *thisFont;
        !          1390:            register struct txtLine *thisLine;
        !          1391:            register int charWidth;
        !          1392:            
        !          1393:            /* Determine size of character */
        !          1394:            thisFont = &(textInfo->theFonts[textInfo->curFont]);
        !          1395: 
        !          1396:            if (*str <= thisFont->min_char_or_byte2 ||
        !          1397:                *str >= thisFont->max_char_or_byte2 ||
        !          1398:                thisFont->per_char == 0)
        !          1399:                charWidth = thisFont->max_bounds.width + 1;
        !          1400:            else
        !          1401:                charWidth = thisFont->per_char[*str].width + 1;
        !          1402: 
        !          1403:            /* Check to see if line wrap is required */
        !          1404:            thisLine = textInfo->txtBuffer[textInfo->curLine];
        !          1405:            if (thisLine->lineWidth + charWidth >
        !          1406:                (textInfo->w-BARSIZE-WRAPINDSIZE))
        !          1407:              {
        !          1408:                  thisLine->lineFlags |= WRAPFLAG;
        !          1409:                  /* Handle the spacing problem the same way as a newline */
        !          1410:                  HandleNewLine(display, textInfo, NONEWLINE);
        !          1411:                  thisLine = textInfo->txtBuffer[textInfo->curLine];
        !          1412:              }
        !          1413:            /* Append character onto main buffer */
        !          1414:            if (textInfo->bufSpot >= textInfo->bufAlloc)
        !          1415:              /* Make room for more characters */
        !          1416:              ExpandBuffer(textInfo);
        !          1417:            textInfo->mainBuffer[(textInfo->bufSpot)++] =
        !          1418:              (textInfo->curFont << FONTSHIFT) | (*str);
        !          1419:            
        !          1420:            /* Update the line start array */
        !          1421:            thisLine->lineLength += 1;
        !          1422:            thisLine->lineWidth += charWidth;
        !          1423:        } else if (*str == NEWLINE) {
        !          1424:            HandleNewLine(display, textInfo, 0);
        !          1425:        } else if (*str == NEWFONT) {
        !          1426:            /* Go into waiting for font number mode */
        !          1427:            textInfo->flagWord |= FONTNUMWAIT;
        !          1428:        } else if (*str == BACKSPACE) {
        !          1429:            HandleBackspace(display, textInfo, 0);
        !          1430:        } else {
        !          1431:            /* Ignore all others */
        !          1432:        }
        !          1433:     }
        !          1434:     textInfo->flagWord |= SCREENWRONG;
        !          1435:     return 1;
        !          1436: }
        !          1437: 
        !          1438: 
        !          1439: 
        !          1440: int TxtRepaint(display,w)
        !          1441: Display *display;
        !          1442: Window w;
        !          1443: /*
        !          1444:  * Repaints the given scrollable text window.  The routine repaints
        !          1445:  * the entire window.  For handling exposure events,  the TxtFilter 
        !          1446:  * routine should be used.
        !          1447:  */
        !          1448: {
        !          1449:     struct txtWin *textInfo;
        !          1450:     int index, ypos;
        !          1451: 
        !          1452:     if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)
        !          1453:         ) == 0)
        !          1454:       return 0;
        !          1455: 
        !          1456:     /* Check to see if the screen is up to date */
        !          1457:     if (textInfo->flagWord & SCREENWRONG) {
        !          1458:        textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
        !          1459:        textInfo->flagWord &= (~SCREENWRONG);
        !          1460:     }
        !          1461: 
        !          1462:     ypos = YPADDING;
        !          1463:     index = textInfo->startLine;
        !          1464:     for (;;) {
        !          1465:        DrawLine(display, textInfo, index, ypos);
        !          1466:        if (index >= textInfo->endLine) break;
        !          1467:        ypos += (textInfo->txtBuffer[index]->lineHeight + INTERLINE);
        !          1468:        index++;
        !          1469:     }
        !          1470:     /* Draw the cursor (if on screen) */
        !          1471:     if (textInfo->endLine == textInfo->curLine) {
        !          1472:        XFillRectangle(display, w, textInfo->CursorGC,
        !          1473:                       textInfo->txtBuffer[index]->lineWidth + CUROFFSET,
        !          1474:                       ypos /* + textInfo->txtBuffer[index]->lineHeight */,
        !          1475:                       CURSORWIDTH, textInfo->txtBuffer[index]->lineHeight);
        !          1476: 
        !          1477:     }
        !          1478:     /* Update the scroll bar */
        !          1479:     UpdateScroll(display, textInfo);
        !          1480:     return 1;
        !          1481: }
        !          1482: 
        !          1483: 
        !          1484: 
        !          1485: static int InsertIndex(textInfo, thisIndex, ypos)
        !          1486: struct txtWin *textInfo;       /* Text Window Information    */
        !          1487: int thisIndex;                 /* Line index of exposed line */
        !          1488: int ypos;                      /* Drawing position of line   */
        !          1489: /*
        !          1490:  * This routine inserts the supplied line index into the copy
        !          1491:  * exposure array for 'textInfo'.  The array is kept sorted
        !          1492:  * from lowest to highest using insertion sort.  The array
        !          1493:  * is dynamically expanded if needed.
        !          1494:  */
        !          1495: {
        !          1496:     struct expEvent *newItem;
        !          1497:     int newSize, index, downIndex;
        !          1498: 
        !          1499:     /* Check to see if we need to expand it */
        !          1500:     if ((textInfo->exposeSize + 3) >= textInfo->exposeAlloc) {
        !          1501:        newSize = textInfo->exposeAlloc +
        !          1502:          (textInfo->exposeAlloc * EXPANDPERCENT / 100);
        !          1503:        textInfo->exposeAry = (struct expEvent **)
        !          1504:          realloc((char *) textInfo->exposeAry,
        !          1505:                  (unsigned) (newSize * sizeof(struct expEvent *)));
        !          1506:        for (index = textInfo->exposeAlloc;  index < newSize;  index++)
        !          1507:          textInfo->exposeAry[index] = alloc(struct expEvent);
        !          1508:        textInfo->exposeAlloc = newSize;
        !          1509:     }
        !          1510:     /* Find spot for insertion.  NOTE: last spot has big number */
        !          1511:     for (index = 0;  index <= textInfo->exposeSize;  index++) {
        !          1512:        if (textInfo->exposeAry[index]->lineIndex >= thisIndex) {
        !          1513:            if (textInfo->exposeAry[index]->lineIndex > thisIndex) {
        !          1514:                /* Insert before this entry */
        !          1515:                newItem = textInfo->exposeAry[textInfo->exposeSize+1];
        !          1516:                for (downIndex = textInfo->exposeSize;
        !          1517:                     downIndex >= index;
        !          1518:                     downIndex--)
        !          1519:                  {
        !          1520:                      textInfo->exposeAry[downIndex+1] =
        !          1521:                        textInfo->exposeAry[downIndex];
        !          1522:                  }
        !          1523:                /* Put a free structure at this spot */
        !          1524:                textInfo->exposeAry[index] = newItem;
        !          1525:                /* Fill it in */
        !          1526:                textInfo->exposeAry[index]->lineIndex = thisIndex;
        !          1527:                textInfo->exposeAry[index]->ypos = ypos;
        !          1528:                /* Break out of loop */
        !          1529:                textInfo->exposeSize += 1;
        !          1530:            }
        !          1531:            break;
        !          1532:        }
        !          1533:     }
        !          1534:     return 1;
        !          1535: }
        !          1536: 
        !          1537: 
        !          1538: 
        !          1539: static int ScrollUp(display, textInfo)
        !          1540: Display *display;
        !          1541: struct txtWin *textInfo;       /* Text window information   */
        !          1542: /*
        !          1543:  * This routine scrolls the indicated text window up by one
        !          1544:  * line.  The line above the current line must exist.  The
        !          1545:  * window is scrolled so that the line above the start line
        !          1546:  * is displayed at the top of the screen.  This may cause
        !          1547:  * many lines to scroll off the bottom.  The scrolling is
        !          1548:  * done using XCopyArea.  The exposure events should be caught
        !          1549:  * by ExposeCopy.
        !          1550:  */
        !          1551: {
        !          1552:     int targetSpace;
        !          1553: 
        !          1554:     /* Make sure all exposures have been handled by now */
        !          1555:     if (textInfo->startLine == 0) return 0;
        !          1556:     targetSpace = textInfo->txtBuffer[textInfo->startLine-1]->lineHeight +
        !          1557:       INTERLINE;
        !          1558:     /* Move the area downward by the target amount */
        !          1559:     XCopyArea(display, textInfo->mainWindow, textInfo->mainWindow,
        !          1560:              DEFAULT_GC,
        !          1561:              0, YPADDING, textInfo->w - BARSIZE,
        !          1562:              textInfo->h, 0, targetSpace);
        !          1563: 
        !          1564:     textInfo->flagWord |= COPYEXPOSE;
        !          1565:     /* Update the text window parameters */
        !          1566:     textInfo->startLine -= 1;
        !          1567:     textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
        !          1568: 
        !          1569:     /* Clear out bottom space region */
        !          1570:     XClearArea(display, textInfo->mainWindow,
        !          1571:               0, textInfo->h - textInfo->bottomSpace,
        !          1572:               textInfo->w, textInfo->bottomSpace);
        !          1573:     
        !          1574:     UpdateExposures(display, textInfo);
        !          1575:     UpdateScroll(display, textInfo);
        !          1576: 
        !          1577:     return 1;
        !          1578: }
        !          1579: 
        !          1580: 
        !          1581: static int ScrollToSpot(display, textInfo, ySpot)
        !          1582: Display *display;
        !          1583: struct txtWin *textInfo;       /* Text window information          */
        !          1584: int ySpot;                     /* Button position in scroll window */
        !          1585: /*
        !          1586:  * This routine scrolls the specified text window relative to the
        !          1587:  * position of the mouse in the scroll bar.  The center of the screen
        !          1588:  * will be positioned to correspond to the mouse position.
        !          1589:  */
        !          1590: {
        !          1591:     int targetLine, aboveLines;
        !          1592: 
        !          1593:     targetLine = textInfo->numLines * ySpot / textInfo->h;
        !          1594:     textInfo->startLine = targetLine;
        !          1595:     textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
        !          1596:     aboveLines = 0;
        !          1597:     /* Make the target line the *center* of the window */
        !          1598:     while ((textInfo->startLine > 0) &&
        !          1599:           (aboveLines < textInfo->endLine - targetLine))
        !          1600:       {
        !          1601:          textInfo->startLine -= 1;
        !          1602:          textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
        !          1603:          aboveLines++;
        !          1604:       }
        !          1605:     if (textInfo->endLine == textInfo->numLines-1) {
        !          1606:        WarpToBottom(display, textInfo);
        !          1607:     } else {
        !          1608:        XClearWindow(display, textInfo->mainWindow);
        !          1609:        TxtRepaint(display, textInfo->mainWindow);
        !          1610:     }
        !          1611:     return 1;
        !          1612: }
        !          1613: 
        !          1614: 
        !          1615: 
        !          1616: static int LineToTop(display, textInfo, pos)
        !          1617: Display *display;
        !          1618: struct txtWin *textInfo;       /* Text window information */
        !          1619: int pos;                       /* Y position of mouse     */
        !          1620: /*
        !          1621:  * This routine scrolls the screen down until the line at the
        !          1622:  * mouse position is at the top of the screen.  It stops
        !          1623:  * if it can't scroll the buffer down that far.  If the
        !          1624:  * global 'ScrollOption' is NORMSCROLL,  a smooth scroll
        !          1625:  * is used.  Otherwise,  it jumps to the right position
        !          1626:  * and repaints the screen.
        !          1627:  */
        !          1628: {
        !          1629:     int index, sum;
        !          1630: 
        !          1631:     /* First,  we find the current line */
        !          1632:     sum = 0;
        !          1633:     for (index = textInfo->startLine;  index <= textInfo->endLine;  index++) {
        !          1634:        if (sum + textInfo->txtBuffer[index]->lineHeight + INTERLINE> pos) break;
        !          1635:        sum += textInfo->txtBuffer[index]->lineHeight + INTERLINE;
        !          1636:     }
        !          1637:     /* We always want to scroll down at least one line */
        !          1638:     if (index == textInfo->startLine) index++;
        !          1639:     if (ScrollOption == NORMSCROLL) {
        !          1640:        /* Scroll down until 'index' is the starting line */
        !          1641:        while ((textInfo->startLine < index) && ScrollDown(display, textInfo))
        !          1642:        {
        !          1643:            /* Empty Loop Body */
        !          1644:        }
        !          1645:     } else {
        !          1646:        /* Immediately jump to correct spot */
        !          1647:        textInfo->startLine = index;
        !          1648:        textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
        !          1649:        if (textInfo->endLine == textInfo->numLines-1) {
        !          1650:            WarpToBottom(display, textInfo);
        !          1651:        } else {
        !          1652:            XClearWindow(display, textInfo->mainWindow);
        !          1653:            TxtRepaint(display, textInfo->mainWindow);
        !          1654:        }
        !          1655:     }
        !          1656:     /* Check to see if at end of buffer */
        !          1657:     if (textInfo->endLine >= textInfo->numLines-1) {
        !          1658:        textInfo->flagWord &= (~NOTATBOTTOM);
        !          1659:     }
        !          1660:     return 1;
        !          1661: }
        !          1662: 
        !          1663: 
        !          1664: 
        !          1665: static int TopToHere(display, textInfo, pos)
        !          1666: Display *display;
        !          1667: struct txtWin *textInfo;       /* Text window information */
        !          1668: int pos;                       /* Y position of mouse     */
        !          1669: /*
        !          1670:  * This routine scrolls the screen up until the top line of
        !          1671:  * the screen is at the current Y position of the mouse.  Again,
        !          1672:  * it will stop if it can't scroll that far.  If the global
        !          1673:  * 'ScrollOption' is NORMSCROLL,  a smooth scroll is used.
        !          1674:  * If it's not,  it will simply redraw the screen at the
        !          1675:  * correct spot.
        !          1676:  */
        !          1677: {
        !          1678:     int sum, target, linesup, index;
        !          1679: 
        !          1680:     target = pos - textInfo->txtBuffer[textInfo->startLine]->lineHeight;
        !          1681:     /* We always want to scroll up at least one line */
        !          1682:     if (target <= 0) target = 1;
        !          1683:     sum = 0;
        !          1684:     linesup = 0;
        !          1685:     /* Check to see if we are at the top anyway */
        !          1686:     if (textInfo->startLine == 0) return 0;
        !          1687:     if (ScrollOption == NORMSCROLL) {
        !          1688:        /* Scroll up until sum of new top lines greater than target */
        !          1689:        while ((sum < target) && ScrollUp(display, textInfo)) {
        !          1690:            sum += textInfo->txtBuffer[textInfo->startLine]->lineHeight;
        !          1691:            linesup++;
        !          1692:        }
        !          1693:     } else {
        !          1694:        /* Search backward to find index */
        !          1695:        index = textInfo->startLine - 1;
        !          1696:        while ((index > 0) && (sum < target)) {
        !          1697:            sum += textInfo->txtBuffer[index]->lineHeight;
        !          1698:            linesup++;
        !          1699:            index--;
        !          1700:        }
        !          1701:        /* Go directly to the index */
        !          1702:        textInfo->startLine = index;
        !          1703:        textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
        !          1704:        XClearWindow(display, textInfo->mainWindow);
        !          1705:        TxtRepaint(display, textInfo->mainWindow);
        !          1706:     }
        !          1707:     /* If we scrolled,  assert we are not at bottom of buffer */
        !          1708:     if (linesup > 0) {
        !          1709:        textInfo->flagWord |= NOTATBOTTOM;
        !          1710:     }
        !          1711:     return 1;
        !          1712: }
        !          1713: 
        !          1714: 
        !          1715: 
        !          1716: int TxtFilter(display, evt)
        !          1717: Display *display;
        !          1718: XEvent *evt;
        !          1719: /*
        !          1720:  * This routine handles events associated with scrollable text windows.
        !          1721:  * It will handle all exposure events and any button released events
        !          1722:  * in the scroll bar of a text window.  It does NOT handle any other
        !          1723:  * events.  If it cannot handle the event,  it will return 0.
        !          1724:  */
        !          1725: {
        !          1726:     XExposeEvent *expose = &evt->xexpose;
        !          1727:     XButtonEvent *btEvt = &evt->xbutton;
        !          1728:     XGraphicsExposeEvent *gexpose = &evt->xgraphicsexpose;
        !          1729:     XNoExposeEvent *noexpose = &evt->xnoexpose;
        !          1730:     struct txtWin *textInfo;
        !          1731:     int index, ypos;
        !          1732:     Window w, sw;
        !          1733: 
        !          1734:     if (textWindows == (XAssocTable *) 0) {
        !          1735:        textWindows = XCreateAssocTable(32);
        !          1736:        if (textWindows == (XAssocTable *) 0) return(0);
        !          1737:     }
        !          1738:     if (evt->type == Expose) {
        !          1739:        w = expose->window;
        !          1740:        sw = 0;
        !          1741:     }
        !          1742:     else if (evt->type == GraphicsExpose) {
        !          1743:        w = gexpose->drawable;
        !          1744:        sw = 0;
        !          1745:     }
        !          1746:     else if (evt->type == NoExpose) {
        !          1747:        w = noexpose->drawable;
        !          1748:        sw = 0;
        !          1749:     }
        !          1750:     else if (evt->type == ButtonRelease) {
        !          1751:        w = btEvt->window;
        !          1752:        sw = btEvt->subwindow;
        !          1753:     }
        !          1754:     else
        !          1755:        return 0;
        !          1756: 
        !          1757:     if ((textInfo = (struct txtWin *)
        !          1758:         XLookUpAssoc(display, textWindows, (XID) w)) == 0)     
        !          1759:        return 0;
        !          1760: 
        !          1761:     /* Determine whether it's main window or not */
        !          1762:     if ((w == textInfo->mainWindow) && (sw == 0)) {
        !          1763:        /* Main Window - handle exposures */
        !          1764:        switch (evt->type) {
        !          1765:        case Expose:
        !          1766:            ypos = 0 /*YPADDING*/;
        !          1767:            for (index = textInfo->startLine;
        !          1768:                 index <= textInfo->endLine;
        !          1769:                 index++)
        !          1770:              {
        !          1771:                  int lh = textInfo->txtBuffer[index]->lineHeight;
        !          1772: 
        !          1773:                  if (((ypos + lh) >= expose->y) &&
        !          1774:                      (ypos <= (expose->y + expose->height)))
        !          1775:                    {
        !          1776:                        /* Intersection region */
        !          1777:                        /* Draw line immediately */
        !          1778:                        DrawLine(display, textInfo, index, ypos);
        !          1779:                        /* And possibly draw cursor */
        !          1780:                        if (textInfo->curLine == index) {
        !          1781:                            XFillRectangle(display, w, textInfo->CursorGC,
        !          1782:                                       textInfo->txtBuffer[index]->lineWidth +
        !          1783:                                           CUROFFSET,
        !          1784:                                           ypos,
        !          1785:                                           CURSORWIDTH,
        !          1786:                                           lh);
        !          1787:                        }
        !          1788:                    }
        !          1789:                  ypos += lh + INTERLINE;
        !          1790:              }
        !          1791:            break;
        !          1792:        case GraphicsExpose:
        !          1793:            ypos = 0 /*YPADDING*/;
        !          1794:            for (index = textInfo->startLine;
        !          1795:                 index <= textInfo->endLine;
        !          1796:                 index++)
        !          1797:              {
        !          1798:                  int lh = textInfo->txtBuffer[index]->lineHeight;
        !          1799: 
        !          1800:                  if (((ypos + lh) >= gexpose->y) &&
        !          1801:                      (ypos <= (gexpose->y + gexpose->height)))
        !          1802:                    {
        !          1803:                        /* Intersection region */
        !          1804:                        /* Draw line immediately */
        !          1805:                        DrawLine(display, textInfo, index, ypos);
        !          1806:                        /* And possibly draw cursor */
        !          1807:                        if (textInfo->curLine == index) {
        !          1808:                            XFillRectangle(display, w, textInfo->CursorGC,
        !          1809:                                    textInfo->txtBuffer[index]->lineWidth +
        !          1810:                                    CUROFFSET,
        !          1811:                                    ypos,
        !          1812:                                    CURSORWIDTH,
        !          1813:                                    lh);
        !          1814:                        }
        !          1815:                    }
        !          1816:                  ypos += lh + INTERLINE;
        !          1817:              }
        !          1818:            break;
        !          1819:        case NoExpose:
        !          1820:            break;
        !          1821:        default:
        !          1822:            /* Not one of our events */
        !          1823:            return 0;
        !          1824:        }
        !          1825:     } else {
        !          1826:        switch (evt->type) {
        !          1827:        case Expose:
        !          1828:            UpdateScroll(display, textInfo);
        !          1829:            break;
        !          1830:        case ButtonRelease:
        !          1831:            /* Find out which button */
        !          1832:            switch (btEvt->button) {
        !          1833:            case Button1:
        !          1834:                /* Scroll up until top line is at mouse position */
        !          1835:                TopToHere(display, textInfo, btEvt->y);
        !          1836:                break;
        !          1837:            case Button2:
        !          1838:                /* Scroll to spot relative to position */
        !          1839:                ScrollToSpot(display, textInfo, btEvt->y);
        !          1840:                if (textInfo->endLine >= textInfo->numLines-1) {
        !          1841:                    textInfo->flagWord &= (~NOTATBOTTOM);
        !          1842:                } else {
        !          1843:                    textInfo->flagWord |= NOTATBOTTOM;
        !          1844:                }
        !          1845:                break;
        !          1846:            case Button3:
        !          1847:                /* Scroll down until pointed line is at top */
        !          1848:                LineToTop(display, textInfo, btEvt->y);
        !          1849:                break;
        !          1850:            }
        !          1851:            break;
        !          1852:        default:
        !          1853:            /* Not one of our events */
        !          1854:            return 0;
        !          1855:        }
        !          1856:     }
        !          1857:     return 1;
        !          1858: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.