|
|
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.