Annotation of 43BSDTahoe/new/X/Xlib/Xtextlib.c, revision 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.