Annotation of 43BSDTahoe/new/X/Xlib/Xtextlib.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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