Annotation of src/usr.bin/mg/tty.c, Revision 1.2
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.1 deraadt 113: }
114:
115: /*
116: * Clean up the terminal, in anticipation of
117: * a return to the command interpreter. This is a no-op
118: * on the ANSI display. On the SCALD display, it sets the
119: * window back to half screen scrolling. Perhaps it should
120: * query the display for the increment, and put it
121: * back to what it was.
122: */
123: tttidy() {
1.2 ! millert 124:
! 125: /* set the term back to normal mode */
! 126: if (exit_ca_mode)
! 127: putpad(exit_ca_mode, 1);
1.1 deraadt 128: #ifdef XKEYS
129: ttykeymaptidy();
130: #endif
131: }
132:
133: /*
134: * Move the cursor to the specified
135: * origin 0 row and column position. Try to
136: * optimize out extra moves; redisplay may
137: * have left the cursor in the right
138: * location last time!
139: */
140: ttmove(row, col) {
141: char *tgoto();
142:
1.2 ! millert 143: if (ttrow != row || ttcol !=col) {
! 144: putpad(tgoto(cursor_address, col, row), 1);
! 145: ttrow = row;
! 146: ttcol = col;
1.1 deraadt 147: }
148: }
149:
150: /*
151: * Erase to end of line.
152: */
153: tteeol() {
1.2 ! millert 154:
! 155: if (clr_eol)
! 156: putpad(clr_eol, 1);
! 157: else {
! 158: int i = ncol - ttcol;
! 159: while (i--)
! 160: ttputc(' ');
! 161: ttrow = ttcol = HUGE;
! 162: }
1.1 deraadt 163: }
164:
165: /*
166: * Erase to end of page.
167: */
168: tteeop() {
1.2 ! millert 169: int line;
! 170:
! 171: if (clr_eos)
! 172: putpad(clr_eos, nrow - ttrow);
! 173: else {
! 174: putpad(clr_eol, 1);
! 175: if (insdel)
! 176: ttdell(ttrow + 1, lines, lines - ttrow - 1);
! 177: else { /* do it by hand */
! 178: for (line = ttrow + 1; line <= lines; ++line) {
! 179: ttmove(line, 0);
! 180: tteeol();
! 181: }
! 182: }
! 183: ttrow = ttcol = HUGE;
1.1 deraadt 184: }
185: }
186:
187: /*
188: * Make a noise.
189: */
190: ttbeep() {
1.2 ! millert 191: putpad(bell, 1);
1.1 deraadt 192: ttflush();
193: }
194:
195: /*
196: * Insert nchunk blank line(s) onto the
197: * screen, scrolling the last line on the
198: * screen off the bottom. Use the scrolling
199: * region if possible for a smoother display.
200: * If no scrolling region, use a set
201: * of insert and delete line sequences
202: */
203: ttinsl(row, bot, nchunk) {
1.2 ! millert 204: int i, nl;
1.1 deraadt 205:
1.2 ! millert 206: if (row == bot) { /* Case of one line insert is */
! 207: ttmove(row, 0); /* special */
! 208: tteeol();
! 209: return;
! 210: }
! 211: if (change_scroll_region && scroll_reverse) {
! 212: /* Use scroll region and back index */
! 213: nl = bot - row;
! 214: ttwindow(row,bot);
! 215: ttmove(row, 0);
! 216: while (nchunk--)
! 217: putpad(scroll_reverse, nl);
! 218: ttnowindow();
! 219: return;
! 220: } else if (insdel) {
! 221: ttmove(1+bot-nchunk, 0);
! 222: nl = nrow - ttrow;
! 223: if (parm_delete_line)
! 224: putpad(tgoto(parm_delete_line, 0, nchunk), nl);
! 225: else
! 226: /* For all lines in the chunk */
! 227: for (i=0; i<nchunk; i++)
! 228: putpad(delete_line, nl);
! 229: ttmove(row, 0);
! 230: nl = nrow - ttrow; /* ttmove() changes ttrow */
! 231: if (parm_insert_line)
! 232: putpad(tgoto(parm_insert_line, 0, nchunk), nl);
! 233: else
! 234: /* For all lines in the chunk */
! 235: for (i=0; i<nchunk; i++)
! 236: putpad(insert_line, nl);
! 237: ttrow = HUGE;
! 238: ttcol = HUGE;
! 239: } else
! 240: panic("ttinsl: Can't insert/delete line");
1.1 deraadt 241: }
242:
243: /*
244: * Delete nchunk line(s) from "row", replacing the
245: * bottom line on the screen with a blank line.
246: * Unless we're using the scrolling region, this is
247: * done with a crafty sequences of insert and delete
248: * lines. The presence of the echo area makes a
249: * boundry condition go away.
250: */
251: ttdell(row, bot, nchunk)
252: {
1.2 ! millert 253: int i, nl;
1.1 deraadt 254:
1.2 ! millert 255: if (row == bot) { /* One line special case */
! 256: ttmove(row, 0);
! 257: tteeol();
! 258: return;
! 259: }
! 260: if (change_scroll_region) { /* scrolling region */
! 261: nl = bot - row;
! 262: ttwindow(row, bot);
! 263: ttmove(bot, 0);
! 264: while (nchunk--)
! 265: putpad(scroll_fwd, nl);
! 266: ttnowindow();
! 267: }
! 268: else if (insdel) {
! 269: ttmove(row, 0); /* Else use insert/delete line */
! 270: nl = nrow - ttrow;
! 271: if (parm_delete_line)
! 272: putpad(tgoto(parm_delete_line, 0, nchunk), nl);
! 273: else
! 274: /* For all lines in the chunk */
! 275: for (i=0; i<nchunk; i++)
! 276: putpad(delete_line, nl);
! 277: ttmove(1+bot-nchunk,0);
! 278: nl = nrow - ttrow; /* ttmove() changes ttrow */
! 279: if (parm_insert_line)
! 280: putpad(tgoto(parm_insert_line, 0, nchunk), nl);
! 281: else
! 282: /* For all lines in the chunk */
! 283: for (i=0; i<nchunk; i++)
! 284: putpad(insert_line, nl);
! 285: ttrow = HUGE;
! 286: ttcol = HUGE;
! 287: } else
! 288: panic("ttdell: Can't insert/delete line");
1.1 deraadt 289: }
290:
291: /*
292: * This routine sets the scrolling window
293: * on the display to go from line "top" to line
294: * "bot" (origin 0, inclusive). The caller checks
295: * for the pathalogical 1 line scroll window that
296: * doesn't work right, and avoids it. The "ttrow"
297: * and "ttcol" variables are set to a crazy value
298: * to ensure that the next call to "ttmove" does
299: * not turn into a no-op (the window adjustment
300: * moves the cursor).
301: *
302: */
303: ttwindow(top, bot)
304: {
1.2 ! millert 305: if (change_scroll_region && (tttop != top || ttbot != bot)) {
! 306: putpad(tgoto(change_scroll_region, bot, top), nrow - ttrow);
1.1 deraadt 307: ttrow = HUGE; /* Unknown. */
308: ttcol = HUGE;
309: tttop = top; /* Remember region. */
310: ttbot = bot;
311: }
312: }
313:
314: /*
315: * Switch to full screen scroll. This is
316: * used by "spawn.c" just before is suspends the
317: * editor, and by "display.c" when it is getting ready
318: * to exit. This function gets to full screen scroll
319: * by telling the terminal to set a scrolling regin
1.2 ! millert 320: * that is lines or nrow rows high, whichever is larger.
1.1 deraadt 321: * This behavior seems to work right on systems
322: * where you can set your terminal size.
323: */
324: ttnowindow()
325: {
1.2 ! millert 326: if (change_scroll_region) {
! 327: putpad(tgoto(change_scroll_region,
! 328: (nrow > lines ? nrow : lines) - 1, 0), nrow - ttrow);
! 329: ttrow = HUGE; /* Unknown. */
! 330: ttcol = HUGE;
! 331: tttop = HUGE; /* No scroll region. */
! 332: ttbot = HUGE;
! 333: }
1.1 deraadt 334: }
335:
336: /*
337: * Set the current writing color to the
338: * specified color. Watch for color changes that are
339: * not going to do anything (the color is already right)
340: * and don't send anything to the display.
341: * The rainbow version does this in putline.s on a
342: * line by line basis, so don't bother sending
343: * out the color shift.
344: */
1.2 ! millert 345: ttcolor(color)
! 346: int color;
! 347: {
! 348:
! 349: if (color != tthue) {
! 350: if (color == CTEXT) /* Normal video. */
! 351: putpad(exit_standout_mode, 1);
! 352: else if (color == CMODE) /* Reverse video. */
! 353: putpad(enter_standout_mode, 1);
! 354: tthue = color; /* Save the color. */
1.1 deraadt 355: }
356: }
357:
358: /*
359: * This routine is called by the
360: * "refresh the screen" command to try and resize
361: * the display. The new size, which must be deadstopped
362: * to not exceed the NROW and NCOL limits, it stored
363: * back into "nrow" and "ncol". Display can always deal
364: * with a screen NROW by NCOL. Look in "window.c" to
365: * see how the caller deals with a change.
366: */
367: ttresize() {
1.2 ! millert 368:
1.1 deraadt 369: setttysize(); /* found in "ttyio.c", */
370: /* ask OS for tty size */
371: if (nrow < 1) /* Check limits. */
372: nrow = 1;
373: else if (nrow > NROW)
374: nrow = NROW;
375: if (ncol < 1)
376: ncol = 1;
377: else if (ncol > NCOL)
378: ncol = NCOL;
379: }
380:
381: #ifdef NO_RESIZE
382: static setttysize() {
383: nrow = tgetnum("li");
384: ncol = tgetnum("co");
385: }
386: #endif
387:
388: static int cci;
389:
390: /*ARGSUSED*/
391: static int /* fake char output for charcost() */
392: fakec(c)
393: char c;
394: {
395: cci++;
396: }
397:
398: /* calculate the cost of doing string s */
399: charcost (s) char *s; {
1.2 ! millert 400: cci = 0;
1.1 deraadt 401:
1.2 ! millert 402: tputs(s, nrow, fakec);
! 403: return (cci);
1.1 deraadt 404: }