Annotation of 43BSD/contrib/X/Xlib/Xtextlib.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.