Updated st to version 0.8.5. Updated patches as well

master
_N0x 2 years ago
parent abc1d97e2d
commit 86753fdeef

@ -4,7 +4,7 @@
include config.mk
SRC = st.c x.c
SRC = st.c x.c hb.c
OBJ = $(SRC:.c=.o)
all: options st
@ -22,7 +22,8 @@ config.h:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
x.o: arg.h config.h st.h win.h
x.o: arg.h config.h st.h win.h hb.h
hb.o: st.h
$(OBJ): config.h config.mk

@ -5,8 +5,9 @@
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
static int borderpx = 2;
//static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
static char *font = "Hack Nerd Font Mono:pixelsize=16:antialias=true:autohint=true";
static int borderpx = 30;
/*
* What program is execed by st depends of these precedence rules:
@ -91,37 +92,40 @@ char *termname = "st-256color";
*
* stty tabs
*/
unsigned int tabspaces = 8;
unsigned int tabspaces = 4;
/* bg opacity */
float alpha = 0.80;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* 8 normal colors */
"black",
"red3",
"green3",
"yellow3",
"blue2",
"magenta3",
"cyan3",
"gray90",
"#3b4252", /* black */
"#bf616a", /* red */
"#a3be8c", /* green */
"#ebcb8b", /* yellow */
"#81a1c1", /* blue */
"#b48ead", /* magenta */
"#88c0d0", /* cyan */
"#e5e9f0", /* white */
/* 8 bright colors */
"gray50",
"red",
"green",
"yellow",
"#5c5cff",
"magenta",
"cyan",
"white",
"#4c566a", /* black */
"#bf616a", /* red */
"#a3be8c", /* green */
"#ebcb8b", /* yellow */
"#81a1c1", /* blue */
"#b48ead", /* magenta */
"#8fbcbb", /* cyan */
"#eceff4", /* white */
[255] = 0,
/* more colors can be added after 255 to use with DefaultXX */
"#cccccc",
"#555555",
"gray90", /* default foreground colour */
"black", /* default background colour */
"#555555",
"#d8dee9", /* foreground */
"#2e3440", /* background */
};
@ -176,6 +180,8 @@ static uint forcemousemod = ShiftMask;
*/
static MouseShortcut mshortcuts[] = {
/* mask button function argument release */
{ ShiftMask, Button4, kscrollup, {.i = 1} },
{ ShiftMask, Button5, kscrolldown, {.i = 1} },
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
@ -201,6 +207,9 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
{ TERMMOD, XK_Return, newterm, {.i = 0} },
};
/*
@ -472,3 +481,9 @@ static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";
/*
* plumb_cmd is run on mouse button 3 click, with argument set to
* current selection and with cwd set to the cwd of the active shell
*/
static char *plumb_cmd = "plumb";

@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
`$(PKG_CONFIG) --cflags freetype2`
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
`$(PKG_CONFIG) --cflags freetype2` \
`$(PKG_CONFIG) --cflags harfbuzz`
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
`$(PKG_CONFIG) --libs fontconfig` \
`$(PKG_CONFIG) --libs freetype2`
`$(PKG_CONFIG) --libs freetype2` \
`$(PKG_CONFIG) --libs harfbuzz`
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600

@ -0,0 +1,136 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <X11/Xft/Xft.h>
#include <hb.h>
#include <hb-ft.h>
#include "st.h"
void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length);
hb_font_t *hbfindfont(XftFont *match);
typedef struct {
XftFont *match;
hb_font_t *font;
} HbFontMatch;
static int hbfontslen = 0;
static HbFontMatch *hbfontcache = NULL;
void
hbunloadfonts()
{
for (int i = 0; i < hbfontslen; i++) {
hb_font_destroy(hbfontcache[i].font);
XftUnlockFace(hbfontcache[i].match);
}
if (hbfontcache != NULL) {
free(hbfontcache);
hbfontcache = NULL;
}
hbfontslen = 0;
}
hb_font_t *
hbfindfont(XftFont *match)
{
for (int i = 0; i < hbfontslen; i++) {
if (hbfontcache[i].match == match)
return hbfontcache[i].font;
}
/* Font not found in cache, caching it now. */
hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
FT_Face face = XftLockFace(match);
hb_font_t *font = hb_ft_font_create(face, NULL);
if (font == NULL)
die("Failed to load Harfbuzz font.");
hbfontcache[hbfontslen].match = match;
hbfontcache[hbfontslen].font = font;
hbfontslen += 1;
return font;
}
void
hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y)
{
int start = 0, length = 1, gstart = 0;
hb_codepoint_t *codepoints = calloc(len, sizeof(hb_codepoint_t));
for (int idx = 1, specidx = 1; idx < len; idx++) {
if (glyphs[idx].mode & ATTR_WDUMMY) {
length += 1;
continue;
}
if (specs[specidx].font != specs[start].font || ATTRCMP(glyphs[gstart], glyphs[idx]) || selected(x + idx, y) != selected(x + gstart, y)) {
hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
/* Reset the sequence. */
length = 1;
start = specidx;
gstart = idx;
} else {
length += 1;
}
specidx++;
}
/* EOL. */
hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
/* Apply the transformation to glyph specs. */
for (int i = 0, specidx = 0; i < len; i++) {
if (glyphs[i].mode & ATTR_WDUMMY)
continue;
if (codepoints[i] != specs[specidx].glyph)
((Glyph *)glyphs)[i].mode |= ATTR_LIGA;
specs[specidx++].glyph = codepoints[i];
}
free(codepoints);
}
void
hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length)
{
hb_font_t *font = hbfindfont(xfont);
if (font == NULL)
return;
Rune rune;
ushort mode = USHRT_MAX;
hb_buffer_t *buffer = hb_buffer_create();
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
/* Fill buffer with codepoints. */
for (int i = start; i < (start+length); i++) {
rune = string[i].u;
mode = string[i].mode;
if (mode & ATTR_WDUMMY)
rune = 0x0020;
hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
}
/* Shape the segment. */
hb_shape(font, buffer, NULL, 0);
/* Get new glyph info. */
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL);
/* Write new codepoints. */
for (int i = 0; i < length; i++) {
hb_codepoint_t gid = info[i].codepoint;
codepoints[start+i] = gid;
}
/* Cleanup. */
hb_buffer_destroy(buffer);
}

@ -0,0 +1,7 @@
#include <X11/Xft/Xft.h>
#include <hb.h>
#include <hb-ft.h>
void hbunloadfonts();
void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int);

@ -0,0 +1,130 @@
config.def.h | 6 ++++++
st.c | 21 ++++++++++++++++++++-
st.h | 2 ++
x.c | 26 ++++++++++++++++++++++++++
4 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 823e79f..08e6ed4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -459,3 +459,9 @@ static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";
+
+/*
+ * plumb_cmd is run on mouse button 3 click, with argument set to
+ * current selection and with cwd set to the cwd of the active shell
+ */
+static char *plumb_cmd = "plumb";
diff --git a/st.c b/st.c
index 46cf2da..46d7c8a 100644
--- a/st.c
+++ b/st.c
@@ -27,6 +27,9 @@
#elif defined(__FreeBSD__) || defined(__DragonFly__)
#include <libutil.h>
#endif
+#if defined(__OpenBSD__)
+ #include <sys/sysctl.h>
+#endif
/* Arbitrary sizes */
#define UTF_INVALID 0xFFFD
@@ -232,6 +235,22 @@ static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
+int
+subprocwd(char *path)
+{
+#if defined(__linux)
+ if (snprintf(path, PATH_MAX, "/proc/%d/cwd", pid) < 0)
+ return -1;
+ return 0;
+#elif defined(__OpenBSD__)
+ size_t sz = PATH_MAX;
+ int name[3] = {CTL_KERN, KERN_PROC_CWD, pid};
+ if (sysctl(name, 3, path, &sz, 0, 0) == -1)
+ return -1;
+ return 0;
+#endif
+}
+
ssize_t
xwrite(int fd, const char *s, size_t len)
{
@@ -810,7 +829,7 @@ ttynew(char *line, char *cmd, char *out, char **args)
break;
default:
#ifdef __OpenBSD__
- if (pledge("stdio rpath tty proc", NULL) == -1)
+ if (pledge("stdio rpath tty proc ps exec", NULL) == -1)
die("pledge\n");
#endif
close(s);
diff --git a/st.h b/st.h
index 38c61c4..1f87287 100644
--- a/st.h
+++ b/st.h
@@ -110,6 +110,8 @@ void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(char *);
+int subprocwd(char *);
+
/* config.h globals */
extern char *utmp;
extern char *stty_args;
diff --git a/x.c b/x.c
index 00cb6b1..e03dc71 100644
--- a/x.c
+++ b/x.c
@@ -5,6 +5,7 @@
#include <locale.h>
#include <signal.h>
#include <sys/select.h>
+#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <libgen.h>
@@ -635,6 +636,29 @@ xsetsel(char *str)
setsel(str, CurrentTime);
}
+void
+plumb(char *sel) {
+ if (sel == NULL)
+ return;
+ char cwd[PATH_MAX];
+ pid_t child;
+ if (subprocwd(cwd) != 0)
+ return;
+
+ switch(child = fork()) {
+ case -1:
+ return;
+ case 0:
+ if (chdir(cwd) != 0)
+ exit(1);
+ if (execvp(plumb_cmd, (char *const []){plumb_cmd, sel, 0}) == -1)
+ exit(1);
+ exit(0);
+ default:
+ waitpid(child, NULL, 0);
+ }
+}
+
void
brelease(XEvent *e)
{
@@ -647,6 +671,8 @@ brelease(XEvent *e)
selpaste(NULL);
else if (e->xbutton.button == Button1)
mousesel(e, 1);
+ else if (e->xbutton.button == Button3)
+ plumb(xsel.primary);
}
void

@ -0,0 +1,146 @@
diff --git a/config.def.h b/config.def.h
index 91ab8ca..6af616e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -93,6 +93,9 @@ char *termname = "st-256color";
*/
unsigned int tabspaces = 8;
+/* bg opacity */
+float alpha = 0.8;
+
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* 8 normal colors */
diff --git a/config.mk b/config.mk
index 4c4c5d5..0114bad 100644
--- a/config.mk
+++ b/config.mk
@@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config
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.h b/st.h
index 519b9bd..8bb533d 100644
--- a/st.h
+++ b/st.h
@@ -126,3 +126,4 @@ extern unsigned int tabspaces;
extern unsigned int defaultfg;
extern unsigned int defaultbg;
extern unsigned int defaultcs;
+extern float alpha;
diff --git a/x.c b/x.c
index 8a16faa..ddf4178 100644
--- a/x.c
+++ b/x.c
@@ -105,6 +105,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;
@@ -243,6 +244,7 @@ static char *usedfont = NULL;
static double usedfontsize = 0;
static double defaultfontsize = 0;
+static char *opt_alpha = NULL;
static char *opt_class = NULL;
static char **opt_cmd = NULL;
static char *opt_embed = NULL;
@@ -736,7 +738,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);
@@ -796,6 +798,13 @@ xloadcols(void)
else
die("could not allocate color %d\n", i);
}
+
+ /* set alpha value of bg color */
+ if (opt_alpha)
+ alpha = strtof(opt_alpha, NULL);
+ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
+ dc.col[defaultbg].pixel &= 0x00FFFFFF;
+ dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
loaded = 1;
}
@@ -1118,11 +1127,23 @@ xinit(int cols, int rows)
Window parent;
pid_t thispid = getpid();
XColor xmousefg, xmousebg;
+ XWindowAttributes attr;
+ XVisualInfo vis;
if (!(xw.dpy = XOpenDisplay(NULL)))
die("can't open display\n");
xw.scr = XDefaultScreen(xw.dpy);
- xw.vis = XDefaultVisual(xw.dpy, xw.scr);
+
+ if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) {
+ parent = XRootWindow(xw.dpy, xw.scr);
+ xw.depth = 32;
+ } else {
+ XGetWindowAttributes(xw.dpy, parent, &attr);
+ xw.depth = attr.depth;
+ }
+
+ XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis);
+ xw.vis = vis.visual;
/* font */
if (!FcInit())
@@ -1132,7 +1153,7 @@ xinit(int cols, int rows)
xloadfonts(usedfont, 0);
/* colors */
- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
+ xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
xloadcols();
/* adjust fixed window geometry */
@@ -1152,19 +1173,15 @@ xinit(int cols, int rows)
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
xw.attrs.colormap = xw.cmap;
- 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, xw.buf, GCGraphicsExposures, &gcvalues);
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
@@ -2019,6 +2036,9 @@ main(int argc, char *argv[])
case 'a':
allowaltscreen = 0;
break;
+ case 'A':
+ opt_alpha = EARGF(usage());
+ break;
case 'c':
opt_class = EARGF(usage());
break;

