Xinqi Bao's Git
projects
/
st.git
/ blobdiff
summary
|
log
|
commit
|
diff
|
tree
raw
|
inline
| side by side
added support for alternate screen.
[st.git]
/
st.c
diff --git
a/st.c
b/st.c
index
5c7d855
..
d928f0d
100644
(file)
--- a/
st.c
+++ b/
st.c
@@
-20,11
+20,11
@@
#include <X11/keysym.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
-#if defined(
LINUX
)
+#if defined(
__linux
)
#include <pty.h>
#include <pty.h>
-#elif defined(
OPENBSD
)
+#elif defined(
__OpenBSD__) || defined(__NetBSD__
)
#include <util.h>
#include <util.h>
-#elif defined(
FREEBSD
)
+#elif defined(
__FreeBSD__) || defined(__DragonFly__
)
#include <libutil.h>
#endif
#include <libutil.h>
#endif
@@
-46,10
+46,11
@@
/* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
/* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
-enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE = 1,
- CURSOR_DRAW = 0, CURSOR_SAVE, CURSOR_LOAD };
+enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
+ CURSOR_SAVE, CURSOR_LOAD };
+enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
-enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 };
+enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4
, MODE_ALTSCREEN=8
};
enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
enum { SCREEN_UPDATE, SCREEN_REDRAW };
enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
enum { SCREEN_UPDATE, SCREEN_REDRAW };
@@
-67,7
+68,7
@@
typedef struct {
Glyph attr; /* current char attributes */
int x;
int y;
Glyph attr; /* current char attributes */
int x;
int y;
- char
hid
e;
+ char
stat
e;
} TCursor;
/* CSI Escape sequence structs */
} TCursor;
/* CSI Escape sequence structs */
@@
-85,7
+86,8
@@
typedef struct {
typedef struct {
int row; /* nb row */
int col; /* nb col */
typedef struct {
int row; /* nb row */
int col; /* nb col */
- Line* line; /* screen */
+ Line* line; /* screen */
+ Line* alt; /* alternate screen */
TCursor c; /* cursor */
int top; /* top scroll limit */
int bot; /* bottom scroll limit */
TCursor c; /* cursor */
int top; /* top scroll limit */
int bot; /* bottom scroll limit */
@@
-107,6
+109,7
@@
typedef struct {
int bufh; /* pixmap height */
int ch; /* char height */
int cw; /* char width */
int bufh; /* pixmap height */
int ch; /* char height */
int cw; /* char width */
+ int hasfocus;
} XWindow;
typedef struct {
} XWindow;
typedef struct {
@@
-154,29
+157,34
@@
static void tscrolldown(int);
static void tsetattr(int*, int);
static void tsetchar(char);
static void tsetscroll(int, int);
static void tsetattr(int*, int);
static void tsetchar(char);
static void tsetscroll(int, int);
+static void tswapscreen(void);
static void ttynew(void);
static void ttyread(void);
static void ttyresize(int, int);
static void ttywrite(const char *, size_t);
static void ttynew(void);
static void ttyread(void);
static void ttyresize(int, int);
static void ttywrite(const char *, size_t);
-static void xbell(void);
static void xdraws(char *, Glyph, int, int, int);
static void xhints(void);
static void xclear(int, int, int, int);
static void xdraws(char *, Glyph, int, int, int);
static void xhints(void);
static void xclear(int, int, int, int);
-static void x
cursor(int
);
+static void x
drawcursor(void
);
static void xinit(void);
static void xloadcols(void);
static void xinit(void);
static void xloadcols(void);
+static void xseturgency(int);
static void expose(XEvent *);
static char* kmap(KeySym);
static void kpress(XEvent *);
static void resize(XEvent *);
static void expose(XEvent *);
static char* kmap(KeySym);
static void kpress(XEvent *);
static void resize(XEvent *);
+static void focus(XEvent *);
+
static void (*handler[LASTEvent])(XEvent *) = {
[KeyPress] = kpress,
[Expose] = expose,
static void (*handler[LASTEvent])(XEvent *) = {
[KeyPress] = kpress,
[Expose] = expose,
- [ConfigureNotify] = resize
+ [ConfigureNotify] = resize,
+ [FocusIn] = focus,
+ [FocusOut] = focus,
};
/* Globals */
};
/* Globals */
@@
-186,7
+194,6
@@
static Term term;
static CSIEscape escseq;
static int cmdfd;
static pid_t pid;
static CSIEscape escseq;
static int cmdfd;
static pid_t pid;
-static int running;
#ifdef DEBUG
void
#ifdef DEBUG
void
@@
-226,15
+233,6
@@
execsh(void) {
execvp(args[0], args);
}
execvp(args[0], args);
}
-void
-xbell(void) {
- XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
- XFillRectangle(xw.dis, xw.win, dc.gc, BORDER, BORDER, xw.bufw, xw.bufh);
- XFlush(xw.dis);
- usleep(BellTime);
- draw(SCREEN_REDRAW);
-}
-
void
sigchld(int a) {
int stat = 0;
void
sigchld(int a) {
int stat = 0;
@@
-329,7
+327,7
@@
treset(void) {
.mode = ATTR_NULL,
.fg = DefaultFG,
.bg = DefaultBG
.mode = ATTR_NULL,
.fg = DefaultFG,
.bg = DefaultBG
- }, .x = 0, .y = 0, .
hide = 0
};
+ }, .x = 0, .y = 0, .
state = CURSOR_DEFAULT
};
term.top = 0, term.bot = term.row - 1;
term.mode = MODE_WRAP;
term.top = 0, term.bot = term.row - 1;
term.mode = MODE_WRAP;
@@
-341,12
+339,23
@@
tnew(int col, int row) {
/* set screen size */
term.row = row, term.col = col;
term.line = malloc(term.row * sizeof(Line));
/* set screen size */
term.row = row, term.col = col;
term.line = malloc(term.row * sizeof(Line));
- for(row = 0 ; row < term.row; row++)
+ term.alt = malloc(term.row * sizeof(Line));
+ for(row = 0 ; row < term.row; row++) {
term.line[row] = malloc(term.col * sizeof(Glyph));
term.line[row] = malloc(term.col * sizeof(Glyph));
+ term.alt [row] = malloc(term.col * sizeof(Glyph));
+ }
/* setup screen */
treset();
}
/* setup screen */
treset();
}
+void
+tswapscreen(void) {
+ Line* tmp = term.line;
+ term.line = term.alt;
+ term.alt = tmp;
+ term.mode ^= MODE_ALTSCREEN;
+}
+
void
tscrolldown (int n) {
int i;
void
tscrolldown (int n) {
int i;
@@
-414,8
+423,11
@@
csiparse(void) {
void
tmoveto(int x, int y) {
void
tmoveto(int x, int y) {
- term.c.x = x < 0 ? 0 : x >= term.col ? term.col-1 : x;
- term.c.y = y < 0 ? 0 : y >= term.row ? term.row-1 : y;
+ LIMIT(x, 0, term.col-1);
+ LIMIT(y, 0, term.row-1);
+ term.c.state &= ~CURSOR_WRAPNEXT;
+ term.c.x = x;
+ term.c.y = y;
}
void
}
void
@@
-711,12
+723,23
@@
csihandle(void) {
case 12: /* att610 -- Stop blinking cursor (IGNORED) */
break;
case 25:
case 12: /* att610 -- Stop blinking cursor (IGNORED) */
break;
case 25:
- term.c.hide = CURSOR_HIDE;
+ term.c.state |= CURSOR_HIDE;
+ break;
+ case 1047:
+ if(IS_SET(MODE_ALTSCREEN)) {
+ tclearregion(0, 0, term.col-1, term.row-1);
+ tswapscreen();
+ }
+ break;
+ case 1048:
+ tcursor(CURSOR_LOAD);
break;
break;
- case 1048: /* XXX: no alt. screen to erase/save */
case 1049:
tcursor(CURSOR_LOAD);
case 1049:
tcursor(CURSOR_LOAD);
- tclearregion(0, 0, term.col-1, term.row-1);
+ if(IS_SET(MODE_ALTSCREEN)) {
+ tclearregion(0, 0, term.col-1, term.row-1);
+ tswapscreen();
+ }
break;
default:
goto unknown;
break;
default:
goto unknown;
@@
-760,12
+783,23
@@
csihandle(void) {
case 12: /* att610 -- Start blinking cursor (IGNORED) */
break;
case 25:
case 12: /* att610 -- Start blinking cursor (IGNORED) */
break;
case 25:
- term.c.
hide = CURSOR_DRAW
;
+ term.c.
state &= ~CURSOR_HIDE
;
break;
break;
- case 1048:
- case 1049: /* XXX: no alt. screen to erase/save */
+ case 1047:
+ if(IS_SET(MODE_ALTSCREEN))
+ tclearregion(0, 0, term.col-1, term.row-1);
+ else
+ tswapscreen();
+ break;
+ case 1048:
tcursor(CURSOR_SAVE);
tcursor(CURSOR_SAVE);
- tclearregion(0, 0, term.col-1, term.row-1);
+ break;
+ case 1049:
+ tcursor(CURSOR_SAVE);
+ if(IS_SET(MODE_ALTSCREEN))
+ tclearregion(0, 0, term.col-1, term.row-1);
+ else
+ tswapscreen();
break;
default: goto unknown;
}
break;
default: goto unknown;
}
@@
-788,6
+822,7
@@
csihandle(void) {
DEFAULT(escseq.arg[0], 1);
DEFAULT(escseq.arg[1], term.row);
tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
DEFAULT(escseq.arg[0], 1);
DEFAULT(escseq.arg[1], term.row);
tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
+ tmoveto(0, 0);
}
break;
case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
}
break;
case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
@@
-867,20
+902,11
@@
tputc(char c) {
case '(':
term.esc |= ESC_ALTCHARSET;
break;
case '(':
term.esc |= ESC_ALTCHARSET;
break;
- case 'A':
- tmoveto(term.c.x, term.c.y-1);
- term.esc = 0;
- break;
- case 'B':
- tmoveto(term.c.x, term.c.y+1);
- term.esc = 0;
- break;
- case 'C':
- tmoveto(term.c.x+1, term.c.y);
- term.esc = 0;
- break;
- case 'D': /* XXX: CUP (VT100) or IND (VT52) ... */
- tmoveto(term.c.x-1, term.c.y);
+ case 'D': /* IND -- Linefeed */
+ if(term.c.y == term.bot)
+ tscrollup(1);
+ else
+ tmoveto(term.c.x, term.c.y+1);
term.esc = 0;
break;
case 'E': /* NEL -- Next line */
term.esc = 0;
break;
case 'E': /* NEL -- Next line */
@@
-898,19
+924,19
@@
tputc(char c) {
treset();
term.esc = 0;
break;
treset();
term.esc = 0;
break;
- case '=': /* DECPAM */
+ case '=': /* DECPAM
-- Application keypad
*/
term.mode |= MODE_APPKEYPAD;
term.esc = 0;
break;
term.mode |= MODE_APPKEYPAD;
term.esc = 0;
break;
- case '>': /* DECPNM */
+ case '>': /* DECPNM
-- Normal keypad
*/
term.mode &= ~MODE_APPKEYPAD;
term.esc = 0;
break;
term.mode &= ~MODE_APPKEYPAD;
term.esc = 0;
break;
- case '7':
+ case '7':
/* DECSC -- Save Cursor*/
tcursor(CURSOR_SAVE);
term.esc = 0;
break;
tcursor(CURSOR_SAVE);
term.esc = 0;
break;
- case '8':
+ case '8':
/* DECRC -- Restore Cursor */
tcursor(CURSOR_LOAD);
term.esc = 0;
break;
tcursor(CURSOR_LOAD);
term.esc = 0;
break;
@@
-934,18
+960,21
@@
tputc(char c) {
tnewline();
break;
case '\a':
tnewline();
break;
case '\a':
- xbell();
+ if(!xw.hasfocus)
+ xseturgency(1);
break;
case '\033':
csireset();
term.esc = ESC_START;
break;
default:
break;
case '\033':
csireset();
term.esc = ESC_START;
break;
default:
+ if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
+ tnewline();
tsetchar(c);
tsetchar(c);
- if(term.c.x+1 < term.col)
{
+ if(term.c.x+1 < term.col)
tmoveto(term.c.x+1, term.c.y);
tmoveto(term.c.x+1, term.c.y);
- } else if(IS_SET(MODE_WRAP))
- t
newline()
;
+ else
+ t
erm.c.state |= CURSOR_WRAPNEXT
;
break;
}
}
break;
}
}
@@
-967,29
+996,35
@@
tresize(int col, int row) {
return;
/* free uneeded rows */
return;
/* free uneeded rows */
- for(i = row; i < term.row; i++)
+ for(i = row; i < term.row; i++)
{
free(term.line[i]);
free(term.line[i]);
+ free(term.alt[i]);
+ }
/* resize to new height */
term.line = realloc(term.line, row * sizeof(Line));
/* resize to new height */
term.line = realloc(term.line, row * sizeof(Line));
+ term.line = realloc(term.alt, row * sizeof(Line));
/* resize each row to new width, zero-pad if needed */
for(i = 0; i < minrow; i++) {
term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
/* resize each row to new width, zero-pad if needed */
for(i = 0; i < minrow; i++) {
term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
+ term.alt[i] = realloc(term.alt[i], col * sizeof(Glyph));
memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
+ memset(term.alt[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
}
/* allocate any new rows */
}
/* allocate any new rows */
- for(/* i == minrow */; i < row; i++)
+ for(/* i == minrow */; i < row; i++)
{
term.line[i] = calloc(col, sizeof(Glyph));
term.line[i] = calloc(col, sizeof(Glyph));
+ term.alt [i] = calloc(col, sizeof(Glyph));
+ }
- LIMIT(term.c.x, 0, col-1);
- LIMIT(term.c.y, 0, row-1);
- LIMIT(term.top, 0, row-1);
- LIMIT(term.bot, 0, row-1);
-
- term.bot = row-1;
+ /* update terminal size */
term.col = col, term.row = row;
term.col = col, term.row = row;
+ /* make use of the LIMIT in tmoveto */
+ tmoveto(term.c.x, term.c.y);
+ /* reset scrolling region */
+ tsetscroll(0, row-1);
}
void
}
void
@@
-1074,9
+1109,6
@@
xinit(void) {
/* colors */
xloadcols();
/* colors */
xloadcols();
- term.c.attr.fg = DefaultFG;
- term.c.attr.bg = DefaultBG;
- term.c.attr.mode = ATTR_NULL;
/* windows */
xw.h = term.row * xw.ch + 2*BORDER;
xw.w = term.col * xw.cw + 2*BORDER;
/* windows */
xw.h = term.row * xw.ch + 2*BORDER;
xw.w = term.col * xw.cw + 2*BORDER;
@@
-1121,7
+1153,7
@@
xdraws(char *s, Glyph base, int x, int y, int len) {
}
void
}
void
-x
cursor(int mode
) {
+x
drawcursor(void
) {
static int oldx = 0;
static int oldy = 0;
Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0};
static int oldx = 0;
static int oldy = 0;
Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0};
@@
-1139,7
+1171,7
@@
xcursor(int mode) {
xclear(oldx, oldy, oldx, oldy);
/* draw the new one */
xclear(oldx, oldy, oldx, oldy);
/* draw the new one */
- if(
mode == CURSOR_DRAW
) {
+ if(
!(term.c.state & CURSOR_HIDE) && xw.hasfocus
) {
xdraws(&g.c, g, term.c.x, term.c.y, 1);
oldx = term.c.x, oldy = term.c.y;
}
xdraws(&g.c, g, term.c.x, term.c.y, 1);
oldx = term.c.x, oldy = term.c.y;
}
@@
-1166,7
+1198,7
@@
draw(int dummy) {
if(term.line[y][x].state & GLYPH_SET)
xdrawc(x, y, term.line[y][x]);
if(term.line[y][x].state & GLYPH_SET)
xdrawc(x, y, term.line[y][x]);
- x
cursor(term.c.hide
);
+ x
drawcursor(
);
XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
XFlush(xw.dis);
}
XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
XFlush(xw.dis);
}
@@
-1202,7
+1234,7
@@
draw(int redraw_all) {
if(i > 0)
xdraws(buf, base, ox, y, i);
}
if(i > 0)
xdraws(buf, base, ox, y, i);
}
- x
cursor(term.c.hide
);
+ x
drawcursor(
);
XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
XFlush(xw.dis);
}
XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
XFlush(xw.dis);
}
@@
-1214,6
+1246,21
@@
expose(XEvent *ev) {
draw(SCREEN_REDRAW);
}
draw(SCREEN_REDRAW);
}
+void
+xseturgency(int add) {
+ XWMHints *h = XGetWMHints(xw.dis, xw.win);
+ h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
+ XSetWMHints(xw.dis, xw.win, h);
+ XFree(h);
+}
+
+void
+focus(XEvent *ev) {
+ if((xw.hasfocus = ev->type == FocusIn))
+ xseturgency(0);
+ draw(SCREEN_UPDATE);
+}
+
char*
kmap(KeySym k) {
int i;
char*
kmap(KeySym k) {
int i;
@@
-1288,12
+1335,12
@@
run(void) {
XEvent ev;
fd_set rfd;
int xfd = XConnectionNumber(xw.dis);
XEvent ev;
fd_set rfd;
int xfd = XConnectionNumber(xw.dis);
+ long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask;
- running = 1;
- XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask);
+ XSelectInput(xw.dis, xw.win, mask);
XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */
XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */
- while(
running
) {
+ while(
1
) {
FD_ZERO(&rfd);
FD_SET(cmdfd, &rfd);
FD_SET(xfd, &rfd);
FD_ZERO(&rfd);
FD_SET(cmdfd, &rfd);
FD_SET(xfd, &rfd);