diff --git a/Xdefaults b/Xdefaults index 5362be3..a57010d 100644 --- a/Xdefaults +++ b/Xdefaults @@ -55,12 +55,13 @@ dzen2.font: mononoki ! Set depth to make transparency work. URxvt*depth: 32 -*.font: font1,font2,font3,font4 +*.font: mononoki:minispace=False:size=10:antialias=true URxvt.font: font1,font2,font3,font4 URxvt.boldFont: font1:style=bold,font2:style=bold,font3:style=bold,font4 URxvt.italicFont:font1:style=italic,font2:style=italic,font3:style=italic,font4 URxvt.boldItalicfont: font1:style=bolditalic,font2:style=bolditalic,font3:style=bolditalic,font4 +*.borderpx: 20 URxvt.internalBorder: 20 *.cursorBlink: true URxvt.cursorUnderline: true @@ -72,12 +73,10 @@ URxvt.geometry: 92x24 URxvt.urgentOnBell: true URxvt.iso14755: false -urxvt*dynamicColors: on +URxvt*dynamicColors: on XTerm*faceName: font1,font2,font3,font4 - - !-- Xft settings -- ! Xft.dpi: 112 Xft.antialias: true @@ -85,7 +84,7 @@ Xft.rgba: rgb Xft.hinting: true Xft.hintstyle: hintfull -URxvt.perl-ext-common: resize-font,config-reload +URxvt.perl-ext-common: resize-font URxvt.url-launcher: /usr/bin/xdg-open URxvt.matcher.button: 1 diff --git a/deploy.sh b/deploy.sh index acc9f45..2858b25 100755 --- a/deploy.sh +++ b/deploy.sh @@ -79,14 +79,19 @@ load () { cp -r icons/* $HOME/.local/share/icons/ cp .local/share/kaomoji ~/.local/share/ - git clone https://github.com/simmel/urxvt-resize-font /tmp/urxvt-resize-font mkdir -p ~/.urxvt/ext/ + + git clone https://github.com/simmel/urxvt-resize-font /tmp/urxvt-resize-font cp /tmp/urxvt-resize-font/resize-font ~/.urxvt/ext/ cd slock ./deploy.sh cd - + cd st + ./deploy.sh + cd - + echo "Copied configurations!" else diff --git a/profile b/profile index 125007f..098e3b9 100644 --- a/profile +++ b/profile @@ -8,7 +8,7 @@ export XDG_RUNTIME_DIR=/tmp/$USER-$(uuidgen) alias editor=vim -export TERMINAL="urxvt" +export TERMINAL="st" export BROWSER="/usr/bin/firefox" export FILE_MANAGER="/usr/bin/thunar" export EMAIL_CLIENT="/usr/bin/thunderbird" 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 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 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 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 + #include + #include ++#include + + 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