@ -0,0 +1,152 @@
diff --git a/x.c b/x.c
index 8bf998e..e2cda07 100644
--- a/x.c
+++ b/x.c
@@ -81,6 +81,7 @@ typedef XftGlyphFontSpec GlyphFontSpec;
typedef struct {
int tw, th; /* tty width and height */
int w, h; /* window width and height */
+ int hborderpx, vborderpx;
int ch; /* char height */
int cw; /* char width */
int mode; /* window state/mode flags */
@@ -331,7 +332,7 @@ ttysend(const Arg *arg)
int
evcol(XEvent *e)
{
- int x = e->xbutton.x - borderpx;
+ int x = e->xbutton.x - win.hborderpx;
LIMIT(x, 0, win.tw - 1);
return x / win.cw;
}
@@ -339,7 +340,7 @@ evcol(XEvent *e)
int
evrow(XEvent *e)
{
- int y = e->xbutton.y - borderpx;
+ int y = e->xbutton.y - win.vborderpx;
LIMIT(y, 0, win.th - 1);
return y / win.ch;
}
@@ -723,6 +724,9 @@ cresize(int width, int height)
col = MAX(1, col);
row = MAX(1, row);
+ win.hborderpx = (win.w - col * win.cw) / 2;
+ win.vborderpx = (win.h - row * win.ch) / 2;
+
tresize(col, row);
xresize(col, row);
ttyresize(win.tw, win.th);
@@ -840,8 +844,8 @@ xhints(void)
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
sizeh->height = win.h;
sizeh->width = win.w;
- sizeh->height_inc = win.ch;
- sizeh->width_inc = win.cw;
+ sizeh->height_inc = 1;
+ sizeh->width_inc = 1;
sizeh->base_height = 2 * borderpx;
sizeh->base_width = 2 * borderpx;
sizeh->min_height = win.ch + 2 * borderpx;
@@ -1123,8 +1127,8 @@ xinit(int cols, int rows)
xloadcols();
/* adjust fixed window geometry */
- win.w = 2 * borderpx + cols * win.cw;
- win.h = 2 * borderpx + rows * win.ch;
+ win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw;
+ win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch;
if (xw.gm & XNegative)
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
if (xw.gm & YNegative)
@@ -1213,7 +1217,7 @@ xinit(int cols, int rows)
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
- float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
+ float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp;
ushort mode, prevmode = USHRT_MAX;
Font *font = &dc.font;
int frcflags = FRC_NORMAL;
@@ -1346,7 +1350,7 @@ void
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
{
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
- int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
+ int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch,
width = charlen * win.cw;
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg;
@@ -1436,17 +1440,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Intelligent cleaning up of the borders. */
if (x == 0) {
- xclear(0, (y == 0)? 0 : winy, borderpx,
+ xclear(0, (y == 0)? 0 : winy, win.vborderpx,
winy + win.ch +
- ((winy + win.ch >= borderpx + win.th)? win.h : 0));
+ ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
}
- if (winx + width >= borderpx + win.tw) {
+ if (winx + width >= win.hborderpx + win.tw) {
xclear(winx + width, (y == 0)? 0 : winy, win.w,
- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
+ ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
}
if (y == 0)
- xclear(winx, 0, winx + width, borderpx);
- if (winy + win.ch >= borderpx + win.th)
+ xclear(winx, 0, winx + width, win.vborderpx);
+ if (winy + win.ch >= win.vborderpx + win.th)
xclear(winx, winy + win.ch, winx + width, win.h);
/* Clean up the region we want to draw to. */
@@ -1540,35 +1544,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
case 3: /* Blinking Underline */
case 4: /* Steady Underline */
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + (cy + 1) * win.ch - \
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + (cy + 1) * win.ch - \
cursorthickness,
win.cw, cursorthickness);
break;
case 5: /* Blinking bar */
case 6: /* Steady bar */
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + cy * win.ch,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
cursorthickness, win.ch);
break;
}
} else {
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + cy * win.ch,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
win.cw - 1, 1);
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + cy * win.ch,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
- borderpx + (cx + 1) * win.cw - 1,
- borderpx + cy * win.ch,
+ win.hborderpx + (cx + 1) * win.cw - 1,
+ win.vborderpx + cy * win.ch,
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + (cy + 1) * win.ch - 1,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + (cy + 1) * win.ch - 1,
win.cw, 1);
}
}

@ -0,0 +1,17 @@
diff --git a/x.c b/x.c
index 65cae94..096471c 100644
--- a/x.c
+++ b/x.c
@@ -1501,6 +1501,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
if (winy + win.ch >= win.vborderpx + win.th)
xclear(winx, winy + win.ch, winx + width, win.h);
+ /* Clear border for anysize patch */
+ xclear(0, 0, win.w, win.vborderpx);
+ xclear(0, 0, win.hborderpx, win.h);
+ xclear(0, win.h - win.vborderpx, win.w, win.vborderpx);
+ xclear(win.w - win.hborderpx, 0, win.hborderpx, win.h);
+
/* Clean up the region we want to draw to. */
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);

@ -0,0 +1,12 @@
diff --git a/x.c b/x.c
index e5f1737..5cabd60 100644
--- a/x.c
+++ b/x.c
@@ -673,6 +673,7 @@ setsel(char *str, Time t)
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
selclear();
+ clipcopy(NULL);
}
void

@ -0,0 +1,20 @@
--- a/config.def.h 2020-11-12 20:23:48.867954750 +0100
+++ b/config.def.h 2020-11-12 20:21:15.055922720 +0100
@@ -276,7 +276,7 @@
{ XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
- { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+ { XK_KP_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
{ XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
{ XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
@@ -344,7 +344,7 @@
{ XK_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
- { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+ { XK_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
{ XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
{ XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
{ XK_BackSpace, Mod1Mask, "\033\177", 0, 0},

@ -0,0 +1,307 @@
diff --git a/Makefile b/Makefile
index 470ac86..38240da 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
include config.mk
-SRC = st.c x.c
+SRC = st.c x.c hb.c
OBJ = $(SRC:.c=.o)
all: options st
@@ -22,7 +22,8 @@ config.h:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
-x.o: arg.h config.h st.h win.h
+x.o: arg.h config.h st.h win.h hb.h
+hb.o: st.h
$(OBJ): config.h config.mk
diff --git a/config.mk b/config.mk
index ddc65ae..07a3d14 100644
--- a/config.mk
+++ b/config.mk
@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
- `$(PKG_CONFIG) --cflags freetype2`
+ `$(PKG_CONFIG) --cflags freetype2` \
+ `$(PKG_CONFIG) --cflags harfbuzz`
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
`$(PKG_CONFIG) --libs fontconfig` \
- `$(PKG_CONFIG) --libs freetype2`
+ `$(PKG_CONFIG) --libs freetype2` \
+ `$(PKG_CONFIG) --libs harfbuzz`
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
diff --git a/hb.c b/hb.c
new file mode 100644
index 0000000..7df2828
--- /dev/null
+++ b/hb.c
@@ -0,0 +1,136 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <X11/Xft/Xft.h>
+#include <hb.h>
+#include <hb-ft.h>
+
+#include "st.h"
+
+void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length);
+hb_font_t *hbfindfont(XftFont *match);
+
+typedef struct {
+ XftFont *match;
+ hb_font_t *font;
+} HbFontMatch;
+
+static int hbfontslen = 0;
+static HbFontMatch *hbfontcache = NULL;
+
+void
+hbunloadfonts()
+{
+ for (int i = 0; i < hbfontslen; i++) {
+ hb_font_destroy(hbfontcache[i].font);
+ XftUnlockFace(hbfontcache[i].match);
+ }
+
+ if (hbfontcache != NULL) {
+ free(hbfontcache);
+ hbfontcache = NULL;
+ }
+ hbfontslen = 0;
+}
+
+hb_font_t *
+hbfindfont(XftFont *match)
+{
+ for (int i = 0; i < hbfontslen; i++) {
+ if (hbfontcache[i].match == match)
+ return hbfontcache[i].font;
+ }
+
+ /* Font not found in cache, caching it now. */
+ hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
+ FT_Face face = XftLockFace(match);
+ hb_font_t *font = hb_ft_font_create(face, NULL);
+ if (font == NULL)
+ die("Failed to load Harfbuzz font.");
+
+ hbfontcache[hbfontslen].match = match;
+ hbfontcache[hbfontslen].font = font;
+ hbfontslen += 1;
+
+ return font;
+}
+
+void
+hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y)
+{
+ int start = 0, length = 1, gstart = 0;
+ hb_codepoint_t *codepoints = calloc(len, sizeof(hb_codepoint_t));
+
+ for (int idx = 1, specidx = 1; idx < len; idx++) {
+ if (glyphs[idx].mode & ATTR_WDUMMY) {
+ length += 1;
+ continue;
+ }
+
+ if (specs[specidx].font != specs[start].font || ATTRCMP(glyphs[gstart], glyphs[idx]) || selected(x + idx, y) != selected(x + gstart, y)) {
+ hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
+
+ /* Reset the sequence. */
+ length = 1;
+ start = specidx;
+ gstart = idx;
+ } else {
+ length += 1;
+ }
+
+ specidx++;
+ }
+
+ /* EOL. */
+ hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
+
+ /* Apply the transformation to glyph specs. */
+ for (int i = 0, specidx = 0; i < len; i++) {
+ if (glyphs[i].mode & ATTR_WDUMMY)
+ continue;
+
+ if (codepoints[i] != specs[specidx].glyph)
+ ((Glyph *)glyphs)[i].mode |= ATTR_LIGA;
+
+ specs[specidx++].glyph = codepoints[i];
+ }
+
+ free(codepoints);
+}
+
+void
+hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length)
+{
+ hb_font_t *font = hbfindfont(xfont);
+ if (font == NULL)
+ return;
+
+ Rune rune;
+ ushort mode = USHRT_MAX;
+ hb_buffer_t *buffer = hb_buffer_create();
+ hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
+
+ /* Fill buffer with codepoints. */
+ for (int i = start; i < (start+length); i++) {
+ rune = string[i].u;
+ mode = string[i].mode;
+ if (mode & ATTR_WDUMMY)
+ rune = 0x0020;
+ hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
+ }
+
+ /* Shape the segment. */
+ hb_shape(font, buffer, NULL, 0);
+
+ /* Get new glyph info. */
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL);
+
+ /* Write new codepoints. */
+ for (int i = 0; i < length; i++) {
+ hb_codepoint_t gid = info[i].codepoint;
+ codepoints[start+i] = gid;
+ }
+
+ /* Cleanup. */
+ hb_buffer_destroy(buffer);
+}
diff --git a/hb.h b/hb.h
new file mode 100644
index 0000000..b3e02d0
--- /dev/null
+++ b/hb.h
@@ -0,0 +1,7 @@
+#include <X11/Xft/Xft.h>
+#include <hb.h>
+#include <hb-ft.h>
+
+void hbunloadfonts();
+void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int);
+
diff --git a/st.c b/st.c
index 641edc0..14a0b66 100644
--- a/st.c
+++ b/st.c
@@ -2670,7 +2670,8 @@ draw(void)
drawregion(0, 0, term.col, term.row);
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, term.ocy, term.line[term.ocy][term.ocx],
+ term.line[term.ocy], term.col);
term.ocx = cx;
term.ocy = term.c.y;
xfinishdraw();
diff --git a/st.h b/st.h
index 2b2ba94..01bfb05 100644
--- a/st.h
+++ b/st.h
@@ -11,7 +11,8 @@
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
-#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
+#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \
+ (a).fg != (b).fg || \
(a).bg != (b).bg)
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
(t1.tv_nsec-t2.tv_nsec)/1E6)
@@ -33,6 +34,7 @@ enum glyph_attribute {
ATTR_WRAP = 1 << 8,
ATTR_WIDE = 1 << 9,
ATTR_WDUMMY = 1 << 10,
+ ATTR_LIGA = 1 << 11,
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
};
diff --git a/win.h b/win.h
index a6ef1b9..bc0d180 100644
--- a/win.h
+++ b/win.h
@@ -25,7 +25,7 @@ enum win_mode {
void xbell(void);
void xclipcopy(void);
-void xdrawcursor(int, int, Glyph, int, int, Glyph);
+void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
void xdrawline(Line, int, int, int);
void xfinishdraw(void);
void xloadcols(void);
diff --git a/x.c b/x.c
index 50da23c..bec3e76 100644
--- a/x.c
+++ b/x.c
@@ -19,6 +19,7 @@ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
+#include "hb.h"
/* types used in config.h */
typedef struct {
@@ -1040,6 +1041,9 @@ xunloadfont(Font *f)
void
xunloadfonts(void)
{
+ /* Clear Harfbuzz font cache. */
+ hbunloadfonts();
+
/* Free the loaded fonts in the font cache. */
while (frclen > 0)
XftFontClose(xw.dpy, frc[--frclen].font);
@@ -1246,7 +1250,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
mode = glyphs[i].mode;
/* Skip dummy wide-character spacing. */
- if (mode == ATTR_WDUMMY)
+ if (mode & ATTR_WDUMMY)
continue;
/* Determine font for glyph if different from previous glyph. */
@@ -1353,6 +1357,9 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
numspecs++;
}
+ /* Harfbuzz transformation for ligatures. */
+ hbtransform(specs, glyphs, len, x, y);
+
return numspecs;
}
@@ -1502,14 +1509,17 @@ xdrawglyph(Glyph g, int x, int y)
}
void
-xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len)
{
Color drawcol;
/* remove the old cursor */
if (selected(ox, oy))
og.mode ^= ATTR_REVERSE;
- xdrawglyph(og, ox, oy);
+
+ /* Redraw the line where cursor was previously.
+ * It will restore the ligatures broken by the cursor. */
+ xdrawline(line, 0, oy, len);
if (IS_SET(MODE_HIDE))
return;

@ -0,0 +1,111 @@
From 063d3eff86c788798d8219a7eb10b39d41f06482 Mon Sep 17 00:00:00 2001
From: Santtu Lakkala <inz@inz.fi>
Date: Sat, 19 Feb 2022 14:12:02 +0200
Subject: [PATCH] Add shortcut to spawn new terminal in the current dir
Build on bakkeby's doule fork version. Use /proc/self/exe as the binary,
and argv[0] as the called name. This allows to have several different
st's and running from build tree etc. Also skip the unnecessary readlink
part, shell shall do that anyway. Futher mark the pty master as cloexec,
so the fd's are not leaked to spawned processes.
---
config.def.h | 1 +
st.c | 36 ++++++++++++++++++++++++++++++++++++
st.h | 1 +
3 files changed, 38 insertions(+)
diff --git a/config.def.h b/config.def.h
index 91ab8ca..7c75246 100644
--- a/config.def.h
+++ b/config.def.h
@@ -201,6 +201,7 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
+ { TERMMOD, XK_Return, newterm, {.i = 0} },
};
/*
diff --git a/st.c b/st.c
index 51049ba..5d435de 100644
--- a/st.c
+++ b/st.c
@@ -20,6 +20,8 @@
#include "st.h"
#include "win.h"
+extern char *argv0;
+
#if defined(__linux)
#include <pty.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@@ -153,6 +155,7 @@ typedef struct {
} STREscape;
static void execsh(char *, char **);
+static int chdir_by_pid(pid_t pid);
static void stty(char **);
static void sigchld(int);
static void ttywriteraw(const char *, size_t);
@@ -813,6 +816,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
if (pledge("stdio rpath tty proc", NULL) == -1)
die("pledge\n");
#endif
+ fcntl(m, F_SETFD, FD_CLOEXEC);
close(s);
cmdfd = m;
signal(SIGCHLD, sigchld);
@@ -1061,6 +1065,38 @@ tswapscreen(void)
tfulldirt();
}
+void
+newterm(const Arg* a)
+{
+ int res;
+ switch (fork()) {
+ case -1:
+ die("fork failed: %s\n", strerror(errno));
+ break;
+ case 0:
+ switch (fork()) {
+ case -1:
+ die("fork failed: %s\n", strerror(errno));
+ break;
+ case 0:
+ chdir_by_pid(pid);
+ execlp("/proc/self/exe", argv0, NULL);
+ exit(1);
+ break;
+ default:
+ exit(0);
+ }
+ default:
+ wait(NULL);
+ }
+}
+
+static int chdir_by_pid(pid_t pid) {
+ char buf[32];
+ snprintf(buf, sizeof buf, "/proc/%ld/cwd", (long)pid);
+ return chdir(buf);
+}
+
void
tscrolldown(int orig, int n)
{
diff --git a/st.h b/st.h
index 519b9bd..fbdad18 100644
--- a/st.h
+++ b/st.h
@@ -81,6 +81,7 @@ void die(const char *, ...);
void redraw(void);
void draw(void);
+void newterm(const Arg *);
void printscreen(const Arg *);
void printsel(const Arg *);
void sendbreak(const Arg *);
--
2.32.0

@ -0,0 +1,90 @@
From 1904cbc9af2d518a77331deb082750366aaec90b Mon Sep 17 00:00:00 2001
From: aleks <aleks.stier@icloud.com>
Date: Tue, 31 May 2022 13:09:47 +0200
Subject: [PATCH] Use nord-theme
*"Inspired by the beauty of the arctic, the colors reflect the cold, yet
harmonious world of ice and the colorfulness of the Aurora Borealis."* -
[Nord Theme](https://www.nordtheme.com/)
The default behaviour of st is to reverse the fore- and background
colors of each selected cell. If you don't want the selection-colors to
be reveresed but instead have fixed fore- and background colors apply on
top of this patch the [selectioncolors](../selectioncolors/)-patch. Then
set the following settings in your config.h:
unsigned int selectionbg = 0;
unsigned int selectionfg = 256;
---
config.def.h | 42 ++++++++++++++++++++----------------------
1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/config.def.h b/config.def.h
index 91ab8ca..afd00fd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -96,32 +96,30 @@ unsigned int tabspaces = 8;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* 8 normal colors */
- "black",
- "red3",
- "green3",
- "yellow3",
- "blue2",
- "magenta3",
- "cyan3",
- "gray90",
+ "#3b4252", /* black */
+ "#bf616a", /* red */
+ "#a3be8c", /* green */
+ "#ebcb8b", /* yellow */
+ "#81a1c1", /* blue */
+ "#b48ead", /* magenta */
+ "#88c0d0", /* cyan */
+ "#e5e9f0", /* white */
/* 8 bright colors */
- "gray50",
- "red",
- "green",
- "yellow",
- "#5c5cff",
- "magenta",
- "cyan",
- "white",
+ "#4c566a", /* black */
+ "#bf616a", /* red */
+ "#a3be8c", /* green */
+ "#ebcb8b", /* yellow */
+ "#81a1c1", /* blue */
+ "#b48ead", /* magenta */
+ "#8fbcbb", /* cyan */
+ "#eceff4", /* white */
[255] = 0,
/* more colors can be added after 255 to use with DefaultXX */
- "#cccccc",
- "#555555",
- "gray90", /* default foreground colour */
- "black", /* default background colour */
+ "#d8dee9", /* default foreground colour */
+ "#2e3440", /* default background colour */
};
@@ -129,8 +127,8 @@ static const char *colorname[] = {
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
-unsigned int defaultfg = 258;
-unsigned int defaultbg = 259;
+unsigned int defaultfg = 256;
+unsigned int defaultbg = 257;
unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257;
--
2.36.1

@ -0,0 +1,28 @@
From 111e5d0311f174592ccecee2af11067103abaee7 Mon Sep 17 00:00:00 2001
From: aleks <aleks.stier@icloud.com>
Date: Sun, 11 Aug 2019 03:15:26 +0200
Subject: [PATCH] Make right-click paste
Pressing right-click pastes from the primary-selection.
If combined with the clipboard-patch right-click pastes from the clipboard.
Middle-click does nothing.
---
x.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x.c b/x.c
index 0422421..13a5849 100644
--- a/x.c
+++ b/x.c
@@ -643,7 +643,7 @@ brelease(XEvent *e)
return;
}
- if (e->xbutton.button == Button2)
+ if (e->xbutton.button == Button3)
selpaste(NULL);
else if (e->xbutton.button == Button1)
mousesel(e, 1);
--
2.22.0

@ -0,0 +1,350 @@
diff --git a/config.def.h b/config.def.h
index 91ab8ca..e3b469b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
};
/*
diff --git a/st.c b/st.c
index 51049ba..cd750f2 100644
--- a/st.c
+++ b/st.c
@@ -35,6 +35,7 @@
#define ESC_ARG_SIZ 16
#define STR_BUF_SIZ ESC_BUF_SIZ
#define STR_ARG_SIZ ESC_ARG_SIZ
+#define HISTSIZE 2000
/* macros */
#define IS_SET(flag) ((term.mode & (flag)) != 0)
@@ -42,6 +43,9 @@
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
+ term.scr + HISTSIZE + 1) % HISTSIZE] : \
+ term.line[(y) - term.scr])
enum term_mode {
MODE_WRAP = 1 << 0,
@@ -115,6 +119,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 */
@@ -184,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(const int *, int);
static void tsetchar(Rune, const Glyph *, int, int);
static void tsetdirt(int, int);
@@ -416,10 +423,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;
@@ -528,7 +535,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;
@@ -543,14 +550,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)))
@@ -571,14 +578,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;
}
@@ -609,13 +616,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;
@@ -851,6 +858,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);
@@ -1062,12 +1072,52 @@ 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);
@@ -1078,17 +1128,28 @@ tscrolldown(int orig, int n)
term.line[i-n] = temp;
}
- selscroll(orig, n);
+ if (term.scr == 0)
+ selscroll(orig, 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;
+ }
+
+ if (term.scr > 0 && term.scr < HISTSIZE)
+ term.scr = MIN(term.scr + n, HISTSIZE-1);
+
tclearregion(0, orig, term.col-1, orig+n-1);
tsetdirt(orig+n, term.bot);
@@ -1098,7 +1159,8 @@ tscrollup(int orig, int n)
term.line[i+n] = temp;
}
- selscroll(orig, -n);
+ if (term.scr == 0)
+ selscroll(orig, -n);
}
void
@@ -1127,7 +1189,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++;
}
@@ -1292,14 +1354,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
@@ -1736,11 +1798,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);
@@ -2330,7 +2392,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);
}
@@ -2343,7 +2405,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);
}
@@ -2557,7 +2619,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;
@@ -2594,6 +2656,14 @@ tresize(int col, int row)
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
+ 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 row to new width, zero-pad if needed */
for (i = 0; i < minrow; i++) {
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
@@ -2652,7 +2722,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);
}
}
@@ -2673,8 +2743,9 @@ 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 519b9bd..da36b34 100644
--- a/st.h
+++ b/st.h
@@ -81,6 +81,8 @@ void die(const char *, ...);
void redraw(void);
void draw(void);
+void kscrolldown(const Arg *);
+void kscrollup(const Arg *);
void printscreen(const Arg *);
void printsel(const Arg *);
void sendbreak(const Arg *);

