Last active
April 16, 2018 21:31
-
-
Save runcom/52394a6cc855cae4151ba966338ad8b8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/config.def.h b/config.def.h | |
index 82b1b09..cfbdc9f 100644 | |
--- a/config.def.h | |
+++ b/config.def.h | |
@@ -82,6 +82,9 @@ char *termname = "st-256color"; | |
*/ | |
unsigned int tabspaces = 8; | |
+/* bg opacity */ | |
+unsigned int alpha = 0xcc; | |
+ | |
/* Terminal colors (16 first used in escape sequence) */ | |
static const char *colorname[] = { | |
/* 8 normal colors */ | |
@@ -109,6 +112,7 @@ static const char *colorname[] = { | |
/* more colors can be added after 255 to use with DefaultXX */ | |
"#cccccc", | |
"#555555", | |
+ "black, | |
}; | |
@@ -178,6 +182,8 @@ static Shortcut shortcuts[] = { | |
{ TERMMOD, XK_Y, selpaste, {.i = 0} }, | |
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, | |
{ TERMMOD, XK_I, iso14755, {.i = 0} }, | |
+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, | |
+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, | |
}; | |
/* | |
diff --git a/config.mk b/config.mk | |
index 039c42c..eb2dc01 100644 | |
--- a/config.mk | |
+++ b/config.mk | |
@@ -14,7 +14,7 @@ X11LIB = /usr/X11R6/lib | |
INCS = -I$(X11INC) \ | |
`pkg-config --cflags fontconfig` \ | |
`pkg-config --cflags freetype2` | |
-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ | |
+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ | |
`pkg-config --libs fontconfig` \ | |
`pkg-config --libs freetype2` | |
diff --git a/st.c b/st.c | |
index 0628707..2888643 100644 | |
--- a/st.c | |
+++ b/st.c | |
@@ -121,6 +121,9 @@ typedef struct { | |
int col; /* nb col */ | |
Line *line; /* screen */ | |
Line *alt; /* alternate screen */ | |
+ Line hist[HISTSIZE]; /* history buffer */ | |
+ int histi; /* history index */ | |
+ int scr; /* scroll back */ | |
int *dirty; /* dirtyness of lines */ | |
TCursor c; /* cursor */ | |
int ocx; /* old cursor col */ | |
@@ -188,8 +191,8 @@ static void tnewline(int); | |
static void tputtab(int); | |
static void tputc(Rune); | |
static void treset(void); | |
-static void tscrollup(int, int); | |
-static void tscrolldown(int, int); | |
+static void tscrollup(int, int, int); | |
+static void tscrolldown(int, int, int); | |
static void tsetattr(int *, int); | |
static void tsetchar(Rune, Glyph *, int, int); | |
static void tsetdirt(int, int); | |
@@ -431,10 +434,10 @@ tlinelen(int y) | |
{ | |
int i = term.col; | |
- if (term.line[y][i - 1].mode & ATTR_WRAP) | |
+ if (TLINE(y)[i - 1].mode & ATTR_WRAP) | |
return i; | |
- while (i > 0 && term.line[y][i - 1].u == ' ') | |
+ while (i > 0 && TLINE(y)[i - 1].u == ' ') | |
--i; | |
return i; | |
@@ -543,7 +546,7 @@ selsnap(int *x, int *y, int direction) | |
* Snap around if the word wraps around at the end or | |
* beginning of a line. | |
*/ | |
- prevgp = &term.line[*y][*x]; | |
+ prevgp = &TLINE(*y)[*x]; | |
prevdelim = ISDELIM(prevgp->u); | |
for (;;) { | |
newx = *x + direction; | |
@@ -558,14 +561,14 @@ selsnap(int *x, int *y, int direction) | |
yt = *y, xt = *x; | |
else | |
yt = newy, xt = newx; | |
- if (!(term.line[yt][xt].mode & ATTR_WRAP)) | |
+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) | |
break; | |
} | |
if (newx >= tlinelen(newy)) | |
break; | |
- gp = &term.line[newy][newx]; | |
+ gp = &TLINE(newy)[newx]; | |
delim = ISDELIM(gp->u); | |
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim | |
|| (delim && gp->u != prevgp->u))) | |
@@ -586,14 +589,14 @@ selsnap(int *x, int *y, int direction) | |
*x = (direction < 0) ? 0 : term.col - 1; | |
if (direction < 0) { | |
for (; *y > 0; *y += direction) { | |
- if (!(term.line[*y-1][term.col-1].mode | |
+ if (!(TLINE(*y-1)[term.col-1].mode | |
& ATTR_WRAP)) { | |
break; | |
} | |
} | |
} else if (direction > 0) { | |
for (; *y < term.row-1; *y += direction) { | |
- if (!(term.line[*y][term.col-1].mode | |
+ if (!(TLINE(*y)[term.col-1].mode | |
& ATTR_WRAP)) { | |
break; | |
} | |
@@ -624,13 +627,13 @@ getsel(void) | |
} | |
if (sel.type == SEL_RECTANGULAR) { | |
- gp = &term.line[y][sel.nb.x]; | |
+ gp = &TLINE(y)[sel.nb.x]; | |
lastx = sel.ne.x; | |
} else { | |
- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; | |
+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; | |
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; | |
} | |
- last = &term.line[y][MIN(lastx, linelen-1)]; | |
+ last = &TLINE(y)[MIN(lastx, linelen-1)]; | |
while (last >= gp && last->u == ' ') | |
--last; | |
@@ -836,6 +839,9 @@ ttyread(void) | |
if (buflen > 0) | |
memmove(buf, buf + written, buflen); | |
+ if (term.scr > 0 && term.scr < HISTSIZE-1) | |
+ term.scr++; | |
+ | |
return ret; | |
} | |
@@ -843,6 +849,9 @@ void | |
ttywrite(const char *s, size_t n, int may_echo) | |
{ | |
const char *next; | |
+ Arg arg = (Arg) { .i = term.scr }; | |
+ | |
+ kscrolldown(&arg); | |
if (may_echo && IS_SET(MODE_ECHO)) | |
twrite(s, n, 1); | |
@@ -1054,13 +1063,54 @@ tswapscreen(void) | |
} | |
void | |
-tscrolldown(int orig, int n) | |
+kscrolldown(const Arg* a) | |
+{ | |
+ int n = a->i; | |
+ | |
+ if (n < 0) | |
+ n = term.row + n; | |
+ | |
+ if (n > term.scr) | |
+ n = term.scr; | |
+ | |
+ if (term.scr > 0) { | |
+ term.scr -= n; | |
+ selscroll(0, -n); | |
+ tfulldirt(); | |
+ } | |
+} | |
+ | |
+void | |
+kscrollup(const Arg* a) | |
+{ | |
+ int n = a->i; | |
+ | |
+ if (n < 0) | |
+ n = term.row + n; | |
+ | |
+ if (term.scr <= HISTSIZE-n) { | |
+ term.scr += n; | |
+ selscroll(0, n); | |
+ tfulldirt(); | |
+ } | |
+} | |
+ | |
+ | |
+void | |
+tscrolldown(int orig, int n, int copyhist) | |
{ | |
int i; | |
Line temp; | |
LIMIT(n, 0, term.bot-orig+1); | |
+ if (copyhist) { | |
+ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; | |
+ temp = term.hist[term.histi]; | |
+ term.hist[term.histi] = term.line[term.bot]; | |
+ term.line[term.bot] = temp; | |
+ } | |
+ | |
tsetdirt(orig, term.bot-n); | |
tclearregion(0, term.bot-n+1, term.col-1, term.bot); | |
@@ -1074,13 +1124,20 @@ tscrolldown(int orig, int n) | |
} | |
void | |
-tscrollup(int orig, int n) | |
+tscrollup(int orig, int n, int copyhist) | |
{ | |
int i; | |
Line temp; | |
LIMIT(n, 0, term.bot-orig+1); | |
+ if (copyhist) { | |
+ term.histi = (term.histi + 1) % HISTSIZE; | |
+ temp = term.hist[term.histi]; | |
+ term.hist[term.histi] = term.line[orig]; | |
+ term.line[orig] = temp; | |
+ } | |
+ | |
tclearregion(0, orig, term.col-1, orig+n-1); | |
tsetdirt(orig+n, term.bot); | |
@@ -1129,7 +1186,7 @@ tnewline(int first_col) | |
int y = term.c.y; | |
if (y == term.bot) { | |
- tscrollup(term.top, 1); | |
+ tscrollup(term.top, 1, 1); | |
} else { | |
y++; | |
} | |
@@ -1294,14 +1351,14 @@ void | |
tinsertblankline(int n) | |
{ | |
if (BETWEEN(term.c.y, term.top, term.bot)) | |
- tscrolldown(term.c.y, n); | |
+ tscrolldown(term.c.y, n, 0); | |
} | |
void | |
tdeleteline(int n) | |
{ | |
if (BETWEEN(term.c.y, term.top, term.bot)) | |
- tscrollup(term.c.y, n); | |
+ tscrollup(term.c.y, n, 0); | |
} | |
int32_t | |
@@ -1730,11 +1787,11 @@ csihandle(void) | |
break; | |
case 'S': /* SU -- Scroll <n> line up */ | |
DEFAULT(csiescseq.arg[0], 1); | |
- tscrollup(term.top, csiescseq.arg[0]); | |
+ tscrollup(term.top, csiescseq.arg[0], 0); | |
break; | |
case 'T': /* SD -- Scroll <n> line down */ | |
DEFAULT(csiescseq.arg[0], 1); | |
- tscrolldown(term.top, csiescseq.arg[0]); | |
+ tscrolldown(term.top, csiescseq.arg[0], 0); | |
break; | |
case 'L': /* IL -- Insert <n> blank lines */ | |
DEFAULT(csiescseq.arg[0], 1); | |
@@ -2258,7 +2315,7 @@ eschandle(uchar ascii) | |
return 0; | |
case 'D': /* IND -- Linefeed */ | |
if (term.c.y == term.bot) { | |
- tscrollup(term.top, 1); | |
+ tscrollup(term.top, 1, 1); | |
} else { | |
tmoveto(term.c.x, term.c.y+1); | |
} | |
@@ -2271,7 +2328,7 @@ eschandle(uchar ascii) | |
break; | |
case 'M': /* RI -- Reverse index */ | |
if (term.c.y == term.top) { | |
- tscrolldown(term.top, 1); | |
+ tscrolldown(term.top, 1, 1); | |
} else { | |
tmoveto(term.c.x, term.c.y-1); | |
} | |
@@ -2490,7 +2547,7 @@ twrite(const char *buf, int buflen, int show_ctrl) | |
void | |
tresize(int col, int row) | |
{ | |
- int i; | |
+ int i, j; | |
int minrow = MIN(row, term.row); | |
int mincol = MIN(col, term.col); | |
int *bp; | |
@@ -2527,7 +2584,15 @@ tresize(int col, int row) | |
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); | |
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); | |
- /* resize each row to new width, zero-pad if needed */ | |
+ for (i = 0; i < HISTSIZE; i++) { | |
+ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); | |
+ for (j = mincol; j < col; j++) { | |
+ term.hist[i][j] = term.c.attr; | |
+ term.hist[i][j].u = ' '; | |
+ } | |
+ } | |
+ | |
+ /* resize each r w to new width, zero-pad if needed */ | |
for (i = 0; i < minrow; i++) { | |
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); | |
term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); | |
@@ -2584,7 +2649,7 @@ drawregion(int x1, int y1, int x2, int y2) | |
continue; | |
term.dirty[y] = 0; | |
- xdrawline(term.line[y], x1, y, x2); | |
+ xdrawline(TLINE(y), x1, y, x2); | |
} | |
} | |
@@ -2605,8 +2670,10 @@ draw(void) | |
cx--; | |
drawregion(0, 0, term.col, term.row); | |
- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], | |
- term.ocx, term.ocy, term.line[term.ocy][term.ocx]); | |
+ if (term.scr == 0) { | |
+ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], | |
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]); | |
+ } | |
term.ocx = cx, term.ocy = term.c.y; | |
xfinishdraw(); | |
} | |
diff --git a/st.h b/st.h | |
index dac64d8..a2f8335 100644 | |
--- a/st.h | |
+++ b/st.h | |
@@ -3,6 +3,9 @@ | |
#include <stdint.h> | |
#include <sys/types.h> | |
+/* Arbitrary size */ | |
+#define HISTSIZE 2000 | |
+ | |
/* macros */ | |
#define MIN(a, b) ((a) < (b) ? (a) : (b)) | |
#define MAX(a, b) ((a) < (b) ? (b) : (a)) | |
@@ -19,6 +22,8 @@ | |
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) | |
#define IS_TRUECOL(x) (1 << 24 & (x)) | |
+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \ | |
+ + HISTSIZE + 1) % HISTSIZE] : term.line[(y) - term.scr]) | |
enum glyph_attribute { | |
ATTR_NULL = 0, | |
@@ -111,6 +116,9 @@ void *xmalloc(size_t); | |
void *xrealloc(void *, size_t); | |
char *xstrdup(char *); | |
+void kscrolldown(const Arg *); | |
+void kscrollup(const Arg *); | |
+ | |
/* config.h globals */ | |
extern char *utmp; | |
extern char *stty_args; | |
@@ -118,6 +126,7 @@ extern char *vtiden; | |
extern char *worddelimiters; | |
extern int allowaltscreen; | |
extern char *termname; | |
+extern unsigned int alpha; | |
extern unsigned int tabspaces; | |
extern unsigned int defaultfg; | |
extern unsigned int defaultbg; | |
diff --git a/win.h b/win.h | |
index 31f327d..d277477 100644 | |
--- a/win.h | |
+++ b/win.h | |
@@ -23,6 +23,10 @@ enum win_mode { | |
|MODE_MOUSEMANY, | |
}; | |
+/* alpha */ | |
+#define OPAQUE 0Xff | |
+#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) | |
+ | |
void xbell(void); | |
void xclipcopy(void); | |
void xdrawcursor(int, int, Glyph, int, int, Glyph); | |
diff --git a/x.c b/x.c | |
index c0bd890..8ced567 100644 | |
--- a/x.c | |
+++ b/x.c | |
@@ -98,6 +98,7 @@ typedef struct { | |
XSetWindowAttributes attrs; | |
int scr; | |
int isfixed; /* is fixed geometry? */ | |
+ int depth; /* bit depth */ | |
int l, t; /* left and top offset */ | |
int gm; /* geometry mask */ | |
} XWindow; | |
@@ -686,7 +687,7 @@ xresize(int col, int row) | |
XFreePixmap(xw.dpy, xw.buf); | |
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, | |
- DefaultDepth(xw.dpy, xw.scr)); | |
+ xw.depth); | |
XftDrawChange(xw.draw, xw.buf); | |
xclear(0, 0, win.w, win.h); | |
@@ -746,6 +747,12 @@ xloadcols(void) | |
else | |
die("could not allocate color %d\n", i); | |
} | |
+ /* set alpha value of bg color */ | |
+ if (USE_ARGB) { | |
+ dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE; | |
+ dc.col[defaultbg].pixel &= 0x00111111; | |
+ dc.col[defaultbg].pixel |= alpha << 24; | |
+ } | |
loaded = 1; | |
} | |
@@ -767,6 +774,17 @@ xsetcolorname(int x, const char *name) | |
return 0; | |
} | |
+void | |
+xtermclear(int col1, int row1, int col2, int row2) | |
+{ | |
+ XftDrawRect(xw.draw, | |
+ &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], | |
+ borderpx + col1 * win.cw, | |
+ borderpx + row1 * win.ch, | |
+ (col2-col1+1) * win.cw, | |
+ (row2-row1+1) * win.ch); | |
+} | |
+ | |
/* | |
* Absolute coordinates. | |
*/ | |
@@ -1004,7 +1022,40 @@ xinit(int cols, int rows) | |
if (!(xw.dpy = XOpenDisplay(NULL))) | |
die("can't open display\n"); | |
xw.scr = XDefaultScreen(xw.dpy); | |
- xw.vis = XDefaultVisual(xw.dpy, xw.scr); | |
+ xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr); | |
+ if (!USE_ARGB) | |
+ xw.vis = XDefaultVisual(xw.dpy, xw.scr); | |
+ else { | |
+ XVisualInfo *vis; | |
+ XRenderPictFormat *fmt; | |
+ int nvi; | |
+ int i; | |
+ | |
+ XVisualInfo tpl = { | |
+ .screen = xw.scr, | |
+ .depth = 32, | |
+ .class = TrueColor | |
+ }; | |
+ | |
+ vis = XGetVisualInfo(xw.dpy, | |
+ VisualScreenMask | VisualDepthMask | VisualClassMask, | |
+ &tpl, &nvi); | |
+ xw.vis = NULL; | |
+ for (i = 0; i < nvi; i++) { | |
+ fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual); | |
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) { | |
+ xw.vis = vis[i].visual; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ XFree(vis); | |
+ | |
+ if (!xw.vis) { | |
+ fprintf(stderr, "Couldn't find ARGB visual.\n"); | |
+ exit(1); | |
+ } | |
+ } | |
/* font */ | |
if (!FcInit()) | |
@@ -1014,7 +1065,11 @@ xinit(int cols, int rows) | |
xloadfonts(usedfont, 0); | |
/* colors */ | |
- xw.cmap = XDefaultColormap(xw.dpy, xw.scr); | |
+ if (!USE_ARGB) | |
+ xw.cmap = XDefaultColormap(xw.dpy, xw.scr); | |
+ else | |
+ xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr), | |
+ xw.vis, None); | |
xloadcols(); | |
/* adjust fixed window geometry */ | |
@@ -1037,16 +1092,15 @@ xinit(int cols, int rows) | |
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) | |
parent = XRootWindow(xw.dpy, xw.scr); | |
xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, | |
- win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, | |
+ win.w, win.h, 0, xw.depth, InputOutput, | |
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity | |
| CWEventMask | CWColormap, &xw.attrs); | |
memset(&gcvalues, 0, sizeof(gcvalues)); | |
gcvalues.graphics_exposures = False; | |
- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, | |
- &gcvalues); | |
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, | |
- DefaultDepth(xw.dpy, xw.scr)); | |
+ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); | |
+ dc.gc = XCreateGC(xw.dpy, (USE_ARGB) ? xw.buf: parent, | |
+ GCGraphicsExposures, &gcvalues); | |
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); | |
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment