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: }