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: }

Defined functions

Change_text_window_size defined in line 348; used 1 times
Clear_lines defined in line 564; used 1 times
Count_lines defined in line 522; used 1 times
Do_text_string defined in line 597; used 1 times
Normalize defined in line 423; used 1 times
Redisplay_lines defined in line 257; used 2 times
Scroll_text_window defined in line 698; used 2 times
Spin_lines defined in line 444; used 1 times
TextClear defined in line 219; used 2 times
TextCreate defined in line 92; used 1 times
TextDestroy defined in line 186; used 8 times
TextEvent defined in line 289; never used
TextPrintf defined in line 748; never used
TextPutChar defined in line 638; used 1 times
TextPutString defined in line 484; used 1 times
TextRedisplay defined in line 240; used 3 times

Defined variables

dont_update defined in line 83; used 6 times

Defined macros

FALSE defined in line 71; used 10 times
TEXT_BUFSIZE defined in line 746; used 2 times
TRUE defined in line 70; used 6 times
mar_width defined in line 76; used 13 times
verybig defined in line 482; used 2 times
Last modified: 1986-02-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2416
Valid CSS Valid XHTML 1.0 Strict