@ -0,0 +1,25 @@
From b5d3351a21442a842e01e8c0317603b6890b379c Mon Sep 17 00:00:00 2001
From: asparagii <michele.lambertucci1@gmail.com>
Date: Thu, 27 Jan 2022 15:44:02 +0100
Subject: [PATCH] st-scrollback-mouse
---
config.def.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/config.def.h b/config.def.h
index e3b469b..c217315 100644
--- a/config.def.h
+++ b/config.def.h
@@ -176,6 +176,8 @@ static uint forcemousemod = ShiftMask;
*/
static MouseShortcut mshortcuts[] = {
/* mask button function argument release */
+ { ShiftMask, Button4, kscrollup, {.i = 1} },
+ { ShiftMask, Button5, kscrolldown, {.i = 1} },
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
--
2.34.1

@ -0,0 +1,42 @@
From 69cffc587b54b0a9cd81adb87abad8e526d5b25b Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Thu, 4 Jun 2020 17:35:08 +0300
Subject: [PATCH] support w3m images
w3m images are a hack which renders on top of the terminal's drawable,
which didn't work in st because when using double buffering, the front
buffer (on which w3m draws its images) is ignored, and st draws only
on the back buffer, which is then copied to the front buffer.
There's a patch to make it work at the FAQ already, but that patch
canceles double-buffering, which can have negative side effects on
some cases such as flickering.
This patch achieves the same goal but instead of canceling the double
buffer it first copies the front buffer to the back buffer.
This has the same issues as the FAQ patch in that the cursor line is
deleted at the image (because st renders always full lines), but
otherwise it's simpler and does keeps double buffering.
---
x.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/x.c b/x.c
index e5f1737..b6ae162 100644
--- a/x.c
+++ b/x.c
@@ -1594,6 +1594,8 @@ xsettitle(char *p)
int
xstartdraw(void)
{
+ if (IS_SET(MODE_VISIBLE))
+ XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0);
return IS_SET(MODE_VISIBLE);
}
base-commit: 43a395ae91f7d67ce694e65edeaa7bbc720dd027
--
2.17.1

