📄 nxterm.c
字号:
/*
* nxterm - terminal emulator for Nano-X
*
* (C) 1994,95,96 by Torsten Scherer (TeSche)
* itschere@techfak.uni-bielefeld.de
*
* - quite some changes for W1R1
* - yet more changes for W1R2
*
* TeSche 01/96:
* - supports W_ICON & W_CLOSE
* - supports /etc/utmp logging for SunOS4 and Linux
* - supports catching of console output for SunOS4
* Phx 02-06/96:
* - supports NetBSD-Amiga
* Eero 11/97:
* - unsetenv(DISPLAY), setenv(LINES, COLUMNS).
* - Add new text modes (you need to use terminfo...).
* Eero 2/98:
* - Implemented fg/bgcolor setting. With monochrome server it changes
* bgmode variable, which tells in which mode to draw to screen
* (M_CLEAR/M_DRAW) and affects F_REVERSE settings.
* - Added a couple of checks.
*
* TODO:
* - Allocate and set sensible window palette for fg/bg color setting.
* - add scroll-region ('cs') command. Fairly many programs
* can take advantage of that.
* - Add xterm like mouse event to terminfo key event conversion... :)
* - check if current NetBSD really needs ifdefs below with
* current W server/library.
*/
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <utmp.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <pwd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MWINCLUDECOLORS
#include "nano-X.h"
#include "nxterm.h"
#define TITLE "nxterm"
#define SMALLBUFFER 80
#define LARGEBUFFER 1024
/*
* some pty helper functions
*/
#ifdef linux
#define NSIG _NSIG
#endif
#ifdef __FreeBSD__
#include <libutil.h>
#endif
/*
* some global variables
*/
static GR_WINDOW_ID w1; /* id for window */
static GR_GC_ID gc1; /* graphics context */
static GR_FONT_ID regFont;
/*static GR_FONT_ID boldFont;*/
static GR_SCREEN_INFO si; /* screen info */
static GR_FONT_INFO fi; /* Font Info */
static GR_WINDOW_INFO wi;
static GR_GC_INFO gi;
static GR_BOOL havefocus = GR_FALSE;
static short winw, winh, pid, console;
static int pipeh;
static short cblink = 0, visualbell = 0, debug = 0;
#ifdef __FreeBSD__
static char pty[SMALLBUFFER];
static struct winsize winsz;
#endif
#define fonh fi.height
#define fonw fi.maxwidth
int term_init();
/****************************************************************************/
/*
*
*/
/* static int isIconified; */
static int isMaximized=0;
void maximize(void)
{
static short x0, y0, w, h, w_max,h_max;
if (!isMaximized)
{
w_max=si.cols-wi.bordersize;
h_max=si.rows-wi.bordersize;
GrMoveWindow(w1,0,0);
GrResizeWindow(w1,w_max, h_max);
isMaximized=1;
}
else
{
GrResizeWindow(w1, w, h);
GrMoveWindow(w1, x0, y0);
isMaximized=0;
}
}
/****************************************************************************/
/*
* some common tool functions
*/
void sigpipe(int sig)
{
/* this one musn't close the window */
/* _write_utmp(pty, "", "", 0); */
kill(-pid, SIGHUP);
_exit(sig);
}
void sigchld(int sig)
{
/* _write_utmp(pty, "", "", 0); */
_exit(sig);
}
void sigquit(int sig)
{
signal(sig, SIG_IGN);
kill(-pid, SIGHUP);
}
/*
* this is the wterm terminal code, almost like VT52
*/
short bgmode, escstate, curx, cury, curon, curvis;
short savx, savy, wrap, style;
short col, row, colmask = 0x7f, rowmask = 0x7f;
/*
* something to buffer plain text output
*/
short sbufcnt = 0;
short sbufx, sbufy;
char lineBuffer[SMALLBUFFER+1];
char *sbuf=lineBuffer;
void sflush(void)
{
if (sbufcnt)
{
GrText(w1,gc1, sbufx*fonw, sbufy*fonh, sbuf, sbufcnt, GR_TFTOP);
sbufcnt = 0;
}
}
void lineRedraw(void)
{
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
if (sbufcnt)
{
sbuf[sbufcnt] = 0;
GrText(w1,gc1, sbufx*fonw, sbufy*fonh, sbuf, sbufcnt, GR_TFTOP);
}
}
void sadd (char c)
{
if (sbufcnt == SMALLBUFFER)
{
sflush ();
}
if (!sbufcnt)
{
sbufx = curx;
sbufy = cury;
}
sbuf[sbufcnt++] = c;
}
void show_cursor (void)
{
GrSetGCMode(gc1,GR_MODE_XOR);
GrSetGCForeground(gc1, WHITE);
GrFillRect(w1, gc1, curx*fonw, cury*fonh+1, fonw, fonh-1);
GrSetGCForeground(gc1, gi.foreground);
GrSetGCMode(gc1,GR_MODE_COPY);
}
void draw_cursor (void)
{
if (!curvis)
{
curvis = 1;
show_cursor();
}
}
void hide_cursor (void)
{
if (curvis)
{
curvis = 0;
show_cursor();
}
}
void vscroll(int lines)
{
hide_cursor();
GrCopyArea(w1,gc1,0, 0, winw, winh-(lines*fonh),
w1, 0, (lines*fonh), MWROP_SRCCOPY);
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1, gc1, 0, winh-(lines*fonh),
winw, (lines*fonh));
GrSetGCForeground(gc1,gi.foreground);
}
void esc5(unsigned char c) /* setting background color */
{
GrSetGCBackground(gc1, c);
GrGetGCInfo(gc1,&gi);
escstate = 0;
}
void esc4(unsigned char c) /* setting foreground color */
{
GrSetGCForeground(gc1,c);
GrGetGCInfo(gc1,&gi);
escstate = 0;
}
void esc3(unsigned char c) /* cursor position x axis */
{
curx = (c - 32) & colmask;
if (curx >= col)
curx = col - 1;
else if (curx < 0)
curx = 0;
escstate = 0;
}
void esc2(unsigned char c) /* cursor position y axis */
{
cury = (c - 32) & rowmask;
if (cury >= row)
cury = row - 1;
else if (cury < 0)
cury = 0;
escstate = 3;
}
void esc1(unsigned char c) /* various control codes */
{
static int ReverseMode=0;
escstate = 0;
switch(c)
{
case 'A':/* cursor up */
hide_cursor();
if ((cury -= 1) < 0)
cury = 0;
break;
case 'B':/* cursor down */
hide_cursor();
if ((cury += 1) >= row)
cury = row - 1;
break;
case 'C':/* cursor right */
hide_cursor();
if ((curx += 1) >= col)
curx = col - 1;
break;
case 'D':/* cursor left */
hide_cursor();
if ((curx -= 1) < 0)
curx = 0;
break;
case 'E':/* clear screen & home */
GrClearWindow(w1, 0);
curx = 0;
cury = 0;
break;
case 'H':/* cursor home */
curx = 0;
cury = 0;
break;
case 'I':/* reverse index */
if ((cury -= 1) < 0)
{
cury = 0;
vscroll(1);
}
break;
case 'J':/* erase to end of page */
if (cury < row-1)
{
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1,gc1, 0,(cury+1)*fonh, winw, (row-1-cury)*fonh);
GrSetGCForeground(gc1,gi.foreground);
}
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
break;
case 'K':/* erase to end of line */
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
break;
case 'L':/* insert line */
if (cury < row-1)
{
vscroll(1);
}
curx = 0;
break;
case 'M':/* delete line */
if (cury < row-1)
{
vscroll(1);
}
curx = 0;
break;
case 'Y':/* position cursor */
escstate = 2;
break;
case 'b':/* set foreground color */
escstate = 4;
break;
case 'c':/* set background color */
escstate = 5;
break;
case 'd':/* erase beginning of display */
/* w_setmode(win, bgmode); */
if (cury > 0)
{
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1,gc1, 0, 0, winw, cury*fonh);
GrSetGCForeground(gc1,gi.foreground);
}
if (curx > 0)
{
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1,gc1, 0, cury*fonh, curx*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
}
break;
case 'e':/* enable cursor */
curon = 1;
break;
case 'f':/* disable cursor */
curon = 0;
break;
case 'j':/* save cursor position */
savx = curx;
savy = cury;
break;
case 'k':/* restore cursor position */
curx = savx;
cury = savy;
break;
case 'l':/* erase entire line */
GrSetGCForeground(gc1,gi.background);
GrRect(w1,gc1, 0, cury*fonh, winw, fonh);
GrSetGCForeground(gc1,gi.foreground);
curx = 0;
break;
case 'o':/* erase beginning of line */
if (curx > 0)
{
GrSetGCForeground(gc1,gi.background);
GrRect(w1,gc1,0, cury*fonh, curx*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
}
break;
case 'p':/* enter reverse video mode */
{
if(!ReverseMode)
{
GrSetGCForeground(gc1,gi.background);
GrSetGCBackground(gc1,gi.foreground);
ReverseMode=1;
}
}
break;
case 'q':/* exit reverse video mode */
{
if(ReverseMode)
{
GrSetGCForeground(gc1,gi.foreground);
GrSetGCBackground(gc1,gi.background);
ReverseMode=0;
}
}
break;
case 'v':/* enable wrap at end of line */
wrap = 1;
break;
case 'w':/* disable wrap at end of line */
wrap = 0;
break;
/* and these are the extentions not in VT52 */
case 'G': /* clear all attributes */
break;
case 'g': /* enter bold mode */
/* GrSetGCFont(gc1, boldFont); */
break;
case 'h': /* exit bold mode */
/* GrSetGCFont(gc1, regFont); */
break;
case 'i': /* enter underline mode */
break;
/* j, k and l are already used */
case 'm': /* exit underline mode */
break;
/* these ones aren't yet on the termcap entries */
case 'n': /* enter italic mode */
break;
/* o, p and q are already used */
case 'r': /* exit italic mode */
break;
case 's': /* enter light mode */
break;
case 't': /* exit ligth mode */
break;
default: /* unknown escape sequence */
break;
}
}
/*
* un-escaped character print routine
*/
void esc0 (unsigned char c)
{
switch (c)
{
case 0:
/*
* printing \000 on a terminal means "do nothing".
* But since we use \000 as string terminator none
* of the characters that follow were printed.
*
* perl -e 'printf("a%ca", 0);'
*
* said 'a' in a wterm, but should say 'aa'. This
* bug screwed up most ncurses programs.
*
* kay.
*/
break;
case 7: /* bell */
if (visualbell)
{
/* w_setmode(win, M_INVERS); */
/* w_pbox(win, 0, 0, winw, winh); */
/* w_test(win, 0, 0); */
/* w_pbox(win, 0, 0, winw, winh); */
;
}
else
{
;
GrBell();
}
break;
case 8: /* backspace */
lineRedraw();
if (--curx < 0)
{
curx = 0;
}
break;
case 9: /* tab */
{
int borg,i;
borg=(((curx >> 3) + 1) << 3);
if(borg >= col)
{
borg=col-1;
}
borg=borg-curx;
for(i=0; i < borg; ++i){sadd(' ');}
if ((curx = ((curx >> 3) + 1) << 3) >= col)
{
curx = col - 1;
}
}
break;
case 10: /* line feed */
sflush();
if (++cury >= row)
{
vscroll(1);
cury = row-1;
}
break;
case 13: /* carriage return */
sflush();
curx = 0;
break;
case 27: /* escape */
sflush();
escstate = 1;
break;
case 127: /* delete */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -