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

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