[BACK]Return to tty.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/tty.c, Revision 1.6

1.1       deraadt     1: /*
1.2       millert     2:  * Terminfo display driver
1.1       deraadt     3:  *
1.2       millert     4:  * Terminfo is a terminal information database and routines to describe
                      5:  * terminals on most modern UNIX systems.  Many other systems have adopted
1.1       deraadt     6:  * this as a reasonable way to allow for widly varying and ever changing
                      7:  * varieties of terminal types.         This should be used where practical.
                      8:  */
1.5       millert     9: /*
                     10:  * Known problems: If you have a terminal with no clear to end of screen and
                     11:  * memory of lines below the ones visible on the screen, display will be
                     12:  * wrong in some cases.  I doubt that any such terminal was ever made, but I
                     13:  * thought everyone with delete line would have clear to end of screen too...
1.1       deraadt    14:  *
1.5       millert    15:  * Code for terminals without clear to end of screen and/or clear to end of line
                     16:  * has not been extensivly tested.
1.1       deraadt    17:  *
1.5       millert    18:  * Cost calculations are very rough.  Costs of insert/delete line may be far
                     19:  * from the truth.  This is accentuated by display.c not knowing about
                     20:  * multi-line insert/delete.
1.1       deraadt    21:  *
1.5       millert    22:  * Using scrolling region vs insert/delete line should probably be based on cost
                     23:  * rather than the assuption that scrolling region operations look better.
1.1       deraadt    24:  */
                     25:
1.6     ! millert    26: #include "def.h"
1.1       deraadt    27:
1.6     ! millert    28: #include <term.h>
1.5       millert    29:
1.6     ! millert    30: #ifdef NO_RESIZE
        !            31: static int      setttysize     __P((void));
        !            32: #endif /* NO_RESIZE */
1.1       deraadt    33:
1.6     ! millert    34: static int      charcost       __P((char *));
1.1       deraadt    35:
1.6     ! millert    36: static int      cci;
        !            37: static int      insdel;        /* Do we have both insert & delete line? */
        !            38: static char    *scroll_fwd;    /* How to scroll forward. */
1.1       deraadt    39:
                     40: /*
                     41:  * Initialize the terminal when the editor
                     42:  * gets started up.
                     43:  */
1.5       millert    44: VOID
                     45: ttinit()
                     46: {
1.6     ! millert    47:        char    *tv_stype, *p;
        !            48:
        !            49: /* system dependent function to determine terminal type, if necessary. */
        !            50: #ifndef gettermtype
        !            51:        char    *gettermtype();
        !            52: #endif /* gettermtype */
1.1       deraadt    53:
1.2       millert    54:        if ((tv_stype = gettermtype()) == NULL)
1.6     ! millert    55:                panic("Could not determine terminal type!");
        !            56:
1.5       millert    57:        if (setupterm(tv_stype, 1, NULL)) {
1.6     ! millert    58:                (void)asprintf(&p, "Unknown terminal type: %s", tv_stype);
1.2       millert    59:                panic(p);
1.1       deraadt    60:        }
1.6     ! millert    61:
1.2       millert    62:        scroll_fwd = scroll_forward;
1.6     ! millert    63:        if (scroll_fwd == NULL || *scroll_fwd == '\0') {
1.2       millert    64:                /* this is what GNU Emacs does */
                     65:                scroll_fwd = parm_down_cursor;
1.6     ! millert    66:                if (scroll_fwd == NULL || *scroll_fwd == '\0')
1.2       millert    67:                        scroll_fwd = "\n";
1.1       deraadt    68:        }
1.6     ! millert    69:
        !            70:        if (cursor_address == NULL || cursor_up == NULL)
        !            71:                panic("This terminal is too stupid to run mg");
        !            72:
        !            73:        /* set nrow & ncol */
        !            74:        ttresize();
1.1       deraadt    75:
1.2       millert    76:        if (!clr_eol)
                     77:                tceeol = ncol;
                     78:        else
                     79:                tceeol = charcost(clr_eol);
1.1       deraadt    80:
                     81:        /* Estimate cost of inserting a line */
1.2       millert    82:        if (change_scroll_region && scroll_reverse)
1.5       millert    83:                tcinsl = charcost(change_scroll_region) * 2 +
1.6     ! millert    84:                    charcost(scroll_reverse);
1.2       millert    85:        else if (parm_insert_line)
                     86:                tcinsl = charcost(parm_insert_line);
                     87:        else if (insert_line)
                     88:                tcinsl = charcost(insert_line);
                     89:        else
1.6     ! millert    90:                /* make this cost high enough */
        !            91:                tcinsl = NROW * NCOL;
1.1       deraadt    92:
                     93:        /* Estimate cost of deleting a line */
1.2       millert    94:        if (change_scroll_region)
1.5       millert    95:                tcdell = charcost(change_scroll_region) * 2 +
1.6     ! millert    96:                    charcost(scroll_fwd);
1.2       millert    97:        else if (parm_delete_line)
                     98:                tcdell = charcost(parm_delete_line);
                     99:        else if (delete_line)
                    100:                tcdell = charcost(delete_line);
1.5       millert   101:        else
1.6     ! millert   102:                /* make this cost high enough */
        !           103:                tcdell = NROW * NCOL;
1.1       deraadt   104:
                    105:        /* Flag to indicate that we can both insert and delete lines */
1.6     ! millert   106:        insdel = (insert_line || parm_insert_line) &&
        !           107:            (delete_line || parm_delete_line);
1.1       deraadt   108:
1.2       millert   109:        if (enter_ca_mode)
1.6     ! millert   110:                /* enter application mode */
        !           111:                putpad(enter_ca_mode, 1);
1.3       millert   112:
                    113:        setttysize();
1.1       deraadt   114: }
                    115:
                    116: /*
1.4       millert   117:  * Re-initialize the terminal when the editor is resumed.
                    118:  * The keypad_xmit doesn't really belong here but...
                    119:  */
1.5       millert   120: VOID
                    121: ttreinit()
                    122: {
1.4       millert   123:        if (enter_ca_mode)
1.6     ! millert   124:                /* enter application mode */
        !           125:                putpad(enter_ca_mode, 1);
1.4       millert   126:        if (keypad_xmit)
1.6     ! millert   127:                /* turn on keypad */
        !           128:                putpad(keypad_xmit, 1);
1.4       millert   129:
                    130:        setttysize();
                    131: }
                    132:
                    133: /*
1.6     ! millert   134:  * Clean up the terminal, in anticipation of a return to the command
        !           135:  * interpreter. This is a no-op on the ANSI display. On the SCALD display,
        !           136:  * it sets the window back to half screen scrolling. Perhaps it should
        !           137:  * query the display for the increment, and put it back to what it was.
1.1       deraadt   138:  */
1.5       millert   139: VOID
                    140: tttidy()
                    141: {
                    142: #ifdef XKEYS
                    143:        ttykeymaptidy();
1.6     ! millert   144: #endif /* XKEYS */
        !           145:
1.2       millert   146:        /* set the term back to normal mode */
                    147:        if (exit_ca_mode)
                    148:                putpad(exit_ca_mode, 1);
1.1       deraadt   149: }
                    150:
                    151: /*
1.6     ! millert   152:  * Move the cursor to the specified origin 0 row and column position. Try to
        !           153:  * optimize out extra moves; redisplay may have left the cursor in the right
1.1       deraadt   154:  * location last time!
                    155:  */
1.5       millert   156: VOID
                    157: ttmove(row, col)
1.6     ! millert   158:        int row, col;
1.5       millert   159: {
                    160:        if (ttrow != row || ttcol != col) {
                    161:                putpad(tgoto(cursor_address, col, row), 1);
                    162:                ttrow = row;
                    163:                ttcol = col;
                    164:        }
1.1       deraadt   165: }
                    166:
                    167: /*
                    168:  * Erase to end of line.
                    169:  */
1.5       millert   170: VOID
                    171: tteeol()
                    172: {
1.6     ! millert   173:        int     i;
1.2       millert   174:
                    175:        if (clr_eol)
                    176:                putpad(clr_eol, 1);
                    177:        else {
1.6     ! millert   178:                i = ncol - ttcol;
1.2       millert   179:                while (i--)
                    180:                        ttputc(' ');
                    181:                ttrow = ttcol = HUGE;
                    182:        }
1.1       deraadt   183: }
                    184:
                    185: /*
                    186:  * Erase to end of page.
                    187:  */
1.5       millert   188: VOID
                    189: tteeop()
                    190: {
1.6     ! millert   191:        int     line;
1.2       millert   192:
                    193:        if (clr_eos)
                    194:                putpad(clr_eos, nrow - ttrow);
                    195:        else {
                    196:                putpad(clr_eol, 1);
                    197:                if (insdel)
                    198:                        ttdell(ttrow + 1, lines, lines - ttrow - 1);
1.6     ! millert   199:                else {
        !           200:                        /* do it by hand */
1.2       millert   201:                        for (line = ttrow + 1; line <= lines; ++line) {
                    202:                                ttmove(line, 0);
                    203:                                tteeol();
                    204:                        }
                    205:                }
                    206:                ttrow = ttcol = HUGE;
1.1       deraadt   207:        }
                    208: }
                    209:
                    210: /*
                    211:  * Make a noise.
                    212:  */
1.5       millert   213: VOID
                    214: ttbeep()
                    215: {
1.2       millert   216:        putpad(bell, 1);
1.1       deraadt   217:        ttflush();
                    218: }
                    219:
                    220: /*
1.6     ! millert   221:  * Insert nchunk blank line(s) onto the screen, scrolling the last line on
        !           222:  * the screen off the bottom.  Use the scrolling region if possible for a
        !           223:  * smoother display.  If there is no scrolling region, use a set of insert
        !           224:  * and delete line sequences.
1.1       deraadt   225:  */
1.5       millert   226: VOID
                    227: ttinsl(row, bot, nchunk)
1.6     ! millert   228:        int row, bot, nchunk;
1.5       millert   229: {
1.6     ! millert   230:        int     i, nl;
1.1       deraadt   231:
1.6     ! millert   232:        /* Case of one line insert is special. */
        !           233:        if (row == bot) {
        !           234:                ttmove(row, 0);
1.2       millert   235:                tteeol();
                    236:                return;
                    237:        }
                    238:        if (change_scroll_region && scroll_reverse) {
1.5       millert   239:                /* Use scroll region and back index      */
1.2       millert   240:                nl = bot - row;
1.5       millert   241:                ttwindow(row, bot);
1.2       millert   242:                ttmove(row, 0);
                    243:                while (nchunk--)
                    244:                        putpad(scroll_reverse, nl);
                    245:                ttnowindow();
                    246:                return;
                    247:        } else if (insdel) {
1.5       millert   248:                ttmove(1 + bot - nchunk, 0);
1.2       millert   249:                nl = nrow - ttrow;
                    250:                if (parm_delete_line)
                    251:                        putpad(tgoto(parm_delete_line, 0, nchunk), nl);
                    252:                else
1.6     ! millert   253:                        /* For all lines in the chunk... */
1.5       millert   254:                        for (i = 0; i < nchunk; i++)
1.2       millert   255:                                putpad(delete_line, nl);
                    256:                ttmove(row, 0);
1.6     ! millert   257:
        !           258:                /* ttmove() changes ttrow */
        !           259:                nl = nrow - ttrow;
        !           260:
1.2       millert   261:                if (parm_insert_line)
                    262:                        putpad(tgoto(parm_insert_line, 0, nchunk), nl);
                    263:                else
                    264:                        /* For all lines in the chunk */
1.5       millert   265:                        for (i = 0; i < nchunk; i++)
1.2       millert   266:                                putpad(insert_line, nl);
                    267:                ttrow = HUGE;
                    268:                ttcol = HUGE;
                    269:        } else
                    270:                panic("ttinsl: Can't insert/delete line");
1.1       deraadt   271: }
                    272:
                    273: /*
1.6     ! millert   274:  * Delete nchunk line(s) from "row", replacing the bottom line on the
        !           275:  * screen with a blank line.  Unless we're using the scrolling region,
        !           276:  * this is done with crafty sequences of insert and delete lines.  The
        !           277:  * presence of the echo area makes a boundry condition go away.
1.1       deraadt   278:  */
1.5       millert   279: VOID
1.1       deraadt   280: ttdell(row, bot, nchunk)
1.6     ! millert   281:        int row, bot, nchunk;
1.1       deraadt   282: {
1.6     ! millert   283:        int     i, nl;
1.1       deraadt   284:
1.6     ! millert   285:        /* One line special cases */
        !           286:        if (row == bot) {
1.2       millert   287:                ttmove(row, 0);
                    288:                tteeol();
                    289:                return;
                    290:        }
1.6     ! millert   291:        /* scrolling region */
        !           292:        if (change_scroll_region) {
1.2       millert   293:                nl = bot - row;
                    294:                ttwindow(row, bot);
                    295:                ttmove(bot, 0);
                    296:                while (nchunk--)
                    297:                        putpad(scroll_fwd, nl);
                    298:                ttnowindow();
1.6     ! millert   299:        /* else use insert/delete line */
1.5       millert   300:        } else if (insdel) {
1.6     ! millert   301:                ttmove(row, 0);
1.2       millert   302:                nl = nrow - ttrow;
                    303:                if (parm_delete_line)
                    304:                        putpad(tgoto(parm_delete_line, 0, nchunk), nl);
                    305:                else
1.5       millert   306:                        /* For all lines in the chunk    */
                    307:                        for (i = 0; i < nchunk; i++)
1.2       millert   308:                                putpad(delete_line, nl);
1.5       millert   309:                ttmove(1 + bot - nchunk, 0);
1.6     ! millert   310:
        !           311:                /* ttmove() changes ttrow */
        !           312:                nl = nrow - ttrow;
1.2       millert   313:                if (parm_insert_line)
                    314:                        putpad(tgoto(parm_insert_line, 0, nchunk), nl);
                    315:                else
                    316:                        /* For all lines in the chunk */
1.5       millert   317:                        for (i = 0; i < nchunk; i++)
1.2       millert   318:                                putpad(insert_line, nl);
                    319:                ttrow = HUGE;
                    320:                ttcol = HUGE;
                    321:        } else
                    322:                panic("ttdell: Can't insert/delete line");
1.1       deraadt   323: }
                    324:
                    325: /*
1.6     ! millert   326:  * This routine sets the scrolling window on the display to go from line
        !           327:  * "top" to line "bot" (origin 0, inclusive).  The caller checks for the
        !           328:  * pathological 1-line scroll window which doesn't work right and avoids
        !           329:  * it.  The "ttrow" and "ttcol" variables are set to a crazy value to
        !           330:  * ensure that the next call to "ttmove" does not turn into a no-op (the
        !           331:  * window adjustment moves the cursor).
1.1       deraadt   332:  */
1.5       millert   333: VOID
1.1       deraadt   334: ttwindow(top, bot)
1.6     ! millert   335:        int top, bot;
1.1       deraadt   336: {
1.2       millert   337:        if (change_scroll_region && (tttop != top || ttbot != bot)) {
                    338:                putpad(tgoto(change_scroll_region, bot, top), nrow - ttrow);
1.5       millert   339:                ttrow = HUGE;   /* Unknown.              */
1.1       deraadt   340:                ttcol = HUGE;
1.5       millert   341:                tttop = top;    /* Remember region.      */
1.1       deraadt   342:                ttbot = bot;
                    343:        }
                    344: }
                    345:
                    346: /*
1.6     ! millert   347:  * Switch to full screen scroll. This is used by "spawn.c" just before it
        !           348:  * suspends the editor and by "display.c" when it is getting ready to
        !           349:  * exit.  This function does a full screen scroll by telling the terminal
        !           350:  * to set a scrolling region that is lines or nrow rows high, whichever is
        !           351:  * larger.  This behavior seems to work right on systems where you can set
        !           352:  * your terminal size.
1.1       deraadt   353:  */
1.5       millert   354: VOID
1.1       deraadt   355: ttnowindow()
                    356: {
1.2       millert   357:        if (change_scroll_region) {
                    358:                putpad(tgoto(change_scroll_region,
1.5       millert   359:                       (nrow > lines ? nrow : lines) - 1, 0), nrow - ttrow);
                    360:                ttrow = HUGE;   /* Unknown.              */
1.2       millert   361:                ttcol = HUGE;
1.5       millert   362:                tttop = HUGE;   /* No scroll region.     */
1.2       millert   363:                ttbot = HUGE;
                    364:        }
1.1       deraadt   365: }
                    366:
                    367: /*
1.6     ! millert   368:  * Set the current writing color to the specified color. Watch for color
        !           369:  * changes that are not going to do anything (the color is already right)
        !           370:  * and don't send anything to the display.  The rainbow version does this
        !           371:  * in putline.s on a line by line basis, so don't bother sending out the
        !           372:  * color shift.
1.1       deraadt   373:  */
1.5       millert   374: VOID
1.2       millert   375: ttcolor(color)
1.6     ! millert   376:        int color;
1.2       millert   377: {
                    378:        if (color != tthue) {
1.6     ! millert   379:                if (color == CTEXT)
        !           380:                        /* normal video */
1.5       millert   381:                        putpad(exit_standout_mode, 1);
1.6     ! millert   382:                else if (color == CMODE)
        !           383:                        /* reverse video */
1.5       millert   384:                        putpad(enter_standout_mode, 1);
1.6     ! millert   385:                /* save the color */
        !           386:                tthue = color;
1.1       deraadt   387:        }
                    388: }
                    389:
                    390: /*
1.6     ! millert   391:  * This routine is called by the "refresh the screen" command to try
        !           392:  * to resize the display. The new size, which must not exceed the NROW
        !           393:  * and NCOL limits, is stored back into "nrow" and * "ncol". Display can
        !           394:  * always deal with a screen NROW by NCOL. Look in "window.c" to see how
        !           395:  * the caller deals with a change.
1.1       deraadt   396:  */
1.5       millert   397: VOID
                    398: ttresize()
                    399: {
1.6     ! millert   400:        /* found in "ttyio.c" */
        !           401:        setttysize();
1.2       millert   402:
1.6     ! millert   403:        /* ask OS for tty size and check limits */
        !           404:        if (nrow < 1)
1.1       deraadt   405:                nrow = 1;
                    406:        else if (nrow > NROW)
                    407:                nrow = NROW;
                    408:        if (ncol < 1)
                    409:                ncol = 1;
                    410:        else if (ncol > NCOL)
                    411:                ncol = NCOL;
                    412: }
                    413:
                    414: #ifdef NO_RESIZE
1.5       millert   415: static
                    416: setttysize()
                    417: {
1.3       millert   418:        nrow = lines;
                    419:        ncol = columns;
1.1       deraadt   420: }
1.6     ! millert   421: #endif /* NO_RESIZE */
1.1       deraadt   422:
1.6     ! millert   423: /*
        !           424:  * fake char output for charcost()
        !           425:  */
1.5       millert   426: /* ARGSUSED */
1.6     ! millert   427: static int
1.1       deraadt   428: fakec(c)
1.6     ! millert   429:        char c;
1.1       deraadt   430: {
                    431:        cci++;
1.6     ! millert   432:        return 0;
1.1       deraadt   433: }
                    434:
                    435: /* calculate the cost of doing string s */
1.6     ! millert   436: static int
1.5       millert   437: charcost(s)
1.6     ! millert   438:        char *s;
1.5       millert   439: {
1.6     ! millert   440:        int     cci = 0;
1.1       deraadt   441:
1.2       millert   442:        tputs(s, nrow, fakec);
                    443:        return (cci);
1.1       deraadt   444: }