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

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