|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.