Annotation of 43BSDReno/games/chess/Xchess/scrollText.c, revision 1.1.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.