diff options
| author | davidovski <david@davidovski.xyz> | 2023-07-15 23:30:56 +0100 | 
|---|---|---|
| committer | davidovski <david@davidovski.xyz> | 2023-07-15 23:30:56 +0100 | 
| commit | 4f5d2bab933323cab147e57a3f04dd128049822a (patch) | |
| tree | ea0e00f333014a076807dc8004e57d300510b098 /st | |
| parent | b85872dfc933ff3bd2e95303d8327c357c8b9ca6 (diff) | |
add st as default terminal
Diffstat (limited to 'st')
| -rw-r--r-- | st/davidovski.patch | 1004 | ||||
| -rwxr-xr-x | st/deploy.sh | 12 | 
2 files changed, 1016 insertions, 0 deletions
| diff --git a/st/davidovski.patch b/st/davidovski.patch new file mode 100644 index 0000000..dc2e303 --- /dev/null +++ b/st/davidovski.patch @@ -0,0 +1,1004 @@ +diff --git a/Makefile b/Makefile +index 470ac86..be32361 100644 +--- a/Makefile ++++ b/Makefile +@@ -4,7 +4,7 @@ +  + include config.mk +  +-SRC = st.c x.c ++SRC = st.c x.c boxdraw.c + OBJ = $(SRC:.c=.o) +  + all: options st +@@ -23,6 +23,7 @@ config.h: +  + st.o: config.h st.h win.h + x.o: arg.h config.h st.h win.h ++boxdraw.o: config.h st.h boxdraw_data.h +  + $(OBJ): config.h config.mk +  +@@ -49,9 +50,12 @@ install: st + 	chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 + 	tic -sx st.info + 	@echo Please see the README file regarding the terminfo entry of st. ++	mkdir -p $(DESTDIR)$(PREFIX)/share/applications ++	cp -f st.desktop $(DESTDIR)$(PREFIX)/share/applications +  + uninstall: + 	rm -f $(DESTDIR)$(PREFIX)/bin/st + 	rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 ++	rm -f $(DESTDIR)$(PREFIX)/share/applications/st.desktop +  + .PHONY: all options clean dist install uninstall +diff --git a/config.def.h b/config.def.h +index 91ab8ca..b55e689 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -5,7 +5,13 @@ +  * +  * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html +  */ +-static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; ++static char *font = "Liberation Mono:pixelsize=10:antialias=true:autohint=true"; ++/* Spare fonts */ ++static char *font2[] = { ++/*	"Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */ ++/*	"Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */ ++}; ++ + static int borderpx = 2; +  + /* +@@ -67,6 +73,18 @@ static unsigned int blinktimeout = 800; +  */ + static unsigned int cursorthickness = 2; +  ++/* ++ * 1: render most of the lines/blocks characters without using the font for ++ *    perfect alignment between cells (U2500 - U259F except dashes/diagonals). ++ *    Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. ++ * 0: disable (render all U25XX glyphs normally from the font). ++ */ ++const int boxdraw = 0; ++const int boxdraw_bold = 0; ++ ++/* braille (U28XX):  1: render as adjacent "pixels",  0: use font */ ++const int boxdraw_braille = 0; ++ + /* +  * bell volume. It must be a value between -100 and 100. Use 0 for disabling +  * it +@@ -170,12 +188,50 @@ static unsigned int defaultattr = 11; +  */ + static uint forcemousemod = ShiftMask; +  ++/* ++ * Xresources preferences to load at startup ++ */ ++ResourcePref resources[] = { ++		{ "font",         STRING,  &font }, ++		{ "color0",       STRING,  &colorname[0] }, ++		{ "color1",       STRING,  &colorname[1] }, ++		{ "color2",       STRING,  &colorname[2] }, ++		{ "color3",       STRING,  &colorname[3] }, ++		{ "color4",       STRING,  &colorname[4] }, ++		{ "color5",       STRING,  &colorname[5] }, ++		{ "color6",       STRING,  &colorname[6] }, ++		{ "color7",       STRING,  &colorname[7] }, ++		{ "color8",       STRING,  &colorname[8] }, ++		{ "color9",       STRING,  &colorname[9] }, ++		{ "color10",      STRING,  &colorname[10] }, ++		{ "color11",      STRING,  &colorname[11] }, ++		{ "color12",      STRING,  &colorname[12] }, ++		{ "color13",      STRING,  &colorname[13] }, ++		{ "color14",      STRING,  &colorname[14] }, ++		{ "color15",      STRING,  &colorname[15] }, ++		{ "background",   STRING,  &colorname[259] }, ++		{ "foreground",   STRING,  &colorname[258] }, ++		{ "cursorColor",  STRING,  &colorname[256] }, ++		{ "termname",     STRING,  &termname }, ++		{ "shell",        STRING,  &shell }, ++		{ "minlatency",   INTEGER, &minlatency }, ++		{ "maxlatency",   INTEGER, &maxlatency }, ++		{ "blinktimeout", INTEGER, &blinktimeout }, ++		{ "bellvolume",   INTEGER, &bellvolume }, ++		{ "tabspaces",    INTEGER, &tabspaces }, ++		{ "borderpx",     INTEGER, &borderpx }, ++		{ "cwscale",      FLOAT,   &cwscale }, ++		{ "chscale",      FLOAT,   &chscale }, ++}; ++ + /* +  * Internal mouse shortcuts. +  * Beware that overloading Button1 will disable the selection. +  */ + static MouseShortcut mshortcuts[] = { + 	/* mask                 button   function        argument       release */ ++	{ XK_ANY_MOD,           Button4, kscrollup,      {.i = 5} }, ++	{ XK_ANY_MOD,           Button5, kscrolldown,    {.i = 5} }, + 	{ XK_ANY_MOD,           Button2, selpaste,       {.i = 0},      1 }, + 	{ ShiftMask,            Button4, ttysend,        {.s = "\033[5;2~"} }, + 	{ XK_ANY_MOD,           Button4, ttysend,        {.s = "\031"} }, +@@ -201,6 +257,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 623376e..bc95e89 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 */ +@@ -185,8 +192,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); +@@ -409,10 +416,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; +@@ -521,7 +528,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; +@@ -536,14 +543,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))) +@@ -564,14 +571,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; + 				} +@@ -602,13 +609,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; +  +@@ -844,6 +851,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); +@@ -1055,13 +1065,53 @@ 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); +  +@@ -1071,17 +1121,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); +  +@@ -1091,7 +1152,8 @@ tscrollup(int orig, int n) + 		term.line[i+n] = temp; + 	} +  +-	selscroll(orig, -n); ++	if (term.scr == 0) ++		selscroll(orig, -n); + } +  + void +@@ -1120,7 +1182,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++; + 	} +@@ -1215,6 +1277,9 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) + 	term.dirty[y] = 1; + 	term.line[y][x] = *attr; + 	term.line[y][x].u = u; ++ ++	if (isboxdraw(u)) ++		term.line[y][x].mode |= ATTR_BOXDRAW; + } +  + void +@@ -1285,14 +1350,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 +@@ -1729,11 +1794,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); +@@ -1809,6 +1874,33 @@ csihandle(void) + 			goto unknown; + 		} + 		break; ++	case 't': /* title stack operations */ ++		switch (csiescseq.arg[0]) { ++		case 22: /* pust current title on stack */ ++			switch (csiescseq.arg[1]) { ++			case 0: ++			case 1: ++			case 2: ++				xpushtitle(); ++				break; ++			default: ++				goto unknown; ++			} ++			break; ++		case 23: /* pop last title from stack */ ++			switch (csiescseq.arg[1]) { ++			case 0: ++			case 1: ++			case 2: ++				xsettitle(NULL, 1); ++				break; ++			default: ++				goto unknown; ++			} ++			break; ++		default: ++			goto unknown; ++		} + 	} + } +  +@@ -1887,7 +1979,7 @@ strhandle(void) + 		switch (par) { + 		case 0: + 			if (narg > 1) { +-				xsettitle(strescseq.args[1]); ++				xsettitle(strescseq.args[1], 0); + 				xseticontitle(strescseq.args[1]); + 			} + 			return; +@@ -1897,7 +1989,7 @@ strhandle(void) + 			return; + 		case 2: + 			if (narg > 1) +-				xsettitle(strescseq.args[1]); ++				xsettitle(strescseq.args[1], 0); + 			return; + 		case 52: + 			if (narg > 2 && allowwindowops) { +@@ -1956,7 +2048,7 @@ strhandle(void) + 		} + 		break; + 	case 'k': /* old title set compatibility */ +-		xsettitle(strescseq.args[0]); ++		xsettitle(strescseq.args[0], 0); + 		return; + 	case 'P': /* DCS -- Device Control String */ + 	case '_': /* APC -- Application Program Command */ +@@ -2305,7 +2397,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); + 		} +@@ -2318,7 +2410,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); + 		} +@@ -2328,6 +2420,7 @@ eschandle(uchar ascii) + 		break; + 	case 'c': /* RIS -- Reset to initial state */ + 		treset(); ++		xfreetitlestack(); + 		resettitle(); + 		xloadcols(); + 		break; +@@ -2537,7 +2630,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; +@@ -2574,6 +2667,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)); +@@ -2619,7 +2720,7 @@ tresize(int col, int row) + void + resettitle(void) + { +-	xsettitle(NULL); ++	xsettitle(NULL, 0); + } +  + void +@@ -2632,7 +2733,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); + 	} + } +  +@@ -2653,8 +2754,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 fd3b0d8..f6bd3b4 100644 +--- a/st.h ++++ b/st.h +@@ -33,6 +33,7 @@ enum glyph_attribute { + 	ATTR_WRAP       = 1 << 8, + 	ATTR_WIDE       = 1 << 9, + 	ATTR_WDUMMY     = 1 << 10, ++	ATTR_BOXDRAW    = 1 << 11, + 	ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + }; +  +@@ -81,6 +82,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 *); +@@ -111,6 +114,14 @@ void *xmalloc(size_t); + void *xrealloc(void *, size_t); + char *xstrdup(const char *); +  ++int isboxdraw(Rune); ++ushort boxdrawindex(const Glyph *); ++#ifdef XFT_VERSION ++/* only exposed to x.c, otherwise we'll need Xft.h for the types */ ++void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *); ++void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int); ++#endif ++ + /* config.h globals */ + extern char *utmp; + extern char *scroll; +@@ -124,3 +135,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern const int boxdraw, boxdraw_bold, boxdraw_braille; +diff --git a/st.info b/st.info +index 8201ad6..aeef606 100644 +--- a/st.info ++++ b/st.info +@@ -161,7 +161,7 @@ st-mono| simpleterm monocolor, + 	rin=\E[%p1%dT, + 	ritm=\E[23m, + 	rmacs=\E(B, +-	rmcup=\E[?1049l, ++	rmcup=\E[?1049l\E[23;0;0t, + 	rmir=\E[4l, + 	rmkx=\E[?1l\E>, + 	rmso=\E[27m, +@@ -172,7 +172,7 @@ st-mono| simpleterm monocolor, + 	sitm=\E[3m, + 	sgr0=\E[0m, + 	smacs=\E(0, +-	smcup=\E[?1049h, ++	smcup=\E[?1049h\E[22;0;0t, + 	smir=\E[4h, + 	smkx=\E[?1h\E=, + 	smso=\E[7m, +diff --git a/win.h b/win.h +index 6de960d..2a40aa0 100644 +--- a/win.h ++++ b/win.h +@@ -32,7 +32,9 @@ void xloadcols(void); + int xsetcolorname(int, const char *); + int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *); + void xseticontitle(char *); +-void xsettitle(char *); ++void xfreetitlestack(void); ++void xsettitle(char *, int); ++void xpushtitle(void); + int xsetcursor(int); + void xsetmode(int, unsigned int); + void xsetpointermotion(int); +diff --git a/x.c b/x.c +index aa09997..5d2c640 100644 +--- a/x.c ++++ b/x.c +@@ -14,6 +14,7 @@ + #include <X11/keysym.h> + #include <X11/Xft/Xft.h> + #include <X11/XKBlib.h> ++#include <X11/Xresource.h> +  + char *argv0; + #include "arg.h" +@@ -45,6 +46,19 @@ typedef struct { + 	signed char appcursor; /* application cursor */ + } Key; +  ++/* Xresources preferences */ ++enum resource_type { ++	STRING = 0, ++	INTEGER = 1, ++	FLOAT = 2 ++}; ++ ++typedef struct { ++	char *name; ++	enum resource_type type; ++	void *dst; ++} ResourcePref; ++ + /* X modifiers */ + #define XK_ANY_MOD    UINT_MAX + #define XK_NO_MOD     0 +@@ -63,6 +77,9 @@ static void ttysend(const Arg *); + /* config.h for applying patches and the configuration. */ + #include "config.h" +  ++/* size of title stack */ ++#define TITLESTACKSIZE 8 ++ + /* XEMBED messages */ + #define XEMBED_FOCUS_IN  4 + #define XEMBED_FOCUS_OUT 5 +@@ -157,6 +174,8 @@ static void xhints(void); + static int xloadcolor(int, const char *, Color *); + static int xloadfont(Font *, FcPattern *); + static void xloadfonts(const char *, double); ++static int xloadsparefont(FcPattern *, int); ++static void xloadsparefonts(void); + static void xunloadfont(Font *); + static void xunloadfonts(void); + static void xsetenv(void); +@@ -220,6 +239,8 @@ static DC dc; + static XWindow xw; + static XSelection xsel; + static TermWindow win; ++static int tstki; /* title stack index */ ++static char *titlestack[TITLESTACKSIZE]; /* title stack */ +  + /* Font Ring Cache */ + enum { +@@ -306,6 +327,7 @@ zoomabs(const Arg *arg) + { + 	xunloadfonts(); + 	xloadfonts(usedfont, arg->f); ++	xloadsparefonts(); + 	cresize(0, 0); + 	redraw(); + 	xhints(); +@@ -686,6 +708,8 @@ setsel(char *str, Time t) + 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); + 	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) + 		selclear(); ++ ++	xclipcopy(); + } +  + void +@@ -859,8 +883,8 @@ xclear(int x1, int y1, int x2, int y2) + void + xhints(void) + { +-	XClassHint class = {opt_name ? opt_name : termname, +-	                    opt_class ? opt_class : termname}; ++	XClassHint class = {opt_name ? opt_name : "st", ++	                    opt_class ? opt_class : "St"}; + 	XWMHints wm = {.flags = InputHint, .input = 1}; + 	XSizeHints *sizeh; +  +@@ -1050,6 +1074,101 @@ xloadfonts(const char *fontstr, double fontsize) + 	FcPatternDestroy(pattern); + } +  ++int ++xloadsparefont(FcPattern *pattern, int flags) ++{ ++	FcPattern *match; ++	FcResult result; ++ ++	match = FcFontMatch(NULL, pattern, &result); ++	if (!match) { ++		return 1; ++	} ++ ++	if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) { ++		FcPatternDestroy(match); ++		return 1; ++	} ++ ++	frc[frclen].flags = flags; ++	/* Believe U+0000 glyph will present in each default font */ ++	frc[frclen].unicodep = 0; ++	frclen++; ++ ++	return 0; ++} ++ ++void ++xloadsparefonts(void) ++{ ++	FcPattern *pattern; ++	double sizeshift, fontval; ++	int fc; ++	char **fp; ++ ++	if (frclen != 0) ++		die("can't embed spare fonts. cache isn't empty"); ++ ++	/* Calculate count of spare fonts */ ++	fc = sizeof(font2) / sizeof(*font2); ++	if (fc == 0) ++		return; ++ ++	/* Allocate memory for cache entries. */ ++	if (frccap < 4 * fc) { ++		frccap += 4 * fc - frccap; ++		frc = xrealloc(frc, frccap * sizeof(Fontcache)); ++	} ++ ++	for (fp = font2; fp - font2 < fc; ++fp) { ++ ++		if (**fp == '-') ++			pattern = XftXlfdParse(*fp, False, False); ++		else ++			pattern = FcNameParse((FcChar8 *)*fp); ++ ++		if (!pattern) ++			die("can't open spare font %s\n", *fp); ++ ++		if (defaultfontsize > 0) { ++			sizeshift = usedfontsize - defaultfontsize; ++			if (sizeshift != 0 && ++					FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == ++					FcResultMatch) { ++				fontval += sizeshift; ++				FcPatternDel(pattern, FC_PIXEL_SIZE); ++				FcPatternDel(pattern, FC_SIZE); ++				FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval); ++			} ++		} ++ ++		FcPatternAddBool(pattern, FC_SCALABLE, 1); ++ ++		FcConfigSubstitute(NULL, pattern, FcMatchPattern); ++		XftDefaultSubstitute(xw.dpy, xw.scr, pattern); ++ ++		if (xloadsparefont(pattern, FRC_NORMAL)) ++			die("can't open spare font %s\n", *fp); ++ ++		FcPatternDel(pattern, FC_SLANT); ++		FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); ++		if (xloadsparefont(pattern, FRC_ITALIC)) ++			die("can't open spare font %s\n", *fp); ++ ++		FcPatternDel(pattern, FC_WEIGHT); ++		FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); ++		if (xloadsparefont(pattern, FRC_ITALICBOLD)) ++			die("can't open spare font %s\n", *fp); ++ ++		FcPatternDel(pattern, FC_SLANT); ++		FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); ++		if (xloadsparefont(pattern, FRC_BOLD)) ++			die("can't open spare font %s\n", *fp); ++ ++		FcPatternDestroy(pattern); ++	} ++} ++ + void + xunloadfont(Font *f) + { +@@ -1135,8 +1254,6 @@ xinit(int cols, int rows) + 	pid_t thispid = getpid(); + 	XColor xmousefg, xmousebg; +  +-	if (!(xw.dpy = XOpenDisplay(NULL))) +-		die("can't open display\n"); + 	xw.scr = XDefaultScreen(xw.dpy); + 	xw.vis = XDefaultVisual(xw.dpy, xw.scr); +  +@@ -1147,6 +1264,9 @@ xinit(int cols, int rows) + 	usedfont = (opt_font == NULL)? font : opt_font; + 	xloadfonts(usedfont, 0); +  ++	/* spare fonts */ ++	xloadsparefonts(); ++ + 	/* colors */ + 	xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + 	xloadcols(); +@@ -1237,6 +1357,8 @@ xinit(int cols, int rows) + 	xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); + 	if (xsel.xtarget == None) + 		xsel.xtarget = XA_STRING; ++ ++	boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); + } +  + int +@@ -1283,8 +1405,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + 			yp = winy + font->ascent; + 		} +  +-		/* Lookup character index with default font. */ +-		glyphidx = XftCharIndex(xw.dpy, font->match, rune); ++		if (mode & ATTR_BOXDRAW) { ++			/* minor shoehorning: boxdraw uses only this ushort */ ++			glyphidx = boxdrawindex(&glyphs[i]); ++		} else { ++			/* Lookup character index with default font. */ ++			glyphidx = XftCharIndex(xw.dpy, font->match, rune); ++		} + 		if (glyphidx) { + 			specs[numspecs].font = font->match; + 			specs[numspecs].glyph = glyphidx; +@@ -1488,8 +1615,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + 	r.width = width; + 	XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); +  +-	/* Render the glyphs. */ +-	XftDrawGlyphFontSpec(xw.draw, fg, specs, len); ++	if (base.mode & ATTR_BOXDRAW) { ++		drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); ++	} else { ++		/* Render the glyphs. */ ++		XftDrawGlyphFontSpec(xw.draw, fg, specs, len); ++	} +  + 	/* Render underline and strikethrough. */ + 	if (base.mode & ATTR_UNDERLINE) { +@@ -1532,7 +1663,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + 	/* + 	 * Select the right color for the right mode. + 	 */ +-	g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; ++	g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW; +  + 	if (IS_SET(MODE_REVERSE)) { + 		g.mode |= ATTR_REVERSE; +@@ -1626,10 +1757,30 @@ xseticontitle(char *p) + } +  + void +-xsettitle(char *p) ++xfreetitlestack(void) + { +-	XTextProperty prop; +-	DEFAULT(p, opt_title); ++	for (int i = 0; i < LEN(titlestack); i++) { ++		free(titlestack[i]); ++		titlestack[i] = NULL; ++	} ++} ++ ++void ++xsettitle(char *p, int pop) ++{ ++ 	XTextProperty prop; ++  ++	free(titlestack[tstki]); ++	if (pop) { ++		titlestack[tstki] = NULL; ++		tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE; ++		p = titlestack[tstki] ? titlestack[tstki] : opt_title; ++	} else if (p) { ++		titlestack[tstki] = xstrdup(p); ++	} else { ++		titlestack[tstki] = NULL; ++		p = opt_title; ++	} +  + 	if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + 	                                &prop) != Success) +@@ -1639,6 +1790,16 @@ xsettitle(char *p) + 	XFree(prop.value); + } +  ++void ++xpushtitle(void) ++{ ++	int tstkin = (tstki + 1) % TITLESTACKSIZE; ++ ++	free(titlestack[tstkin]); ++	titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL; ++	tstki = tstkin; ++} ++ + int + xstartdraw(void) + { +@@ -2014,6 +2175,59 @@ run(void) + 	} + } +  ++int ++resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) ++{ ++	char **sdst = dst; ++	int *idst = dst; ++	float *fdst = dst; ++ ++	char fullname[256]; ++	char fullclass[256]; ++	char *type; ++	XrmValue ret; ++ ++	snprintf(fullname, sizeof(fullname), "%s.%s", ++			opt_name ? opt_name : "st", name); ++	snprintf(fullclass, sizeof(fullclass), "%s.%s", ++			opt_class ? opt_class : "St", name); ++	fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0'; ++ ++	XrmGetResource(db, fullname, fullclass, &type, &ret); ++	if (ret.addr == NULL || strncmp("String", type, 64)) ++		return 1; ++ ++	switch (rtype) { ++	case STRING: ++		*sdst = ret.addr; ++		break; ++	case INTEGER: ++		*idst = strtoul(ret.addr, NULL, 10); ++		break; ++	case FLOAT: ++		*fdst = strtof(ret.addr, NULL); ++		break; ++	} ++	return 0; ++} ++ ++void ++config_init(void) ++{ ++	char *resm; ++	XrmDatabase db; ++	ResourcePref *p; ++ ++	XrmInitialize(); ++	resm = XResourceManagerString(xw.dpy); ++	if (!resm) ++		return; ++ ++	db = XrmGetStringDatabase(resm); ++	for (p = resources; p < resources + LEN(resources); p++) ++		resource_load(db, p->name, p->type, p->dst); ++} ++ + void + usage(void) + { +@@ -2087,6 +2301,11 @@ run: +  + 	setlocale(LC_CTYPE, ""); + 	XSetLocaleModifiers(""); ++ ++	if(!(xw.dpy = XOpenDisplay(NULL))) ++		die("Can't open display\n"); ++ ++	config_init(); + 	cols = MAX(cols, 1); + 	rows = MAX(rows, 1); + 	tnew(cols, rows); diff --git a/st/deploy.sh b/st/deploy.sh new file mode 100755 index 0000000..bae1ef3 --- /dev/null +++ b/st/deploy.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +wd="$HOME/.local/src/st" + +[ ! -d "$HOME/.local/src" ] && mkdir -p "$wd" + +git clone https://git.suckless.org/st "$wd" + +patch -d "$wd" -p1 -i davidovski.patch + +make -C "$wd"  +doas make -C "$wd" install PREFIX=/usr | 
