home *** CD-ROM | disk | FTP | other *** search
- /*
- *************
- * DISTRIBUTION NOTICE July 30 1985
- * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
- * Research Triangle Institute, (919) 541-7005.
- * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
- * Naval Research Laboratory, (202) 767-3365.
- * No claims or warranties of any sort are made for this distribution.
- * General permission is granted to copy, but not for profit,
- * any of this distribution, provided that this notice
- * is always included in the copies.
- *************
- */
- /*
- * This file contains routines for low-level virtual
- * terminal emulation.
- */
-
- #include "wm.h"
-
- #define FULLWIDTH(wp) (wcols(wp)==COLS)
- #define FULLSCREEN(wp) (FULLWIDTH(wp) && wlines(wp)==LINES-1)
-
- /* Termcap entry for virtual terminals.
- */
- static char TERMCAP[]="wm|wmvirt|wm virtual terminal:am:bs:ce=\\EK:ho=\\EH:cd=\\EB:cl=\\ES:nd=\\EC:up=\\EA:cm=\\EY%+ %+ :";
- #define TBUFLEN (sizeof(TERMCAP)+300) /* max length of termcap string */
-
- extern char *tgoto(), *tparm();
-
- /*
- * Add 'n' characters of 'p' to window 'w' at its current (y, x) coordinate.
- */
- WMaddbuf(w, p, n)
- int w;
- register char *p;
- register int n;
- {
- register WINDOW *wp;
- register int y, x;
- register int c;
-
- /*
- * Are we in the midst of an escape sequence?
- */
- while (win[w].pend[0] && --n >= 0)
- WMescape(w, toascii(*p++));
-
- wp = win[w].wptr;
- getyx(wp, y, x);
-
-
- while (--n >= 0) switch (c = toascii(*p++))
- {
- case '\t':
- x = (x+8) & ~07;
- while (x >= wcols(wp)) {
- WMaddbuf(w, "\n", 1);
- x -= wcols(wp);
- }
- wmove(wp, y = wcury(wp), x);
- break;
- case '\n':
- if (++y >= wlines(wp)) {
- --y;
- wmove(wp, 0, x); WMdeleteln(w);
- }
- wmove(wp, y, x);
- break;
- case '\r':
- wmove(wp, y, x = 0);
- break;
- case '\b':
- if (x>0) wmove(wp, y, --x);
- break;
- case '\007':
- beep();
- break;
- case '\0':
- break;
- case ESC:
- win[w].pend[0] = ESC;
- win[w].pend[1] = '\0';
- while (win[w].pend[0] && --n >= 0)
- WMescape(w, toascii(*p++));
- getyx(wp, y, x);
- break;
- /* Dummy cases to fool pcc into generating a fast switch table */
- case 01: case 02: case 03: case 04: case 05: case 06:
- default:
- if (isprint(c))
- {
- waddch(wp, c);
- if (++x >= wcols(wp)) {
- if (++y >= wlines(wp)) {
- --y;
- wmove(wp, 0, 0); WMdeleteln(w);
- }
- wmove(wp, y, x = 0);
- }
- }
- else
- {
- char *s = mkprint(c);
- WMaddbuf(w, s, strlen(s));
- getyx(wp, y, x);
- }
- break;
- }
- }
-
- /*
- * Construct virtual terminal escape sequence
- * one character at a time.
- * When escape sequence is complete, perform
- * the indicated action in window 'w'.
- */
- WMescape(w, c)
- int w;
- int c;
- {
- register WINDOW *wp;
- register int y, x;
- register char *pend;
- int oldx, oldy;
-
-
- pend = win[w].pend;
- wp = win[w].wptr;
- getyx(wp, y, x);
-
- /* ESC-Y is a multi-character escape sequence
- * so we need to make sure we have all the
- * characters before we start processing it.
- */
- if (c == 'Y' && pend[1] == '\0') { pend[1]=c; pend[2]='\0'; return; }
-
- else if (pend[1] == 'Y')
- {
- if (pend[2]=='\0') { pend[2]=c; return; }
- else { pend[3]=c; c='Y'; }
- }
-
- /* Process escape sequence.
- */
- pend[0] = '\0'; /* escape no longer pending */
- switch (c)
- {
- case 'Y': /* cursor motion */
- y = oldy = pend[2]-' '; x = oldx = pend[3]-' ';
- if (x < 0) x = 0;
- if (y < 0) y = 0;
- if (x >= wcols(wp)) x = wcols(wp)-1;
- if (y >= wlines(wp)) y = wlines(wp)-1;
- if (y != oldy || x != oldx)
- showmsg("Bad cursor motion to (%d,%d).", oldy, oldx);
- wmove(wp, y, x);
- break;
- case 'K': /* clear to end of line */
- wclrtoeol(wp);
- break;
- case 'B': /* clear to bottom of window */
- wclrtobot(wp);
- break;
- case 'H': /* home cursor */
- wmove(wp, 0, 0);
- break;
- case 'R': /* visual bell */
- flash();
- break;
- case 'D': /* delete line */
- WMdeleteln(w);
- break;
- case 'L': /* insert line */
- WMinsertln(w);
- break;
- case 'P': /* insert character */
- #ifdef CURSEASSIST
- #ifndef TERMINFO
- if (FULLWIDTH(wp) && insert_character && !insert_null_glitch) {
- (void) movecursor(wbegy(wp)+y, wbegx(wp)+x);
- putp(insert_character); winsch(curscr, ' ');
- }
- #endif
- #endif
- winsch(wp, ' ');
- break;
- case 'Q': /* delete character */
- #ifdef CURSEASSIST
- #ifndef TERMINFO
- if (FULLWIDTH(wp) && delete_character) {
- (void) movecursor(wbegy(wp)+y, wbegx(wp)+x);
- putp(delete_character); wdelch(curscr);
- }
- #endif
- #endif
- wdelch(wp);
- break;
- case 'S': /* erase window */
- werase(wp);
- #ifdef CURSEASSIST
- if (FULLSCREEN(wp) && !msgbirth)
- clearok(curscr, TRUE);
- #endif
- break;
- case 'C': /* non-destructive blank */
- if (++x >= wcols(wp)) {
- WMaddbuf(w, "\n", 1);
- x = 0;
- }
- wmove(wp, wcury(wp), x);
- break;
- case 'A': /* cursor up */
- if (--y>=0) wmove(wp, y, x);
- break;
- case 'O': /* enter standout mode */
- wstandout(wp);
- break;
- case 'E': /* leave standout mode */
- wstandend(wp);
- break;
- default:
- {
- char *s;
- s = mkprint(ESC);
- WMaddbuf(w, s, strlen(s));
- s = mkprint(c);
- WMaddbuf(w, s, strlen(s));
- }
- break;
- }
- }
-
- /*
- * Insert a line just above the current line of window wp.
- * The cursor location in wp is not changed.
- */
- WMinsertln(w)
- int w;
- {
- register WINDOW *wp;
- register int curline, curcol;
-
- wp = win[w].wptr;
- wrefresh(wp); /* smooths scrolling. Crucial for untouchwin. */
- winsertln(wp);
-
- #ifdef CURSEASSIST
- /* If this terminal has scrolling regions, use them */
- if (has_scroll_region && FULLWIDTH(wp)) {
- /* First, get curscr management out of the way. */
- curline = cursrow(); curcol = curscol();
- Cmove(wbegy(wp)+wlines(wp)-1, 0);
- Cdeleteln();
- Cmove(wbegy(wp)+wcury(wp), 0);
- Cinsertln();
- Cmove(curline, curcol);
- /* now update the screen itself */
- (void) movecursor(wbegy(wp)+wcury(wp), wbegx(wp)+wcurx(wp));
- putp(save_cursor); /* Save since CS garbles cursor */
- putp(tgoto(change_scroll_region,
- wbegy(wp)+wlines(wp)-1, wbegy(wp)+wcury(wp)));
- putp(restore_cursor); /* CS garbles cursor */
- putp(scroll_reverse);
- putp(tgoto(change_scroll_region, LINES-1, 0));
- putp(restore_cursor); /* Once again put it back */
- Untouchwin(wp);
- }
-
- /* Else if this terminal has scrolling rectangles, use them now. */
- #ifdef SET_WINDOW
- else if (has_scroll_window) {
- overwrite(wp, curscr); /* slow but easy */
- putp(tparm(set_window,
- wbegy(wp)+wcury(wp), wbegy(wp)+wlines(wp)-1,
- wbegx(wp), wbegx(wp)+wcols(wp)-1));
- putp(scroll_reverse);
- putp(tparm(set_window, 0, LINES-1, 0, COLS-1));
- /* get back to where curses thinks we are */
- putp(tgoto(cursor_address, curscol(), cursrow()));
- Untouchwin(wp);
- }
- #endif
-
- /* Else if this terminal has ins/del line, now is the time */
- else if (has_insdel_line && FULLWIDTH(wp)) {
- /* Open a line above current line in window wp,
- * then delete wp's bottom line.
- * Perform identical operations on curscr
- * as we do on the terminal itself.
- */
- (void) movecursor(wbegy(wp)+wcury(wp), 0);
- putp(insert_line); Cinsertln();
- (void) movecursor(wbegy(wp)+wlines(wp), 0);
- putp(delete_line); Cdeleteln();
- RestoreMsg();
- Untouchwin(wp);
- }
- #endif
- }
-
- /*
- * This routine deletes the current line in window wp.
- * The cursor location in wp is not changed.
- */
- WMdeleteln(w)
- int w;
- {
- register WINDOW *wp;
- register int curline, curcol;
-
- wp = win[w].wptr;
-
- /*
- * See what we can do about windows that scroll slowly
- */
- if (!(win[w].flags&FAST)) {
- static int lines_since_refresh = 0;
- if ((lines_since_refresh += 7) >= wlines(wp)) {
- wrefresh(wp);
- lines_since_refresh = 0;
- }
- wdeleteln(wp);
- #ifdef BUGGYTERMINFO
- touchwin(wp);
- #endif
- return;
- }
-
- wrefresh(wp); /* smooths scrolling. Crucial for untouchwin. */
- wdeleteln(wp);
- #ifdef BUGGYTERMINFO
- /* wdeleteln neglects first/bottom info for the last line */
- touchwin(wp);
- #endif
-
- #ifdef CURSEASSIST
- /* If we're deleting top line of a full screen window,
- * this is the same as scrolling.
- * (We do not this if we have scrolling region support
- * and there is a wm message, but what a bother.)
- */
- if (FULLSCREEN(wp) && wcury(wp)==0 && !(has_scroll_region && msgbirth))
- {
- ZapMsgLine(); /* so it doesn't scroll up into our window */
- curline = cursrow(); curcol = curscol();
- Cmove(0, 0); Cdeleteln();
- Cmove(curline, curcol);
-
- /* Cause screen to scroll.
- * Since wm almost always 'wants' the cursor on LINES-2,
- * there is a cheap heuristic thrown in.
- */
- (void) movecursor(LINES, curcol);
- #ifndef TERMINFO
- if (cursor_up) {
- putp(cursor_up);
- Cmove(LINES-2, curcol);
- }
- #endif
- RestoreMsg();
- Untouchwin(wp);
- }
-
- /* Else if this terminal has scrolling regions, use them. */
- else if (has_scroll_region && FULLWIDTH(wp)) {
- curline = cursrow(); curcol = curscol();
- Cmove(wbegy(wp)+wcury(wp), 0);
- Cdeleteln(); /* it is about to be deleted */
- Cmove(wbegy(wp)+wlines(wp)-1, 0);
- Cinsertln(); /* it is about to be cleared */
- Cmove(curline, curcol);
- (void) movecursor(wbegy(wp)+wlines(wp)-1, wbegx(wp)+wcurx(wp));
- putp(save_cursor); /* Save since CS garbles cursor */
- putp(tgoto(change_scroll_region,
- wbegy(wp)+wlines(wp)-1, wbegy(wp)+wcury(wp)));
- putp(restore_cursor); /* put cursor back */
- putp(scroll_forward);
- putp(tgoto(change_scroll_region, LINES-1, 0));
- putp(restore_cursor); /* put cursor back */
- Untouchwin(wp);
- }
-
- /* Else if this terminal has scrolling rectangles, use them. */
- #ifdef SET_WINDOW
- else if (has_scroll_window) {
- overwrite(wp, curscr); /* slow but easy */
- putp(tparm(set_window,
- wbegy(wp)+wcury(wp), wbegy(wp)+wlines(wp)-1,
- wbegx(wp), wbegx(wp)+wcols(wp)-1));
- putp(tgoto(cursor_address, 0, wlines(wp)-1));
- putp(scroll_forward);
- putp(tparm(set_window, 0, LINES-1, 0, COLS-1));
- putp(tgoto(cursor_address, curscol(), cursrow()));
- Untouchwin(wp);
- }
- #endif
-
- /* Else if this terminal has insdel line, use that. */
- else if (has_insdel_line && FULLWIDTH(wp)) {
- /* Open a line below the last line in window wp,
- * then delete wp's current line.
- */
- (void) movecursor(wbegy(wp)+wlines(wp), 0);
- putp(insert_line); Cinsertln();
- (void) movecursor(wbegy(wp)+wcury(wp), 0);
- putp(delete_line); Cdeleteln();
- RestoreMsg();
- Untouchwin(wp);
- }
- #endif
- }
-
- /*
- * Construct termcap for wmvirt terminal in window w.
- */
- char *
- termcap(w)
- int w;
- {
- register WINDOW *wp;
- static char tbuf[TBUFLEN]; /* termcap buffer */
-
- wp = win[w].wptr;
- (void)sprintf(tbuf, "%sco#%d:li#%d:", TERMCAP, wcols(wp), wlines(wp));
-
- /* If terminal scrolls 'quickly', add insert/delete line to termcap. */
- if ((win[w].flags&FAST)
- && (has_insdel_line || has_scroll_region || has_scroll_window))
- strcat(tbuf, "al=\\EL:dl=\\ED:");
-
- /* If terminal has insert/delete character options, add them here */
- if (insert_character || (enter_insert_mode && exit_insert_mode))
- strcat(tbuf, "ic=\\EP:");
- if (delete_character)
- strcat(tbuf, "dc=\\EQ:");
-
- /* If terminal has standout capabilities, add that too. */
- if (enter_standout_mode && exit_standout_mode)
- strcat(tbuf, "so=\\EO:se=\\EE:");
-
- /* Include vb if terminal has a visual bell */
- if (flash_screen)
- strcat(tbuf, "vb=\\ER:");
-
- /* Include keypad capabilities if there is room left */
- if (strlen(tbuf)+strlen(keycap) < TBUFLEN)
- strcat(tbuf, keycap);
-
- return(tbuf);
- }
-