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