@ -20,6 +20,8 @@
#include "st.h"
#include "win.h"
extern char *argv0;
#if defined(__linux)
#include <pty.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@ -27,6 +29,9 @@
#elif defined(__FreeBSD__) || defined(__DragonFly__)
#include <libutil.h>
#endif
#if defined(__OpenBSD__)
#include <sys/sysctl.h>
#endif
/* Arbitrary sizes */
#define UTF_INVALID 0xFFFD
@ -35,6 +40,7 @@
#define ESC_ARG_SIZ 16
#define STR_BUF_SIZ ESC_BUF_SIZ
#define STR_ARG_SIZ ESC_ARG_SIZ
#define HISTSIZE 2000
/* macros */
#define IS_SET(flag) ((term.mode & (flag)) != 0)
@ -42,6 +48,9 @@
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
term.scr + HISTSIZE + 1) % HISTSIZE] : \
term.line[(y) - term.scr])
enum term_mode {
MODE_WRAP = 1 << 0,
@ -115,6 +124,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 */
@ -153,6 +165,7 @@ typedef struct {
} STREscape;
static void execsh(char *, char **);
static int chdir_by_pid(pid_t pid);
static void stty(char **);
static void sigchld(int);
static void ttywriteraw(const char *, size_t);
@ -184,8 +197,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(const int *, int);
static void tsetchar(Rune, const Glyph *, int, int);
static void tsetdirt(int, int);
@ -231,6 +244,22 @@ static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
int
subprocwd(char *path)
{
#if defined(__linux)
if (snprintf(path, PATH_MAX, "/proc/%d/cwd", pid) < 0)
return -1;
return 0;
#elif defined(__OpenBSD__)
size_t sz = PATH_MAX;
int name[3] = {CTL_KERN, KERN_PROC_CWD, pid};
if (sysctl(name, 3, path, &sz, 0, 0) == -1)
return -1;
return 0;
#endif
}
ssize_t
xwrite(int fd, const char *s, size_t len)
{
@ -416,10 +445,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;
@ -528,7 +557,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;
@ -543,14 +572,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)))
@ -571,14 +600,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;
}
@ -609,13 +638,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;
@ -810,9 +839,10 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
break;
default:
#ifdef __OpenBSD__
if (pledge("stdio rpath tty proc", NULL) == -1)
if (pledge("stdio rpath tty proc ps exec", NULL) == -1)
die("pledge\n");
#endif
fcntl(m, F_SETFD, FD_CLOEXEC);
close(s);
cmdfd = m;
signal(SIGCHLD, sigchld);
@ -851,6 +881,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);
@ -1062,12 +1095,84 @@ tswapscreen(void)
}
void
tscrolldown(int orig, int n)
newterm(const Arg* a)
{
int res;
switch (fork()) {
case -1:
die("fork failed: %s\n", strerror(errno));
break;
case 0:
switch (fork()) {
case -1:
die("fork failed: %s\n", strerror(errno));
break;
case 0:
chdir_by_pid(pid);
execlp("/proc/self/exe", argv0, NULL);
exit(1);
break;
default:
exit(0);
}
default:
wait(NULL);
}
}
static int chdir_by_pid(pid_t pid) {
char buf[32];
snprintf(buf, sizeof buf, "/proc/%ld/cwd", (long)pid);
return chdir(buf);
}
void
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);
@ -1078,17 +1183,28 @@ tscrolldown(int orig, int n)
term.line[i-n] = temp;
}
selscroll(orig, n);
if (term.scr == 0)
selscroll(orig, 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;
}
if (term.scr > 0 && term.scr < HISTSIZE)
term.scr = MIN(term.scr + n, HISTSIZE-1);
tclearregion(0, orig, term.col-1, orig+n-1);
tsetdirt(orig+n, term.bot);
@ -1098,7 +1214,8 @@ tscrollup(int orig, int n)
term.line[i+n] = temp;
}
selscroll(orig, -n);
if (term.scr == 0)
selscroll(orig, -n);
}
void
@ -1127,7 +1244,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++;
}
@ -1292,14 +1409,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
@ -1736,11 +1853,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);
@ -2330,7 +2447,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);
}
@ -2343,7 +2460,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);
}
@ -2557,7 +2674,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;
@ -2594,6 +2711,14 @@ tresize(int col, int row)
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
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 row to new width, zero-pad if needed */
for (i = 0; i < minrow; i++) {
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
@ -2652,7 +2777,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);
}
}
@ -2673,8 +2798,11 @@ 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.line[term.ocy], term.col);
}
term.ocx = cx;
term.ocy = term.c.y;
xfinishdraw();

@ -11,7 +11,8 @@
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \
(a).fg != (b).fg || \
(a).bg != (b).bg)
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
(t1.tv_nsec-t2.tv_nsec)/1E6)
@ -33,6 +34,7 @@ enum glyph_attribute {
ATTR_WRAP = 1 << 8,
ATTR_WIDE = 1 << 9,
ATTR_WDUMMY = 1 << 10,
ATTR_LIGA = 1 << 11,
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
};
@ -81,6 +83,9 @@ void die(const char *, ...);
void redraw(void);
void draw(void);
void newterm(const Arg *);
void kscrolldown(const Arg *);
void kscrollup(const Arg *);
void printscreen(const Arg *);
void printsel(const Arg *);
void sendbreak(const Arg *);
@ -113,6 +118,8 @@ char *xstrdup(const char *);
int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b);
int subprocwd(char *);
/* config.h globals */
extern char *utmp;
extern char *scroll;
@ -126,3 +133,4 @@ extern unsigned int tabspaces;
extern unsigned int defaultfg;
extern unsigned int defaultbg;
extern unsigned int defaultcs;
extern float alpha;

