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

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