|
|
1.1 ! root 1: /* $Header: Xtextlib.c,v 10.6 86/04/23 12:03:28 jg Rel $ */ ! 2: /* Library of routines for creating a simple text output window. ! 3: * ! 4: * Routines in the library are: ! 5: * ! 6: * TextCreate Creates a new instance of a text window ! 7: * TextDestroy Destroys the window ! 8: * TextClear Clears a text window ! 9: * TextRedisplay Redisplays one or all windows ! 10: * TextEvent Handles exposure and unmapping events ! 11: * TextFlush Flush and handle all outstanding events for ! 12: * one or all TextWindows. ! 13: * TextPutString Displays a string in a text window ! 14: * TextPutChar Displays a character in a text window ! 15: * TextPrintf Does a printf in a text window ! 16: * ! 17: * Most of these routines pass around a pointer to a TextWindow data structure: ! 18: * ! 19: * typedef struct _TextWindow { ! 20: * Window w; Window to use ! 21: * FontInfo *font; Font to use for text ! 22: * short num_lines; Number of lines in the window ! 23: * short num_chars; The length of each line ! 24: * short mapped; Whether or not the window is mapped ! 25: * short height; Height of window in pixels ! 26: * short width; Width of window in pixels ! 27: * short first_line; The index of the first line ! 28: * char **lines; Ptr to array of text lines ! 29: * short *line_length; Ptr to array of line lengths (in pixels) ! 30: * short *line_chars; Ptr to array of line lengths in chars ! 31: * short last_line; Which line is the last ! 32: * short last_char; Length of the last line ! 33: * short next_x; X-coord for next character ! 34: * short next_y; Y-coord for next character ! 35: * unsigned int eventmask; List of events we're interested in ! 36: * char *scroll_history; Ptr to list of scroll amounts ! 37: * short scroll_count; Number of outstanding scrolls ! 38: * short scroll_start; Where in the history the history starts ! 39: * short old_scrolls; Number of ignorable outstanding scrolls ! 40: * short fastscroll; Whether or not to use fast scrolling ! 41: * } TextWindow; ! 42: * ! 43: * Applications should not modify anything in this data structure, obviously! ! 44: * They may, however, have reason to get information out of it. (Such as the ! 45: * window id for mapping). ! 46: * ! 47: * Information about the first line of the window is stored in the array ! 48: * entries subscripted by [first_line]; the arrays wrap back up at the end. ! 49: * Last_char should always be the same as line_chars[last_line]. ! 50: * Similarly, next_x should always be the same as line_length[last_line]; ! 51: * ! 52: * The only complicated thing about these procedures is the way they keep ! 53: * track of scrolling. When a scroll is done, X sends ExposeRegions for ! 54: * every region that needs to be patched up and then an ExposeCopy event. ! 55: * The ExposeCopy comes even if there were no regions. The only problem ! 56: * is that more scrolls may have been done in the meantime. So we keep a ! 57: * history of how much cumulative scrolling has been done in the ! 58: * scroll_history list. scroll_start tells which one to start with, and ! 59: * scroll_count tells how many there are (they wrap around). The list is ! 60: * num_lines long since anything that's scrolled away longer ago than that ! 61: * has scrolled off the screen. The old_scrolls field gets set whenever the ! 62: * screen is fully updated for some reason or other; it means that that ! 63: * many ExposeCopy events can be completely ignored since the screen has ! 64: * been fully updated. ! 65: */ ! 66: ! 67: #include <stdio.h> ! 68: #include "Xtext.h" ! 69: ! 70: #ifndef TRUE ! 71: #define TRUE 1 ! 72: #define FALSE 0 ! 73: #endif ! 74: ! 75: /* Define the width of the left margin */ ! 76: ! 77: #define mar_width 2 ! 78: ! 79: char *calloc(), *malloc(), *realloc(); ! 80: ! 81: /* The following variable is sometimes set by TextPutString to temporarily ! 82: disable screen updating. */ ! 83: ! 84: static int dont_update = FALSE; ! 85: ! 86: /* ! 87: * the following variable is the head pointer to a list of TextWindows ! 88: */ ! 89: static TextWindow *head=NULL; ! 90: ! 91: ! 92: /* ! 93: * add a new TextWindow to the list of TextWindows created for this ! 94: * process. ! 95: */ ! 96: static AddTextWindow(t) ! 97: TextWindow *t; ! 98: { ! 99: TextWindow *p; ! 100: ! 101: t->next = NULL; ! 102: if (head) { ! 103: p = head; ! 104: while (p->next) p = p->next; ! 105: p->next = t; ! 106: } else { ! 107: head = t; ! 108: } ! 109: } ! 110: ! 111: ! 112: /* ! 113: * delete a TextWindow from the list of TextWindows created for this ! 114: * process. ! 115: */ ! 116: static DelTextWindow(t) ! 117: TextWindow *t; ! 118: { ! 119: TextWindow *p=head; ! 120: ! 121: if (!p) return; /* shouldn't happen! no list. */ ! 122: if (p==t) { ! 123: head = t->next; ! 124: } else { ! 125: while (p->next && (t != p->next)) p = p->next; ! 126: if (t != p->next) return; /* shouldn't happen! not found */ ! 127: p->next = t->next; ! 128: } ! 129: } ! 130: ! 131: /* TextCreate creates a new window which will use the ! 132: * specified font. The window is height lines high and width ! 133: * characters wide. Note that since a variable-width font may be ! 134: * used, the width is calculated using the average width of the font. ! 135: * Colors are used as specified. ! 136: */ ! 137: ! 138: TextWindow *TextCreate (width, height, x, y, parent, fontname, ! 139: bwidth, fgpixel, bgpixel, bordercolor, fastscroll) ! 140: int height, width, x, y, bwidth, fastscroll; ! 141: Window parent; ! 142: char *fontname; ! 143: int fgpixel, bgpixel; ! 144: Pixmap bordercolor; ! 145: { ! 146: register TextWindow *t; ! 147: register int i; ! 148: register FontInfo *f; ! 149: Window XCreateWindow(); ! 150: Pixmap bgpixmap; ! 151: ! 152: if ((t = (TextWindow *) malloc(sizeof(TextWindow))) == ! 153: NULL) return NULL; ! 154: ! 155: AddTextWindow(t); /* add to list of TextWindows */ ! 156: ! 157: if ((f = t->font = XOpenFont(fontname)) == NULL) { ! 158: TextDestroy(t); ! 159: return NULL; ! 160: } ! 161: ! 162: t->fgpixel = fgpixel; ! 163: t->bgpixel = bgpixel; ! 164: ! 165: if ((bgpixmap = XMakeTile(bgpixel)) == NULL) { ! 166: TextDestroy(t); ! 167: return NULL; ! 168: } ! 169: ! 170: t->width = width * f->width + mar_width; ! 171: t->height = height * f->height; ! 172: ! 173: t->w = XCreateWindow (parent, x, y, t->width, t->height, ! 174: bwidth, bordercolor, bgpixmap); ! 175: if (t->w == NULL) { ! 176: TextDestroy(t); ! 177: XFreePixmap(bgpixmap); ! 178: return NULL; ! 179: } ! 180: ! 181: XFreePixmap(bgpixmap); ! 182: ! 183: t->eventmask = ExposeRegion | ExposeWindow | ExposeCopy | UnmapWindow; ! 184: /* (ExposeRegion automatically selects ExposeWindow) */ ! 185: ! 186: XSelectInput (t->w, t->eventmask); ! 187: ! 188: XSetResizeHint (t->w, mar_width, 0, f->width, f->height); ! 189: t->fastscroll = fastscroll; ! 190: t->mapped = FALSE; ! 191: t->num_lines = height; ! 192: t->num_chars = width; ! 193: ! 194: t->first_line = 0; ! 195: ! 196: if ((t->lines = (char **) ! 197: calloc (height, sizeof (char *))) == NULL) { ! 198: TextDestroy(t); ! 199: return NULL; ! 200: } ! 201: ! 202: if ((t->line_length = (short *) ! 203: calloc (height, sizeof (short))) == NULL) { ! 204: TextDestroy(t); ! 205: return NULL; ! 206: } ! 207: ! 208: if ((t->line_chars = (short *) ! 209: calloc (height, sizeof (short))) == NULL) { ! 210: TextDestroy(t); ! 211: return NULL; ! 212: } ! 213: ! 214: for (i = 0; i < height; i++) { ! 215: if ((t->lines[i] = (char *) ! 216: calloc (width+1, sizeof (char))) == NULL) { ! 217: TextDestroy(t); ! 218: return NULL; ! 219: } ! 220: } ! 221: ! 222: if ((t->scroll_history = calloc(height, sizeof (char))) == NULL) { ! 223: TextDestroy(t); ! 224: return NULL; ! 225: } ! 226: ! 227: t->scroll_count = t->scroll_start = t->old_scrolls = 0; ! 228: TextClear(t); ! 229: return t; ! 230: } ! 231: ! 232: /* Free all the storage associated with a textwindow */ ! 233: ! 234: TextDestroy(t) ! 235: register TextWindow *t; ! 236: { ! 237: register int i; ! 238: ! 239: /* Free things in the order we allocated them. If something doesn't ! 240: exist, don't free it!) */ ! 241: ! 242: if (t->font) { ! 243: if (t->font->fixedwidth == 0) free((char *)t->font->widths); ! 244: free((char *)t->font); ! 245: } ! 246: ! 247: if (t->w) XDestroyWindow(t->w); ! 248: ! 249: if (t->lines) { ! 250: for (i = 0; i < t->num_lines; i++) { ! 251: if (t->lines[i]) free((char *)t->lines[i]); ! 252: } ! 253: free((char *)t->lines); ! 254: } ! 255: ! 256: if (t->line_length) free ((char *)t->line_length); ! 257: if (t->line_chars) free ((char *)t->line_chars); ! 258: if (t->scroll_history) free (t->scroll_history); ! 259: ! 260: ! 261: DelTextWindow(t); /* remove from list of TextWindows */ ! 262: ! 263: /* And finally the data structure itself! */ ! 264: free ((char *)t); ! 265: } ! 266: ! 267: /* Clear out a text window and redisplay */ ! 268: ! 269: TextClear(t) ! 270: register TextWindow *t; ! 271: { ! 272: register int i; ! 273: ! 274: for (i = 0; i < t->num_lines; i++) { ! 275: t->lines[i][0] = '\0'; ! 276: t->line_chars[i] = 0; ! 277: t->line_length[i] = mar_width; /* Allow a left margin */ ! 278: } ! 279: t->last_line = 0; ! 280: t->last_char = 0; ! 281: t->next_x = mar_width; /* Allow a left margin */ ! 282: t->next_y = 0; ! 283: t->first_line = 0; ! 284: ! 285: TextRedisplay(t); ! 286: } ! 287: ! 288: /* Redisplays a text window */ ! 289: ! 290: TextRedisplay (t) ! 291: register TextWindow *t; ! 292: { ! 293: if (t==NULL) { ! 294: for (t = head; t!=NULL; t = t->next) { ! 295: TextRedisplay(t); ! 296: } ! 297: return; ! 298: } ! 299: if (!t->mapped) return; ! 300: ! 301: /* Clear the border area */ ! 302: ! 303: XPixSet(t->w, 0, 0, mar_width, t->height, t->bgpixel); ! 304: ! 305: Redisplay_lines(t, 0, t->num_lines - 1); ! 306: ! 307: /* Any outstanding copies from scrolls can now be ignored */ ! 308: ! 309: t->old_scrolls = t->scroll_count; ! 310: t->scroll_count = t->scroll_start = 0; ! 311: } ! 312: ! 313: Redisplay_lines(t, start, finish) ! 314: register TextWindow *t; ! 315: int start, finish; ! 316: { ! 317: register int i, j, y, height = t->font->height, x, width; ! 318: ! 319: if (finish < 0) return; ! 320: if (start < 0) start = 0; ! 321: ! 322: y = start * height; ! 323: j = start + t->first_line; ! 324: ! 325: for (i = start; i <= finish; i++) { ! 326: if (j >= t->num_lines) j = 0; ! 327: ! 328: if (t->line_chars[j]) { ! 329: XText (t->w, mar_width, y, t->lines[j], t->line_chars[j], ! 330: t->font->id, t->fgpixel, t->bgpixel); ! 331: } ! 332: ! 333: x = t->line_length[j]; ! 334: width = t->width - x; ! 335: ! 336: if (width > 0) XPixSet(t->w, x, y, width, height, t->bgpixel); ! 337: y += height; ! 338: j++; ! 339: } ! 340: } ! 341: ! 342: /* Handles an event. If it's not an event it knows how to deal with, ! 343: returns TRUE, otherwise FALSE. */ ! 344: ! 345: int TextEvent(t, e) ! 346: register TextWindow *t; ! 347: XEvent *e; ! 348: { ! 349: XExposeEvent *ee = (XExposeEvent *) e; ! 350: int offset; ! 351: ! 352: switch (e->type) { ! 353: case ExposeWindow: ! 354: if (ee->height != t->height || ee->width != t->width) { ! 355: Change_text_window_size(t, ee->height / t->font->height, ! 356: ee->width / t->font->width); ! 357: } ! 358: t->mapped = TRUE; ! 359: TextRedisplay(t); ! 360: break; ! 361: ! 362: case ExposeRegion: ! 363: /* If there have been more scrolls than there are lines, ! 364: this stuff has already scrolled off! */ ! 365: ! 366: if (t->scroll_count > t->num_lines) return FALSE; ! 367: ! 368: /* If this is for an old scroll, ignore it */ ! 369: ! 370: if (ee->detail == ExposeCopy && t->old_scrolls) return FALSE; ! 371: ! 372: if (t->scroll_count > 0) { ! 373: offset = t->scroll_history[t->scroll_start]; ! 374: } else offset = 0; ! 375: Redisplay_lines(t, ee->y / t->font->height - offset, ! 376: (ee->y + ee->height - 1) / t->font->height - offset); ! 377: break; ! 378: ! 379: case UnmapWindow: ! 380: t->mapped = FALSE; ! 381: break; ! 382: ! 383: case ExposeCopy: /* We've finished the events for one scroll */ ! 384: /* If there are old scrolls, just decrement the count and ! 385: return */ ! 386: ! 387: if (t->old_scrolls) { ! 388: t->old_scrolls--; ! 389: return FALSE; ! 390: } ! 391: t->scroll_count--; ! 392: if (t->scroll_count < t->num_lines) { ! 393: t->scroll_start++; ! 394: if (t->scroll_start >= t->num_lines) t->scroll_start = 0; ! 395: } ! 396: break; ! 397: ! 398: default: ! 399: return TRUE; ! 400: } ! 401: return FALSE; ! 402: } ! 403: ! 404: /* ! 405: * Flush all outstanding events for all existent TextWindows. ! 406: */ ! 407: TextFlush(t) ! 408: TextWindow *t; ! 409: { ! 410: XEvent e; ! 411: ! 412: if (t==NULL) { ! 413: for (t=head; t!=NULL; t=t->next) { ! 414: TextFlush(t); ! 415: } ! 416: return; ! 417: } ! 418: ! 419: XSync(0); ! 420: ! 421: while (XCheckWindowEvent(t->w,t->eventmask|ExposeWindow,&e)) { ! 422: if (TextEvent(t,&e)) { ! 423: /* ! 424: * We should never get here. Accordingly, we ! 425: * don't do anything if we do, somehow, get here. ! 426: */ ! 427: } ! 428: } ! 429: ! 430: } ! 431: ! 432: Change_text_window_size (t, new_h, new_w) ! 433: register TextWindow *t; ! 434: register int new_h, new_w; ! 435: { ! 436: register int i; ! 437: register char *curline; ! 438: ! 439: Normalize(t); /* Rearrange lines so that first_line = 0 */ ! 440: ! 441: /* First free up any now extraneous lines */ ! 442: ! 443: for (i = new_h; i < t->num_lines; i++) free((char *)t->lines[i]); ! 444: ! 445: if ((t->lines = (char **) ! 446: realloc((char *)t->lines, new_h * sizeof (char *))) == NULL) { ! 447: return; ! 448: } ! 449: ! 450: if ((t->line_length = (short *) ! 451: realloc((char *)t->line_length, new_h * sizeof (short))) == NULL) { ! 452: return; ! 453: } ! 454: ! 455: if ((t->line_chars = (short *) ! 456: realloc((char *)t->line_chars, new_h * sizeof (short))) == NULL) { ! 457: return; ! 458: } ! 459: ! 460: if ((t->scroll_history = realloc(t->scroll_history, new_h)) == NULL) { ! 461: return; ! 462: } ! 463: ! 464: for (i = 0; i < new_h; i++) { ! 465: if (i < t->num_lines) { ! 466: if ((curline = t->lines[i] = ! 467: realloc(t->lines[i], new_w + 1)) == NULL) { ! 468: return; ! 469: } ! 470: ! 471: if (t->line_chars[i] > new_w) { ! 472: t->line_chars[i] = new_w; ! 473: curline[new_w] = '\0'; /* Truncate the line */ ! 474: t->line_length[i] = mar_width + ! 475: XStringWidth (curline, t->font, 0, 0); ! 476: } ! 477: } else { ! 478: if ((t->lines[i] = malloc(new_w+1)) == NULL) { ! 479: return; ! 480: } ! 481: t->lines[i][0] = '\0'; ! 482: t->line_chars[i] = 0; ! 483: t->line_length[i] = mar_width; ! 484: } ! 485: } ! 486: ! 487: if (t->last_line >= new_h) { ! 488: t->last_line = new_h - 1; ! 489: t->last_char = t->line_chars[t->last_line]; ! 490: t->next_x = t->line_length[t->last_line]; ! 491: t->next_y = t->last_line * t->font->height; ! 492: ! 493: } else if (t->last_char > new_w) { ! 494: t->last_char = t->line_chars[t->last_line]; ! 495: t->next_x = t->line_length[t->last_line]; ! 496: } ! 497: ! 498: t->num_lines = new_h; ! 499: t->num_chars = new_w; ! 500: t->height = new_h * t->font->height; ! 501: t->width = new_w * t->font->width + mar_width; ! 502: } ! 503: ! 504: /* Routine to re-arrange the lines in a window structure so that first_line ! 505: is equal to 0. */ ! 506: ! 507: Normalize(t) ! 508: register TextWindow *t; ! 509: { ! 510: if (t->first_line == 0) return; ! 511: ! 512: t->last_line -= t->first_line; ! 513: if (t->last_line < 0) t->last_line += t->num_lines; ! 514: ! 515: Spin_lines(t, 0, t->num_lines-1, t->first_line); ! 516: ! 517: t->first_line = 0; ! 518: } ! 519: ! 520: /* Spin lines rotates the m through n lines of the arrays ! 521: forward offset places. For example, 012345 spun forward 2 is 234501. ! 522: It's straightforward to spin the first part of the arrays; and we ! 523: call Spin_lines recursively to do the last offset elements */ ! 524: ! 525: /* Actually, it's tail-recursive, so I just use a loop. But I can ! 526: pretend, can't I? */ ! 527: ! 528: Spin_lines(t, m, n, offset) ! 529: register TextWindow *t; ! 530: int m, n; ! 531: register int offset; ! 532: { ! 533: register int i; ! 534: register int temp; /* Temporaries */ ! 535: register char *tempc; ! 536: ! 537: while (1) { ! 538: if (offset == 0 || offset > n-m) return; ! 539: ! 540: for (i = m; i <= n-offset; i++) { ! 541: temp = t->line_length[i]; ! 542: t->line_length[i] = t->line_length[offset+i]; ! 543: t->line_length[offset+i] = temp; ! 544: ! 545: temp = t->line_chars[i]; ! 546: t->line_chars[i] = t->line_chars[offset+i]; ! 547: t->line_chars[offset+i] = temp; ! 548: ! 549: tempc = t->lines[i]; ! 550: t->lines[i] = t->lines[offset+i]; ! 551: t->lines[offset+i] = tempc; ! 552: } ! 553: ! 554: /* Spin_lines(t, n-offset+1, n, offset - ((n-m+1) % offset)); */ ! 555: ! 556: temp = m; ! 557: m = n - offset + 1; ! 558: offset -= (n - temp + 1) % offset; ! 559: } ! 560: } ! 561: ! 562: /* Routine to put a string in a text window. If fastscroll is ! 563: set in the TextWindow structure, a single block scroll is done instead ! 564: of scrolling at each newline. */ ! 565: ! 566: #define verybig 10000 /* Amount to scroll if we should refresh instead */ ! 567: ! 568: TextPutString (t, str) ! 569: register TextWindow *t; ! 570: register char *str; ! 571: { ! 572: register char *ch = str; ! 573: register char oldch; ! 574: int jump = t->fastscroll; /* Whether to do jump scrolling */ ! 575: int newlines, scroll; ! 576: ! 577: if (jump) jump = Count_lines (t, str, &newlines, &scroll); ! 578: ! 579: while (1) { ! 580: while (*ch != '\0' && *ch != '\n') ch++; ! 581: if (ch != str) { ! 582: oldch = *ch; ! 583: *ch = '\0'; ! 584: Do_text_string (t, str); ! 585: *ch = oldch; ! 586: } ! 587: if (*ch == '\0') break; ! 588: if (jump && newlines == scroll) { ! 589: Clear_lines (t, newlines); ! 590: dont_update = TRUE; /* Stop updating now */ ! 591: } ! 592: newlines--; ! 593: TextPutChar (t, *ch); ! 594: str = ++ch; ! 595: } ! 596: if (t->mapped && jump) { ! 597: if (scroll != verybig) Scroll_text_window (t, scroll); ! 598: else TextRedisplay (t); ! 599: } ! 600: dont_update = FALSE; ! 601: } ! 602: ! 603: /* Count the number of lines in str, calculate how much scrolling ! 604: will be needed, and return whether this amount is positive */ ! 605: ! 606: int Count_lines (t, str, newlines, scroll) ! 607: register TextWindow *t; ! 608: register char *str; ! 609: int *newlines, *scroll; ! 610: { ! 611: register int num_lines = 0; ! 612: register int lines_left, height = t->num_lines; ! 613: ! 614: *scroll = 0; ! 615: ! 616: while (*str) { ! 617: if (*str++ == '\n') num_lines++; ! 618: } ! 619: ! 620: *newlines = num_lines; ! 621: ! 622: if (num_lines <= 1) return FALSE; /* Don't bother jump scrolling */ ! 623: ! 624: /* Would this fill the screen? */ ! 625: ! 626: if (num_lines >= height) { ! 627: *scroll = verybig; ! 628: return TRUE; ! 629: } ! 630: ! 631: /* Calculate the number of lines left in the window */ ! 632: ! 633: lines_left = height - (t->last_line - t->first_line + 1); ! 634: if (lines_left >= height) lines_left -= height; ! 635: ! 636: /* Figure out how many lines to scroll */ ! 637: ! 638: num_lines -= lines_left; ! 639: ! 640: if (num_lines <= 0) return FALSE; /* Enough room already */ ! 641: ! 642: *scroll = num_lines; ! 643: return TRUE; ! 644: } ! 645: ! 646: /* Clear a number of lines in the window data structure */ ! 647: ! 648: Clear_lines (t, scroll) ! 649: register TextWindow *t; ! 650: register int scroll; ! 651: { ! 652: register int i, start = t->first_line; ! 653: register int height = t->num_lines; ! 654: ! 655: /* If this would fill the screen, clear it instead */ ! 656: ! 657: if (scroll >= t->height ) { ! 658: TextClear (t); ! 659: return; ! 660: } ! 661: ! 662: /* Shift the contents */ ! 663: ! 664: t->first_line += scroll; ! 665: if (t->first_line >= height) t->first_line -= height; ! 666: ! 667: /* Now clear the blank lines */ ! 668: ! 669: for (i = 0; i < scroll; i++) { ! 670: t->lines[start][0] = '\0'; ! 671: t->line_chars[start] = 0; ! 672: t->line_length[start] = mar_width; /* Allow a left margin */ ! 673: start++; ! 674: if (start >= height) start = 0; ! 675: } ! 676: } ! 677: ! 678: /* Store the characters of a string in the window and update the screen, ! 679: but only if dont_update isn't set */ ! 680: ! 681: Do_text_string (t, str) ! 682: register TextWindow *t; ! 683: char *str; ! 684: { ! 685: register char *ch = str; ! 686: register char *curline = t->lines[t->last_line]; ! 687: register int curchar = t->last_char; ! 688: register int x = t->next_x; ! 689: register FontInfo *f = t->font; ! 690: int start_x = t->next_x, start = curchar, ! 691: minch = f->firstchar, maxch = f->lastchar; ! 692: ! 693: /* First store the characters in the line */ ! 694: ! 695: while (*ch != '\0' && curchar < t->num_chars) { ! 696: curline[curchar] = *ch; ! 697: if (*ch >= minch && *ch <= maxch) { ! 698: x += f->fixedwidth ? f->width : f->widths[*ch - minch]; ! 699: } ! 700: curchar++; ! 701: ch++; ! 702: } ! 703: ! 704: curline[curchar] = '\0'; ! 705: t->line_chars[t->last_line] = t->last_char = curchar; ! 706: t->line_length[t->last_line] = t->next_x = x; ! 707: ! 708: if (dont_update || !t->mapped) return; ! 709: ! 710: /* And then update the screen */ ! 711: ! 712: if (start < t->num_chars) { ! 713: XText (t->w, start_x, t->next_y, str, curchar-start, ! 714: f->id, t->fgpixel, t->bgpixel); ! 715: } ! 716: } ! 717: ! 718: /* Textputchar displays a character in the text window. It ! 719: * responds to \n as a special character and just displays anything else. ! 720: */ ! 721: ! 722: TextPutChar (t, ch) ! 723: register TextWindow *t; ! 724: char ch; ! 725: { ! 726: register int i, height = t->num_lines; ! 727: register char *curline = t->lines[t->last_line]; ! 728: register FontInfo *f = t->font; ! 729: ! 730: switch (ch) { ! 731: case '\0': /* NULL */ ! 732: break; ! 733: ! 734: case '\n': /* newline */ ! 735: if (t->last_line == t->first_line - 1 || ! 736: (t->last_line == height - 1 && t->first_line == 0)) { ! 737: ! 738: /* The screen is full...clear out the first line */ ! 739: ! 740: t->lines[t->first_line][0] = '\0'; ! 741: t->line_chars[t->first_line] = 0; ! 742: t->line_length[t->first_line] = mar_width; ! 743: ! 744: t->first_line++; /* And advance it */ ! 745: if (t->first_line == height) t->first_line = 0; ! 746: ! 747: if (!dont_update && t->mapped) Scroll_text_window (t, 1); ! 748: ! 749: } else if (!dont_update) t->next_y += f->height; ! 750: ! 751: t->last_line++; ! 752: if (t->last_line == height) t->last_line = 0; ! 753: ! 754: t->last_char = 0; ! 755: t->next_x = mar_width; ! 756: break; ! 757: ! 758: default: /* Just insert the character */ ! 759: t->last_char++; ! 760: t->line_chars[t->last_line]++; ! 761: if (t->last_char > t->num_chars) break; ! 762: ! 763: curline[t->last_char] = ch; ! 764: curline[t->last_char+1] = '\0'; ! 765: ! 766: if (!dont_update && t->mapped) { ! 767: XText(t->w, t->next_x, t->next_y, &ch, 1, ! 768: f->id, t->fgpixel, t->bgpixel); ! 769: } ! 770: if (ch <= f->firstchar && ch >= f->lastchar) { ! 771: t->line_length[t->last_line] = t->next_x += ! 772: (f->fixedwidth ? f->width : ! 773: f->widths[ch - f->lastchar]); ! 774: } ! 775: break; ! 776: } ! 777: } ! 778: ! 779: /* This procedure moves the contents of a text window up n lines. ! 780: */ ! 781: ! 782: Scroll_text_window (t, n) ! 783: register TextWindow *t; ! 784: register int n; ! 785: { ! 786: register int i, y, x, width, j; ! 787: int height = t->font->height; ! 788: int scrollsize = n * height; ! 789: ! 790: /* First shift up the contents */ ! 791: ! 792: XMoveArea(t->w, 0, scrollsize, 0, 0, t->width, t->height-scrollsize); ! 793: ! 794: /* Now redisplay the bottom n lines */ ! 795: ! 796: y = height * (t->num_lines - n); ! 797: i = t->first_line - n; ! 798: if (i < 0) i += t->num_lines; ! 799: ! 800: for (j = 0; j < n; j++) { ! 801: if (t->line_chars[i]) { ! 802: XText (t->w, mar_width, y, t->lines[i], t->line_chars[i], ! 803: t->font->id, t->fgpixel, t->bgpixel); ! 804: } ! 805: x = t->line_length[i]; ! 806: width = t->width - x; ! 807: ! 808: if (width > 0) XPixSet(t->w, x, y, width, height, t->bgpixel); ! 809: y += height; ! 810: i++; ! 811: if (i == t->num_lines) i = 0; ! 812: } ! 813: ! 814: /* Add the current scroll to all values in the scroll history, ! 815: then add a new entry at the end (the history wraps!) */ ! 816: ! 817: i = t->scroll_start; ! 818: ! 819: for (j = 0; j < t->scroll_count; j++) { ! 820: t->scroll_history[i] += n; ! 821: i++; ! 822: if (i >= t->num_lines) i = 0; ! 823: } ! 824: t->scroll_count++; ! 825: t->scroll_history[i] = n; ! 826: ! 827: if (t->scroll_count > t->num_lines) t->scroll_start++; /* trash one */ ! 828: } ! 829: ! 830: #define TEXT_BUFSIZE 2048 ! 831: ! 832: TextPrintf(t, format, args) ! 833: TextWindow *t; ! 834: char *format; ! 835: { ! 836: char buffer[TEXT_BUFSIZE+1]; ! 837: struct _iobuf _strbuf; ! 838: ! 839: _strbuf._flag = _IOWRT+_IOSTRG; ! 840: _strbuf._ptr = buffer; ! 841: _strbuf._cnt = TEXT_BUFSIZE; ! 842: _doprnt(format, &args, &_strbuf); ! 843: _strbuf._cnt++; /* Be sure there's room for the \0 */ ! 844: putc('\0', &_strbuf); ! 845: TextPutString(t, buffer); ! 846: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.