@ -25,7 +25,7 @@ enum win_mode {
void xbell(void);
void xclipcopy(void);
void xdrawcursor(int, int, Glyph, int, int, Glyph);
void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
void xdrawline(Line, int, int, int);
void xfinishdraw(void);
void xloadcols(void);

@ -5,6 +5,7 @@
#include <locale.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <libgen.h>
@ -19,6 +20,7 @@ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
#include "hb.h"
/* types used in config.h */
typedef struct {
@ -81,6 +83,7 @@ typedef XftGlyphFontSpec GlyphFontSpec;
typedef struct {
int tw, th; /* tty width and height */
int w, h; /* window width and height */
int hborderpx, vborderpx;
int ch; /* char height */
int cw; /* char width */
int mode; /* window state/mode flags */
@ -105,6 +108,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;
@ -243,6 +247,7 @@ static char *usedfont = NULL;
static double usedfontsize = 0;
static double defaultfontsize = 0;
static char *opt_alpha = NULL;
static char *opt_class = NULL;
static char **opt_cmd = NULL;
static char *opt_embed = NULL;
@ -331,7 +336,7 @@ ttysend(const Arg *arg)
int
evcol(XEvent *e)
{
int x = e->xbutton.x - borderpx;
int x = e->xbutton.x - win.hborderpx;
LIMIT(x, 0, win.tw - 1);
return x / win.cw;
}
@ -339,7 +344,7 @@ evcol(XEvent *e)
int
evrow(XEvent *e)
{
int y = e->xbutton.y - borderpx;
int y = e->xbutton.y - win.vborderpx;
LIMIT(y, 0, win.th - 1);
return y / win.ch;
}
@ -675,6 +680,7 @@ setsel(char *str, Time t)
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
selclear();
clipcopy(NULL);
}
void
@ -683,6 +689,29 @@ xsetsel(char *str)
setsel(str, CurrentTime);
}
void
plumb(char *sel) {
if (sel == NULL)
return;
char cwd[PATH_MAX];
pid_t child;
if (subprocwd(cwd) != 0)
return;
switch(child = fork()) {
case -1:
return;
case 0:
if (chdir(cwd) != 0)
exit(1);
if (execvp(plumb_cmd, (char *const []){plumb_cmd, sel, 0}) == -1)
exit(1);
exit(0);
default:
waitpid(child, NULL, 0);
}
}
void
brelease(XEvent *e)
{
@ -693,8 +722,10 @@ brelease(XEvent *e)
if (mouseaction(e, 1))
return;
if (e->xbutton.button == Button1)
if (e->xbutton.button == Button3)
mousesel(e, 1);
else if (e->xbutton.button == Button3)
plumb(xsel.primary);
}
void
@ -723,6 +754,9 @@ cresize(int width, int height)
col = MAX(1, col);
row = MAX(1, row);
win.hborderpx = (win.w - col * win.cw) / 2;
win.vborderpx = (win.h - row * win.ch) / 2;
tresize(col, row);
xresize(col, row);
ttyresize(win.tw, win.th);
@ -736,7 +770,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);
@ -796,6 +830,13 @@ xloadcols(void)
else
die("could not allocate color %d\n", i);
}
/* set alpha value of bg color */
if (opt_alpha)
alpha = strtof(opt_alpha, NULL);
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
dc.col[defaultbg].pixel &= 0x00FFFFFF;
dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
loaded = 1;
}
@ -853,8 +894,8 @@ xhints(void)
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
sizeh->height = win.h;
sizeh->width = win.w;
sizeh->height_inc = win.ch;
sizeh->width_inc = win.cw;
sizeh->height_inc = 1;
sizeh->width_inc = 1;
sizeh->base_height = 2 * borderpx;
sizeh->base_width = 2 * borderpx;
sizeh->min_height = win.ch + 2 * borderpx;
@ -1046,6 +1087,9 @@ xunloadfont(Font *f)
void
xunloadfonts(void)
{
/* Clear Harfbuzz font cache. */
hbunloadfonts();
/* Free the loaded fonts in the font cache. */
while (frclen > 0)
XftFontClose(xw.dpy, frc[--frclen].font);
@ -1118,11 +1162,23 @@ xinit(int cols, int rows)
Window parent;
pid_t thispid = getpid();
XColor xmousefg, xmousebg;
XWindowAttributes attr;
XVisualInfo vis;
if (!(xw.dpy = XOpenDisplay(NULL)))
die("can't open display\n");
xw.scr = XDefaultScreen(xw.dpy);
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) {
parent = XRootWindow(xw.dpy, xw.scr);
xw.depth = 32;
} else {
XGetWindowAttributes(xw.dpy, parent, &attr);
xw.depth = attr.depth;
}
XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis);
xw.vis = vis.visual;
/* font */
if (!FcInit())
@ -1132,12 +1188,12 @@ xinit(int cols, int rows)
xloadfonts(usedfont, 0);
/* colors */
xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
xloadcols();
/* adjust fixed window geometry */
win.w = 2 * borderpx + cols * win.cw;
win.h = 2 * borderpx + rows * win.ch;
win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw;
win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch;
if (xw.gm & XNegative)
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
if (xw.gm & YNegative)
@ -1152,19 +1208,15 @@ xinit(int cols, int rows)
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
xw.attrs.colormap = xw.cmap;
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, xw.buf, GCGraphicsExposures, &gcvalues);
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
@ -1226,7 +1278,7 @@ xinit(int cols, int rows)
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp;
ushort mode, prevmode = USHRT_MAX;
Font *font = &dc.font;
int frcflags = FRC_NORMAL;
@ -1245,7 +1297,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
mode = glyphs[i].mode;
/* Skip dummy wide-character spacing. */
if (mode == ATTR_WDUMMY)
if (mode & ATTR_WDUMMY)
continue;
/* Determine font for glyph if different from previous glyph. */
@ -1352,6 +1404,9 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
numspecs++;
}
/* Harfbuzz transformation for ligatures. */
hbtransform(specs, glyphs, len, x, y);
return numspecs;
}
@ -1359,7 +1414,7 @@ void
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
{
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch,
width = charlen * win.cw;
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg;
@ -1449,19 +1504,25 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Intelligent cleaning up of the borders. */
if (x == 0) {
xclear(0, (y == 0)? 0 : winy, borderpx,
xclear(0, (y == 0)? 0 : winy, win.vborderpx,
winy + win.ch +
((winy + win.ch >= borderpx + win.th)? win.h : 0));
((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
}
if (winx + width >= borderpx + win.tw) {
if (winx + width >= win.hborderpx + win.tw) {
xclear(winx + width, (y == 0)? 0 : winy, win.w,
((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
}
if (y == 0)
xclear(winx, 0, winx + width, borderpx);
if (winy + win.ch >= borderpx + win.th)
xclear(winx, 0, winx + width, win.vborderpx);
if (winy + win.ch >= win.vborderpx + win.th)
xclear(winx, winy + win.ch, winx + width, win.h);
/* Clear border for anysize patch */
xclear(0, 0, win.w, win.vborderpx);
xclear(0, 0, win.hborderpx, win.h);
xclear(0, win.h - win.vborderpx, win.w, win.vborderpx);
xclear(win.w - win.hborderpx, 0, win.hborderpx, win.h);
/* Clean up the region we want to draw to. */
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
@ -1501,14 +1562,17 @@ xdrawglyph(Glyph g, int x, int y)
}
void
xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len)
{
Color drawcol;
/* remove the old cursor */
if (selected(ox, oy))
og.mode ^= ATTR_REVERSE;
xdrawglyph(og, ox, oy);
/* Redraw the line where cursor was previously.
* It will restore the ligatures broken by the cursor. */
xdrawline(line, 0, oy, len);
if (IS_SET(MODE_HIDE))
return;
@ -1553,35 +1617,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
case 3: /* Blinking Underline */
case 4: /* Steady Underline */
XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw,
borderpx + (cy + 1) * win.ch - \
win.hborderpx + cx * win.cw,
win.vborderpx + (cy + 1) * win.ch - \
cursorthickness,
win.cw, cursorthickness);
break;
case 5: /* Blinking bar */
case 6: /* Steady bar */
XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw,
borderpx + cy * win.ch,
win.hborderpx + cx * win.cw,
win.vborderpx + cy * win.ch,
cursorthickness, win.ch);
break;
}
} else {
XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw,
borderpx + cy * win.ch,
win.hborderpx + cx * win.cw,
win.vborderpx + cy * win.ch,
win.cw - 1, 1);
XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw,
borderpx + cy * win.ch,
win.hborderpx + cx * win.cw,
win.vborderpx + cy * win.ch,
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
borderpx + (cx + 1) * win.cw - 1,
borderpx + cy * win.ch,
win.hborderpx + (cx + 1) * win.cw - 1,
win.vborderpx + cy * win.ch,
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw,
borderpx + (cy + 1) * win.ch - 1,
win.hborderpx + cx * win.cw,
win.vborderpx + (cy + 1) * win.ch - 1,
win.cw, 1);
}
}
@ -1626,6 +1690,8 @@ xsettitle(char *p)
int
xstartdraw(void)
{
if (IS_SET(MODE_VISIBLE))
XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0);
return IS_SET(MODE_VISIBLE);
}
@ -2019,6 +2085,9 @@ main(int argc, char *argv[])
case 'a':
allowaltscreen = 0;
break;
case 'A':
opt_alpha = EARGF(usage());
break;
case 'c':
opt_class = EARGF(usage());
break;

Loading…
Cancel
Save