diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2025-03-08 15:21:28 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2025-03-08 15:21:28 +0900 |
| commit | 4437d5b3c3eea76f6e2b0fd4a2ba21c02a098aeb (patch) | |
| tree | e8dcb20bf144aacf88f93b012dccacdeb08015cd /st/patches | |
| parent | c2b06f0d5795a789f4ddab459179ff89aedfee98 (diff) | |
updates
Diffstat (limited to 'st/patches')
42 files changed, 6926 insertions, 0 deletions
diff --git a/st/patches/st-anygeometry-0.8.1.diff b/st/patches/st-anygeometry-0.8.1.diff new file mode 100644 index 0000000..b04d36c --- /dev/null +++ b/st/patches/st-anygeometry-0.8.1.diff @@ -0,0 +1,123 @@ +From 6a5a862569912e34febe2dbd5244062013840204 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Miguel=20S=C3=A1nchez=20Garc=C3=ADa?= + <soy.jmi2k@gmail.com> +Date: Thu, 13 Aug 2020 11:02:01 +0000 +Subject: [PATCH] add -G to set pixel-based geometry + +--- + config.def.h | 13 +++++++++++++ + x.c | 36 ++++++++++++++++++++++++++++++++---- + 2 files changed, 45 insertions(+), 4 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 6f05dce..bea316a 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -141,6 +141,12 @@ static unsigned int defaultrcs = 257; + */ + static unsigned int cursorshape = 2; + ++/* ++ * Whether to use pixel geometry or cell geometry ++ */ ++ ++static Geometry geometry = CellGeometry; ++ + /* + * Default columns and rows numbers + */ +@@ -148,6 +154,13 @@ static unsigned int cursorshape = 2; + static unsigned int cols = 80; + static unsigned int rows = 24; + ++/* ++ * Default width and height (including borders!) ++ */ ++ ++static unsigned int width = 564; ++static unsigned int height = 364; ++ + /* + * Default colour and shape of the mouse cursor + */ +diff --git a/x.c b/x.c +index 210f184..29e35d0 100644 +--- a/x.c ++++ b/x.c +@@ -45,6 +45,11 @@ typedef struct { + signed char appcursor; /* application cursor */ + } Key; + ++typedef enum { ++ PixelGeometry, ++ CellGeometry ++} Geometry; ++ + /* X modifiers */ + #define XK_ANY_MOD UINT_MAX + #define XK_NO_MOD 0 +@@ -1096,7 +1101,7 @@ xicdestroy(XIC xim, XPointer client, XPointer call) + } + + void +-xinit(int cols, int rows) ++xinit(int w, int h) + { + XGCValues gcvalues; + Cursor cursor; +@@ -1121,8 +1126,16 @@ xinit(int cols, int rows) + xloadcols(); + + /* adjust fixed window geometry */ +- win.w = 2 * borderpx + cols * win.cw; +- win.h = 2 * borderpx + rows * win.ch; ++ switch (geometry) { ++ case CellGeometry: ++ win.w = 2 * borderpx + w * win.cw; ++ win.h = 2 * borderpx + h * win.ch; ++ break; ++ case PixelGeometry: ++ win.w = w; ++ win.h = h; ++ break; ++ } + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) +@@ -2001,6 +2014,12 @@ main(int argc, char *argv[]) + case 'g': + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &cols, &rows); ++ geometry = CellGeometry; ++ break; ++ case 'G': ++ xw.gm = XParseGeometry(EARGF(usage()), ++ &xw.l, &xw.t, &width, &height); ++ geometry = PixelGeometry; + break; + case 'i': + xw.isfixed = 1; +@@ -2037,10 +2056,19 @@ run: + + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); ++ switch (geometry) { ++ case CellGeometry: ++ xinit(cols, rows); ++ break; ++ case PixelGeometry: ++ xinit(width, height); ++ cols = (win.w - 2 * borderpx) / win.cw; ++ rows = (win.h - 2 * borderpx) / win.ch; ++ break; ++ } + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); +- xinit(cols, rows); + xsetenv(); + selinit(); + run(); +-- +2.28.0 + diff --git a/st/patches/st-anysize-20220718-baa9357.diff b/st/patches/st-anysize-20220718-baa9357.diff new file mode 100644 index 0000000..773cb09 --- /dev/null +++ b/st/patches/st-anysize-20220718-baa9357.diff @@ -0,0 +1,163 @@ +# From 8dcdc4b21a73268e167d98aa30f24315c7f3b7ff Mon Sep 17 00:00:00 2001 +# From: Bakkeby <bakkeby@gmail.com> +# Date: Mon, 18 Jul 2022 16:52:03 +0200 +# Subject: [PATCH] Adding anysize patch +# +# --- +# x.c | 56 ++++++++++++++++++++++++++++++-------------------------- +# 1 file changed, 30 insertions(+), 26 deletions(-) + +diff --git a/x.c b/x.c +index 2a3bd38..f534347 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; + } +@@ -739,6 +740,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); +@@ -869,8 +873,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; +@@ -1152,8 +1156,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) +@@ -1242,7 +1246,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; +@@ -1375,7 +1379,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; +@@ -1465,17 +1469,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.hborderpx, + 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. */ +@@ -1569,35 +1573,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); + } + } +-- +2.37.1 diff --git a/st/patches/st-autocomplete-20240703-6508693.diff b/st/patches/st-autocomplete-20240703-6508693.diff new file mode 100644 index 0000000..89c0ee2 --- /dev/null +++ b/st/patches/st-autocomplete-20240703-6508693.diff @@ -0,0 +1,702 @@ +From 650869359d3568dd2a000d474054e835a9c7ac74 Mon Sep 17 00:00:00 2001 +From: elbachir-one <bachiralfa@gmail.com> +Date: Wed, 3 Jul 2024 22:44:40 +0100 +Subject: [PATCH] The use of mkstemp' + +--- + Makefile | 3 + + autocomplete.h | 16 +++ + config.def.h | 12 ++ + st-autocomplete | 310 ++++++++++++++++++++++++++++++++++++++++++++++++ + st.c | 227 +++++++++++++++++++++++++++++++++++ + st.h | 2 + + x.c | 9 ++ + 7 files changed, 579 insertions(+) + create mode 100644 autocomplete.h + create mode 100644 st-autocomplete + +diff --git a/Makefile b/Makefile +index 93fed02..9aff9e0 100644 +--- a/Makefile ++++ b/Makefile +@@ -38,6 +38,8 @@ install: st + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f st $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/st ++ cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin ++ chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 +@@ -46,6 +48,7 @@ install: st + + uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/st ++ rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete + rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 + + .PHONY: all clean dist install uninstall +diff --git a/autocomplete.h b/autocomplete.h +new file mode 100644 +index 0000000..fc88447 +--- /dev/null ++++ b/autocomplete.h +@@ -0,0 +1,16 @@ ++# ifndef __ST_AUTOCOMPLETE_H ++# define __ST_AUTOCOMPLETE_H ++ ++enum { ++ ACMPL_DEACTIVATE, ++ ACMPL_WORD, ++ ACMPL_WWORD, ++ ACMPL_FUZZY_WORD, ++ ACMPL_FUZZY_WWORD, ++ ACMPL_FUZZY, ++ ACMPL_SUFFIX, ++ ACMPL_SURROUND, ++ ACMPL_UNDO, ++}; ++ ++# endif // __ST_AUTOCOMPLETE_H +diff --git a/config.def.h b/config.def.h +index 2cd740a..b74e03e 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -170,6 +170,8 @@ static unsigned int defaultattr = 11; + */ + static uint forcemousemod = ShiftMask; + ++#include "autocomplete.h" ++ + /* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. +@@ -187,6 +189,8 @@ static MouseShortcut mshortcuts[] = { + #define MODKEY Mod1Mask + #define TERMMOD (ControlMask|ShiftMask) + ++#define ACMPL_MOD ControlMask|Mod1Mask ++ + static Shortcut shortcuts[] = { + /* mask keysym function argument */ + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, +@@ -201,6 +205,14 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { ACMPL_MOD, XK_slash, autocomplete, { .i = ACMPL_WORD } }, ++ { ACMPL_MOD, XK_period, autocomplete, { .i = ACMPL_FUZZY_WORD } }, ++ { ACMPL_MOD, XK_comma, autocomplete, { .i = ACMPL_FUZZY } }, ++ { ACMPL_MOD, XK_apostrophe, autocomplete, { .i = ACMPL_SUFFIX } }, ++ { ACMPL_MOD, XK_semicolon, autocomplete, { .i = ACMPL_SURROUND } }, ++ { ACMPL_MOD, XK_bracketright,autocomplete, { .i = ACMPL_WWORD } }, ++ { ACMPL_MOD, XK_bracketleft, autocomplete, { .i = ACMPL_FUZZY_WWORD } }, ++ { ACMPL_MOD, XK_equal, autocomplete, { .i = ACMPL_UNDO } }, + }; + + /* +diff --git a/st-autocomplete b/st-autocomplete +new file mode 100644 +index 0000000..0fad536 +--- /dev/null ++++ b/st-autocomplete +@@ -0,0 +1,310 @@ ++#!/usr/bin/perl ++######################################################################### ++# Copyright (C) 2012-2017 Wojciech Siewierski # ++# # ++# This program is free software: you can redistribute it and/or modify # ++# it under the terms of the GNU General Public License as published by # ++# the Free Software Foundation, either version 3 of the License, or # ++# (at your option) any later version. # ++# # ++# This program is distributed in the hope that it will be useful, # ++# but WITHOUT ANY WARRANTY; without even the implied warranty of # ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # ++# GNU General Public License for more details. # ++# # ++# You should have received a copy of the GNU General Public License # ++# along with this program. If not, see <http://www.gnu.org/licenses/>. # ++######################################################################### ++ ++my ($cmd, $cursor_row, $cursor_column) = @ARGV; ++ ++my $lines = []; ++my $lines1 = []; ++ ++my $last_line = -1; ++my $lines_before_cursor = 0; ++ ++while (<stdin>) ++{ ++ $last_line++; ++ ++ s/[^[:print:]]/?/g; ++ ++ if ($last_line < $cursor_row) ++ { ++ unshift @{$lines1}, $_; ++ $lines_before_cursor++; ++ } ++ else ++ { ++ unshift @{$lines}, $_; ++ } ++} ++ ++foreach (@{$lines1}) ++{ ++ unshift @{$lines}, $_; ++} ++ ++my $cursor_row_in = $cursor_row; ++ ++$cursor_row = $last_line; ++ ++ ++$self = {}; ++ ++# A reference to a function that transforms the completed word ++# into a regex matching the completions. Usually generated by ++# generate_matcher(). ++# ++# For example ++# $fun = generate_matcher(".*"); ++# $fun->("foo"); ++# would return "f.*o.*o" ++# ++# In other words, indirectly decides which characters can ++# appear in the completion. ++my $matcher; ++ ++# A regular expression matching a character before each match. ++# For example, it you want to match the text after a ++# whitespace, set it to "\s". ++my $char_class_before; ++ ++# A regular expression matching every character in the entered ++# text that will be used to find matching completions. Usually ++# "\w" or similar. ++my $char_class_to_complete; ++ ++# A regular expression matching every allowed last character ++# of the completion (uses greedy matching). ++my $char_class_at_end; ++ ++if ($cmd eq 'word-complete') { ++ # Basic word completion. Completes the current word ++ # without any special matching. ++ $char_class_before = '[^-\w]'; ++ $matcher = sub { quotemeta shift }; # identity ++ $char_class_at_end = '[-\w]'; ++ $char_class_to_complete = '[-\w]'; ++} elsif ($cmd eq 'WORD-complete') { ++ # The same as above but in the Vim meaning of a "WORD" -- ++ # whitespace delimited. ++ $char_class_before = '\s'; ++ $matcher = sub { quotemeta shift }; ++ $char_class_at_end = '\S'; ++ $char_class_to_complete = '\S'; ++} elsif ($cmd eq 'fuzzy-word-complete' || ++ $cmd eq 'skeleton-word-complete') { ++ # Fuzzy completion of the current word. ++ $char_class_before = '[^-\w]'; ++ $matcher = generate_matcher('[-\w]*'); ++ $char_class_at_end = '[-\w]'; ++ $char_class_to_complete = '[-\w]'; ++} elsif ($cmd eq 'fuzzy-WORD-complete') { ++ # Fuzzy completion of the current WORD. ++ $char_class_before = '\s'; ++ $matcher = generate_matcher('\S*'); ++ $char_class_at_end = '\S'; ++ $char_class_to_complete = '\S'; ++} elsif ($cmd eq 'fuzzy-complete' || ++ $cmd eq 'skeleton-complete') { ++ # Fuzzy completion of an arbitrary text. ++ $char_class_before = '\W'; ++ $matcher = generate_matcher('.*?'); ++ $char_class_at_end = '\w'; ++ $char_class_to_complete = '\S'; ++} elsif ($cmd eq 'suffix-complete') { ++ # Fuzzy completion of an completing suffixes, like ++ # completing test=hello from /blah/hello. ++ $char_class_before = '\S'; ++ $matcher = generate_matcher('\S*'); ++ $char_class_at_end = '\S'; ++ $char_class_to_complete = '\S'; ++} elsif ($cmd eq 'surround-complete') { ++ # Completing contents of quotes and braces. ++ ++ # Here we are using three named groups: s, b, p for quotes, braces ++ # and parenthesis. ++ $char_class_before = '((?<q>["\'`])|(?<b>\[)|(?<p>\())'; ++ ++ $matcher = generate_matcher('.*?'); ++ ++ # Here we match text till enclosing pair, using perl conditionals in ++ # regexps (?(condition)yes-expression|no-expression). ++ # \0 is used to hack concatenation with '*' later in the code. ++ $char_class_at_end = '.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))\0'; ++ $char_class_to_complete = '\S'; ++} ++ ++ ++# use the last used word or read the word behind the cursor ++my $word_to_complete = read_word_at_coord($self, $cursor_row, $cursor_column, ++ $char_class_to_complete); ++ ++print stdout "$word_to_complete\n"; ++ ++if ($word_to_complete) { ++ while (1) { ++ # ignore the completed word itself ++ $self->{already_completed}{$word_to_complete} = 1; ++ ++ # continue the last search or start from the current row ++ my $completion = find_match($self, ++ $word_to_complete, ++ $self->{next_row} // $cursor_row, ++ $matcher->($word_to_complete), ++ $char_class_before, ++ $char_class_at_end); ++ if ($completion) { ++ print stdout $completion."\n".join ("\n", @{$self->{highlight}})."\n"; ++ } ++ else { ++ last; ++ } ++ } ++} ++ ++###################################################################### ++ ++sub highlight_match { ++ my ($self, $linenum, $completion) = @_; ++ ++ # clear_highlight($self); ++ ++ my $line = @{$lines}[$linenum]; ++ my $re = quotemeta $completion; ++ ++ $line =~ /$re/; ++ ++ my $beg = $-[0]; ++ my $end = $+[0]; ++ ++ if ($linenum >= $lines_before_cursor) ++ { ++ $lline = $last_line - $lines_before_cursor; ++ $linenum -= $lines_before_cursor; ++ $linenum = $lline - $linenum; ++ $linenum += $lines_before_cursor; ++ } ++ ++ ++ $self->{highlight} = [$linenum, $beg, $end]; ++} ++ ++###################################################################### ++ ++sub read_word_at_coord { ++ my ($self, $row, $col, $char_class) = @_; ++ ++ $_ = substr(@{$lines} [$row], 0, $col); # get the current line up to the cursor... ++ s/.*?($char_class*)$/$1/; # ...and read the last word from it ++ return $_; ++} ++ ++###################################################################### ++ ++# Returns a function that takes a string and returns that string with ++# this function's argument inserted between its every two characters. ++# The resulting string is used as a regular expression matching the ++# completion candidates. ++sub generate_matcher { ++ my $regex_between = shift; ++ ++ sub { ++ $_ = shift; ++ ++ # sorry for this lispy code, I couldn't resist ;) ++ (join "$regex_between", ++ (map quotemeta, ++ (split //))) ++ } ++} ++ ++###################################################################### ++ ++# Checks whether the completion found by find_match() was already ++# found and if it was, calls find_match() again to find the next ++# completion. ++# ++# Takes all the arguments that find_match() would take, to make a ++# mutually recursive call. ++sub skip_duplicates { ++ my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_; ++ my $completion; ++ ++ if ($current_row <= $lines_before_cursor) ++ { ++ $completion = shift @{$self->{matches_in_row}}; # get the leftmost one ++ } ++ else ++ { ++ $completion = pop @{$self->{matches_in_row}}; # get the leftmost one ++ } ++ ++ # check for duplicates ++ if (exists $self->{already_completed}{$completion}) { ++ # skip this completion ++ return find_match(@_); ++ } else { ++ $self->{already_completed}{$completion} = 1; ++ ++ highlight_match($self, ++ $self->{next_row}+1, ++ $completion); ++ ++ return $completion; ++ } ++} ++ ++###################################################################### ++ ++# Finds the next matching completion in the row current row or above ++# while skipping duplicates using skip_duplicates(). ++sub find_match { ++ my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_; ++ $self->{matches_in_row} //= []; ++ ++ # cycle through all the matches in the current row if not starting a new search ++ if (@{$self->{matches_in_row}}) { ++ return skip_duplicates($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end); ++ } ++ ++ ++ my $i; ++ # search through all the rows starting with current one or one above the last checked ++ for ($i = $current_row; $i >= 0; --$i) { ++ my $line = @{$lines}[$i]; # get the line of text from the row ++ ++ # if ($i == $cursor_row) { ++ # $line = substr $line, 0, $cursor_column; ++ # } ++ ++ $_ = $line; ++ ++ # find all the matches in the current line ++ my $match; ++ push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = / ++ (.*${char_class_before}) ++ (?<match> ++ ${regexp} ++ ${char_class_at_end}* ++ ) ++ /ix; ++ # corner case: match at the very beginning of line ++ push @{$self->{matches_in_row}}, $+{match} if $line =~ /^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i; ++ ++ if (@{$self->{matches_in_row}}) { ++ # remember which row should be searched next ++ $self->{next_row} = --$i; ++ ++ # arguments needed for find_match() mutual recursion ++ return skip_duplicates($self, $word_to_match, $i, $regexp, $char_class_before, $char_class_at_end); ++ } ++ } ++ ++ # # no more possible completions, revert to the original word ++ # undo_completion($self) if $i < 0; ++ ++ return undef; ++} +diff --git a/st.c b/st.c +index 57c6e96..9ff8d00 100644 +--- a/st.c ++++ b/st.c +@@ -17,6 +17,7 @@ + #include <unistd.h> + #include <wchar.h> + ++#include "autocomplete.h" + #include "st.h" + #include "win.h" + +@@ -2557,6 +2558,8 @@ tresize(int col, int row) + return; + } + ++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); ++ + /* + * slide screen to keep cursor where we expect it - + * tscrollup would work here, but we can optimize to +@@ -2676,3 +2679,227 @@ redraw(void) + tfulldirt(); + draw(); + } ++ ++void autocomplete (const Arg *arg) { ++ static _Bool active = 0; ++ int acmpl_cmdindex = arg->i; ++ static int acmpl_cmdindex_prev; ++ ++ if (active == 0) ++ acmpl_cmdindex_prev = acmpl_cmdindex; ++ ++ static const char * const acmpl_cmd[] = { ++ [ACMPL_DEACTIVATE] = "__DEACTIVATE__", ++ [ACMPL_WORD] = "word-complete", ++ [ACMPL_WWORD] = "WORD-complete", ++ [ACMPL_FUZZY_WORD] = "fuzzy-word-complete", ++ [ACMPL_FUZZY_WWORD] = "fuzzy-WORD-complete", ++ [ACMPL_FUZZY] = "fuzzy-complete", ++ [ACMPL_SUFFIX] = "suffix-complete", ++ [ACMPL_SURROUND] = "surround-complete", ++ [ACMPL_UNDO] = "__UNDO__", ++ }; ++ ++ static FILE *acmpl_exec = NULL; ++ static int acmpl_status; ++ static char *stbuffile; ++ static char *target = NULL; ++ static size_t targetlen; ++ static char *completion = NULL; ++ static size_t complen_prev = 0; ++ static int cx, cy; ++ ++ if (acmpl_cmdindex == ACMPL_DEACTIVATE) { ++ if (active) { ++ active = 0; ++ pclose(acmpl_exec); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ ++ if (complen_prev) { ++ selclear(); ++ complen_prev = 0; ++ } ++ } ++ return; ++ } ++ ++ if (acmpl_cmdindex == ACMPL_UNDO) { ++ if (active) { ++ active = 0; ++ pclose(acmpl_exec); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ ++ if (complen_prev) { ++ selclear(); ++ for (size_t i = 0; i < complen_prev; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ complen_prev = 0; ++ ttywrite(target, targetlen, 0); ++ } ++ } ++ return; ++ } ++ ++ if (acmpl_cmdindex != acmpl_cmdindex_prev) { ++ if (active) { ++ acmpl_cmdindex_prev = acmpl_cmdindex; ++ goto acmpl_begin; ++ } ++ } ++ ++ if (active == 0) { ++ acmpl_cmdindex_prev = acmpl_cmdindex; ++ cx = term.c.x; ++ cy = term.c.y; ++ ++ char filename[] = "/tmp/st-autocomplete-XXXXXX"; ++ int fd = mkstemp(filename); ++ ++ if (fd == -1) { ++ perror("mkstemp"); ++ return; ++ } ++ ++ stbuffile = strdup(filename); ++ ++ FILE *stbuf = fdopen(fd, "w"); ++ if (!stbuf) { ++ perror("fdopen"); ++ close(fd); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ char *stbufline = malloc(term.col + 2); ++ if (!stbufline) { ++ perror("malloc"); ++ fclose(stbuf); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ int cxp = 0; ++ for (size_t y = 0; y < term.row; y++) { ++ if (y == term.c.y) cx += cxp * term.col; ++ ++ size_t x = 0; ++ for (; x < term.col; x++) ++ utf8encode(term.line[y][x].u, stbufline + x); ++ if (term.line[y][x - 1].mode & ATTR_WRAP) { ++ x--; ++ if (y <= term.c.y) cy--; ++ cxp++; ++ } else { ++ stbufline[x] = '\n'; ++ cxp = 0; ++ } ++ stbufline[x + 1] = 0; ++ fputs(stbufline, stbuf); ++ } ++ ++ free(stbufline); ++ fclose(stbuf); ++ ++acmpl_begin: ++ target = malloc(term.col + 1); ++ completion = malloc(term.col + 1); ++ if (!target || !completion) { ++ perror("malloc"); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ char acmpl[1500]; ++ snprintf(acmpl, sizeof(acmpl), ++ "cat %s | st-autocomplete %s %d %d", ++ stbuffile, acmpl_cmd[acmpl_cmdindex], cy, cx); ++ ++ acmpl_exec = popen(acmpl, "r"); ++ if (!acmpl_exec) { ++ perror("popen"); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ if (fscanf(acmpl_exec, "%s\n", target) != 1) { ++ perror("fscanf"); ++ pclose(acmpl_exec); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ targetlen = strlen(target); ++ } ++ ++ unsigned line, beg, end; ++ ++ acmpl_status = fscanf(acmpl_exec, "%[^\n]\n%u\n%u\n%u\n", completion, &line, &beg, &end); ++ if (acmpl_status == EOF) { ++ if (active == 0) { ++ pclose(acmpl_exec); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ active = 0; ++ pclose(acmpl_exec); ++ ttywrite(target, targetlen, 0); ++ goto acmpl_begin; ++ } ++ ++ active = 1; ++ ++ if (complen_prev == 0) { ++ for (size_t i = 0; i < targetlen; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ } else { ++ selclear(); ++ for (size_t i = 0; i < complen_prev; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ complen_prev = 0; ++ } ++ ++ complen_prev = strlen(completion); ++ ttywrite(completion, complen_prev, 0); ++ ++ if (line == cy && beg > cx) { ++ beg += complen_prev - targetlen; ++ end += complen_prev - targetlen; ++ } ++ ++ end--; ++ ++ int wl = 0; ++ int tl = line; ++ for (int l = 0; l < tl; l++) ++ if (term.line[l][term.col - 1].mode & ATTR_WRAP) { ++ wl++; ++ tl++; ++ } ++ ++ selstart(beg % term.col, line + wl + beg / term.col, 0); ++ selextend(end % term.col, line + wl + end / term.col, 1, 0); ++ xsetsel(getsel()); ++} +diff --git a/st.h b/st.h +index fd3b0d8..113ebad 100644 +--- a/st.h ++++ b/st.h +@@ -77,6 +77,8 @@ typedef union { + const char *s; + } Arg; + ++void autocomplete (const Arg *); ++ + void die(const char *, ...); + void redraw(void); + void draw(void); +diff --git a/x.c b/x.c +index bd23686..c647721 100644 +--- a/x.c ++++ b/x.c +@@ -1859,11 +1859,20 @@ kpress(XEvent *ev) + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { ++ if (bp -> func != autocomplete) ++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); + bp->func(&(bp->arg)); + return; + } + } + ++ if (!( ++ len == 0 && ++ e -> state & ~ignoremod // ACMPL_ISSUE: I'm not sure that this is the right way ++ | ACMPL_MOD == ACMPL_MOD ++ )) ++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); ++ + /* 2. custom keys from config.h */ + if ((customkey = kmap(ksym, e->state))) { + ttywrite(customkey, strlen(customkey), 1); +-- +2.45.2 diff --git a/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff b/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff new file mode 100644 index 0000000..337abf1 --- /dev/null +++ b/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff @@ -0,0 +1,153 @@ +From feec0e2239d81373bd2ffcc28bdcf331328391f6 Mon Sep 17 00:00:00 2001 +From: Steven Ward <planet36@gmail.com> +Date: Sat, 19 Aug 2023 08:05:36 -0500 +Subject: [PATCH] Add different cursor styles + +--- + config.def.h | 19 +++++++++++++------ + x.c | 47 +++++++++++++++++++++++++++++++++++------------ + 2 files changed, 48 insertions(+), 18 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..b33a2ac 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -135,13 +135,20 @@ unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; + + /* +- * Default shape of cursor +- * 2: Block ("█") +- * 4: Underline ("_") +- * 6: Bar ("|") +- * 7: Snowman ("☃") ++ * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81 ++ * Default style of cursor ++ * 0: blinking block ++ * 1: blinking block (default) ++ * 2: steady block ("█") ++ * 3: blinking underline ++ * 4: steady underline ("_") ++ * 5: blinking bar ++ * 6: steady bar ("|") ++ * 7: blinking st cursor ++ * 8: steady st cursor + */ +-static unsigned int cursorshape = 2; ++static unsigned int cursorstyle = 1; ++static Rune stcursor = 0x2603; /* snowman ("☃") */ + + /* + * Default columns and rows numbers +diff --git a/x.c b/x.c +index aa09997..b33a963 100644 +--- a/x.c ++++ b/x.c +@@ -253,6 +253,7 @@ static char *opt_name = NULL; + static char *opt_title = NULL; + + static uint buttons; /* bit field of pressed buttons */ ++static int cursorblinks = 0; + + void + clipcopy(const Arg *dummy) +@@ -1558,29 +1559,44 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + /* draw the new one */ + if (IS_SET(MODE_FOCUSED)) { + switch (win.cursor) { +- case 7: /* st extension */ +- g.u = 0x2603; /* snowman (U+2603) */ ++ default: ++ case 0: /* blinking block */ ++ case 1: /* blinking block (default) */ ++ if (IS_SET(MODE_BLINK)) ++ break; + /* FALLTHROUGH */ +- case 0: /* Blinking Block */ +- case 1: /* Blinking Block (Default) */ +- case 2: /* Steady Block */ ++ case 2: /* steady block */ + xdrawglyph(g, cx, cy); + break; +- case 3: /* Blinking Underline */ +- case 4: /* Steady Underline */ ++ case 3: /* blinking underline */ ++ if (IS_SET(MODE_BLINK)) ++ break; ++ /* FALLTHROUGH */ ++ case 4: /* steady underline */ + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - \ + cursorthickness, + win.cw, cursorthickness); + break; +- case 5: /* Blinking bar */ +- case 6: /* Steady bar */ ++ case 5: /* blinking bar */ ++ if (IS_SET(MODE_BLINK)) ++ break; ++ /* FALLTHROUGH */ ++ case 6: /* steady bar */ + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + cursorthickness, win.ch); + break; ++ case 7: /* blinking st cursor */ ++ if (IS_SET(MODE_BLINK)) ++ break; ++ /* FALLTHROUGH */ ++ case 8: /* steady st cursor */ ++ g.u = stcursor; ++ xdrawglyph(g, cx, cy); ++ break; + } + } else { + XftDrawRect(xw.draw, &drawcol, +@@ -1737,9 +1753,12 @@ xsetmode(int set, unsigned int flags) + int + xsetcursor(int cursor) + { +- if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ ++ if (!BETWEEN(cursor, 0, 8)) /* 7-8: st extensions */ + return 1; + win.cursor = cursor; ++ cursorblinks = win.cursor == 0 || win.cursor == 1 || ++ win.cursor == 3 || win.cursor == 5 || ++ win.cursor == 7; + return 0; + } + +@@ -1986,6 +2005,10 @@ run(void) + if (FD_ISSET(ttyfd, &rfd) || xev) { + if (!drawing) { + trigger = now; ++ if (IS_SET(MODE_BLINK)) { ++ win.mode ^= MODE_BLINK; ++ } ++ lastblink = now; + drawing = 1; + } + timeout = (maxlatency - TIMEDIFF(now, trigger)) \ +@@ -1996,7 +2019,7 @@ run(void) + + /* idle detected or maxlatency exhausted -> draw */ + timeout = -1; +- if (blinktimeout && tattrset(ATTR_BLINK)) { ++ if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK))) { + timeout = blinktimeout - TIMEDIFF(now, lastblink); + if (timeout <= 0) { + if (-timeout > blinktimeout) /* start visible */ +@@ -2032,7 +2055,7 @@ main(int argc, char *argv[]) + { + xw.l = xw.t = 0; + xw.isfixed = False; +- xsetcursor(cursorshape); ++ xsetcursor(cursorstyle); + + ARGBEGIN { + case 'a': +-- +2.41.0 + diff --git a/st/patches/st-borderpx-option-20241008-e015463.diff b/st/patches/st-borderpx-option-20241008-e015463.diff new file mode 100644 index 0000000..8dce419 --- /dev/null +++ b/st/patches/st-borderpx-option-20241008-e015463.diff @@ -0,0 +1,74 @@ +From e01546322047ad4d0c5b613dc83f1425c360839a Mon Sep 17 00:00:00 2001 +From: cedilla <cedilla@dimension.sh> +Date: Tue, 8 Oct 2024 16:25:03 +0200 +Subject: [PATCH] Allow to set border value using for example -b 18 + +--- + st.1 | 8 ++++++++ + x.c | 7 +++++-- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/st.1 b/st.1 +index 39120b4..9ad3783 100644 +--- a/st.1 ++++ b/st.1 +@@ -4,6 +4,8 @@ st \- simple terminal + .SH SYNOPSIS + .B st + .RB [ \-aiv ] ++.RB [ \-b ++.IR borderpx ] + .RB [ \-c + .IR class ] + .RB [ \-f +@@ -28,6 +30,8 @@ st \- simple terminal + .PP + .B st + .RB [ \-aiv ] ++.RB [ \-b ++.IR borderpx ] + .RB [ \-c + .IR class ] + .RB [ \-f +@@ -55,6 +59,10 @@ is a simple terminal emulator. + .B \-a + disable alternate screens in terminal + .TP ++.BI \-b " borderpx" ++set border size to ++.I borderpx ++.TP + .BI \-c " class" + defines the window class (default $TERM). + .TP +diff --git a/x.c b/x.c +index d73152b..bda127c 100644 +--- a/x.c ++++ b/x.c +@@ -2026,11 +2026,11 @@ run(void) + void + usage(void) + { +- die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" ++ die("usage: %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid]" + " [[-e] command [args ...]]\n" +- " %s [-aiv] [-c class] [-f font] [-g geometry]" ++ " %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid] -l line" + " [stty_args ...]\n", argv0, argv0); +@@ -2047,6 +2047,9 @@ main(int argc, char *argv[]) + case 'a': + allowaltscreen = 0; + break; ++ case 'b': ++ borderpx = atoi(EARGF(usage())); ++ break; + case 'c': + opt_class = EARGF(usage()); + break; +-- +2.45.2 + diff --git a/st/patches/st-boxdraw_v2-0.8.5.diff b/st/patches/st-boxdraw_v2-0.8.5.diff new file mode 100644 index 0000000..b06aa3a --- /dev/null +++ b/st/patches/st-boxdraw_v2-0.8.5.diff @@ -0,0 +1,582 @@ +From 46a1124957b8de5e7f827656b64bfc3baeaa097f Mon Sep 17 00:00:00 2001 +From: wael <40663@protonmail.com> +Date: Mon, 11 Apr 2022 17:04:30 +0300 +Subject: [PATCH] [st][patch][boxdraw] update to 0.8.5 + +--- + Makefile | 3 +- + boxdraw.c | 194 ++++++++++++++++++++++++++++++++++++++++++++ + boxdraw_data.h | 214 +++++++++++++++++++++++++++++++++++++++++++++++++ + config.def.h | 12 +++ + st.c | 3 + + st.h | 10 +++ + x.c | 21 +++-- + 7 files changed, 451 insertions(+), 6 deletions(-) + create mode 100644 boxdraw.c + create mode 100644 boxdraw_data.h + +diff --git a/Makefile b/Makefile +index 470ac86..6dfa212 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 + +diff --git a/boxdraw.c b/boxdraw.c +new file mode 100644 +index 0000000..28a92d0 +--- /dev/null ++++ b/boxdraw.c +@@ -0,0 +1,194 @@ ++/* ++ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih ++ * MIT/X Consortium License ++ */ ++ ++#include <X11/Xft/Xft.h> ++#include "st.h" ++#include "boxdraw_data.h" ++ ++/* Rounded non-negative integers division of n / d */ ++#define DIV(n, d) (((n) + (d) / 2) / (d)) ++ ++static Display *xdpy; ++static Colormap xcmap; ++static XftDraw *xd; ++static Visual *xvis; ++ ++static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort); ++static void drawboxlines(int, int, int, int, XftColor *, ushort); ++ ++/* public API */ ++ ++void ++boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis) ++{ ++ xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis; ++} ++ ++int ++isboxdraw(Rune u) ++{ ++ Rune block = u & ~0xff; ++ return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) || ++ (boxdraw_braille && block == 0x2800); ++} ++ ++/* the "index" is actually the entire shape data encoded as ushort */ ++ushort ++boxdrawindex(const Glyph *g) ++{ ++ if (boxdraw_braille && (g->u & ~0xff) == 0x2800) ++ return BRL | (uint8_t)g->u; ++ if (boxdraw_bold && (g->mode & ATTR_BOLD)) ++ return BDB | boxdata[(uint8_t)g->u]; ++ return boxdata[(uint8_t)g->u]; ++} ++ ++void ++drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg, ++ const XftGlyphFontSpec *specs, int len) ++{ ++ for ( ; len-- > 0; x += cw, specs++) ++ drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph); ++} ++ ++/* implementation */ ++ ++void ++drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd) ++{ ++ ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */ ++ if (bd & (BDL | BDA)) { ++ /* lines (light/double/heavy/arcs) */ ++ drawboxlines(x, y, w, h, fg, bd); ++ ++ } else if (cat == BBD) { ++ /* lower (8-X)/8 block */ ++ int d = DIV((uint8_t)bd * h, 8); ++ XftDrawRect(xd, fg, x, y + d, w, h - d); ++ ++ } else if (cat == BBU) { ++ /* upper X/8 block */ ++ XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8)); ++ ++ } else if (cat == BBL) { ++ /* left X/8 block */ ++ XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h); ++ ++ } else if (cat == BBR) { ++ /* right (8-X)/8 block */ ++ int d = DIV((uint8_t)bd * w, 8); ++ XftDrawRect(xd, fg, x + d, y, w - d, h); ++ ++ } else if (cat == BBQ) { ++ /* Quadrants */ ++ int w2 = DIV(w, 2), h2 = DIV(h, 2); ++ if (bd & TL) ++ XftDrawRect(xd, fg, x, y, w2, h2); ++ if (bd & TR) ++ XftDrawRect(xd, fg, x + w2, y, w - w2, h2); ++ if (bd & BL) ++ XftDrawRect(xd, fg, x, y + h2, w2, h - h2); ++ if (bd & BR) ++ XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2); ++ ++ } else if (bd & BBS) { ++ /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */ ++ int d = (uint8_t)bd; ++ XftColor xfc; ++ XRenderColor xrc = { .alpha = 0xffff }; ++ ++ xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4); ++ xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4); ++ xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4); ++ ++ XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc); ++ XftDrawRect(xd, &xfc, x, y, w, h); ++ XftColorFree(xdpy, xvis, xcmap, &xfc); ++ ++ } else if (cat == BRL) { ++ /* braille, each data bit corresponds to one dot at 2x4 grid */ ++ int w1 = DIV(w, 2); ++ int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4); ++ ++ if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1); ++ if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1); ++ if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2); ++ if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1); ++ if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1); ++ if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2); ++ if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3); ++ if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3); ++ ++ } ++} ++ ++void ++drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd) ++{ ++ /* s: stem thickness. width/8 roughly matches underscore thickness. */ ++ /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */ ++ /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */ ++ int mwh = MIN(w, h); ++ int base_s = MAX(1, DIV(mwh, 8)); ++ int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */ ++ int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s; ++ int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2); ++ /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */ ++ /* The base length (per direction till edge) includes this square. */ ++ ++ int light = bd & (LL | LU | LR | LD); ++ int double_ = bd & (DL | DU | DR | DD); ++ ++ if (light) { ++ /* d: additional (negative) length to not-draw the center */ ++ /* texel - at arcs and avoid drawing inside (some) doubles */ ++ int arc = bd & BDA; ++ int multi_light = light & (light - 1); ++ int multi_double = double_ & (double_ - 1); ++ /* light crosses double only at DH+LV, DV+LH (ref. shapes) */ ++ int d = arc || (multi_double && !multi_light) ? -s : 0; ++ ++ if (bd & LL) ++ XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s); ++ if (bd & LU) ++ XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d); ++ if (bd & LR) ++ XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s); ++ if (bd & LD) ++ XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d); ++ } ++ ++ /* double lines - also align with light to form heavy when combined */ ++ if (double_) { ++ /* ++ * going clockwise, for each double-ray: p is additional length ++ * to the single-ray nearer to the previous direction, and n to ++ * the next. p and n adjust from the base length to lengths ++ * which consider other doubles - shorter to avoid intersections ++ * (p, n), or longer to draw the far-corner texel (n). ++ */ ++ int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD; ++ if (dl) { ++ int p = dd ? -s : 0, n = du ? -s : dd ? s : 0; ++ XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s); ++ XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s); ++ } ++ if (du) { ++ int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0; ++ XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p); ++ XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n); ++ } ++ if (dr) { ++ int p = du ? -s : 0, n = dd ? -s : du ? s : 0; ++ XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s); ++ XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s); ++ } ++ if (dd) { ++ int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0; ++ XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p); ++ XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n); ++ } ++ } ++} +diff --git a/boxdraw_data.h b/boxdraw_data.h +new file mode 100644 +index 0000000..7890500 +--- /dev/null ++++ b/boxdraw_data.h +@@ -0,0 +1,214 @@ ++/* ++ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih ++ * MIT/X Consortium License ++ */ ++ ++/* ++ * U+25XX codepoints data ++ * ++ * References: ++ * http://www.unicode.org/charts/PDF/U2500.pdf ++ * http://www.unicode.org/charts/PDF/U2580.pdf ++ * ++ * Test page: ++ * https://github.com/GNOME/vte/blob/master/doc/boxes.txt ++ */ ++ ++/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */ ++/* Categories (mutually exclusive except BDB): */ ++/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */ ++#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */ ++#define BDA (1<<9) /* Box Draw Arc (light) */ ++ ++#define BBD (1<<10) /* Box Block Down (lower) X/8 */ ++#define BBL (2<<10) /* Box Block Left X/8 */ ++#define BBU (3<<10) /* Box Block Upper X/8 */ ++#define BBR (4<<10) /* Box Block Right X/8 */ ++#define BBQ (5<<10) /* Box Block Quadrants */ ++#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */ ++ ++#define BBS (1<<14) /* Box Block Shades */ ++#define BDB (1<<15) /* Box Draw is Bold */ ++ ++/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */ ++/* Heavy is light+double (literally drawing light+double align to form heavy) */ ++#define LL (1<<0) ++#define LU (1<<1) ++#define LR (1<<2) ++#define LD (1<<3) ++#define LH (LL+LR) ++#define LV (LU+LD) ++ ++#define DL (1<<4) ++#define DU (1<<5) ++#define DR (1<<6) ++#define DD (1<<7) ++#define DH (DL+DR) ++#define DV (DU+DD) ++ ++#define HL (LL+DL) ++#define HU (LU+DU) ++#define HR (LR+DR) ++#define HD (LD+DD) ++#define HH (HL+HR) ++#define HV (HU+HD) ++ ++/* (BBQ) Quadrants Top/Bottom x Left/Right */ ++#define TL (1<<0) ++#define TR (1<<1) ++#define BL (1<<2) ++#define BR (1<<3) ++ ++/* Data for U+2500 - U+259F except dashes/diagonals */ ++static const unsigned short boxdata[256] = { ++ /* light lines */ ++ [0x00] = BDL + LH, /* light horizontal */ ++ [0x02] = BDL + LV, /* light vertical */ ++ [0x0c] = BDL + LD + LR, /* light down and right */ ++ [0x10] = BDL + LD + LL, /* light down and left */ ++ [0x14] = BDL + LU + LR, /* light up and right */ ++ [0x18] = BDL + LU + LL, /* light up and left */ ++ [0x1c] = BDL + LV + LR, /* light vertical and right */ ++ [0x24] = BDL + LV + LL, /* light vertical and left */ ++ [0x2c] = BDL + LH + LD, /* light horizontal and down */ ++ [0x34] = BDL + LH + LU, /* light horizontal and up */ ++ [0x3c] = BDL + LV + LH, /* light vertical and horizontal */ ++ [0x74] = BDL + LL, /* light left */ ++ [0x75] = BDL + LU, /* light up */ ++ [0x76] = BDL + LR, /* light right */ ++ [0x77] = BDL + LD, /* light down */ ++ ++ /* heavy [+light] lines */ ++ [0x01] = BDL + HH, ++ [0x03] = BDL + HV, ++ [0x0d] = BDL + HR + LD, ++ [0x0e] = BDL + HD + LR, ++ [0x0f] = BDL + HD + HR, ++ [0x11] = BDL + HL + LD, ++ [0x12] = BDL + HD + LL, ++ [0x13] = BDL + HD + HL, ++ [0x15] = BDL + HR + LU, ++ [0x16] = BDL + HU + LR, ++ [0x17] = BDL + HU + HR, ++ [0x19] = BDL + HL + LU, ++ [0x1a] = BDL + HU + LL, ++ [0x1b] = BDL + HU + HL, ++ [0x1d] = BDL + HR + LV, ++ [0x1e] = BDL + HU + LD + LR, ++ [0x1f] = BDL + HD + LR + LU, ++ [0x20] = BDL + HV + LR, ++ [0x21] = BDL + HU + HR + LD, ++ [0x22] = BDL + HD + HR + LU, ++ [0x23] = BDL + HV + HR, ++ [0x25] = BDL + HL + LV, ++ [0x26] = BDL + HU + LD + LL, ++ [0x27] = BDL + HD + LU + LL, ++ [0x28] = BDL + HV + LL, ++ [0x29] = BDL + HU + HL + LD, ++ [0x2a] = BDL + HD + HL + LU, ++ [0x2b] = BDL + HV + HL, ++ [0x2d] = BDL + HL + LD + LR, ++ [0x2e] = BDL + HR + LL + LD, ++ [0x2f] = BDL + HH + LD, ++ [0x30] = BDL + HD + LH, ++ [0x31] = BDL + HD + HL + LR, ++ [0x32] = BDL + HR + HD + LL, ++ [0x33] = BDL + HH + HD, ++ [0x35] = BDL + HL + LU + LR, ++ [0x36] = BDL + HR + LU + LL, ++ [0x37] = BDL + HH + LU, ++ [0x38] = BDL + HU + LH, ++ [0x39] = BDL + HU + HL + LR, ++ [0x3a] = BDL + HU + HR + LL, ++ [0x3b] = BDL + HH + HU, ++ [0x3d] = BDL + HL + LV + LR, ++ [0x3e] = BDL + HR + LV + LL, ++ [0x3f] = BDL + HH + LV, ++ [0x40] = BDL + HU + LH + LD, ++ [0x41] = BDL + HD + LH + LU, ++ [0x42] = BDL + HV + LH, ++ [0x43] = BDL + HU + HL + LD + LR, ++ [0x44] = BDL + HU + HR + LD + LL, ++ [0x45] = BDL + HD + HL + LU + LR, ++ [0x46] = BDL + HD + HR + LU + LL, ++ [0x47] = BDL + HH + HU + LD, ++ [0x48] = BDL + HH + HD + LU, ++ [0x49] = BDL + HV + HL + LR, ++ [0x4a] = BDL + HV + HR + LL, ++ [0x4b] = BDL + HV + HH, ++ [0x78] = BDL + HL, ++ [0x79] = BDL + HU, ++ [0x7a] = BDL + HR, ++ [0x7b] = BDL + HD, ++ [0x7c] = BDL + HR + LL, ++ [0x7d] = BDL + HD + LU, ++ [0x7e] = BDL + HL + LR, ++ [0x7f] = BDL + HU + LD, ++ ++ /* double [+light] lines */ ++ [0x50] = BDL + DH, ++ [0x51] = BDL + DV, ++ [0x52] = BDL + DR + LD, ++ [0x53] = BDL + DD + LR, ++ [0x54] = BDL + DR + DD, ++ [0x55] = BDL + DL + LD, ++ [0x56] = BDL + DD + LL, ++ [0x57] = BDL + DL + DD, ++ [0x58] = BDL + DR + LU, ++ [0x59] = BDL + DU + LR, ++ [0x5a] = BDL + DU + DR, ++ [0x5b] = BDL + DL + LU, ++ [0x5c] = BDL + DU + LL, ++ [0x5d] = BDL + DL + DU, ++ [0x5e] = BDL + DR + LV, ++ [0x5f] = BDL + DV + LR, ++ [0x60] = BDL + DV + DR, ++ [0x61] = BDL + DL + LV, ++ [0x62] = BDL + DV + LL, ++ [0x63] = BDL + DV + DL, ++ [0x64] = BDL + DH + LD, ++ [0x65] = BDL + DD + LH, ++ [0x66] = BDL + DD + DH, ++ [0x67] = BDL + DH + LU, ++ [0x68] = BDL + DU + LH, ++ [0x69] = BDL + DH + DU, ++ [0x6a] = BDL + DH + LV, ++ [0x6b] = BDL + DV + LH, ++ [0x6c] = BDL + DH + DV, ++ ++ /* (light) arcs */ ++ [0x6d] = BDA + LD + LR, ++ [0x6e] = BDA + LD + LL, ++ [0x6f] = BDA + LU + LL, ++ [0x70] = BDA + LU + LR, ++ ++ /* Lower (Down) X/8 block (data is 8 - X) */ ++ [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4, ++ [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0, ++ ++ /* Left X/8 block (data is X) */ ++ [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4, ++ [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1, ++ ++ /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */ ++ [0x80] = BBU + 4, [0x94] = BBU + 1, ++ [0x90] = BBR + 4, [0x95] = BBR + 7, ++ ++ /* Quadrants */ ++ [0x96] = BBQ + BL, ++ [0x97] = BBQ + BR, ++ [0x98] = BBQ + TL, ++ [0x99] = BBQ + TL + BL + BR, ++ [0x9a] = BBQ + TL + BR, ++ [0x9b] = BBQ + TL + TR + BL, ++ [0x9c] = BBQ + TL + TR + BR, ++ [0x9d] = BBQ + TR, ++ [0x9e] = BBQ + BL + TR, ++ [0x9f] = BBQ + BL + TR + BR, ++ ++ /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */ ++ [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3, ++ ++ /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */ ++ /* U+2571 - U+2573: unsupported (diagonals) */ ++}; +diff --git a/config.def.h b/config.def.h +index 91ab8ca..7bb3ff7 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -67,6 +67,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 +diff --git a/st.c b/st.c +index f43cfd3..baa2bed 100644 +--- a/st.c ++++ b/st.c +@@ -1214,6 +1214,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 +diff --git a/st.h b/st.h +index 519b9bd..07a7c66 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, + }; + +@@ -113,6 +114,14 @@ char *xstrdup(const char *); + + int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b); + ++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; +@@ -126,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/x.c b/x.c +index 2a3bd38..bf6bbf9 100644 +--- a/x.c ++++ b/x.c +@@ -1237,6 +1237,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 +1285,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 +1495,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 +1543,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; +-- +2.35.1 diff --git a/st/patches/st-changealpha-20230519-b44f2ad.diff b/st/patches/st-changealpha-20230519-b44f2ad.diff new file mode 100644 index 0000000..172969f --- /dev/null +++ b/st/patches/st-changealpha-20230519-b44f2ad.diff @@ -0,0 +1,80 @@ +diff --git a/config.def.h b/config.def.h +index 91ab8ca..8a06176 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -93,6 +93,9 @@ char *termname = "st-256color"; + */ + unsigned int tabspaces = 8; + ++/* Background opacity */ ++float alpha_def; ++ + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { + /* 8 normal colors */ +@@ -201,6 +204,9 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY, XK_bracketleft, chgalpha, {.f = -1} }, /* Decrease opacity */ ++ { MODKEY|ShiftMask, XK_braceright, chgalpha, {.f = +1} }, /* Increase opacity */ ++ { MODKEY, XK_bracketright,chgalpha, {.f = 0} }, /* Reset opacity */ + }; + + /* +diff --git a/st.h b/st.h +index fd3b0d8..3bb587e 100644 +--- a/st.h ++++ b/st.h +@@ -124,3 +124,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern float alpha_def; +diff --git a/x.c b/x.c +index aa09997..f8c8c1a 100644 +--- a/x.c ++++ b/x.c +@@ -59,6 +59,7 @@ static void zoom(const Arg *); + static void zoomabs(const Arg *); + static void zoomreset(const Arg *); + static void ttysend(const Arg *); ++static void chgalpha(const Arg *); + + /* config.h for applying patches and the configuration. */ + #include "config.h" +@@ -1147,6 +1148,9 @@ xinit(int cols, int rows) + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + ++ /* Backup default alpha value */ ++ alpha_def = alpha; ++ + /* colors */ + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xloadcols(); +@@ -1371,6 +1375,24 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + return numspecs; + } + ++void ++chgalpha(const Arg *arg) ++{ ++ if (arg->f == -1.0f && alpha >= 0.1f) ++ alpha -= 0.1f; ++ else if (arg->f == 1.0f && alpha < 1.0f) ++ alpha += 0.1f; ++ else if (arg->f == 0.0f) ++ alpha = alpha_def; ++ else ++ return; ++ ++ dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha); ++ /* Required to remove artifacting from borderpx */ ++ cresize(0, 0); ++ redraw(); ++} ++ + void + xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) + { diff --git a/st/patches/st-charoffsets-20220311-0.8.5.diff b/st/patches/st-charoffsets-20220311-0.8.5.diff new file mode 100644 index 0000000..4034d3f --- /dev/null +++ b/st/patches/st-charoffsets-20220311-0.8.5.diff @@ -0,0 +1,43 @@ +From 944b234710e2fc00ea6e9ce9d925dc85514ac9c3 Mon Sep 17 00:00:00 2001 +From: Zacchary Dempsey-Plante <zacc@ztdp.ca> +Date: Fri, 11 Mar 2022 01:33:05 -0500 +Subject: [PATCH] Added character rendering offsets for correcting different + font dimensions. + +--- + config.def.h | 3 +++ + x.c | 4 ++-- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..8877e5c 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -28,6 +28,9 @@ char *vtiden = "\033[?6c"; + /* Kerning / character bounding-box multipliers */ + static float cwscale = 1.0; + static float chscale = 1.0; ++/* Character rendering offsets in pixels */ ++static short cxoffset = 0; ++static short cyoffset = 0; + + /* + * word delimiter string +diff --git a/x.c b/x.c +index cd96575..6983743 100644 +--- a/x.c ++++ b/x.c +@@ -1288,8 +1288,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; +- specs[numspecs].x = (short)xp; +- specs[numspecs].y = (short)yp; ++ specs[numspecs].x = (short)xp + cxoffset; ++ specs[numspecs].y = (short)yp + cyoffset; + xp += runewidth; + numspecs++; + continue; +-- +2.35.1 + diff --git a/st/patches/st-clickurl-nocontrol-0.8.5.diff b/st/patches/st-clickurl-nocontrol-0.8.5.diff new file mode 100644 index 0000000..018939f --- /dev/null +++ b/st/patches/st-clickurl-nocontrol-0.8.5.diff @@ -0,0 +1,214 @@ +From 8d13e4a296f0b2a625df10c8ee6d2fc96ec97580 Mon Sep 17 00:00:00 2001 +From: Kyle Chui <kyle.chui+suckless@pm.me> +Date: Tue, 9 Apr 2024 16:31:25 -0700 +Subject: [PATCH] Underline URLs and follow with click + +--- + config.def.h | 11 +++++++ + st.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + st.h | 9 ++++++ + x.c | 12 ++++++- + 4 files changed, 119 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..4961830 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -472,3 +472,14 @@ static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; ++ ++/* ++ * Open urls starting with urlprefixes, contatining urlchars ++ * by passing as ARG1 to urlhandler. ++ */ ++char* urlhandler = "xdg-open"; ++char urlchars[] = ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "abcdefghijklmnopqrstuvwxyz" ++ "0123456789-._~:/?#@!$&'*+,;=%"; ++char* urlprefixes[] = {"http://", "https://", NULL}; +diff --git a/st.c b/st.c +index 51049ba..a7eb86e 100644 +--- a/st.c ++++ b/st.c +@@ -643,6 +643,92 @@ getsel(void) + return str; + } + ++char * ++strstrany(char* s, char** strs) { ++ char *match; ++ for (int i = 0; strs[i]; i++) { ++ if ((match = strstr(s, strs[i]))) { ++ return match; ++ } ++ } ++ return NULL; ++} ++ ++void ++highlighturlsline(int row) ++{ ++ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ ++ char *match; ++ for (int j = 0; j < term.col; j++) { ++ if (term.line[row][j].u < 127) { ++ linestr[j] = term.line[row][j].u; ++ } ++ linestr[term.col] = '\0'; ++ } ++ int url_start = -1; ++ while ((match = strstrany(linestr + url_start + 1, urlprefixes))) { ++ url_start = match - linestr; ++ for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) { ++ term.line[row][c].mode |= ATTR_URL; ++ tsetdirt(row, c); ++ } ++ } ++ free(linestr); ++} ++ ++void ++unhighlighturlsline(int row) ++{ ++ for (int j = 0; j < term.col; j++) { ++ Glyph* g = &term.line[row][j]; ++ if (g->mode & ATTR_URL) { ++ g->mode &= ~ATTR_URL; ++ tsetdirt(row, j); ++ } ++ } ++ return; ++} ++ ++int ++followurl(int col, int row) { ++ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ ++ char *match; ++ for (int i = 0; i < term.col; i++) { ++ if (term.line[row][i].u < 127) { ++ linestr[i] = term.line[row][i].u; ++ } ++ linestr[term.col] = '\0'; ++ } ++ int url_start = -1, found_url = 0; ++ while ((match = strstrany(linestr + url_start + 1, urlprefixes))) { ++ url_start = match - linestr; ++ int url_end = url_start; ++ for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) { ++ url_end++; ++ } ++ if (url_start <= col && col < url_end) { ++ found_url = 1; ++ linestr[url_end] = '\0'; ++ break; ++ } ++ } ++ if (!found_url) { ++ free(linestr); ++ return 0; ++ } ++ ++ pid_t chpid; ++ if ((chpid = fork()) == 0) { ++ if (fork() == 0) ++ execlp(urlhandler, urlhandler, linestr + url_start, NULL); ++ exit(1); ++ } ++ if (chpid > 0) ++ waitpid(chpid, NULL, 0); ++ free(linestr); ++ return 1; ++} ++ + void + selclear(void) + { +@@ -2652,6 +2738,8 @@ drawregion(int x1, int y1, int x2, int y2) + continue; + + term.dirty[y] = 0; ++ unhighlighturlsline(y); ++ highlighturlsline(y); + xdrawline(term.line[y], x1, y, x2); + } + } +diff --git a/st.h b/st.h +index 519b9bd..5efc27e 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_URL = 1 << 11, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + }; + +@@ -105,6 +106,10 @@ void selextend(int, int, int, int); + int selected(int, int); + char *getsel(void); + ++void highlighturlsline(int); ++void unhighlighturlsline(int); ++int followurl(int, int); ++ + size_t utf8encode(Rune, char *); + + void *xmalloc(size_t); +@@ -126,3 +131,7 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern char *urlhandler; ++extern char urlchars[]; ++extern char *urlprefixes[]; ++extern int nurlprefixes; +diff --git a/x.c b/x.c +index 8a16faa..c721f8b 100644 +--- a/x.c ++++ b/x.c +@@ -191,6 +191,7 @@ static void usage(void); + + static void (*handler[LASTEvent])(XEvent *) = { + [KeyPress] = kpress, ++ [KeyRelease] = kpress, + [ClientMessage] = cmessage, + [ConfigureNotify] = resize, + [VisibilityNotify] = visibility, +@@ -445,6 +446,10 @@ mouseaction(XEvent *e, uint release) + /* ignore Button<N>mask for Button<N> - it's set on release */ + uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + ++ if (release == 0 && e->xbutton.button == Button1) { ++ return followurl(evcol(e), evrow(e)); ++ } ++ + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && +@@ -1476,7 +1481,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + + /* Render underline and strikethrough. */ +- if (base.mode & ATTR_UNDERLINE) { ++ if (base.mode & ATTR_UNDERLINE || base.mode & ATTR_URL) { + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, + width, 1); + } +@@ -1831,6 +1836,11 @@ kpress(XEvent *ev) + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + else + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); ++ ++ /* KeyRelease not relevant to shortcuts */ ++ if (ev->type == KeyRelease) ++ return; ++ + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { +-- +2.42.0 diff --git a/st/patches/st-clipboard-0.8.3.diff b/st/patches/st-clipboard-0.8.3.diff new file mode 100644 index 0000000..c1e0e9e --- /dev/null +++ b/st/patches/st-clipboard-0.8.3.diff @@ -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 diff --git a/st/patches/st-columnredraw-20241119-fb8569b.diff b/st/patches/st-columnredraw-20241119-fb8569b.diff new file mode 100644 index 0000000..757c795 --- /dev/null +++ b/st/patches/st-columnredraw-20241119-fb8569b.diff @@ -0,0 +1,79 @@ +From fb8569b193cc063ad53388e8e2009fb6682092d2 Mon Sep 17 00:00:00 2001 +From: elbachir-one <bachiralfa@gmail.com> +Date: Tue, 19 Nov 2024 15:39:16 +0100 +Subject: [PATCH] Added columnredraw + +--- + st.c | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/st.c b/st.c +index 57c6e96..7371554 100644 +--- a/st.c ++++ b/st.c +@@ -113,6 +113,7 @@ typedef struct { + typedef struct { + int row; /* nb row */ + int col; /* nb col */ ++ int maxcol; /* Maximum number of columns */ + Line *line; /* screen */ + Line *alt; /* alternate screen */ + int *dirty; /* dirtyness of lines */ +@@ -1231,8 +1232,8 @@ tclearregion(int x1, int y1, int x2, int y2) + if (y1 > y2) + temp = y1, y1 = y2, y2 = temp; + +- LIMIT(x1, 0, term.col-1); +- LIMIT(x2, 0, term.col-1); ++ LIMIT(x1, 0, term.maxcol-1); ++ LIMIT(x2, 0, term.maxcol-1); + LIMIT(y1, 0, term.row-1); + LIMIT(y2, 0, term.row-1); + +@@ -2546,11 +2547,18 @@ void + tresize(int col, int row) + { + int i; +- int minrow = MIN(row, term.row); +- int mincol = MIN(col, term.col); ++ int tmp; ++ int minrow, mincol; + int *bp; + TCursor c; + ++ tmp = col; ++ if (!term.maxcol) ++ term.maxcol = term.col; ++ col = MAX(col, term.maxcol); ++ minrow = MIN(row, term.row); ++ mincol = MIN(col, term.maxcol); ++ + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); +@@ -2593,17 +2601,18 @@ tresize(int col, int row) + term.line[i] = xmalloc(col * sizeof(Glyph)); + term.alt[i] = xmalloc(col * sizeof(Glyph)); + } +- if (col > term.col) { +- bp = term.tabs + term.col; ++ if (col > term.maxcol) { ++ bp = term.tabs + term.maxcol; + +- memset(bp, 0, sizeof(*term.tabs) * (col - term.col)); ++ memset(bp, 0, sizeof(*term.tabs) * (col - term.maxcol)); + while (--bp > term.tabs && !*bp) + /* nothing */ ; + for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) + *bp = 1; + } + /* update terminal size */ +- term.col = col; ++ term.col = tmp; ++ term.maxcol = col; + term.row = row; + /* reset scrolling region */ + tsetscroll(0, row-1); +-- +2.46.2 + diff --git a/st/patches/st-copyurl-multiline-20230406-211964d.diff b/st/patches/st-copyurl-multiline-20230406-211964d.diff new file mode 100644 index 0000000..5169c62 --- /dev/null +++ b/st/patches/st-copyurl-multiline-20230406-211964d.diff @@ -0,0 +1,166 @@ +From 7405bdc89e4c43cfbeabd0d4d822bc62d1e76730 Mon Sep 17 00:00:00 2001 +From: Gildasio Junior <gildasiojunior@riseup.net> +Date: Thu, 6 Apr 2023 14:51:06 -0300 +Subject: [PATCH] Loop through urls on screen in both directions + +Using previous patches one can loop through urls in the screen in one +direction: botton-up. This patch add a way that can go in the opposite +direction: top-down. + +This is usefull in a screen with lots of urls. +--- + config.def.h | 2 + + st.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ + st.h | 1 + + 3 files changed, 104 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..4df78eb 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} }, ++ { MODKEY, XK_l, copyurl, {.i = 0} }, ++ { MODKEY|ShiftMask, XK_L, copyurl, {.i = 1} }, + }; + + /* +diff --git a/st.c b/st.c +index 134e724..c451015 100644 +--- a/st.c ++++ b/st.c +@@ -152,6 +152,11 @@ typedef struct { + int narg; /* nb of args */ + } STREscape; + ++typedef struct { ++ int state; ++ size_t length; ++} URLdfa; ++ + static void execsh(char *, char **); + static void stty(char **); + static void sigchld(int); +@@ -201,6 +206,7 @@ static void tdefutf8(char); + static int32_t tdefcolor(const int *, int *, int); + static void tdeftran(char); + static void tstrsequence(uchar); ++static int daddch(URLdfa *, char); + + static void drawregion(int, int, int, int); + +@@ -2666,3 +2672,98 @@ redraw(void) + tfulldirt(); + draw(); + } ++ ++int ++daddch(URLdfa *dfa, char c) ++{ ++ /* () and [] can appear in urls, but excluding them here will reduce false ++ * positives when figuring out where a given url ends. ++ */ ++ static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "abcdefghijklmnopqrstuvwxyz" ++ "0123456789-._~:/?#@!$&'*+,;=%"; ++ static const char RPFX[] = "//:sptth"; ++ ++ if (!strchr(URLCHARS, c)) { ++ dfa->length = 0; ++ dfa->state = 0; ++ ++ return 0; ++ } ++ ++ dfa->length++; ++ ++ if (dfa->state == 2 && c == '/') { ++ dfa->state = 0; ++ } else if (dfa->state == 3 && c == 'p') { ++ dfa->state++; ++ } else if (c != RPFX[dfa->state]) { ++ dfa->state = 0; ++ return 0; ++ } ++ ++ if (dfa->state++ == 7) { ++ dfa->state = 0; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++** Select and copy the previous url on screen (do nothing if there's no url). ++*/ ++void ++copyurl(const Arg *arg) { ++ int row = 0, /* row of current URL */ ++ col = 0, /* column of current URL start */ ++ colend = 0, /* column of last occurrence */ ++ passes = 0; /* how many rows have been scanned */ ++ ++ const char *c = NULL, ++ *match = NULL; ++ URLdfa dfa = { 0 }; ++ ++ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot; ++ LIMIT(row, term.top, term.bot); ++ ++ colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col; ++ LIMIT(colend, 0, term.col); ++ ++ /* ++ ** Scan from (term.row - 1,term.col - 1) to (0,0) and find ++ ** next occurrance of a URL ++ */ ++ for (passes = 0; passes < term.row; passes++) { ++ /* Read in each column of every row until ++ ** we hit previous occurrence of URL ++ */ ++ for (col = colend; col--;) ++ if (daddch(&dfa, term.line[row][col].u < 128 ? term.line[row][col].u : ' ')) ++ break; ++ ++ if (col >= 0) ++ break; ++ ++ /* .i = 0 --> botton-up ++ * .i = 1 --> top-down ++ */ ++ if (!arg->i) { ++ if (--row < 0) ++ row = term.row - 1; ++ } else { ++ if (++row >= term.row) ++ row = 0; ++ } ++ ++ colend = term.col; ++ } ++ ++ if (passes < term.row) { ++ selstart(col, row, 0); ++ selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 0); ++ selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 1); ++ xsetsel(getsel()); ++ xclipcopy(); ++ } ++} +diff --git a/st.h b/st.h +index fd3b0d8..baa8f29 100644 +--- a/st.h ++++ b/st.h +@@ -85,6 +85,7 @@ void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); + void toggleprinter(const Arg *); ++void copyurl(const Arg *); + + int tattrset(int); + void tnew(int, int); +-- +2.40.0 diff --git a/st/patches/st-csi_22_23-0.8.5.diff b/st/patches/st-csi_22_23-0.8.5.diff new file mode 100644 index 0000000..c49aa30 --- /dev/null +++ b/st/patches/st-csi_22_23-0.8.5.diff @@ -0,0 +1,208 @@ +From c90af45228c1100377d64ad021fa3f0cff9a1df4 Mon Sep 17 00:00:00 2001 +From: wael <40663@protonmail.com> +Date: Mon, 11 Apr 2022 21:28:43 +0300 +Subject: [PATCH] [st][patch][csi 22 23] update to 0.8.5 + +--- + st.c | 36 ++++++++++++++++++++++++++++++++---- + st.info | 4 ++-- + win.h | 4 +++- + x.c | 41 ++++++++++++++++++++++++++++++++++++++--- + 4 files changed, 75 insertions(+), 10 deletions(-) + +diff --git a/st.c b/st.c +index f43cfd3..2802381 100644 +--- a/st.c ++++ b/st.c +@@ -1801,6 +1801,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; ++ } + } + } + +@@ -1885,7 +1912,7 @@ strhandle(void) + switch (par) { + case 0: + if (narg > 1) { +- xsettitle(strescseq.args[1]); ++ xsettitle(strescseq.args[1], 0); + xseticontitle(strescseq.args[1]); + } + return; +@@ -1895,7 +1922,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) { +@@ -1973,7 +2000,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 */ +@@ -2345,6 +2372,7 @@ eschandle(uchar ascii) + break; + case 'c': /* RIS -- Reset to initial state */ + treset(); ++ xfreetitlestack(); + resettitle(); + xloadcols(); + break; +@@ -2631,7 +2659,7 @@ tresize(int col, int row) + void + resettitle(void) + { +- xsettitle(NULL); ++ xsettitle(NULL, 0); + } + + void +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 e6e4369..ef67fd6 100644 +--- a/win.h ++++ b/win.h +@@ -31,7 +31,9 @@ void xfinishdraw(void); + void xloadcols(void); + int xsetcolorname(int, const 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 2a3bd38..babb04c 100644 +--- a/x.c ++++ b/x.c +@@ -63,6 +63,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 +@@ -220,6 +223,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 { +@@ -1626,10 +1631,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 +1664,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) + { +-- +2.35.1 + diff --git a/st/patches/st-cyclefonts-20220731-baa9357.diff b/st/patches/st-cyclefonts-20220731-baa9357.diff new file mode 100644 index 0000000..1f0297b --- /dev/null +++ b/st/patches/st-cyclefonts-20220731-baa9357.diff @@ -0,0 +1,97 @@ +From 3c83f90504445efb358f18b4ae86193c6baa709c Mon Sep 17 00:00:00 2001 +From: Justinas Grigas <jstn_as@protonmail.com> +Date: Sun, 31 Jul 2022 10:43:14 +0300 +Subject: [PATCH] cyclefonts: keybind to cycle fonts + +This patch is an update to the 20210604, which fixes zoomreset. + +Because the cyclefonts function doesn't change the defaultfontsize +variable, zoomreset function resets all fonts to the size of the first +one loaded. + +With this patch, zoomreset will reset the font to the specified fontsize +--- + config.def.h | 7 ++++++- + x.c | 20 ++++++++++++++------ + 2 files changed, 20 insertions(+), 7 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..c213e48 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -5,7 +5,11 @@ + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +-static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; ++static char *fonts[] = { ++ "Liberation Mono:pixelsize=12:antialias=true:autohint=true", ++ "Gohu GohuFont:pixelsize=11:antialias=false:autohint=false", ++}; ++static size_t currentfont = 0; + static int borderpx = 2; + + /* +@@ -201,6 +205,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_S, cyclefonts, {} }, + }; + + /* +diff --git a/x.c b/x.c +index 2a3bd38..08f7275 100644 +--- a/x.c ++++ b/x.c +@@ -59,6 +59,7 @@ static void zoom(const Arg *); + static void zoomabs(const Arg *); + static void zoomreset(const Arg *); + static void ttysend(const Arg *); ++static void cyclefonts(const Arg *); + + /* config.h for applying patches and the configuration. */ + #include "config.h" +@@ -315,11 +316,7 @@ void + zoomreset(const Arg *arg) + { + Arg larg; +- +- if (defaultfontsize > 0) { +- larg.f = defaultfontsize; +- zoomabs(&larg); +- } ++ zoomabs(&larg); + } + + void +@@ -328,6 +325,17 @@ ttysend(const Arg *arg) + ttywrite(arg->s, strlen(arg->s), 1); + } + ++void ++cyclefonts(const Arg *arg) ++{ ++ currentfont++; ++ currentfont %= (sizeof fonts / sizeof fonts[0]); ++ usedfont = fonts[currentfont]; ++ Arg larg; ++ larg.f = usedfontsize; ++ zoomabs(&larg); ++} ++ + int + evcol(XEvent *e) + { +@@ -1144,7 +1152,7 @@ xinit(int cols, int rows) + if (!FcInit()) + die("could not init fontconfig.\n"); + +- usedfont = (opt_font == NULL)? font : opt_font; ++ usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font; + xloadfonts(usedfont, 0); + + /* colors */ +-- +2.37.1 + diff --git a/st/patches/st-disable-bold-italic-fonts-0.8.2.diff b/st/patches/st-disable-bold-italic-fonts-0.8.2.diff new file mode 100644 index 0000000..385f1b4 --- /dev/null +++ b/st/patches/st-disable-bold-italic-fonts-0.8.2.diff @@ -0,0 +1,70 @@ +From 0856fbfcdae3f8e48db791984591b0bb8a91de68 Mon Sep 17 00:00:00 2001 +From: Ryan Kes <alrayyes@gmail.com> +Date: Fri, 29 Mar 2019 10:59:09 +0100 +Subject: [PATCH] st-disable-bold-italic-fonts-0.8.2 + +--- + config.def.h | 6 ++++++ + x.c | 10 +++++++++- + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 482901e..4f5aeac 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -6,6 +6,12 @@ + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ + static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; ++ ++/* disable bold, italic and roman fonts globally */ ++int disablebold = 0; ++int disableitalic = 0; ++int disableroman = 0; ++ + static int borderpx = 2; + + /* +diff --git a/x.c b/x.c +index 5828a3b..9663fa6 100644 +--- a/x.c ++++ b/x.c +@@ -233,6 +233,11 @@ static char *usedfont = NULL; + static double usedfontsize = 0; + static double defaultfontsize = 0; + ++/* declared in config.h */ ++extern int disablebold; ++extern int disableitalic; ++extern int disableroman; ++ + static char *opt_class = NULL; + static char **opt_cmd = NULL; + static char *opt_embed = NULL; +@@ -966,17 +971,20 @@ xloadfonts(char *fontstr, double fontsize) + win.ch = ceilf(dc.font.height * chscale); + + FcPatternDel(pattern, FC_SLANT); +- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); ++ if (!disableitalic) ++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (xloadfont(&dc.ifont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_WEIGHT); +- FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); ++ if (!disablebold) ++ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (xloadfont(&dc.ibfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); +- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); ++ if (!disableroman) ++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadfont(&dc.bfont, pattern)) + die("can't open font %s\n", fontstr); + +-- +2.39.2 + diff --git a/st/patches/st-dynamic-cursor-color-0.9.diff b/st/patches/st-dynamic-cursor-color-0.9.diff new file mode 100644 index 0000000..1034595 --- /dev/null +++ b/st/patches/st-dynamic-cursor-color-0.9.diff @@ -0,0 +1,50 @@ +From 215ec30d6b5fe3319f88f1c9d16a37b6e14e5a53 Mon Sep 17 00:00:00 2001 +From: Bakkeby <bakkeby@gmail.com> +Date: Mon, 19 Dec 2022 10:20:47 +0100 +Subject: [PATCH] dynamic cursor color: cursor color taken from current + character + +--- + x.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/x.c b/x.c +index 2a3bd38..21aadce 100644 +--- a/x.c ++++ b/x.c +@@ -1520,6 +1520,7 @@ void + xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + { + Color drawcol; ++ XRenderColor colbg; + + /* remove the old cursor */ + if (selected(ox, oy)) +@@ -1548,11 +1549,21 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + if (selected(cx, cy)) { + g.fg = defaultfg; + g.bg = defaultrcs; ++ } else if (!(og.mode & ATTR_REVERSE)) { ++ unsigned long col = g.bg; ++ g.bg = g.fg; ++ g.fg = col; ++ } ++ ++ if (IS_TRUECOL(g.bg)) { ++ colbg.alpha = 0xffff; ++ colbg.red = TRUERED(g.bg); ++ colbg.green = TRUEGREEN(g.bg); ++ colbg.blue = TRUEBLUE(g.bg); ++ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &drawcol); + } else { +- g.fg = defaultbg; +- g.bg = defaultcs; ++ drawcol = dc.col[g.bg]; + } +- drawcol = dc.col[g.bg]; + } + + /* draw the new one */ +-- +2.38.1 + diff --git a/st/patches/st-externalpipe-0.8.5.diff b/st/patches/st-externalpipe-0.8.5.diff new file mode 100644 index 0000000..daf91d3 --- /dev/null +++ b/st/patches/st-externalpipe-0.8.5.diff @@ -0,0 +1,104 @@ +diff --git a/st.c b/st.c +index 034954d..98f2589 100644 +--- a/st.c ++++ b/st.c +@@ -718,8 +718,14 @@ sigchld(int a) + if ((p = waitpid(pid, &stat, WNOHANG)) < 0) + die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); + +- if (pid != p) ++ if (pid != p) { ++ if (p == 0 && wait(&stat) < 0) ++ die("wait: %s\n", strerror(errno)); ++ ++ /* reinstall sigchld handler */ ++ signal(SIGCHLD, sigchld); + return; ++ } + + if (WIFEXITED(stat) && WEXITSTATUS(stat)) + die("child exited with status %d\n", WEXITSTATUS(stat)); +@@ -803,7 +809,7 @@ 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 exec", NULL) == -1) + die("pledge\n"); + #endif + close(s); +@@ -1991,6 +1997,59 @@ strparse(void) + } + } + ++void ++externalpipe(const Arg *arg) ++{ ++ int to[2]; ++ char buf[UTF_SIZ]; ++ void (*oldsigpipe)(int); ++ Glyph *bp, *end; ++ int lastpos, n, newline; ++ ++ if (pipe(to) == -1) ++ return; ++ ++ switch (fork()) { ++ case -1: ++ close(to[0]); ++ close(to[1]); ++ return; ++ case 0: ++ dup2(to[0], STDIN_FILENO); ++ close(to[0]); ++ close(to[1]); ++ execvp(((char **)arg->v)[0], (char **)arg->v); ++ fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]); ++ perror("failed"); ++ exit(0); ++ } ++ ++ close(to[0]); ++ /* ignore sigpipe for now, in case child exists early */ ++ oldsigpipe = signal(SIGPIPE, SIG_IGN); ++ newline = 0; ++ for (n = 0; n < term.row; n++) { ++ bp = term.line[n]; ++ lastpos = MIN(tlinelen(n) + 1, term.col) - 1; ++ if (lastpos < 0) ++ break; ++ end = &bp[lastpos + 1]; ++ for (; bp < end; ++bp) ++ if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0) ++ break; ++ if ((newline = term.line[n][lastpos].mode & ATTR_WRAP)) ++ continue; ++ if (xwrite(to[1], "\n", 1) < 0) ++ break; ++ newline = 0; ++ } ++ if (newline) ++ (void)xwrite(to[1], "\n", 1); ++ close(to[1]); ++ /* restore */ ++ signal(SIGPIPE, oldsigpipe); ++} ++ + void + strdump(void) + { +diff --git a/st.h b/st.h +index fd3b0d8..754cd08 100644 +--- a/st.h ++++ b/st.h +@@ -81,6 +81,7 @@ void die(const char *, ...); + void redraw(void); + void draw(void); + ++void externalpipe(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +-- +2.42.0 + diff --git a/st/patches/st-externalpipe-eternal-0.8.3.diff b/st/patches/st-externalpipe-eternal-0.8.3.diff new file mode 100644 index 0000000..4ba830b --- /dev/null +++ b/st/patches/st-externalpipe-eternal-0.8.3.diff @@ -0,0 +1,74 @@ +From 2228468a6db1e648c69849860d30867c0e77650e Mon Sep 17 00:00:00 2001 +From: AtomToast <reg-2@t-online.de> +Date: Wed, 29 Apr 2020 02:31:29 +0200 +Subject: [PATCH] apply Luke Smiths external pipe eternal patch + +Enables external pipe to work on the entire scrollback history. + +Source: https://github.com/LukeSmithxyz/st/commit/da13ef12463d1870caed94584db464d68c6b3182 +Made to work on semi-vanilla st. + +This patch requires both externalpipe and scrollback patch in order to work +--- + st.c | 25 +++++++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) + +diff --git a/st.c b/st.c +index d4c88a2..2716f44 100644 +--- a/st.c ++++ b/st.c +@@ -46,6 +46,7 @@ + #define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ + term.scr + HISTSIZE + 1) % HISTSIZE] : \ + term.line[(y) - term.scr]) ++#define TLINE_HIST(y) ((y) <= HISTSIZE-term.row+2 ? term.hist[(y)] : term.line[(y-HISTSIZE+term.row-3)]) + + enum term_mode { + MODE_WRAP = 1 << 0, +@@ -431,6 +432,20 @@ tlinelen(int y) + return i; + } + ++int ++tlinehistlen(int y) ++{ ++ int i = term.col; ++ ++ if (TLINE_HIST(y)[i - 1].mode & ATTR_WRAP) ++ return i; ++ ++ while (i > 0 && TLINE_HIST(y)[i - 1].u == ' ') ++ --i; ++ ++ return i; ++} ++ + void + selstart(int col, int row, int snap) + { +@@ -2025,16 +2040,18 @@ externalpipe(const Arg *arg) + /* ignore sigpipe for now, in case child exists early */ + oldsigpipe = signal(SIGPIPE, SIG_IGN); + newline = 0; +- for (n = 0; n < term.row; n++) { +- bp = term.line[n]; +- lastpos = MIN(tlinelen(n) + 1, term.col) - 1; ++ for (n = 0; n <= HISTSIZE + 2; n++) { ++ bp = TLINE_HIST(n); ++ lastpos = MIN(tlinehistlen(n) + 1, term.col) - 1; + if (lastpos < 0) + break; ++ if (lastpos == 0) ++ continue; + end = &bp[lastpos + 1]; + for (; bp < end; ++bp) + if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0) + break; +- if ((newline = term.line[n][lastpos].mode & ATTR_WRAP)) ++ if ((newline = TLINE_HIST(n)[lastpos].mode & ATTR_WRAP)) + continue; + if (xwrite(to[1], "\n", 1) < 0) + break; +-- +2.26.2 + diff --git a/st/patches/st-externalpipe-signal-0.8.2.diff b/st/patches/st-externalpipe-signal-0.8.2.diff new file mode 100644 index 0000000..c573d51 --- /dev/null +++ b/st/patches/st-externalpipe-signal-0.8.2.diff @@ -0,0 +1,74 @@ +From df32a82e8a889629ed406ce468f24c35da7e9a03 Mon Sep 17 00:00:00 2001 +From: Miles Alan <m@milesalan.com> +Date: Sun, 11 Aug 2019 21:33:55 -0500 +Subject: [PATCH] Add handler for SIGUSR1 signal to run an externalpipe command + +--- + config.def.h | 1 + + st.c | 14 ++++++++++++++ + st.h | 1 + + 3 files changed, 16 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 0e01717..96d1bdd 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -1,3 +1,4 @@ ++char *externalpipe_sigusr1[] = {"/bin/sh", "-c", "externalpipe_buffer.sh st_strings_read"}; + /* See LICENSE file for copyright and license details. */ + + /* +diff --git a/st.c b/st.c +index b8e6077..48cae2e 100644 +--- a/st.c ++++ b/st.c +@@ -155,6 +155,7 @@ typedef struct { + static void execsh(char *, char **); + static void stty(char **); + static void sigchld(int); ++static void sigusr1(int); + static void ttywriteraw(const char *, size_t); + + static void csidump(void); +@@ -719,6 +720,13 @@ execsh(char *cmd, char **args) + _exit(1); + } + ++void ++sigusr1(int unused) ++{ ++ static Arg a = {.v = externalpipe_sigusr1}; ++ externalpipe(&a); ++} ++ + void + sigchld(int a) + { +@@ -765,6 +773,12 @@ stty(char **args) + int + ttynew(char *line, char *cmd, char *out, char **args) + { ++ static struct sigaction sa; ++ sa.sa_handler = sigusr1; ++ sigemptyset(&sa.sa_mask); ++ sa.sa_flags = SA_RESTART; ++ sigaction(SIGUSR1, &sa, NULL); ++ + int m, s; + + if (out) { +diff --git a/st.h b/st.h +index 38c61c4..794b4ff 100644 +--- a/st.h ++++ b/st.h +@@ -111,6 +111,7 @@ void *xrealloc(void *, size_t); + char *xstrdup(char *); + + /* config.h globals */ ++extern char *externalpipe_sigusr1[]; + extern char *utmp; + extern char *stty_args; + extern char *vtiden; +-- +2.19.2 + diff --git a/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff b/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff new file mode 100644 index 0000000..50bada0 --- /dev/null +++ b/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff @@ -0,0 +1,760 @@ +Author: Jan Christoph Ebersbach <jceb@e-jc.de> +URL: http://st.suckless.org/patches/fix_keyboard_input +Fix keyboard input on terminal + +Index: st-patches/st/config.def.h +=================================================================== +--- a/config.def.h ++++ b/config.def.h +@@ -209,7 +209,80 @@ Shortcut shortcuts[] = { + * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) + * to be mapped below, add them to this array. + */ +-static KeySym mappedkeys[] = { -1 }; ++static KeySym mappedkeys[] = { ++ XK_space, ++ XK_m, ++ XK_i, ++ XK_A, ++ XK_B, ++ XK_C, ++ XK_D, ++ XK_E, ++ XK_F, ++ XK_G, ++ XK_H, ++ XK_I, ++ XK_K, ++ XK_J, ++ XK_L, ++ XK_M, ++ XK_N, ++ XK_O, ++ XK_P, ++ XK_Q, ++ XK_R, ++ XK_S, ++ XK_T, ++ XK_U, ++ XK_V, ++ XK_W, ++ XK_X, ++ XK_Y, ++ XK_Z, ++ XK_Z, ++ XK_0, ++ XK_1, ++ XK_2, ++ XK_3, ++ XK_4, ++ XK_5, ++ XK_6, ++ XK_7, ++ XK_8, ++ XK_9, ++ XK_exclam, ++ XK_quotedbl, ++ XK_numbersign, ++ XK_dollar, ++ XK_percent, ++ XK_ampersand, ++ XK_apostrophe, ++ XK_parenleft, ++ XK_parenright, ++ XK_asterisk, ++ XK_plus, ++ XK_comma, ++ XK_minus, ++ XK_period, ++ XK_slash, ++ XK_colon, ++ XK_semicolon, ++ XK_less, ++ XK_equal, ++ XK_greater, ++ XK_question, ++ XK_at, ++ XK_bracketleft, ++ XK_backslash, ++ XK_bracketright, ++ XK_asciicircum, ++ XK_underscore, ++ XK_grave, ++ XK_braceleft, ++ XK_bar, ++ XK_braceright, ++ XK_asciitilde, ++}; + + /* + * State bits to ignore when matching key or button events. By default, +@@ -232,59 +305,20 @@ static Key key[] = { + /* keysym mask string appkey appcursor */ + { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, +- { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, +- { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, +- { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, +- { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, +- { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, +- { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, +- { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, +- { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, +- { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, +- { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, +- { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, +- { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, +- { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, +- { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, +- { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, +- { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, + { XK_KP_End, ControlMask, "\033[J", -1, 0}, + { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_KP_End, ShiftMask, "\033[K", -1, 0}, + { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, +- { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, +- { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, +- { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, +- { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, + { 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_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, +- { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, +- { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, +- { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, +- { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, +- { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, +- { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, +- { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, +- { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, +- { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, +- { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, +- { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, +- { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, +- { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, +- { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, +- { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, +- { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, + { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, + { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, + { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, +@@ -323,35 +356,26 @@ static Key key[] = { + { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, + { XK_Return, Mod1Mask, "\033\r", 0, 0}, +- { XK_Return, XK_ANY_MOD, "\r", 0, 0}, ++ { XK_Return, XK_NO_MOD, "\r", 0, 0}, + { XK_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_Insert, ControlMask, "\033[L", -1, 0}, + { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, +- { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, +- { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_Delete, ControlMask, "\033[M", -1, 0}, + { 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_BackSpace, XK_NO_MOD, "\177", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, +- { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, +- { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_End, ControlMask, "\033[J", -1, 0}, + { XK_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_End, ShiftMask, "\033[K", -1, 0}, + { XK_End, ShiftMask, "\033[1;2F", +1, 0}, +- { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, + { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, +- { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_Next, ControlMask, "\033[6;5~", 0, 0}, + { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, +- { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, + { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, + { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, +@@ -438,6 +462,572 @@ static Key key[] = { + { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, + { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, + { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, ++ ++ // libtermkey compatible keyboard input ++ { XK_KP_Home, XK_NO_MOD, "\033[H", 0, -1}, ++ { XK_KP_Home, XK_NO_MOD, "\033[1~", 0, +1}, ++ { XK_KP_Home, ControlMask, "\033[149;5u", 0, 0}, ++ { XK_KP_Home, ControlMask|ShiftMask, "\033[149;6u", 0, 0}, ++ { XK_KP_Home, Mod1Mask, "\033[149;3u", 0, 0}, ++ { XK_KP_Home, Mod1Mask|ControlMask, "\033[149;7u", 0, 0}, ++ { XK_KP_Home, Mod1Mask|ControlMask|ShiftMask, "\033[149;8u", 0, 0}, ++ { XK_KP_Home, Mod1Mask|ShiftMask, "\033[149;4u", 0, 0}, ++ { XK_KP_Home, ShiftMask, "\033[149;2u", 0, 0}, ++ { XK_KP_Up, XK_NO_MOD, "\033Ox", +1, 0}, ++ { XK_KP_Up, XK_NO_MOD, "\033[A", 0, -1}, ++ { XK_KP_Up, XK_NO_MOD, "\033OA", 0, +1}, ++ { XK_KP_Up, ControlMask, "\033[151;5u", 0, 0}, ++ { XK_KP_Up, ControlMask|ShiftMask, "\033[151;6u", 0, 0}, ++ { XK_KP_Up, Mod1Mask, "\033[151;3u", 0, 0}, ++ { XK_KP_Up, Mod1Mask|ControlMask, "\033[151;7u", 0, 0}, ++ { XK_KP_Up, Mod1Mask|ControlMask|ShiftMask, "\033[151;8u", 0, 0}, ++ { XK_KP_Up, Mod1Mask|ShiftMask, "\033[151;4u", 0, 0}, ++ { XK_KP_Up, ShiftMask, "\033[151;2u", 0, 0}, ++ { XK_KP_Down, XK_NO_MOD, "\033Or", +1, 0}, ++ { XK_KP_Down, XK_NO_MOD, "\033[B", 0, -1}, ++ { XK_KP_Down, XK_NO_MOD, "\033OB", 0, +1}, ++ { XK_KP_Down, ControlMask, "\033[153;5u", 0, 0}, ++ { XK_KP_Down, ControlMask|ShiftMask, "\033[153;6u", 0, 0}, ++ { XK_KP_Down, Mod1Mask, "\033[153;3u", 0, 0}, ++ { XK_KP_Down, Mod1Mask|ControlMask, "\033[153;7u", 0, 0}, ++ { XK_KP_Down, Mod1Mask|ControlMask|ShiftMask, "\033[153;8u", 0, 0}, ++ { XK_KP_Down, Mod1Mask|ShiftMask, "\033[153;4u", 0, 0}, ++ { XK_KP_Down, ShiftMask, "\033[153;2u", 0, 0}, ++ { XK_KP_Left, XK_NO_MOD, "\033Ot", +1, 0}, ++ { XK_KP_Left, XK_NO_MOD, "\033[D", 0, -1}, ++ { XK_KP_Left, XK_NO_MOD, "\033OD", 0, +1}, ++ { XK_KP_Left, ControlMask, "\033[150;5u", 0, 0}, ++ { XK_KP_Left, ControlMask|ShiftMask, "\033[150;6u", 0, 0}, ++ { XK_KP_Left, Mod1Mask, "\033[150;3u", 0, 0}, ++ { XK_KP_Left, Mod1Mask|ControlMask, "\033[150;7u", 0, 0}, ++ { XK_KP_Left, Mod1Mask|ControlMask|ShiftMask, "\033[150;8u", 0, 0}, ++ { XK_KP_Left, Mod1Mask|ShiftMask, "\033[150;4u", 0, 0}, ++ { XK_KP_Left, ShiftMask, "\033[150;2u", 0, 0}, ++ { XK_KP_Right, XK_NO_MOD, "\033Ov", +1, 0}, ++ { XK_KP_Right, XK_NO_MOD, "\033[C", 0, -1}, ++ { XK_KP_Right, XK_NO_MOD, "\033OC", 0, +1}, ++ { XK_KP_Right, ControlMask, "\033[152;5u", 0, 0}, ++ { XK_KP_Right, ControlMask|ShiftMask, "\033[152;6u", 0, 0}, ++ { XK_KP_Right, Mod1Mask, "\033[152;3u", 0, 0}, ++ { XK_KP_Right, Mod1Mask|ControlMask, "\033[152;7u", 0, 0}, ++ { XK_KP_Right, Mod1Mask|ControlMask|ShiftMask, "\033[152;8u", 0, 0}, ++ { XK_KP_Right, Mod1Mask|ShiftMask, "\033[152;4u", 0, 0}, ++ { XK_KP_Right, ShiftMask, "\033[152;2u", 0, 0}, ++ { XK_KP_Prior, XK_NO_MOD, "\033[5~", 0, 0}, ++ { XK_KP_Prior, ControlMask, "\033[154;5u", 0, 0}, ++ { XK_KP_Prior, ControlMask|ShiftMask, "\033[154;6u", 0, 0}, ++ { XK_KP_Prior, Mod1Mask, "\033[154;3u", 0, 0}, ++ { XK_KP_Prior, Mod1Mask|ControlMask, "\033[154;7u", 0, 0}, ++ { XK_KP_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[154;8u", 0, 0}, ++ { XK_KP_Prior, Mod1Mask|ShiftMask, "\033[154;4u", 0, 0}, ++ { XK_KP_Begin, XK_NO_MOD, "\033[E", 0, 0}, ++ { XK_KP_Begin, ControlMask, "\033[157;5u", 0, 0}, ++ { XK_KP_Begin, ControlMask|ShiftMask, "\033[157;6u", 0, 0}, ++ { XK_KP_Begin, Mod1Mask, "\033[157;3u", 0, 0}, ++ { XK_KP_Begin, Mod1Mask|ControlMask, "\033[157;7u", 0, 0}, ++ { XK_KP_Begin, Mod1Mask|ControlMask|ShiftMask, "\033[157;8u", 0, 0}, ++ { XK_KP_Begin, Mod1Mask|ShiftMask, "\033[157;4u", 0, 0}, ++ { XK_KP_Begin, ShiftMask, "\033[157;2u", 0, 0}, ++ { XK_KP_End, XK_NO_MOD, "\033[4~", 0, 0}, ++ { XK_KP_End, ControlMask|ShiftMask, "\033[156;6u", 0, 0}, ++ { XK_KP_End, Mod1Mask, "\033[156;3u", 0, 0}, ++ { XK_KP_End, Mod1Mask|ControlMask, "\033[156;7u", 0, 0}, ++ { XK_KP_End, Mod1Mask|ControlMask|ShiftMask, "\033[156;8u", 0, 0}, ++ { XK_KP_End, Mod1Mask|ShiftMask, "\033[156;4u", 0, 0}, ++ { XK_KP_Next, XK_NO_MOD, "\033[6~", 0, 0}, ++ { XK_KP_Next, ControlMask, "\033[155;5u", 0, 0}, ++ { XK_KP_Next, ControlMask|ShiftMask, "\033[155;6u", 0, 0}, ++ { XK_KP_Next, Mod1Mask, "\033[155;3u", 0, 0}, ++ { XK_KP_Next, Mod1Mask|ControlMask, "\033[155;7u", 0, 0}, ++ { XK_KP_Next, Mod1Mask|ControlMask|ShiftMask, "\033[155;8u", 0, 0}, ++ { XK_KP_Next, Mod1Mask|ShiftMask, "\033[155;4u", 0, 0}, ++ { XK_KP_Insert, XK_NO_MOD, "\033[4h", -1, 0}, ++ { XK_KP_Insert, XK_NO_MOD, "\033[2~", +1, 0}, ++ { XK_KP_Insert, ControlMask|ShiftMask, "\033[158;6u", 0, 0}, ++ { XK_KP_Insert, Mod1Mask, "\033[158;3u", 0, 0}, ++ { XK_KP_Insert, Mod1Mask|ControlMask, "\033[158;7u", 0, 0}, ++ { XK_KP_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[158;8u", 0, 0}, ++ { XK_KP_Insert, Mod1Mask|ShiftMask, "\033[158;4u", 0, 0}, ++ { XK_KP_Delete, XK_NO_MOD, "\033[P", -1, 0}, ++ { XK_KP_Delete, XK_NO_MOD, "\033[3~", +1, 0}, ++ { XK_KP_Delete, ControlMask|ShiftMask, "\033[159;6u", 0, 0}, ++ { XK_KP_Delete, Mod1Mask, "\033[159;3u", 0, 0}, ++ { XK_KP_Delete, Mod1Mask|ControlMask, "\033[159;7u", 0, 0}, ++ { XK_KP_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[159;8u", 0, 0}, ++ { XK_KP_Delete, Mod1Mask|ShiftMask, "\033[159;4u", 0, 0}, ++ { XK_KP_Multiply, XK_NO_MOD, "\033Oj", +2, 0}, ++ { XK_KP_Multiply, ControlMask, "\033[170;5u", 0, 0}, ++ { XK_KP_Multiply, ControlMask|ShiftMask, "\033[170;6u", 0, 0}, ++ { XK_KP_Multiply, Mod1Mask, "\033[170;3u", 0, 0}, ++ { XK_KP_Multiply, Mod1Mask|ControlMask, "\033[170;7u", 0, 0}, ++ { XK_KP_Multiply, Mod1Mask|ControlMask|ShiftMask, "\033[170;8u", 0, 0}, ++ { XK_KP_Multiply, Mod1Mask|ShiftMask, "\033[170;4u", 0, 0}, ++ { XK_KP_Multiply, ShiftMask, "\033[170;2u", 0, 0}, ++ { XK_KP_Add, XK_NO_MOD, "\033Ok", +2, 0}, ++ { XK_KP_Add, ControlMask, "\033[171;5u", 0, 0}, ++ { XK_KP_Add, ControlMask|ShiftMask, "\033[171;6u", 0, 0}, ++ { XK_KP_Add, Mod1Mask, "\033[171;3u", 0, 0}, ++ { XK_KP_Add, Mod1Mask|ControlMask, "\033[171;7u", 0, 0}, ++ { XK_KP_Add, Mod1Mask|ControlMask|ShiftMask, "\033[171;8u", 0, 0}, ++ { XK_KP_Add, Mod1Mask|ShiftMask, "\033[171;4u", 0, 0}, ++ { XK_KP_Add, ShiftMask, "\033[171;2u", 0, 0}, ++ { XK_KP_Enter, XK_NO_MOD, "\033OM", +2, 0}, ++ { XK_KP_Enter, XK_NO_MOD, "\r", -1, 0}, ++ { XK_KP_Enter, XK_NO_MOD, "\r\n", -1, 0}, ++ { XK_KP_Enter, ControlMask, "\033[141;5u", 0, 0}, ++ { XK_KP_Enter, ControlMask|ShiftMask, "\033[141;6u", 0, 0}, ++ { XK_KP_Enter, Mod1Mask, "\033[141;3u", 0, 0}, ++ { XK_KP_Enter, Mod1Mask|ControlMask, "\033[141;7u", 0, 0}, ++ { XK_KP_Enter, Mod1Mask|ControlMask|ShiftMask, "\033[141;8u", 0, 0}, ++ { XK_KP_Enter, Mod1Mask|ShiftMask, "\033[141;4u", 0, 0}, ++ { XK_KP_Enter, ShiftMask, "\033[141;2u", 0, 0}, ++ { XK_KP_Subtract, XK_NO_MOD, "\033Om", +2, 0}, ++ { XK_KP_Subtract, ControlMask, "\033[173;5u", 0, 0}, ++ { XK_KP_Subtract, ControlMask|ShiftMask, "\033[173;6u", 0, 0}, ++ { XK_KP_Subtract, Mod1Mask, "\033[173;3u", 0, 0}, ++ { XK_KP_Subtract, Mod1Mask|ControlMask, "\033[173;7u", 0, 0}, ++ { XK_KP_Subtract, Mod1Mask|ControlMask|ShiftMask, "\033[173;8u", 0, 0}, ++ { XK_KP_Subtract, Mod1Mask|ShiftMask, "\033[173;4u", 0, 0}, ++ { XK_KP_Subtract, ShiftMask, "\033[173;2u", 0, 0}, ++ { XK_KP_Decimal, XK_NO_MOD, "\033On", +2, 0}, ++ { XK_KP_Decimal, ControlMask, "\033[174;5u", 0, 0}, ++ { XK_KP_Decimal, ControlMask|ShiftMask, "\033[174;6u", 0, 0}, ++ { XK_KP_Decimal, Mod1Mask, "\033[174;3u", 0, 0}, ++ { XK_KP_Decimal, Mod1Mask|ControlMask, "\033[174;7u", 0, 0}, ++ { XK_KP_Decimal, Mod1Mask|ControlMask|ShiftMask, "\033[174;8u", 0, 0}, ++ { XK_KP_Decimal, Mod1Mask|ShiftMask, "\033[174;4u", 0, 0}, ++ { XK_KP_Decimal, ShiftMask, "\033[174;2u", 0, 0}, ++ { XK_KP_Divide, XK_NO_MOD, "\033Oo", +2, 0}, ++ { XK_KP_Divide, ControlMask, "\033[175;5u", 0, 0}, ++ { XK_KP_Divide, ControlMask|ShiftMask, "\033[175;6u", 0, 0}, ++ { XK_KP_Divide, Mod1Mask, "\033[175;3u", 0, 0}, ++ { XK_KP_Divide, Mod1Mask|ControlMask, "\033[175;7u", 0, 0}, ++ { XK_KP_Divide, Mod1Mask|ControlMask|ShiftMask, "\033[175;8u", 0, 0}, ++ { XK_KP_Divide, Mod1Mask|ShiftMask, "\033[175;4u", 0, 0}, ++ { XK_KP_Divide, ShiftMask, "\033[175;2u", 0, 0}, ++ { XK_KP_0, XK_NO_MOD, "\033Op", +2, 0}, ++ { XK_KP_0, ControlMask, "\033[176;5u", 0, 0}, ++ { XK_KP_0, ControlMask|ShiftMask, "\033[176;6u", 0, 0}, ++ { XK_KP_0, Mod1Mask, "\033[176;3u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ControlMask, "\033[176;7u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[176;8u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ShiftMask, "\033[176;4u", 0, 0}, ++ { XK_KP_0, ShiftMask, "\033[176;2u", 0, 0}, ++ { XK_KP_1, XK_NO_MOD, "\033Oq", +2, 0}, ++ { XK_KP_0, ControlMask, "\033[177;5u", 0, 0}, ++ { XK_KP_0, ControlMask|ShiftMask, "\033[177;6u", 0, 0}, ++ { XK_KP_0, Mod1Mask, "\033[177;3u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ControlMask, "\033[177;7u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[177;8u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ShiftMask, "\033[177;4u", 0, 0}, ++ { XK_KP_0, ShiftMask, "\033[177;2u", 0, 0}, ++ { XK_KP_2, XK_NO_MOD, "\033Or", +2, 0}, ++ { XK_KP_2, ControlMask, "\033[178;5u", 0, 0}, ++ { XK_KP_2, ControlMask|ShiftMask, "\033[178;6u", 0, 0}, ++ { XK_KP_2, Mod1Mask, "\033[178;3u", 0, 0}, ++ { XK_KP_2, Mod1Mask|ControlMask, "\033[178;7u", 0, 0}, ++ { XK_KP_2, Mod1Mask|ControlMask|ShiftMask, "\033[178;8u", 0, 0}, ++ { XK_KP_2, Mod1Mask|ShiftMask, "\033[178;4u", 0, 0}, ++ { XK_KP_2, ShiftMask, "\033[178;2u", 0, 0}, ++ { XK_KP_3, XK_NO_MOD, "\033Os", +2, 0}, ++ { XK_KP_3, ControlMask, "\033[179;5u", 0, 0}, ++ { XK_KP_3, ControlMask|ShiftMask, "\033[179;6u", 0, 0}, ++ { XK_KP_3, Mod1Mask, "\033[179;3u", 0, 0}, ++ { XK_KP_3, Mod1Mask|ControlMask, "\033[179;7u", 0, 0}, ++ { XK_KP_3, Mod1Mask|ControlMask|ShiftMask, "\033[179;8u", 0, 0}, ++ { XK_KP_3, Mod1Mask|ShiftMask, "\033[179;4u", 0, 0}, ++ { XK_KP_3, ShiftMask, "\033[179;2u", 0, 0}, ++ { XK_KP_4, XK_NO_MOD, "\033Ot", +2, 0}, ++ { XK_KP_4, ControlMask, "\033[180;5u", 0, 0}, ++ { XK_KP_4, ControlMask|ShiftMask, "\033[180;6u", 0, 0}, ++ { XK_KP_4, Mod1Mask, "\033[180;3u", 0, 0}, ++ { XK_KP_4, Mod1Mask|ControlMask, "\033[180;7u", 0, 0}, ++ { XK_KP_4, Mod1Mask|ControlMask|ShiftMask, "\033[180;8u", 0, 0}, ++ { XK_KP_4, Mod1Mask|ShiftMask, "\033[180;4u", 0, 0}, ++ { XK_KP_4, ShiftMask, "\033[180;2u", 0, 0}, ++ { XK_KP_5, XK_NO_MOD, "\033Ou", +2, 0}, ++ { XK_KP_5, ControlMask, "\033[181;5u", 0, 0}, ++ { XK_KP_5, ControlMask|ShiftMask, "\033[181;6u", 0, 0}, ++ { XK_KP_5, Mod1Mask, "\033[181;3u", 0, 0}, ++ { XK_KP_5, Mod1Mask|ControlMask, "\033[181;7u", 0, 0}, ++ { XK_KP_5, Mod1Mask|ControlMask|ShiftMask, "\033[181;8u", 0, 0}, ++ { XK_KP_5, Mod1Mask|ShiftMask, "\033[181;4u", 0, 0}, ++ { XK_KP_5, ShiftMask, "\033[181;2u", 0, 0}, ++ { XK_KP_6, XK_NO_MOD, "\033Ov", +2, 0}, ++ { XK_KP_6, ControlMask, "\033[182;5u", 0, 0}, ++ { XK_KP_6, ControlMask|ShiftMask, "\033[182;6u", 0, 0}, ++ { XK_KP_6, Mod1Mask, "\033[182;3u", 0, 0}, ++ { XK_KP_6, Mod1Mask|ControlMask, "\033[182;7u", 0, 0}, ++ { XK_KP_6, Mod1Mask|ControlMask|ShiftMask, "\033[182;8u", 0, 0}, ++ { XK_KP_6, Mod1Mask|ShiftMask, "\033[182;4u", 0, 0}, ++ { XK_KP_6, ShiftMask, "\033[182;2u", 0, 0}, ++ { XK_KP_7, XK_NO_MOD, "\033Ow", +2, 0}, ++ { XK_KP_7, ControlMask, "\033[183;5u", 0, 0}, ++ { XK_KP_7, ControlMask|ShiftMask, "\033[183;6u", 0, 0}, ++ { XK_KP_7, Mod1Mask, "\033[183;3u", 0, 0}, ++ { XK_KP_7, Mod1Mask|ControlMask, "\033[183;7u", 0, 0}, ++ { XK_KP_7, Mod1Mask|ControlMask|ShiftMask, "\033[183;8u", 0, 0}, ++ { XK_KP_7, Mod1Mask|ShiftMask, "\033[183;4u", 0, 0}, ++ { XK_KP_7, ShiftMask, "\033[183;2u", 0, 0}, ++ { XK_KP_8, XK_NO_MOD, "\033Ox", +2, 0}, ++ { XK_KP_8, ControlMask, "\033[184;5u", 0, 0}, ++ { XK_KP_8, ControlMask|ShiftMask, "\033[184;6u", 0, 0}, ++ { XK_KP_8, Mod1Mask, "\033[184;3u", 0, 0}, ++ { XK_KP_8, Mod1Mask|ControlMask, "\033[184;7u", 0, 0}, ++ { XK_KP_8, Mod1Mask|ControlMask|ShiftMask, "\033[184;8u", 0, 0}, ++ { XK_KP_8, Mod1Mask|ShiftMask, "\033[184;4u", 0, 0}, ++ { XK_KP_8, ShiftMask, "\033[184;2u", 0, 0}, ++ { XK_KP_9, XK_NO_MOD, "\033Oy", +2, 0}, ++ { XK_KP_9, ControlMask, "\033[185;5u", 0, 0}, ++ { XK_KP_9, ControlMask|ShiftMask, "\033[185;6u", 0, 0}, ++ { XK_KP_9, Mod1Mask, "\033[185;3u", 0, 0}, ++ { XK_KP_9, Mod1Mask|ControlMask, "\033[185;7u", 0, 0}, ++ { XK_KP_9, Mod1Mask|ControlMask|ShiftMask, "\033[185;8u", 0, 0}, ++ { XK_KP_9, Mod1Mask|ShiftMask, "\033[185;4u", 0, 0}, ++ { XK_KP_9, ShiftMask, "\033[185;2u", 0, 0}, ++ { XK_BackSpace, ControlMask, "\033[127;5u", 0, 0}, ++ { XK_BackSpace, ControlMask|ShiftMask, "\033[127;6u", 0, 0}, ++ { XK_BackSpace, Mod1Mask, "\033[127;3u", 0, 0}, ++ { XK_BackSpace, Mod1Mask|ControlMask, "\033[127;7u", 0, 0}, ++ { XK_BackSpace, Mod1Mask|ControlMask|ShiftMask, "\033[127;8u", 0, 0}, ++ { XK_BackSpace, Mod1Mask|ShiftMask, "\033[127;4u", 0, 0}, ++ { XK_BackSpace, ShiftMask, "\033[127;2u", 0, 0}, ++ { XK_Tab, ControlMask, "\033[9;5u", 0, 0}, ++ { XK_Tab, ControlMask|ShiftMask, "\033[1;5Z", 0, 0}, ++ { XK_Tab, Mod1Mask, "\033[1;3Z", 0, 0}, ++ { XK_Tab, Mod1Mask|ControlMask, "\033[1;7Z", 0, 0}, ++ { XK_Tab, Mod1Mask|ControlMask|ShiftMask, "\033[1;8Z", 0, 0}, ++ { XK_Tab, Mod1Mask|ShiftMask, "\033[1;4Z", 0, 0}, ++ { XK_Return, ControlMask, "\033[13;5u", 0, 0}, ++ { XK_Return, ControlMask|ShiftMask, "\033[13;6u", 0, 0}, ++ { XK_Return, Mod1Mask, "\033[13;3u", 0, 0}, ++ { XK_Return, Mod1Mask|ControlMask, "\033[13;7u", 0, 0}, ++ { XK_Return, Mod1Mask|ControlMask|ShiftMask, "\033[13;8u", 0, 0}, ++ { XK_Return, Mod1Mask|ShiftMask, "\033[13;4u", 0, 0}, ++ { XK_Return, ShiftMask, "\033[13;2u", 0, 0}, ++ { XK_Pause, ControlMask, "\033[18;5u", 0, 0}, ++ { XK_Pause, ControlMask|ShiftMask, "\033[18;6u", 0, 0}, ++ { XK_Pause, Mod1Mask, "\033[18;3u", 0, 0}, ++ { XK_Pause, Mod1Mask|ControlMask, "\033[18;7u", 0, 0}, ++ { XK_Pause, Mod1Mask|ControlMask|ShiftMask, "\033[18;8u", 0, 0}, ++ { XK_Pause, Mod1Mask|ShiftMask, "\033[18;4u", 0, 0}, ++ { XK_Pause, ShiftMask, "\033[18;2u", 0, 0}, ++ { XK_Scroll_Lock, ControlMask, "\033[20;5u", 0, 0}, ++ { XK_Scroll_Lock, ControlMask|ShiftMask, "\033[20;6u", 0, 0}, ++ { XK_Scroll_Lock, Mod1Mask, "\033[20;3u", 0, 0}, ++ { XK_Scroll_Lock, Mod1Mask|ControlMask, "\033[20;7u", 0, 0}, ++ { XK_Scroll_Lock, Mod1Mask|ControlMask|ShiftMask, "\033[20;8u", 0, 0}, ++ { XK_Scroll_Lock, Mod1Mask|ShiftMask, "\033[20;4u", 0, 0}, ++ { XK_Scroll_Lock, ShiftMask, "\033[20;2u", 0, 0}, ++ { XK_Escape, ControlMask, "\033[27;5u", 0, 0}, ++ { XK_Escape, ControlMask|ShiftMask, "\033[27;6u", 0, 0}, ++ { XK_Escape, Mod1Mask, "\033[27;3u", 0, 0}, ++ { XK_Escape, Mod1Mask|ControlMask, "\033[27;7u", 0, 0}, ++ { XK_Escape, Mod1Mask|ControlMask|ShiftMask, "\033[27;8u", 0, 0}, ++ { XK_Escape, Mod1Mask|ShiftMask, "\033[27;4u", 0, 0}, ++ { XK_Escape, ShiftMask, "\033[27;2u", 0, 0}, ++ { XK_Home, XK_NO_MOD, "\033[H", 0, -1}, ++ { XK_Home, XK_NO_MOD, "\033[1~", 0, +1}, ++ { XK_Home, ControlMask|ShiftMask, "\033[80;6u", 0, 0}, ++ { XK_Home, Mod1Mask, "\033[80;3u", 0, 0}, ++ { XK_Home, Mod1Mask|ControlMask, "\033[80;7u", 0, 0}, ++ { XK_Home, Mod1Mask|ControlMask|ShiftMask, "\033[80;8u", 0, 0}, ++ { XK_Home, Mod1Mask|ShiftMask, "\033[80;4u", 0, 0}, ++ { XK_End, XK_NO_MOD, "\033[4~", 0, 0}, ++ { XK_End, ControlMask|ShiftMask, "\033[87;6u", 0, 0}, ++ { XK_End, Mod1Mask, "\033[87;3u", 0, 0}, ++ { XK_End, Mod1Mask|ControlMask, "\033[87;7u", 0, 0}, ++ { XK_End, Mod1Mask|ControlMask|ShiftMask, "\033[87;8u", 0, 0}, ++ { XK_End, Mod1Mask|ShiftMask, "\033[87;4u", 0, 0}, ++ { XK_Prior, XK_NO_MOD, "\033[5~", 0, 0}, ++ { XK_Prior, ControlMask|ShiftMask, "\033[85;6u", 0, 0}, ++ { XK_Prior, Mod1Mask, "\033[85;3u", 0, 0}, ++ { XK_Prior, Mod1Mask|ControlMask, "\033[85;7u", 0, 0}, ++ { XK_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[85;8u", 0, 0}, ++ { XK_Prior, Mod1Mask|ShiftMask, "\033[85;4u", 0, 0}, ++ { XK_Next, XK_NO_MOD, "\033[6~", 0, 0}, ++ { XK_Next, ControlMask|ShiftMask, "\033[86;6u", 0, 0}, ++ { XK_Next, Mod1Mask, "\033[86;3u", 0, 0}, ++ { XK_Next, Mod1Mask|ControlMask, "\033[86;7u", 0, 0}, ++ { XK_Next, Mod1Mask|ControlMask|ShiftMask, "\033[86;8u", 0, 0}, ++ { XK_Next, Mod1Mask|ShiftMask, "\033[86;4u", 0, 0}, ++ { XK_Print, ControlMask, "\033[97;5u", 0, 0}, ++ { XK_Print, ControlMask|ShiftMask, "\033[97;6u", 0, 0}, ++ { XK_Print, Mod1Mask, "\033[97;3u", 0, 0}, ++ { XK_Print, Mod1Mask|ControlMask, "\033[97;7u", 0, 0}, ++ { XK_Print, Mod1Mask|ControlMask|ShiftMask, "\033[97;8u", 0, 0}, ++ { XK_Print, Mod1Mask|ShiftMask, "\033[97;4u", 0, 0}, ++ { XK_Print, ShiftMask, "\033[97;2u", 0, 0}, ++ { XK_Insert, XK_NO_MOD, "\033[4h", -1, 0}, ++ { XK_Insert, XK_NO_MOD, "\033[2~", +1, 0}, ++ { XK_Insert, ControlMask|ShiftMask, "\033[99;6u", 0, 0}, ++ { XK_Insert, Mod1Mask, "\033[99;3u", 0, 0}, ++ { XK_Insert, Mod1Mask|ControlMask, "\033[99;7u", 0, 0}, ++ { XK_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[99;8u", 0, 0}, ++ { XK_Insert, Mod1Mask|ShiftMask, "\033[99;4u", 0, 0}, ++ { XK_Menu, ControlMask, "\033[103;5u", 0, 0}, ++ { XK_Menu, ControlMask|ShiftMask, "\033[103;6u", 0, 0}, ++ { XK_Menu, Mod1Mask, "\033[103;3u", 0, 0}, ++ { XK_Menu, Mod1Mask|ControlMask, "\033[103;7u", 0, 0}, ++ { XK_Menu, Mod1Mask|ControlMask|ShiftMask, "\033[103;8u", 0, 0}, ++ { XK_Menu, Mod1Mask|ShiftMask, "\033[103;4u", 0, 0}, ++ { XK_Menu, ShiftMask, "\033[103;2u", 0, 0}, ++ { XK_Delete, XK_NO_MOD, "\033[P", -1, 0}, ++ { XK_Delete, XK_NO_MOD, "\033[3~", +1, 0}, ++ { XK_Delete, ControlMask|ShiftMask, "\033[255;6u", 0, 0}, ++ { XK_Delete, Mod1Mask, "\033[255;3u", 0, 0}, ++ { XK_Delete, Mod1Mask|ControlMask, "\033[255;7u", 0, 0}, ++ { XK_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[255;8u", 0, 0}, ++ { XK_Delete, Mod1Mask|ShiftMask, "\033[255;4u", 0, 0}, ++ { XK_i, ControlMask, "\033[105;5u", 0, 0}, ++ { XK_i, Mod1Mask|ControlMask, "\033[105;7u", 0, 0}, ++ { XK_m, ControlMask, "\033[109;5u", 0, 0}, ++ { XK_m, Mod1Mask|ControlMask, "\033[109;7u", 0, 0}, ++ { XK_space, ControlMask|ShiftMask, "\033[32;6u", 0, 0}, ++ { XK_space, Mod1Mask, "\033[32;3u", 0, 0}, ++ { XK_space, Mod1Mask|ControlMask, "\033[32;7u", 0, 0}, ++ { XK_space, Mod1Mask|ControlMask|ShiftMask, "\033[32;8u", 0, 0}, ++ { XK_space, Mod1Mask|ShiftMask, "\033[32;4u", 0, 0}, ++ { XK_space, ShiftMask, "\033[32;2u", 0, 0}, ++ { XK_0, ControlMask, "\033[48;5u", 0, 0}, ++ { XK_A, ControlMask|ShiftMask, "\033[65;6u", 0, 0}, ++ { XK_B, ControlMask|ShiftMask, "\033[66;6u", 0, 0}, ++ { XK_C, ControlMask|ShiftMask, "\033[67;6u", 0, 0}, ++ { XK_D, ControlMask|ShiftMask, "\033[68;6u", 0, 0}, ++ { XK_E, ControlMask|ShiftMask, "\033[69;6u", 0, 0}, ++ { XK_F, ControlMask|ShiftMask, "\033[70;6u", 0, 0}, ++ { XK_G, ControlMask|ShiftMask, "\033[71;6u", 0, 0}, ++ { XK_H, ControlMask|ShiftMask, "\033[72;6u", 0, 0}, ++ { XK_I, ControlMask|ShiftMask, "\033[73;6u", 0, 0}, ++ { XK_I, Mod1Mask|ControlMask|ShiftMask, "\033[73;8u", 0, 0}, ++ { XK_J, ControlMask|ShiftMask, "\033[75;6u", 0, 0}, ++ { XK_K, ControlMask|ShiftMask, "\033[74;6u", 0, 0}, ++ { XK_L, ControlMask|ShiftMask, "\033[76;6u", 0, 0}, ++ { XK_M, ControlMask|ShiftMask, "\033[77;6u", 0, 0}, ++ { XK_M, Mod1Mask|ControlMask|ShiftMask, "\033[77;8u", 0, 0}, ++ { XK_N, ControlMask|ShiftMask, "\033[78;6u", 0, 0}, ++ { XK_O, ControlMask|ShiftMask, "\033[79;6u", 0, 0}, ++ { XK_P, ControlMask|ShiftMask, "\033[80;6u", 0, 0}, ++ { XK_Q, ControlMask|ShiftMask, "\033[81;6u", 0, 0}, ++ { XK_R, ControlMask|ShiftMask, "\033[82;6u", 0, 0}, ++ { XK_S, ControlMask|ShiftMask, "\033[83;6u", 0, 0}, ++ { XK_T, ControlMask|ShiftMask, "\033[84;6u", 0, 0}, ++ { XK_U, ControlMask|ShiftMask, "\033[85;6u", 0, 0}, ++ { XK_V, ControlMask|ShiftMask, "\033[86;6u", 0, 0}, ++ { XK_W, ControlMask|ShiftMask, "\033[87;6u", 0, 0}, ++ { XK_X, ControlMask|ShiftMask, "\033[88;6u", 0, 0}, ++ { XK_Y, ControlMask|ShiftMask, "\033[89;6u", 0, 0}, ++ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0}, ++ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0}, ++ { XK_0, Mod1Mask|ControlMask, "\033[48;7u", 0, 0}, ++ { XK_1, ControlMask, "\033[49;5u", 0, 0}, ++ { XK_1, Mod1Mask|ControlMask, "\033[49;7u", 0, 0}, ++ { XK_2, ControlMask, "\033[50;5u", 0, 0}, ++ { XK_2, Mod1Mask|ControlMask, "\033[50;7u", 0, 0}, ++ { XK_3, ControlMask, "\033[51;5u", 0, 0}, ++ { XK_3, Mod1Mask|ControlMask, "\033[51;7u", 0, 0}, ++ { XK_4, ControlMask, "\033[52;5u", 0, 0}, ++ { XK_4, Mod1Mask|ControlMask, "\033[52;7u", 0, 0}, ++ { XK_5, ControlMask, "\033[53;5u", 0, 0}, ++ { XK_5, Mod1Mask|ControlMask, "\033[53;7u", 0, 0}, ++ { XK_6, ControlMask, "\033[54;5u", 0, 0}, ++ { XK_6, Mod1Mask|ControlMask, "\033[54;7u", 0, 0}, ++ { XK_7, ControlMask, "\033[55;5u", 0, 0}, ++ { XK_7, Mod1Mask|ControlMask, "\033[55;7u", 0, 0}, ++ { XK_8, ControlMask, "\033[56;5u", 0, 0}, ++ { XK_8, Mod1Mask|ControlMask, "\033[56;7u", 0, 0}, ++ { XK_9, ControlMask, "\033[57;5u", 0, 0}, ++ { XK_9, Mod1Mask|ControlMask, "\033[57;7u", 0, 0}, ++ { XK_ampersand, ControlMask, "\033[38;5u", 0, 0}, ++ { XK_ampersand, ControlMask|ShiftMask, "\033[38;6u", 0, 0}, ++ { XK_ampersand, Mod1Mask, "\033[38;3u", 0, 0}, ++ { XK_ampersand, Mod1Mask|ControlMask, "\033[38;7u", 0, 0}, ++ { XK_ampersand, Mod1Mask|ControlMask|ShiftMask, "\033[38;8u", 0, 0}, ++ { XK_ampersand, Mod1Mask|ShiftMask, "\033[38;4u", 0, 0}, ++ { XK_apostrophe, ControlMask, "\033[39;5u", 0, 0}, ++ { XK_apostrophe, ControlMask|ShiftMask, "\033[39;6u", 0, 0}, ++ { XK_apostrophe, Mod1Mask, "\033[39;3u", 0, 0}, ++ { XK_apostrophe, Mod1Mask|ControlMask, "\033[39;7u", 0, 0}, ++ { XK_apostrophe, Mod1Mask|ControlMask|ShiftMask, "\033[39;8u", 0, 0}, ++ { XK_apostrophe, Mod1Mask|ShiftMask, "\033[39;4u", 0, 0}, ++ { XK_asciicircum, ControlMask, "\033[94;5u", 0, 0}, ++ { XK_asciicircum, ControlMask|ShiftMask, "\033[94;6u", 0, 0}, ++ { XK_asciicircum, Mod1Mask, "\033[94;3u", 0, 0}, ++ { XK_asciicircum, Mod1Mask|ControlMask, "\033[94;7u", 0, 0}, ++ { XK_asciicircum, Mod1Mask|ControlMask|ShiftMask, "\033[94;8u", 0, 0}, ++ { XK_asciicircum, Mod1Mask|ShiftMask, "\033[94;4u", 0, 0}, ++ { XK_asciitilde, ControlMask, "\033[126;5u", 0, 0}, ++ { XK_asciitilde, ControlMask|ShiftMask, "\033[126;6u", 0, 0}, ++ { XK_asciitilde, Mod1Mask, "\033[126;3u", 0, 0}, ++ { XK_asciitilde, Mod1Mask|ControlMask, "\033[126;7u", 0, 0}, ++ { XK_asciitilde, Mod1Mask|ControlMask|ShiftMask, "\033[126;8u", 0, 0}, ++ { XK_asciitilde, Mod1Mask|ShiftMask, "\033[126;4u", 0, 0}, ++ { XK_asterisk, ControlMask, "\033[42;5u", 0, 0}, ++ { XK_asterisk, ControlMask|ShiftMask, "\033[42;6u", 0, 0}, ++ { XK_asterisk, Mod1Mask, "\033[42;3u", 0, 0}, ++ { XK_asterisk, Mod1Mask|ControlMask, "\033[42;7u", 0, 0}, ++ { XK_asterisk, Mod1Mask|ControlMask|ShiftMask, "\033[42;8u", 0, 0}, ++ { XK_asterisk, Mod1Mask|ShiftMask, "\033[42;4u", 0, 0}, ++ { XK_at, ControlMask, "\033[64;5u", 0, 0}, ++ { XK_at, ControlMask|ShiftMask, "\033[64;6u", 0, 0}, ++ { XK_at, Mod1Mask, "\033[64;3u", 0, 0}, ++ { XK_at, Mod1Mask|ControlMask, "\033[64;7u", 0, 0}, ++ { XK_at, Mod1Mask|ControlMask|ShiftMask, "\033[64;8u", 0, 0}, ++ { XK_at, Mod1Mask|ShiftMask, "\033[64;4u", 0, 0}, ++ { XK_backslash, ControlMask, "\033[92;5u", 0, 0}, ++ { XK_backslash, ControlMask|ShiftMask, "\033[92;6u", 0, 0}, ++ { XK_backslash, Mod1Mask, "\033[92;3u", 0, 0}, ++ { XK_backslash, Mod1Mask|ControlMask, "\033[92;7u", 0, 0}, ++ { XK_backslash, Mod1Mask|ControlMask|ShiftMask, "\033[92;8u", 0, 0}, ++ { XK_backslash, Mod1Mask|ShiftMask, "\033[92;4u", 0, 0}, ++ { XK_bar, ControlMask, "\033[124;5u", 0, 0}, ++ { XK_bar, ControlMask|ShiftMask, "\033[124;6u", 0, 0}, ++ { XK_bar, Mod1Mask, "\033[124;3u", 0, 0}, ++ { XK_bar, Mod1Mask|ControlMask, "\033[124;7u", 0, 0}, ++ { XK_bar, Mod1Mask|ControlMask|ShiftMask, "\033[124;8u", 0, 0}, ++ { XK_bar, Mod1Mask|ShiftMask, "\033[124;4u", 0, 0}, ++ { XK_braceleft, ControlMask, "\033[123;5u", 0, 0}, ++ { XK_braceleft, ControlMask|ShiftMask, "\033[123;6u", 0, 0}, ++ { XK_braceleft, Mod1Mask, "\033[123;3u", 0, 0}, ++ { XK_braceleft, Mod1Mask|ControlMask, "\033[123;7u", 0, 0}, ++ { XK_braceleft, Mod1Mask|ControlMask|ShiftMask, "\033[123;8u", 0, 0}, ++ { XK_braceleft, Mod1Mask|ShiftMask, "\033[123;4u", 0, 0}, ++ { XK_braceright, ControlMask, "\033[125;5u", 0, 0}, ++ { XK_braceright, ControlMask|ShiftMask, "\033[125;6u", 0, 0}, ++ { XK_braceright, Mod1Mask, "\033[125;3u", 0, 0}, ++ { XK_braceright, Mod1Mask|ControlMask, "\033[125;7u", 0, 0}, ++ { XK_braceright, Mod1Mask|ControlMask|ShiftMask, "\033[125;8u", 0, 0}, ++ { XK_braceright, Mod1Mask|ShiftMask, "\033[125;4u", 0, 0}, ++ { XK_bracketleft, ControlMask, "\033[91;5u", 0, 0}, ++ { XK_bracketleft, ControlMask|ShiftMask, "\033[91;6u", 0, 0}, ++ { XK_bracketleft, Mod1Mask, "\033[91;3u", 0, 0}, ++ { XK_bracketleft, Mod1Mask|ControlMask, "\033[91;7u", 0, 0}, ++ { XK_bracketleft, Mod1Mask|ControlMask|ShiftMask, "\033[91;8u", 0, 0}, ++ { XK_bracketleft, Mod1Mask|ShiftMask, "\033[91;4u", 0, 0}, ++ { XK_bracketright, ControlMask, "\033[93;5u", 0, 0}, ++ { XK_bracketright, ControlMask|ShiftMask, "\033[93;6u", 0, 0}, ++ { XK_bracketright, Mod1Mask, "\033[93;3u", 0, 0}, ++ { XK_bracketright, Mod1Mask|ControlMask, "\033[93;7u", 0, 0}, ++ { XK_bracketright, Mod1Mask|ControlMask|ShiftMask, "\033[93;8u", 0, 0}, ++ { XK_bracketright, Mod1Mask|ShiftMask, "\033[93;4u", 0, 0}, ++ { XK_colon, ControlMask, "\033[58;5u", 0, 0}, ++ { XK_colon, ControlMask|ShiftMask, "\033[58;6u", 0, 0}, ++ { XK_colon, Mod1Mask, "\033[58;3u", 0, 0}, ++ { XK_colon, Mod1Mask|ControlMask, "\033[58;7u", 0, 0}, ++ { XK_colon, Mod1Mask|ControlMask|ShiftMask, "\033[58;8u", 0, 0}, ++ { XK_colon, Mod1Mask|ShiftMask, "\033[58;4u", 0, 0}, ++ { XK_comma, ControlMask, "\033[44;5u", 0, 0}, ++ { XK_comma, ControlMask|ShiftMask, "\033[44;6u", 0, 0}, ++ { XK_comma, Mod1Mask, "\033[44;3u", 0, 0}, ++ { XK_comma, Mod1Mask|ControlMask, "\033[44;7u", 0, 0}, ++ { XK_comma, Mod1Mask|ControlMask|ShiftMask, "\033[44;8u", 0, 0}, ++ { XK_comma, Mod1Mask|ShiftMask, "\033[44;4u", 0, 0}, ++ { XK_dollar, ControlMask, "\033[36;5u", 0, 0}, ++ { XK_dollar, ControlMask|ShiftMask, "\033[36;6u", 0, 0}, ++ { XK_dollar, Mod1Mask, "\033[36;3u", 0, 0}, ++ { XK_dollar, Mod1Mask|ControlMask, "\033[36;7u", 0, 0}, ++ { XK_dollar, Mod1Mask|ControlMask|ShiftMask, "\033[36;8u", 0, 0}, ++ { XK_dollar, Mod1Mask|ShiftMask, "\033[36;4u", 0, 0}, ++ { XK_equal, ControlMask, "\033[61;5u", 0, 0}, ++ { XK_equal, ControlMask|ShiftMask, "\033[61;6u", 0, 0}, ++ { XK_equal, Mod1Mask, "\033[61;3u", 0, 0}, ++ { XK_equal, Mod1Mask|ControlMask, "\033[61;7u", 0, 0}, ++ { XK_equal, Mod1Mask|ControlMask|ShiftMask, "\033[61;8u", 0, 0}, ++ { XK_equal, Mod1Mask|ShiftMask, "\033[61;4u", 0, 0}, ++ { XK_exclam, ControlMask, "\033[33;5u", 0, 0}, ++ { XK_exclam, ControlMask|ShiftMask, "\033[33;6u", 0, 0}, ++ { XK_exclam, Mod1Mask, "\033[33;3u", 0, 0}, ++ { XK_exclam, Mod1Mask|ControlMask, "\033[33;7u", 0, 0}, ++ { XK_exclam, Mod1Mask|ControlMask|ShiftMask, "\033[33;8u", 0, 0}, ++ { XK_exclam, Mod1Mask|ShiftMask, "\033[33;4u", 0, 0}, ++ { XK_grave, ControlMask, "\033[96;5u", 0, 0}, ++ { XK_grave, ControlMask|ShiftMask, "\033[96;6u", 0, 0}, ++ { XK_grave, Mod1Mask, "\033[96;3u", 0, 0}, ++ { XK_grave, Mod1Mask|ControlMask, "\033[96;7u", 0, 0}, ++ { XK_grave, Mod1Mask|ControlMask|ShiftMask, "\033[96;8u", 0, 0}, ++ { XK_grave, Mod1Mask|ShiftMask, "\033[96;4u", 0, 0}, ++ { XK_greater, ControlMask, "\033[62;5u", 0, 0}, ++ { XK_greater, ControlMask|ShiftMask, "\033[62;6u", 0, 0}, ++ { XK_greater, Mod1Mask, "\033[62;3u", 0, 0}, ++ { XK_greater, Mod1Mask|ControlMask, "\033[62;7u", 0, 0}, ++ { XK_greater, Mod1Mask|ControlMask|ShiftMask, "\033[62;8u", 0, 0}, ++ { XK_greater, Mod1Mask|ShiftMask, "\033[62;4u", 0, 0}, ++ { XK_less, ControlMask, "\033[60;5u", 0, 0}, ++ { XK_less, ControlMask|ShiftMask, "\033[60;6u", 0, 0}, ++ { XK_less, Mod1Mask, "\033[60;3u", 0, 0}, ++ { XK_less, Mod1Mask|ControlMask, "\033[60;7u", 0, 0}, ++ { XK_less, Mod1Mask|ControlMask|ShiftMask, "\033[60;8u", 0, 0}, ++ { XK_less, Mod1Mask|ShiftMask, "\033[60;4u", 0, 0}, ++ { XK_minus, ControlMask, "\033[45;5u", 0, 0}, ++ { XK_minus, ControlMask|ShiftMask, "\033[45;6u", 0, 0}, ++ { XK_minus, Mod1Mask, "\033[45;3u", 0, 0}, ++ { XK_minus, Mod1Mask|ControlMask, "\033[45;7u", 0, 0}, ++ { XK_minus, Mod1Mask|ControlMask|ShiftMask, "\033[45;8u", 0, 0}, ++ { XK_minus, Mod1Mask|ShiftMask, "\033[45;4u", 0, 0}, ++ { XK_numbersign, ControlMask, "\033[35;5u", 0, 0}, ++ { XK_numbersign, ControlMask|ShiftMask, "\033[35;6u", 0, 0}, ++ { XK_numbersign, Mod1Mask, "\033[35;3u", 0, 0}, ++ { XK_numbersign, Mod1Mask|ControlMask, "\033[35;7u", 0, 0}, ++ { XK_numbersign, Mod1Mask|ControlMask|ShiftMask, "\033[35;8u", 0, 0}, ++ { XK_numbersign, Mod1Mask|ShiftMask, "\033[35;4u", 0, 0}, ++ { XK_parenleft, ControlMask, "\033[40;5u", 0, 0}, ++ { XK_parenleft, ControlMask|ShiftMask, "\033[40;6u", 0, 0}, ++ { XK_parenleft, Mod1Mask, "\033[40;3u", 0, 0}, ++ { XK_parenleft, Mod1Mask|ControlMask, "\033[40;7u", 0, 0}, ++ { XK_parenleft, Mod1Mask|ControlMask|ShiftMask, "\033[40;8u", 0, 0}, ++ { XK_parenleft, Mod1Mask|ShiftMask, "\033[40;4u", 0, 0}, ++ { XK_parenright, ControlMask, "\033[41;5u", 0, 0}, ++ { XK_parenright, ControlMask|ShiftMask, "\033[41;6u", 0, 0}, ++ { XK_parenright, Mod1Mask, "\033[41;3u", 0, 0}, ++ { XK_parenright, Mod1Mask|ControlMask, "\033[41;7u", 0, 0}, ++ { XK_parenright, Mod1Mask|ControlMask|ShiftMask, "\033[41;8u", 0, 0}, ++ { XK_parenright, Mod1Mask|ShiftMask, "\033[41;4u", 0, 0}, ++ { XK_percent, ControlMask, "\033[37;5u", 0, 0}, ++ { XK_percent, ControlMask|ShiftMask, "\033[37;6u", 0, 0}, ++ { XK_percent, Mod1Mask, "\033[37;3u", 0, 0}, ++ { XK_percent, Mod1Mask|ControlMask, "\033[37;7u", 0, 0}, ++ { XK_percent, Mod1Mask|ControlMask|ShiftMask, "\033[37;8u", 0, 0}, ++ { XK_percent, Mod1Mask|ShiftMask, "\033[37;4u", 0, 0}, ++ { XK_period, ControlMask, "\033[46;5u", 0, 0}, ++ { XK_period, ControlMask|ShiftMask, "\033[46;6u", 0, 0}, ++ { XK_period, Mod1Mask|ControlMask, "\033[46;7u", 0, 0}, ++ { XK_period, Mod1Mask|ControlMask|ShiftMask, "\033[46;8u", 0, 0}, ++ { XK_period, Mod1Mask|ShiftMask, "\033[46;4u", 0, 0}, ++ { XK_plus, ControlMask, "\033[43;5u", 0, 0}, ++ { XK_plus, ControlMask|ShiftMask, "\033[43;6u", 0, 0}, ++ { XK_plus, Mod1Mask, "\033[43;3u", 0, 0}, ++ { XK_plus, Mod1Mask|ControlMask, "\033[43;7u", 0, 0}, ++ { XK_plus, Mod1Mask|ControlMask|ShiftMask, "\033[43;8u", 0, 0}, ++ { XK_plus, Mod1Mask|ShiftMask, "\033[43;4u", 0, 0}, ++ { XK_question, ControlMask, "\033[63;5u", 0, 0}, ++ { XK_question, ControlMask|ShiftMask, "\033[63;6u", 0, 0}, ++ { XK_question, Mod1Mask, "\033[63;3u", 0, 0}, ++ { XK_question, Mod1Mask|ControlMask, "\033[63;7u", 0, 0}, ++ { XK_question, Mod1Mask|ControlMask|ShiftMask, "\033[63;8u", 0, 0}, ++ { XK_question, Mod1Mask|ShiftMask, "\033[63;4u", 0, 0}, ++ { XK_quotedbl, ControlMask, "\033[34;5u", 0, 0}, ++ { XK_quotedbl, ControlMask|ShiftMask, "\033[34;6u", 0, 0}, ++ { XK_quotedbl, Mod1Mask, "\033[34;3u", 0, 0}, ++ { XK_quotedbl, Mod1Mask|ControlMask, "\033[34;7u", 0, 0}, ++ { XK_quotedbl, Mod1Mask|ControlMask|ShiftMask, "\033[34;8u", 0, 0}, ++ { XK_quotedbl, Mod1Mask|ShiftMask, "\033[34;4u", 0, 0}, ++ { XK_semicolon, ControlMask, "\033[59;5u", 0, 0}, ++ { XK_semicolon, ControlMask|ShiftMask, "\033[59;6u", 0, 0}, ++ { XK_semicolon, Mod1Mask, "\033[59;3u", 0, 0}, ++ { XK_semicolon, Mod1Mask|ControlMask, "\033[59;7u", 0, 0}, ++ { XK_semicolon, Mod1Mask|ControlMask|ShiftMask, "\033[59;8u", 0, 0}, ++ { XK_semicolon, Mod1Mask|ShiftMask, "\033[59;4u", 0, 0}, ++ { XK_slash, ControlMask|ShiftMask, "\033[47;6u", 0, 0}, ++ { XK_slash, Mod1Mask, "\033[47;3u", 0, 0}, ++ { XK_slash, Mod1Mask|ControlMask, "\033[47;7u", 0, 0}, ++ { XK_slash, Mod1Mask|ControlMask|ShiftMask, "\033[47;8u", 0, 0}, ++ { XK_slash, Mod1Mask|ShiftMask, "\033[47;4u", 0, 0}, ++ { XK_underscore, ControlMask, "\033[95;5u", 0, 0}, ++ { XK_underscore, ControlMask|ShiftMask, "\033[95;6u", 0, 0}, ++ { XK_underscore, Mod1Mask, "\033[95;3u", 0, 0}, ++ { XK_underscore, Mod1Mask|ControlMask, "\033[95;7u", 0, 0}, ++ { XK_underscore, Mod1Mask|ControlMask|ShiftMask, "\033[95;8u", 0, 0}, ++ { XK_underscore, Mod1Mask|ShiftMask, "\033[95;4u", 0, 0}, + }; + + /* diff --git a/st/patches/st-focus-20230610-68d1ad9.diff b/st/patches/st-focus-20230610-68d1ad9.diff new file mode 100644 index 0000000..1c6488a --- /dev/null +++ b/st/patches/st-focus-20230610-68d1ad9.diff @@ -0,0 +1,537 @@ +# From e08d495aaa29c53273942985f40212ef72715604 Mon Sep 17 00:00:00 2001 +# From: Julius Huelsmann <juliusHuelsmann@gmail.com> +# Date: Sat, 30 May 2020 01:11:42 +0200 +# Subject: [PATCH 1/7] chore: add alpha patch +# +# --- +# config.def.h | 11 +++++++---- +# config.mk | 2 +- +# st.h | 1 + +# x.c | 40 ++++++++++++++++++++++++++++++---------- +# 4 files changed, 39 insertions(+), 15 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..6bd6e8d 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 */ +@@ -120,8 +123,7 @@ static const char *colorname[] = { + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", + "#555555", +- "gray90", /* default foreground colour */ +- "black", /* default background colour */ ++ "black", + }; + + +@@ -129,8 +131,9 @@ static const char *colorname[] = { + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +-unsigned int defaultfg = 258; +-unsigned int defaultbg = 259; ++unsigned int defaultfg = 7; ++unsigned int defaultbg = 258; ++//static + unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; + +diff --git a/config.mk b/config.mk +index 1e306f8..47c615e 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 fd3b0d8..9f91e2a 100644 +--- a/st.h ++++ b/st.h +@@ -124,3 +124,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 2a3bd38..27e81d1 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; +@@ -752,7 +754,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); + +@@ -812,6 +814,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; + } + +@@ -1134,11 +1143,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()) +@@ -1148,7 +1169,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 */ +@@ -1168,19 +1189,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); + +@@ -2035,6 +2052,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; +-- +2.34.1 + + +From 292b70d7b9976e624931f8ec264a8875e29d2f3c Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Sat, 30 May 2020 01:13:35 +0200 +Subject: [PATCH 2/7] [patch:focus] add initial patch + +--- + config.def.h | 6 +++--- + st.h | 2 +- + x.c | 33 +++++++++++++++++++-------------- + 3 files changed, 23 insertions(+), 18 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 6bd6e8d..cdfbaf1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -94,7 +94,7 @@ char *termname = "st-256color"; + unsigned int tabspaces = 8; + + /* bg opacity */ +-float alpha = 0.8; ++float alpha = 0.8, alphaUnfocused = 0.6; + + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { +@@ -132,10 +132,10 @@ static const char *colorname[] = { + * foreground, background, cursor, reverse cursor + */ + unsigned int defaultfg = 7; +-unsigned int defaultbg = 258; +-//static ++unsigned int defaultbg = 0; + unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; ++unsigned int bg = 17, bgUnfocused = 16; + + /* + * Default shape of cursor +diff --git a/st.h b/st.h +index 9f91e2a..62e3486 100644 +--- a/st.h ++++ b/st.h +@@ -124,4 +124,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; +-extern float alpha; ++extern float alpha, alphaUnfocused; +diff --git a/x.c b/x.c +index 27e81d1..05d6e2e 100644 +--- a/x.c ++++ b/x.c +@@ -255,6 +255,7 @@ static char *opt_name = NULL; + static char *opt_title = NULL; + + static uint buttons; /* bit field of pressed buttons */ ++static int focused = 0; + + void + clipcopy(const Arg *dummy) +@@ -792,35 +793,38 @@ xloadcolor(int i, const char *name, Color *ncolor) + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); + } + ++void ++xloadalpha(void) ++{ ++ float const usedAlpha = focused ? alpha : alphaUnfocused; ++ if (opt_alpha) alpha = strtof(opt_alpha, NULL); ++ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha); ++ dc.col[defaultbg].pixel &= 0x00FFFFFF; ++ dc.col[defaultbg].pixel |= (unsigned char)(0xff * usedAlpha) << 24; ++} ++ + void + xloadcols(void) + { +- int i; + static int loaded; + Color *cp; + +- if (loaded) { +- for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) +- XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); +- } else { +- dc.collen = MAX(LEN(colorname), 256); +- dc.col = xmalloc(dc.collen * sizeof(Color)); ++ if (!loaded) { ++ dc.collen = 1 + (defaultbg = MAX(LEN(colorname), 256)); ++ dc.col = xmalloc((dc.collen) * sizeof(Color)); + } + +- for (i = 0; i < dc.collen; i++) ++ for (int i = 0; i+1 < dc.collen; ++i) + if (!xloadcolor(i, NULL, &dc.col[i])) { + if (colorname[i]) + die("could not allocate color '%s'\n", colorname[i]); + else + die("could not allocate color %d\n", i); + } ++ if (dc.collen) // cannot die, as the color is already loaded. ++ xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]); + +- /* 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; ++ xloadalpha(); + loaded = 1; + } + +@@ -2106,6 +2110,7 @@ run: + XSetLocaleModifiers(""); + cols = MAX(cols, 1); + rows = MAX(rows, 1); ++ defaultbg = MAX(LEN(colorname), 256); + tnew(cols, rows); + xinit(cols, rows); + xsetenv(); +-- +2.34.1 + + +From 9bb6788325306d9ec2bead559dacd031287a2b8c Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Fri, 5 Jun 2020 20:48:06 +0200 +Subject: [PATCH 3/7] [patch:focus]: fix + +--- + x.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/x.c b/x.c +index 05d6e2e..97481ba 100644 +--- a/x.c ++++ b/x.c +@@ -1798,12 +1798,22 @@ focus(XEvent *ev) + xseturgency(0); + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); ++ if (!focused) { ++ xloadcols(); ++ redraw(); ++ } ++ focused = 1; + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); + win.mode &= ~MODE_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3, 0); ++ if (focused) { ++ xloadcols(); ++ redraw(); ++ } ++ focused = 0; + } + } + +-- +2.34.1 + + +From 62b6683ddf40aff222b59d5e074770d8d7336342 Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Sat, 6 Jun 2020 12:57:43 +0200 +Subject: [PATCH 4/7] [patch:focus]: fix + +--- + x.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/x.c b/x.c +index 97481ba..c4a4b00 100644 +--- a/x.c ++++ b/x.c +@@ -1799,10 +1799,10 @@ focus(XEvent *ev) + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); + if (!focused) { ++ focused = 1; + xloadcols(); + redraw(); + } +- focused = 1; + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); +@@ -1810,10 +1810,10 @@ focus(XEvent *ev) + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3, 0); + if (focused) { ++ focused = 0; + xloadcols(); + redraw(); + } +- focused = 0; + } + } + +-- +2.34.1 + + +From dc6c039192e887e70a2e6f07ac55c317e6b1c3be Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Thu, 23 Jul 2020 18:17:50 +0200 +Subject: [PATCH 5/7] potential fix: exchange redraw with tfulldirt + +--- + st.c | 1 - + st.h | 1 + + x.c | 4 ++-- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/st.c b/st.c +index 62def59..8ee76a3 100644 +--- a/st.c ++++ b/st.c +@@ -194,7 +194,6 @@ static void tsetscroll(int, int); + static void tswapscreen(void); + static void tsetmode(int, int, const int *, int); + static int twrite(const char *, int, int); +-static void tfulldirt(void); + static void tcontrolcode(uchar ); + static void tdectest(char ); + static void tdefutf8(char); +diff --git a/st.h b/st.h +index 62e3486..13be339 100644 +--- a/st.h ++++ b/st.h +@@ -79,6 +79,7 @@ typedef union { + + void die(const char *, ...); + void redraw(void); ++void tfulldirt(void); + void draw(void); + + void printscreen(const Arg *); +diff --git a/x.c b/x.c +index c4a4b00..92c87b4 100644 +--- a/x.c ++++ b/x.c +@@ -1801,7 +1801,7 @@ focus(XEvent *ev) + if (!focused) { + focused = 1; + xloadcols(); +- redraw(); ++ tfulldirt(); + } + } else { + if (xw.ime.xic) +@@ -1812,7 +1812,7 @@ focus(XEvent *ev) + if (focused) { + focused = 0; + xloadcols(); +- redraw(); ++ tfulldirt(); + } + } + } +-- +2.34.1 + + +From 4da97936d57e3528ef7cf36c254c0985f6640132 Mon Sep 17 00:00:00 2001 +From: Wim Stockman <wim@yasendfile.org> +Date: Sat, 4 Feb 2023 13:46:02 +0100 +Subject: [PATCH 6/7] Performs upgrade avoid reloading all the colors again and + again also avoids problem when colors are set dynamically when focus in and + out that the colourpallette is not reset each time. + +--- + x.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/x.c b/x.c +index 92c87b4..879bf0e 100644 +--- a/x.c ++++ b/x.c +@@ -796,6 +796,7 @@ xloadcolor(int i, const char *name, Color *ncolor) + void + xloadalpha(void) + { ++ xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]); + float const usedAlpha = focused ? alpha : alphaUnfocused; + if (opt_alpha) alpha = strtof(opt_alpha, NULL); + dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha); +@@ -821,8 +822,6 @@ xloadcols(void) + else + die("could not allocate color %d\n", i); + } +- if (dc.collen) // cannot die, as the color is already loaded. +- xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]); + + xloadalpha(); + loaded = 1; +@@ -1800,7 +1799,7 @@ focus(XEvent *ev) + ttywrite("\033[I", 3, 0); + if (!focused) { + focused = 1; +- xloadcols(); ++ xloadalpha(); + tfulldirt(); + } + } else { +@@ -1811,7 +1810,7 @@ focus(XEvent *ev) + ttywrite("\033[O", 3, 0); + if (focused) { + focused = 0; +- xloadcols(); ++ xloadalpha(); + tfulldirt(); + } + } +-- +2.34.1 + + +From ec16984d95e0ff9ac33b2b3d30f292c3a327c473 Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Sat, 10 Jun 2023 13:16:11 +0200 +Subject: [PATCH 7/7] changed default config a bit + +--- + config.def.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index cdfbaf1..779178f 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -94,7 +94,7 @@ char *termname = "st-256color"; + unsigned int tabspaces = 8; + + /* bg opacity */ +-float alpha = 0.8, alphaUnfocused = 0.6; ++float alpha = 0.93, alphaUnfocused = 0.6; + + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { +@@ -135,7 +135,7 @@ unsigned int defaultfg = 7; + unsigned int defaultbg = 0; + unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; +-unsigned int bg = 17, bgUnfocused = 16; ++unsigned int bg = 0, bgUnfocused = 16; + + /* + * Default shape of cursor +-- +2.34.1 diff --git a/st/patches/st-font2-0.8.5.diff b/st/patches/st-font2-0.8.5.diff new file mode 100644 index 0000000..9b22b8a --- /dev/null +++ b/st/patches/st-font2-0.8.5.diff @@ -0,0 +1,163 @@ +From 1635e04d3643dd4caa0c7c2043b585c6d7e4705f Mon Sep 17 00:00:00 2001 +From: Rizqi Nur Assyaufi <bandithijo@gmail.com> +Date: Mon, 18 Jul 2022 01:15:45 +0800 +Subject: [PATCH] [st][patch][font2] Add patch for st-0.8.5 + +--- + config.def.h | 6 +++ + x.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 107 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..717b2f0 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -6,6 +6,12 @@ + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ + static char *font = "Liberation Mono:pixelsize=12: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; + + /* +diff --git a/x.c b/x.c +index 8a16faa..220fc4f 100644 +--- a/x.c ++++ b/x.c +@@ -157,6 +157,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); +@@ -306,6 +308,7 @@ zoomabs(const Arg *arg) + { + xunloadfonts(); + xloadfonts(usedfont, arg->f); ++ xloadsparefonts(); + cresize(0, 0); + redraw(); + xhints(); +@@ -1034,6 +1037,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) + { +@@ -1131,6 +1229,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(); +-- +2.37.1 + diff --git a/st/patches/st-fullscreen-0.8.5.diff b/st/patches/st-fullscreen-0.8.5.diff new file mode 100644 index 0000000..3e2868d --- /dev/null +++ b/st/patches/st-fullscreen-0.8.5.diff @@ -0,0 +1,69 @@ +diff -r -u a/config.def.h b/config.def.h +--- a/config.def.h 2022-01-07 06:41:35.000000000 -0500 ++++ b/config.def.h 2022-01-15 13:32:01.644320198 -0500 +@@ -201,6 +201,8 @@ + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { XK_NO_MOD, XK_F11, fullscreen, {.i = 0} }, ++ { MODKEY, XK_Return, fullscreen, {.i = 0} }, + }; + + /* +diff -r -u a/st.h b/st.h +--- a/st.h 2022-01-07 06:41:35.000000000 -0500 ++++ b/st.h 2022-01-15 13:32:40.084320514 -0500 +@@ -81,6 +81,7 @@ + void redraw(void); + void draw(void); + ++void fullscreen(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +diff -r -u a/x.c b/x.c +--- a/x.c 2022-01-07 06:41:35.000000000 -0500 ++++ b/x.c 2022-01-15 13:50:28.164329295 -0500 +@@ -94,6 +94,7 @@ + Drawable buf; + GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ + Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; ++ Atom netwmstate, netwmfullscreen; + struct { + XIM xim; + XIC xic; +@@ -744,6 +745,24 @@ + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); + } + ++void ++fullscreen(const Arg *arg) ++{ ++ XEvent ev; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ++ ev.xclient.type = ClientMessage; ++ ev.xclient.message_type = xw.netwmstate; ++ ev.xclient.display = xw.dpy; ++ ev.xclient.window = xw.win; ++ ev.xclient.format = 32; ++ ev.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */ ++ ev.xclient.data.l[1] = xw.netwmfullscreen; ++ ++ XSendEvent(xw.dpy, DefaultRootWindow(xw.dpy), False, SubstructureNotifyMask|SubstructureRedirectMask, &ev); ++} ++ + ushort + sixd_to_16bit(int x) + { +@@ -1208,6 +1227,9 @@ + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (uchar *)&thispid, 1); + ++ xw.netwmstate = XInternAtom(xw.dpy, "_NET_WM_STATE", False); ++ xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False); ++ + win.mode = MODE_NUMLOCK; + resettitle(); + xhints(); diff --git a/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff b/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff new file mode 100644 index 0000000..0448226 --- /dev/null +++ b/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff @@ -0,0 +1,213 @@ +From 9583955da47177c9557210f70baaaf9511ba106c Mon Sep 17 00:00:00 2001 +From: wael <40663@protonmail.com> +Date: Mon, 11 Apr 2022 17:14:06 +0300 +Subject: [PATCH] boxdraw support for glyph wide support + +--- + st.h | 6 +++ + x.c | 139 ++++++++++++++++++++++++++++++----------------------------- + 2 files changed, 76 insertions(+), 69 deletions(-) + +diff --git a/st.h b/st.h +index 07a7c66..3b8c97d 100644 +--- a/st.h ++++ b/st.h +@@ -37,6 +37,12 @@ enum glyph_attribute { + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + }; + ++enum drawing_mode { ++ DRAW_NONE = 0, ++ DRAW_BG = 1 << 0, ++ DRAW_FG = 1 << 1, ++}; ++ + enum selection_mode { + SEL_IDLE = 0, + SEL_EMPTY = 1, +diff --git a/x.c b/x.c +index bf6bbf9..1311c0d 100644 +--- a/x.c ++++ b/x.c +@@ -142,7 +142,7 @@ typedef struct { + + static inline ushort sixd_to_16bit(int); + static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); +-static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); ++static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int); + static void xdrawglyph(Glyph, int, int); + static void xclear(int, int, int, int); + static int xgeommasktogravity(int); +@@ -1379,7 +1379,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + } + + void +-xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) ++xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode) + { + int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); + int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, +@@ -1470,51 +1470,45 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + if (base.mode & ATTR_INVISIBLE) + fg = bg; + +- /* Intelligent cleaning up of the borders. */ +- if (x == 0) { +- xclear(0, (y == 0)? 0 : winy, borderpx, +- winy + win.ch + +- ((winy + win.ch >= borderpx + win.th)? win.h : 0)); +- } +- if (winx + width >= borderpx + win.tw) { +- xclear(winx + width, (y == 0)? 0 : winy, win.w, +- ((winy + win.ch >= borderpx + 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, winy + win.ch, winx + width, win.h); +- +- /* Clean up the region we want to draw to. */ +- XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); +- +- /* Set the clip region because Xft is sometimes dirty. */ +- r.x = 0; +- r.y = 0; +- r.height = win.ch; +- r.width = width; +- XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); +- +- 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); +- } ++ if (dmode & DRAW_BG) { ++ /* Intelligent cleaning up of the borders. */ ++ if (x == 0) { ++ xclear(0, (y == 0)? 0 : winy, borderpx, ++ winy + win.ch + ++ ((winy + win.ch >= borderpx + win.th)? win.h : 0)); ++ } ++ if (winx + width >= borderpx + win.tw) { ++ xclear(winx + width, (y == 0)? 0 : winy, win.w, ++ ((winy + win.ch >= borderpx + 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, winy + win.ch, winx + width, win.h); ++ /* Fill the background */ ++ XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); ++ } ++ ++ ++ if (dmode & DRAW_FG) { ++ 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) { +- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, +- width, 1); +- } ++ /* Render underline and strikethrough. */ ++ if (base.mode & ATTR_UNDERLINE) { ++ XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, ++ width, 1); ++ } + +- if (base.mode & ATTR_STRUCK) { +- XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, +- width, 1); +- } +- +- /* Reset clip to none. */ +- XftDrawSetClip(xw.draw, 0); ++ if (base.mode & ATTR_STRUCK) { ++ XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, ++ width, 1); ++ } ++ } + } + + void +@@ -1524,7 +1518,7 @@ xdrawglyph(Glyph g, int x, int y) + XftGlyphFontSpec spec; + + numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); +- xdrawglyphfontspecs(&spec, g, numspecs, x, y); ++ xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG); + } + + void +@@ -1659,32 +1653,39 @@ xstartdraw(void) + void + xdrawline(Line line, int x1, int y1, int x2) + { +- int i, x, ox, numspecs; ++ int i, x, ox, numspecs, numspecs_cached; + Glyph base, new; +- XftGlyphFontSpec *specs = xw.specbuf; +- +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); +- i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { +- new = line[x]; +- if (new.mode == ATTR_WDUMMY) +- continue; +- if (selected(x, y1)) +- new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; +- i = 0; +- } +- if (i == 0) { +- ox = x; +- base = new; ++ XftGlyphFontSpec *specs; ++ ++ numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1); ++ ++ /* Draw line in 2 passes: background and foreground. This way wide glyphs ++ won't get truncated (#223) */ ++ for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { ++ specs = xw.specbuf; ++ numspecs = numspecs_cached; ++ i = ox = 0; ++ for (x = x1; x < x2 && i < numspecs; x++) { ++ new = line[x]; ++ if (new.mode == ATTR_WDUMMY) ++ continue; ++ if (selected(x, y1)) ++ new.mode ^= ATTR_REVERSE; ++ if (i > 0 && ATTRCMP(base, new)) { ++ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); ++ specs += i; ++ numspecs -= i; ++ i = 0; ++ } ++ if (i == 0) { ++ ox = x; ++ base = new; ++ } ++ i++; + } +- i++; ++ if (i > 0) ++ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); + } + + void +-- +2.35.1 + diff --git a/st/patches/st-iso14755-0.8.5.diff b/st/patches/st-iso14755-0.8.5.diff new file mode 100644 index 0000000..adaedb4 --- /dev/null +++ b/st/patches/st-iso14755-0.8.5.diff @@ -0,0 +1,89 @@ +diff --git a/config.def.h b/config.def.h +index 91ab8ca..6d1aee0 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -170,6 +170,11 @@ static unsigned int defaultattr = 11; + */ + static uint forcemousemod = ShiftMask; + ++/* ++ * Command used to query unicode glyphs. ++ */ ++char *iso14755_cmd = "dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"; ++ + /* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. +@@ -201,6 +206,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_I, iso14755, {.i = 0} }, + }; + + /* +diff --git a/st.1 b/st.1 +index 39120b4..4a98626 100644 +--- a/st.1 ++++ b/st.1 +@@ -159,6 +159,10 @@ Copy the selected text to the clipboard selection. + .TP + .B Ctrl-Shift-v + Paste from the clipboard selection. ++.TP ++.B Ctrl-Shift-i ++Launch dmenu to enter a unicode codepoint and send the corresponding glyph ++to st. + .SH CUSTOMIZATION + .B st + can be customized by creating a custom config.h and (re)compiling the source +diff --git a/st.c b/st.c +index 51049ba..308162b 100644 +--- a/st.c ++++ b/st.c +@@ -2068,6 +2068,28 @@ tprinter(char *s, size_t len) + } + } + ++void ++iso14755(const Arg *arg) ++{ ++ FILE *p; ++ char *us, *e, codepoint[9], uc[UTF_SIZ]; ++ unsigned long utf32; ++ ++ if (!(p = popen(iso14755_cmd, "r"))) ++ return; ++ ++ us = fgets(codepoint, sizeof(codepoint), p); ++ pclose(p); ++ ++ if (!us || *us == '\0' || *us == '-' || strlen(us) > 7) ++ return; ++ if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || ++ (*e != '\n' && *e != '\0')) ++ return; ++ ++ ttywrite(uc, utf8encode(utf32, uc), 1); ++} ++ + void + toggleprinter(const Arg *arg) + { +diff --git a/st.h b/st.h +index 519b9bd..51aa1ae 100644 +--- a/st.h ++++ b/st.h +@@ -81,6 +81,7 @@ void die(const char *, ...); + void redraw(void); + void draw(void); + ++void iso14755(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +@@ -126,3 +127,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern char *iso14755_cmd; diff --git a/st/patches/st-keyboard_select-20200617-9ba7ecf.diff b/st/patches/st-keyboard_select-20200617-9ba7ecf.diff new file mode 100644 index 0000000..fac41ea --- /dev/null +++ b/st/patches/st-keyboard_select-20200617-9ba7ecf.diff @@ -0,0 +1,319 @@ +diff --git a/config.def.h b/config.def.h +index 6f05dce..54612d1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -199,6 +199,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_Escape, keyboard_select,{.i = 0} }, + }; + + /* +diff --git a/st.c b/st.c +index ef8abd5..0c6c6ca 100644 +--- a/st.c ++++ b/st.c +@@ -16,6 +16,8 @@ + #include <termios.h> + #include <unistd.h> + #include <wchar.h> ++#include <X11/keysym.h> ++#include <X11/X.h> + + #include "st.h" + #include "win.h" +@@ -2487,6 +2489,9 @@ tresize(int col, int row) + int *bp; + TCursor c; + ++ if ( row < term.row || col < term.col ) ++ toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0)); ++ + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); +@@ -2612,3 +2617,220 @@ redraw(void) + tfulldirt(); + draw(); + } ++ ++void set_notifmode(int type, KeySym ksym) { ++ static char *lib[] = { " MOVE ", " SEL "}; ++ static Glyph *g, *deb, *fin; ++ static int col, bot; ++ ++ if ( ksym == -1 ) { ++ free(g); ++ col = term.col, bot = term.bot; ++ g = xmalloc(col * sizeof(Glyph)); ++ memcpy(g, term.line[bot], col * sizeof(Glyph)); ++ ++ } ++ else if ( ksym == -2 ) ++ memcpy(term.line[bot], g, col * sizeof(Glyph)); ++ ++ if ( type < 2 ) { ++ char *z = lib[type]; ++ for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++) ++ deb->mode = ATTR_REVERSE, ++ deb->u = *z, ++ deb->fg = defaultfg, deb->bg = defaultbg; ++ } ++ else if ( type < 5 ) ++ memcpy(term.line[bot], g, col * sizeof(Glyph)); ++ else { ++ for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++) ++ deb->mode = ATTR_REVERSE, ++ deb->u = ' ', ++ deb->fg = defaultfg, deb->bg = defaultbg; ++ term.line[bot][0].u = ksym; ++ } ++ ++ term.dirty[bot] = 1; ++ drawregion(0, bot, col, bot + 1); ++} ++ ++void select_or_drawcursor(int selectsearch_mode, int type) { ++ int done = 0; ++ ++ if ( selectsearch_mode & 1 ) { ++ selextend(term.c.x, term.c.y, type, done); ++ xsetsel(getsel()); ++ } ++ else ++ xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x], ++ term.ocx, term.ocy, term.line[term.ocy][term.ocx]); ++} ++ ++void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) { ++ Rune *r; ++ int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr; ++ ++ for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) { ++ for (r = target; r - target < ptarget; r++) { ++ if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) { ++ if ( r - target == ptarget - 1 ) break; ++ } else { ++ r = NULL; ++ break; ++ } ++ } ++ if ( r != NULL ) break; ++ } ++ ++ if ( i != bound ) { ++ term.c.y = i / term.col, term.c.x = i % term.col; ++ select_or_drawcursor(selectsearch_mode, type); ++ } ++} ++ ++int trt_kbdselect(KeySym ksym, char *buf, int len) { ++ static TCursor cu; ++ static Rune target[64]; ++ static int type = 1, ptarget, in_use; ++ static int sens, quant; ++ static char selectsearch_mode; ++ int i, bound, *xy; ++ ++ ++ if ( selectsearch_mode & 2 ) { ++ if ( ksym == XK_Return ) { ++ selectsearch_mode ^= 2; ++ set_notifmode(selectsearch_mode, -2); ++ if ( ksym == XK_Escape ) ptarget = 0; ++ return 0; ++ } ++ else if ( ksym == XK_BackSpace ) { ++ if ( !ptarget ) return 0; ++ term.line[term.bot][ptarget--].u = ' '; ++ } ++ else if ( len < 1 ) { ++ return 0; ++ } ++ else if ( ptarget == term.col || ksym == XK_Escape ) { ++ return 0; ++ } ++ else { ++ utf8decode(buf, &target[ptarget++], len); ++ term.line[term.bot][ptarget].u = target[ptarget - 1]; ++ } ++ ++ if ( ksym != XK_BackSpace ) ++ search(selectsearch_mode, &target[0], ptarget, sens, type, &cu); ++ ++ term.dirty[term.bot] = 1; ++ drawregion(0, term.bot, term.col, term.bot + 1); ++ return 0; ++ } ++ ++ switch ( ksym ) { ++ case -1 : ++ in_use = 1; ++ cu.x = term.c.x, cu.y = term.c.y; ++ set_notifmode(0, ksym); ++ return MODE_KBDSELECT; ++ case XK_s : ++ if ( selectsearch_mode & 1 ) ++ selclear(); ++ else ++ selstart(term.c.x, term.c.y, 0); ++ set_notifmode(selectsearch_mode ^= 1, ksym); ++ break; ++ case XK_t : ++ selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */ ++ selextend(term.c.x, term.c.y, type, i = 0); ++ break; ++ case XK_slash : ++ case XK_KP_Divide : ++ case XK_question : ++ ksym &= XK_question; /* Divide to slash */ ++ sens = (ksym == XK_slash) ? -1 : 1; ++ ptarget = 0; ++ set_notifmode(15, ksym); ++ selectsearch_mode ^= 2; ++ break; ++ case XK_Escape : ++ if ( !in_use ) break; ++ selclear(); ++ case XK_Return : ++ set_notifmode(4, ksym); ++ term.c.x = cu.x, term.c.y = cu.y; ++ select_or_drawcursor(selectsearch_mode = 0, type); ++ in_use = quant = 0; ++ return MODE_KBDSELECT; ++ case XK_n : ++ case XK_N : ++ if ( ptarget ) ++ search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu); ++ break; ++ case XK_BackSpace : ++ term.c.x = 0; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_dollar : ++ term.c.x = term.col - 1; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_Home : ++ term.c.x = 0, term.c.y = 0; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_End : ++ term.c.x = cu.x, term.c.y = cu.y; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_Page_Up : ++ case XK_Page_Down : ++ term.c.y = (ksym == XK_Prior ) ? 0 : cu.y; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_exclam : ++ term.c.x = term.col >> 1; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_asterisk : ++ case XK_KP_Multiply : ++ term.c.x = term.col >> 1; ++ case XK_underscore : ++ term.c.y = cu.y >> 1; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ default : ++ if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */ ++ quant = (quant * 10) + (ksym ^ XK_0); ++ return 0; ++ } ++ else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */ ++ quant = (quant * 10) + (ksym ^ XK_KP_0); ++ return 0; ++ } ++ else if ( ksym == XK_k || ksym == XK_h ) ++ i = ksym & 1; ++ else if ( ksym == XK_l || ksym == XK_j ) ++ i = ((ksym & 6) | 4) >> 1; ++ else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 ) ++ break; ++ ++ xy = (i & 1) ? &term.c.y : &term.c.x; ++ sens = (i & 2) ? 1 : -1; ++ bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot; ++ ++ if ( quant == 0 ) ++ quant++; ++ ++ if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) ) ++ break; ++ ++ *xy += quant * sens; ++ if ( *xy < 0 || ( bound > 0 && *xy > bound) ) ++ *xy = bound; ++ ++ select_or_drawcursor(selectsearch_mode, type); ++ } ++ quant = 0; ++ return 0; ++} +diff --git a/st.h b/st.h +index 3d351b6..2d1a11b 100644 +--- a/st.h ++++ b/st.h +@@ -110,6 +110,7 @@ size_t utf8encode(Rune, char *); + void *xmalloc(size_t); + void *xrealloc(void *, size_t); + char *xstrdup(char *); ++int trt_kbdselect(KeySym, char *, int); + + /* config.h globals */ + extern char *utmp; +diff --git a/win.h b/win.h +index a6ef1b9..9a47fbb 100644 +--- a/win.h ++++ b/win.h +@@ -21,6 +21,7 @@ enum win_mode { + MODE_NUMLOCK = 1 << 17, + MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ + |MODE_MOUSEMANY, ++ MODE_KBDSELECT = 1 << 18, + }; + + void xbell(void); +@@ -36,4 +37,6 @@ void xsetmode(int, unsigned int); + void xsetpointermotion(int); + void xsetsel(char *); + int xstartdraw(void); ++void toggle_winmode(int); ++void keyboard_select(const Arg *); + void xximspot(int, int); +diff --git a/x.c b/x.c +index 210f184..b77ce54 100644 +--- a/x.c ++++ b/x.c +@@ -1800,6 +1800,12 @@ kpress(XEvent *ev) + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + else + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); ++ if ( IS_SET(MODE_KBDSELECT) ) { ++ if ( match(XK_NO_MOD, e->state) || ++ (XK_Shift_L | XK_Shift_R) & e->state ) ++ win.mode ^= trt_kbdselect(ksym, buf, len); ++ return; ++ } + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { +@@ -1977,6 +1983,14 @@ usage(void) + " [stty_args ...]\n", argv0, argv0); + } + ++void toggle_winmode(int flag) { ++ win.mode ^= flag; ++} ++ ++void keyboard_select(const Arg *dummy) { ++ win.mode ^= trt_kbdselect(-1, NULL, 0); ++} ++ + int + main(int argc, char *argv[]) + { diff --git a/st/patches/st-newterm-0.9-tabbed.diff b/st/patches/st-newterm-0.9-tabbed.diff new file mode 100644 index 0000000..a32c316 --- /dev/null +++ b/st/patches/st-newterm-0.9-tabbed.diff @@ -0,0 +1,38 @@ +From 88559b5cb6ed3f996fc00e923f9ded3c0b353fc5 Mon Sep 17 00:00:00 2001 +From: meator <meator.dev@gmail.com> +Date: Wed, 26 Oct 2022 14:06:49 +0200 +Subject: [PATCH] Make newterm work with the tabbed patch + +This commit is an updated version of st-newterm-0.8.2-tabbed.diff. +--- + st.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/st.c b/st.c +index 0261283..e4a9021 100644 +--- a/st.c ++++ b/st.c +@@ -1061,6 +1061,7 @@ tswapscreen(void) + void + newterm(const Arg* a) + { ++ char *tabbed_win; + switch (fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); +@@ -1073,7 +1074,11 @@ newterm(const Arg* a) + break; + case 0: + chdir_by_pid(pid); +- execl("/proc/self/exe", argv0, NULL); ++ tabbed_win = getenv("XEMBED"); ++ if (tabbed_win) ++ execl("/proc/self/exe", argv0, "-w", tabbed_win, NULL); ++ else ++ execl("/proc/self/exe", argv0, NULL); + _exit(1); + break; + default: +-- +2.38.0 + diff --git a/st/patches/st-newterm-0.9-tmux.diff b/st/patches/st-newterm-0.9-tmux.diff new file mode 100644 index 0000000..cd73e60 --- /dev/null +++ b/st/patches/st-newterm-0.9-tmux.diff @@ -0,0 +1,140 @@ +From 6640cf9809086d8cfb2363571d3e71a1a7a9f6bd Mon Sep 17 00:00:00 2001 +From: meator <meator.dev@gmail.com> +Date: Tue, 25 Oct 2022 20:19:28 +0200 +Subject: [PATCH] Add support for tmux in newterm + +This commit tries to figure out if st's child is tmux and if so, it +launches a shell with the CWD of the current process in the tmux session +instead of the tmux client itself. + +This is heavily inspired by +https://gist.github.com/TiddoLangerak/c61e1e48df91192f9554 (but +converted to C). + +Tmux has to be a direct child of st. This means that you'll have to +usually use the 'exec' shell builtin to attach tmux sessions. + +This patch only works on Linux. Other systems use different procfs which +is incompatible or don't have procfs at all (or it's optional). +--- + st.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 82 insertions(+), 1 deletion(-) + +diff --git a/st.c b/st.c +index 0261283..b95bf7a 100644 +--- a/st.c ++++ b/st.c +@@ -221,6 +221,8 @@ static char base64dec_getc(const char **); + + static ssize_t xwrite(int, const char *, size_t); + ++static int gettmuxpts(void); ++ + /* Globals */ + static Term term; + static Selection sel; +@@ -1061,6 +1063,12 @@ tswapscreen(void) + void + newterm(const Arg* a) + { ++ int pts; ++ FILE *fsession, *fpid; ++ char session[5]; ++ char pidstr[10]; ++ char buf[48]; ++ size_t size; + switch (fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); +@@ -1072,7 +1080,37 @@ newterm(const Arg* a) + _exit(1); + break; + case 0: +- chdir_by_pid(pid); ++ signal(SIGCHLD, SIG_DFL); /* pclose() needs to use wait() */ ++ pts = gettmuxpts(); ++ if (pts != -1) { ++ snprintf(buf, sizeof buf, "tmux lsc -t /dev/pts/%d -F \"#{client_session}\"", pts); ++ fsession = popen(buf, "r"); ++ if (!fsession) { ++ fprintf(stderr, "Couldn't launch tmux."); ++ _exit(1); ++ } ++ size = fread(session, 1, sizeof session, fsession); ++ if (pclose(fsession) != 0 || size == 0) { ++ fprintf(stderr, "Couldn't get tmux session."); ++ _exit(1); ++ } ++ session[size - 1] = '\0'; /* size - 1 is used to also trim the \n */ ++ ++ snprintf(buf, sizeof buf, "tmux list-panes -st %s -F \"#{pane_pid}\"", session); ++ fpid = popen(buf, "r"); ++ if (!fpid) { ++ fprintf(stderr, "Couldn't launch tmux."); ++ _exit(1); ++ } ++ size = fread(pidstr, 1, sizeof pidstr, fpid); ++ if (pclose(fpid) != 0 || size == 0) { ++ fprintf(stderr, "Couldn't get tmux session."); ++ _exit(1); ++ } ++ pidstr[size - 1] = '\0'; ++ } ++ ++ chdir_by_pid(pts != -1 ? atol(pidstr) : pid); + execl("/proc/self/exe", argv0, NULL); + _exit(1); + break; +@@ -1092,6 +1130,49 @@ chdir_by_pid(pid_t pid) + return chdir(buf); + } + ++/* returns the pty of tmux client or -1 if the child of st isn't tmux */ ++static int ++gettmuxpts(void) ++{ ++ char buf[32]; ++ char comm[17]; ++ int tty; ++ FILE *fstat; ++ FILE *fcomm; ++ size_t numread; ++ ++ snprintf(buf, sizeof buf, "/proc/%ld/comm", (long)pid); ++ ++ fcomm = fopen(buf, "r"); ++ if (!fcomm) { ++ fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno)); ++ _exit(1); ++ } ++ ++ numread = fread(comm, 1, sizeof comm - 1, fcomm); ++ comm[numread] = '\0'; ++ ++ fclose(fcomm); ++ ++ if (strcmp("tmux: client\n", comm) != 0) ++ return -1; ++ ++ snprintf(buf, sizeof buf, "/proc/%ld/stat", (long)pid); ++ fstat = fopen(buf, "r"); ++ if (!fstat) { ++ fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno)); ++ _exit(1); ++ } ++ ++ /* ++ * We can't skip the second field with %*s because it contains a space so ++ * we skip strlen("tmux: client") + 2 for the braces which is 14. ++ */ ++ fscanf(fstat, "%*d %*14c %*c %*d %*d %*d %d", &tty); ++ fclose(fstat); ++ return ((0xfff00000 & tty) >> 12) | (0xff & tty); ++} ++ + void + tscrolldown(int orig, int n) + { +-- +2.38.0 + diff --git a/st/patches/st-newterm-0.9.diff b/st/patches/st-newterm-0.9.diff new file mode 100644 index 0000000..5525e7a --- /dev/null +++ b/st/patches/st-newterm-0.9.diff @@ -0,0 +1,112 @@ +From e1cf625f4f225a007a5835421896089669195e02 Mon Sep 17 00:00:00 2001 +From: meator <meator.dev@gmail.com> +Date: Wed, 26 Oct 2022 13:05:38 +0200 +Subject: [PATCH] Add shortcut to spawn new terminal in the current dir + +This commit is inspired by Santtu's st-newterm-20220221-0.8.5.diff. It +removes the unused res variable, it makes use of _exit() instead of +exit() and it replaces execlp() with execl() (PATH searching is useless +when the path is absolute). +--- + config.def.h | 1 + + st.c | 38 ++++++++++++++++++++++++++++++++++++++ + st.h | 1 + + 3 files changed, 40 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 62def59..0261283 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); +@@ -806,6 +809,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); +@@ -1054,6 +1058,40 @@ tswapscreen(void) + tfulldirt(); + } + ++void ++newterm(const Arg* a) ++{ ++ switch (fork()) { ++ case -1: ++ die("fork failed: %s\n", strerror(errno)); ++ break; ++ case 0: ++ switch (fork()) { ++ case -1: ++ fprintf(stderr, "fork failed: %s\n", strerror(errno)); ++ _exit(1); ++ break; ++ case 0: ++ chdir_by_pid(pid); ++ execl("/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 fd3b0d8..f2b03b0 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.38.0 + diff --git a/st/patches/st-openclipboard-20220217-0.8.5.diff b/st/patches/st-openclipboard-20220217-0.8.5.diff new file mode 100644 index 0000000..196c543 --- /dev/null +++ b/st/patches/st-openclipboard-20220217-0.8.5.diff @@ -0,0 +1,91 @@ +From 1e752ae33791652d050e7d03e6d8e9df3fb459e3 Mon Sep 17 00:00:00 2001 +From: Santtu Lakkala <inz@inz.fi> +Date: Thu, 17 Feb 2022 18:11:35 +0200 +Subject: [PATCH] Open url from clipboard + +Based on the previous versions of the patch, but uses double-fork/execlp +instead of system() to avoid potential shell escaping issues and make +the command line building unnecessary. +--- + config.def.h | 1 + + st.c | 2 +- + st.h | 1 + + x.c | 21 +++++++++++++++++++++ + 4 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..a696ec7 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} }, ++ { MODKEY, XK_o, opencopied, {.v = "xdg-open"} }, + }; + + /* +diff --git a/st.c b/st.c +index 51049ba..4fbc5c8 100644 +--- a/st.c ++++ b/st.c +@@ -810,7 +810,7 @@ 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 exec", NULL) == -1) + die("pledge\n"); + #endif + close(s); +diff --git a/st.h b/st.h +index 519b9bd..3b4b395 100644 +--- a/st.h ++++ b/st.h +@@ -81,6 +81,7 @@ void die(const char *, ...); + void redraw(void); + void draw(void); + ++void opencopied(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +diff --git a/x.c b/x.c +index 8a16faa..3a4e5f0 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> +@@ -2078,3 +2079,23 @@ run: + + return 0; + } ++ ++void ++opencopied(const Arg *arg) ++{ ++ char * const clip = xsel.clipboard; ++ pid_t chpid; ++ ++ if(!clip) { ++ fprintf(stderr, "Warning: nothing copied to clipboard\n"); ++ return; ++ } ++ ++ if ((chpid = fork()) == 0) { ++ if (fork() == 0) ++ execlp(arg->v, arg->v, clip, NULL); ++ exit(1); ++ } ++ if (chpid > 0) ++ waitpid(chpid, NULL, 0); ++} +-- +2.32.0 + diff --git a/st/patches/st-scrollback-0.9.2.diff b/st/patches/st-scrollback-0.9.2.diff new file mode 100644 index 0000000..b022a05 --- /dev/null +++ b/st/patches/st-scrollback-0.9.2.diff @@ -0,0 +1,351 @@ +diff --git a/config.def.h b/config.def.h +index 2cd740a..40b7d93 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 b9f66e7..2478942 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++; + } +@@ -1285,14 +1347,14 @@ void + tinsertblankline(int n) + { + if (BETWEEN(term.c.y, term.top, term.bot)) +- tscrolldown(term.c.y, n); ++ tscrolldown(term.c.y, n, 0); + } + + void + tdeleteline(int n) + { + if (BETWEEN(term.c.y, term.top, term.bot)) +- tscrollup(term.c.y, n); ++ tscrollup(term.c.y, n, 0); + } + + int32_t +@@ -1730,11 +1792,11 @@ csihandle(void) + case 'S': /* SU -- Scroll <n> line up */ + if (csiescseq.priv) break; + 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); +@@ -2306,7 +2368,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); + } +@@ -2319,7 +2381,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); + } +@@ -2542,7 +2604,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; +@@ -2579,6 +2641,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)); +@@ -2637,7 +2707,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); + } + } + +@@ -2658,8 +2728,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..818a6f8 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 *); diff --git a/st/patches/st-scrollback-mouse-0.9.2.diff b/st/patches/st-scrollback-mouse-0.9.2.diff new file mode 100644 index 0000000..a956d2b --- /dev/null +++ b/st/patches/st-scrollback-mouse-0.9.2.diff @@ -0,0 +1,25 @@ +From 6b7e7e6c5c44dd6347ad49691b80d808c1b0cb77 Mon Sep 17 00:00:00 2001 +From: Jernej Jakob <jernej.jakob@gmail.com> +Date: Mon, 1 Jul 2024 14:00:02 +0200 +Subject: [PATCH] [st][patch] Update st-scrollback-mouse for 0.9.2 + +--- + config.def.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 8b25d40..d259675 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.44.2 + diff --git a/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff b/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff new file mode 100644 index 0000000..6a8722b --- /dev/null +++ b/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff @@ -0,0 +1,78 @@ +From 580e3f386e9215707100e9ba44797701943fd927 Mon Sep 17 00:00:00 2001 +From: asparagii <michele.lambertucci1@gmail.com> +Date: Thu, 27 Jan 2022 15:49:27 +0100 +Subject: [PATCH] st-scrollback-mouse-altscreen + +--- + config.def.h | 4 ++-- + st.c | 5 +++++ + st.h | 1 + + x.c | 2 ++ + 4 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index c217315..c223706 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -176,8 +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, Button4, kscrollup, {.i = 1}, 0, /* !alt */ -1 }, ++ { XK_ANY_MOD, Button5, kscrolldown, {.i = 1}, 0, /* !alt */ -1 }, + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, + { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, +diff --git a/st.c b/st.c +index f3af82b..876a6bf 100644 +--- a/st.c ++++ b/st.c +@@ -1060,6 +1060,11 @@ tnew(int col, int row) + treset(); + } + ++int tisaltscr(void) ++{ ++ return IS_SET(MODE_ALTSCREEN); ++} ++ + void + tswapscreen(void) + { +diff --git a/st.h b/st.h +index da36b34..e95c6f8 100644 +--- a/st.h ++++ b/st.h +@@ -89,6 +89,7 @@ void sendbreak(const Arg *); + void toggleprinter(const Arg *); + + int tattrset(int); ++int tisaltscr(void); + void tnew(int, int); + void tresize(int, int); + void tsetdirtattr(int); +diff --git a/x.c b/x.c +index cd96575..9274556 100644 +--- a/x.c ++++ b/x.c +@@ -34,6 +34,7 @@ typedef struct { + void (*func)(const Arg *); + const Arg arg; + uint release; ++ int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */ + } MouseShortcut; + + typedef struct { +@@ -455,6 +456,7 @@ mouseaction(XEvent *e, uint release) + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && ++ (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) && + (match(ms->mod, state) || /* exact or forced */ + match(ms->mod, state & ~forcemousemod))) { + ms->func(&(ms->arg)); +-- +2.34.1 + diff --git a/st/patches/st-scrollback-mouse-increment-0.9.2.diff b/st/patches/st-scrollback-mouse-increment-0.9.2.diff new file mode 100644 index 0000000..97689d3 --- /dev/null +++ b/st/patches/st-scrollback-mouse-increment-0.9.2.diff @@ -0,0 +1,30 @@ +From bf7f0cf6ff2b47c65f750de6e30dce09a34f9201 Mon Sep 17 00:00:00 2001 +From: Jernej Jakob <jernej.jakob@gmail.com> +Date: Mon, 1 Jul 2024 14:02:36 +0200 +Subject: [PATCH] [st][patch] Update st-scrollback-mouse-increment for 0.9.2 + +--- + config.def.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index d259675..0c427ee 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -174,10 +174,11 @@ static uint forcemousemod = ShiftMask; + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. + */ ++const unsigned int mousescrollincrement = 1; + static MouseShortcut mshortcuts[] = { + /* mask button function argument release */ +- { ShiftMask, Button4, kscrollup, {.i = 1} }, +- { ShiftMask, Button5, kscrolldown, {.i = 1} }, ++ { ShiftMask, Button4, kscrollup, {.i = mousescrollincrement} }, ++ { ShiftMask, Button5, kscrolldown, {.i = mousescrollincrement} }, + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, + { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, +-- +2.44.2 + diff --git a/st/patches/st-spoiler-20180309-c5ba9c0.diff b/st/patches/st-spoiler-20180309-c5ba9c0.diff new file mode 100644 index 0000000..e6b7ab5 --- /dev/null +++ b/st/patches/st-spoiler-20180309-c5ba9c0.diff @@ -0,0 +1,21 @@ +diff --git a/x.c b/x.c +--- a/x.c ++++ b/x.c +@@ -1330,9 +1330,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + } + + if (base.mode & ATTR_REVERSE) { +- temp = fg; +- fg = bg; +- bg = temp; ++ if (bg == fg) { ++ bg = &dc.col[defaultfg]; ++ fg = &dc.col[defaultbg]; ++ } else { ++ temp = fg; ++ fg = bg; ++ bg = temp; ++ } + } + + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) diff --git a/st/patches/st-swapmouse-0.8.4.diff b/st/patches/st-swapmouse-0.8.4.diff new file mode 100644 index 0000000..d948dae --- /dev/null +++ b/st/patches/st-swapmouse-0.8.4.diff @@ -0,0 +1,37 @@ +diff -up st-0.8.4-ori/x.c st-0.8.4/x.c +--- st-0.8.4-ori/x.c 2020-06-19 14:59:45.000000000 +0530 ++++ st-0.8.4/x.c 2020-07-20 03:39:56.260922736 +0530 +@@ -254,6 +254,9 @@ static char *opt_title = NULL; + + static int oldbutton = 3; /* button event on startup: 3 = release */ + ++static Cursor cursor; ++static XColor xmousefg, xmousebg; ++ + void + clipcopy(const Arg *dummy) + { +@@ -1099,10 +1102,8 @@ void + xinit(int cols, int rows) + { + XGCValues gcvalues; +- Cursor cursor; + Window parent; + pid_t thispid = getpid(); +- XColor xmousefg, xmousebg; + + if (!(xw.dpy = XOpenDisplay(NULL))) + die("can't open display\n"); +@@ -1683,6 +1684,12 @@ xsetmode(int set, unsigned int flags) + { + int mode = win.mode; + MODBIT(win.mode, set, flags); ++ if (flags & MODE_MOUSE) { ++ if (win.mode & MODE_MOUSE) ++ XUndefineCursor(xw.dpy, xw.win); ++ else ++ XDefineCursor(xw.dpy, xw.win, cursor); ++ } + if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) + redraw(); + } diff --git a/st/patches/st-title_parsing_fix-0.8.5.diff b/st/patches/st-title_parsing_fix-0.8.5.diff new file mode 100644 index 0000000..a5cee40 --- /dev/null +++ b/st/patches/st-title_parsing_fix-0.8.5.diff @@ -0,0 +1,145 @@ +From 8446609384429bfc4342ede4b52ff42214ad2b77 Mon Sep 17 00:00:00 2001 +From: Rizqi Nur Assyaufi <bandithijo@gmail.com> +Date: Mon, 18 Jul 2022 00:35:26 +0800 +Subject: [PATCH] Fixes title parsing for st-0.8.5 + +In st, titles get truncated after the first ';' character, this patch +fixes that. +--- + st.c | 38 ++++++++++++++++++++------------------ + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/st.c b/st.c +index 51049ba..a2e595c 100644 +--- a/st.c ++++ b/st.c +@@ -42,6 +42,8 @@ + #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) + #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) + #define ISDELIM(u) (u && wcschr(worddelimiters, u)) ++#define STRESCARGREST(n) ((n) == 0 ? strescseq.buf : strescseq.argp[(n)-1] + 1) ++#define STRESCARGJUST(n) (*(strescseq.argp[n]) = '\0', STRESCARGREST(n)) + + enum term_mode { + MODE_WRAP = 1 << 0, +@@ -148,7 +150,7 @@ typedef struct { + char *buf; /* allocated raw string */ + size_t siz; /* allocation size */ + size_t len; /* raw string length */ +- char *args[STR_ARG_SIZ]; ++ char *argp[STR_ARG_SIZ]; /* pointers to the end of nth argument */ + int narg; /* nb of args */ + } STREscape; + +@@ -1885,29 +1887,30 @@ strhandle(void) + int j, narg, par; + + term.esc &= ~(ESC_STR_END|ESC_STR); +- strparse(); +- par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0; ++ strescseq.buf[strescseq.len] = '\0'; + + switch (strescseq.type) { + case ']': /* OSC -- Operating System Command */ ++ strparse(); ++ par = (narg = strescseq.narg) ? atoi(STRESCARGJUST(0)) : 0; + switch (par) { + case 0: + if (narg > 1) { +- xsettitle(strescseq.args[1]); +- xseticontitle(strescseq.args[1]); ++ xsettitle(STRESCARGREST(1)); ++ xseticontitle(STRESCARGREST(1)); + } + return; + case 1: + if (narg > 1) +- xseticontitle(strescseq.args[1]); ++ xseticontitle(STRESCARGREST(1)); + return; + case 2: + if (narg > 1) +- xsettitle(strescseq.args[1]); ++ xsettitle(STRESCARGREST(1)); + return; + case 52: + if (narg > 2 && allowwindowops) { +- dec = base64dec(strescseq.args[2]); ++ dec = base64dec(STRESCARGJUST(2)); + if (dec) { + xsetsel(dec); + xclipcopy(); +@@ -1920,7 +1923,7 @@ strhandle(void) + if (narg < 2) + break; + +- p = strescseq.args[1]; ++ p = STRESCARGREST(1); + + if (!strcmp(p, "?")) + osc_color_response(defaultfg, 10); +@@ -1933,7 +1936,7 @@ strhandle(void) + if (narg < 2) + break; + +- p = strescseq.args[1]; ++ p = STRESCARGREST(1); + + if (!strcmp(p, "?")) + osc_color_response(defaultbg, 11); +@@ -1946,7 +1949,7 @@ strhandle(void) + if (narg < 2) + break; + +- p = strescseq.args[1]; ++ p = STRESCARGREST(1); + + if (!strcmp(p, "?")) + osc_color_response(defaultcs, 12); +@@ -1958,10 +1961,10 @@ strhandle(void) + case 4: /* color set */ + if (narg < 3) + break; +- p = strescseq.args[2]; ++ p = STRESCARGJUST(2); + /* FALLTHROUGH */ + case 104: /* color reset */ +- j = (narg > 1) ? atoi(strescseq.args[1]) : -1; ++ j = (narg > 1) ? atoi(STRESCARGJUST(1)) : -1; + + if (p && !strcmp(p, "?")) + osc4_color_response(j); +@@ -1981,7 +1984,7 @@ strhandle(void) + } + break; + case 'k': /* old title set compatibility */ +- xsettitle(strescseq.args[0]); ++ xsettitle(strescseq.buf); + return; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ +@@ -2000,18 +2003,17 @@ strparse(void) + char *p = strescseq.buf; + + strescseq.narg = 0; +- strescseq.buf[strescseq.len] = '\0'; + + if (*p == '\0') + return; + + while (strescseq.narg < STR_ARG_SIZ) { +- strescseq.args[strescseq.narg++] = p; + while ((c = *p) != ';' && c != '\0') +- ++p; ++ p++; ++ strescseq.argp[strescseq.narg++] = p; + if (c == '\0') + return; +- *p++ = '\0'; ++ p++; + } + } + +-- +2.37.1 + diff --git a/st/patches/st-vertcenter-20231003-eb3b894.diff b/st/patches/st-vertcenter-20231003-eb3b894.diff new file mode 100644 index 0000000..f2d08a2 --- /dev/null +++ b/st/patches/st-vertcenter-20231003-eb3b894.diff @@ -0,0 +1,65 @@ +From c85891b21261b68b09ed9ae6a1ca18655ef19e69 Mon Sep 17 00:00:00 2001 +From: roket1428 <meorhan@protonmail.com> +Date: Tue, 3 Oct 2023 11:10:39 +0300 +Subject: [PATCH] vertcenter patch + +--- + x.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/x.c b/x.c +index aa09997..9ecb46e 100644 +--- a/x.c ++++ b/x.c +@@ -83,6 +83,7 @@ typedef struct { + int w, h; /* window width and height */ + int ch; /* char height */ + int cw; /* char width */ ++ int cyo; /* char y offset */ + int mode; /* window state/mode flags */ + int cursor; /* cursor style */ + } TermWindow; +@@ -1031,6 +1032,7 @@ xloadfonts(const char *fontstr, double fontsize) + /* Setting character width and height. */ + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); ++ win.cyo = ceilf(dc.font.height * (chscale - 1) / 2); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); +@@ -1255,7 +1257,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + FcCharSet *fccharset; + int i, f, numspecs = 0; + +- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { ++ for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i) { + /* Fetch rune and mode for current glyph. */ + rune = glyphs[i].u; + mode = glyphs[i].mode; +@@ -1280,7 +1282,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + font = &dc.bfont; + frcflags = FRC_BOLD; + } +- yp = winy + font->ascent; ++ yp = winy + font->ascent + win.cyo; + } + + /* Lookup character index with default font. */ +@@ -1493,12 +1495,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { +- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, ++ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent * chscale + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { +- XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, ++ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3, + width, 1); + } + +-- +2.42.0 + diff --git a/st/patches/st-w3m-0.8.3.diff b/st/patches/st-w3m-0.8.3.diff new file mode 100644 index 0000000..a4e104b --- /dev/null +++ b/st/patches/st-w3m-0.8.3.diff @@ -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 + diff --git a/st/patches/st-xclearwin-20200419-6ee7143.diff b/st/patches/st-xclearwin-20200419-6ee7143.diff new file mode 100644 index 0000000..52f0477 --- /dev/null +++ b/st/patches/st-xclearwin-20200419-6ee7143.diff @@ -0,0 +1,62 @@ +From 6ee7143600e5ac6c7a26d2ee985ac2a3087a5570 Mon Sep 17 00:00:00 2001 +From: Christian Tenllado <ctenllado@gmail.com> +Date: Sun, 19 Apr 2020 11:57:31 +0200 +Subject: [PATCH] xclearwin clears the window + +When an OCS sequence was used to change the bg color, the borders where +dirty. This simple patch just clears the window before the redraw of the +terminal when the bg color has been changed. This is apparently enough +and seams to be very smooth. There was a TODO comment for it on the st.c +file, which I removed. +--- + st.c | 6 ++---- + win.h | 1 + + x.c | 6 ++++++ + 3 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/st.c b/st.c +index 3e48410..2efb4bd 100644 +--- a/st.c ++++ b/st.c +@@ -1874,10 +1874,8 @@ strhandle(void) + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); + } else { +- /* +- * TODO if defaultbg color is changed, borders +- * are dirty +- */ ++ if (j == defaultbg) ++ xclearwin(); + redraw(); + } + return; +diff --git a/win.h b/win.h +index a6ef1b9..d7b4980 100644 +--- a/win.h ++++ b/win.h +@@ -37,3 +37,4 @@ void xsetpointermotion(int); + void xsetsel(char *); + int xstartdraw(void); + void xximspot(int, int); ++void xclearwin(void); +diff --git a/x.c b/x.c +index 4cf6b21..afd35e0 100644 +--- a/x.c ++++ b/x.c +@@ -825,6 +825,12 @@ xclear(int x1, int y1, int x2, int y2) + x1, y1, x2-x1, y2-y1); + } + ++void ++xclearwin(void) ++{ ++ xclear(0, 0, win.w, win.h); ++} ++ + void + xhints(void) + { +-- +2.20.1 + diff --git a/st/patches/st-xresources-20200604-9ba7ecf.diff b/st/patches/st-xresources-20200604-9ba7ecf.diff new file mode 100644 index 0000000..01d6db9 --- /dev/null +++ b/st/patches/st-xresources-20200604-9ba7ecf.diff @@ -0,0 +1,183 @@ +# From 2752a599ee01305a435729bfacf43b1dde7cf0ef Mon Sep 17 00:00:00 2001 +# From: Benji Encalada Mora <benji@encalada.dev> +# Date: Thu, 4 Jun 2020 00:41:10 -0500 +# Subject: [PATCH] fix: replace xfps and actionfps variables +# +# --- +# config.def.h | 36 ++++++++++++++++++++++++ +# x.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++--- +# 2 files changed, 110 insertions(+), 4 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 6f05dce..9b99782 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -168,6 +168,42 @@ 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[256] }, ++ { "foreground", STRING, &colorname[257] }, ++ { "cursorColor", STRING, &colorname[258] }, ++ { "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. +diff --git a/x.c b/x.c +index 210f184..76f167f 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 +@@ -828,8 +842,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; + +@@ -1104,8 +1118,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); + +@@ -1964,6 +1976,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) + { +@@ -2037,6 +2102,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); +-- +2.26.2 diff --git a/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff b/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff new file mode 100644 index 0000000..d7817a0 --- /dev/null +++ b/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff @@ -0,0 +1,288 @@ +diff --git a/config.def.h b/config.def.h +index f92798a..517abbb 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -9,5 +9,19 @@ + static int borderpx = 2; + ++/* ++ * Override/adjust fontsize of choosen monitors: ++ */ ++MonitorConfig monitors_config[] = { ++ // skip = fixed relative points size (monitor dpi) ++ // =0 : fixed absolute pixel size (default screen dpi) ++ // >0 : auto absolute pixel size (monitor dpi) ++ // <0 : auto relative points size (monitor dpi) ++ // {"DP-1", 0}, // BUG:(size=0): not restored to default after back'n'forth ++ {"HDMI-0~1", -20}, // BUG:(ignored DPI=220): = 20 is eqv to 10pt (DPI=110) ++ {"HDMI-0~2", -14}, ++}; ++float winmovethreshold = 0.6; ++ + /* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e +@@ -272,6 +272,7 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Prior, zoom, {.f = +1} }, + { TERMMOD, XK_Next, zoom, {.f = -1} }, + { TERMMOD, XK_Home, zoomreset, {.f = 0} }, ++ { TERMMOD, XK_End, refreshxrandr, {.i = 0} }, + { TERMMOD, XK_C, clipcopy, {.i = 0} }, + { TERMMOD, XK_V, clippaste, {.i = 0} }, + { TERMMOD, XK_Y, selpaste, {.i = 0} }, +diff --git a/config.mk b/config.mk +index aaa54ff..2d28597 100644 +--- a/config.mk ++++ b/config.mk +@@ -24,5 +24,7 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + ++LIBS += -lXrandr ++ + # flags + STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 + STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) + STLDFLAGS = $(LIBS) $(LDFLAGS) +diff --git a/x.c b/x.c +index 684311c..ce1c418 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/extensions/Xrandr.h> + + char *argv0; + #include "arg.h" +@@ -45,5 +46,18 @@ typedef struct { + signed char appcursor; /* application cursor */ + } Key; + ++typedef struct { ++ const char *name; ++ float defaultfontsize; ++} MonitorConfig; ++ ++typedef struct { ++ Atom name; ++ int x, y, w, h; ++ float defaultfontsize, usedfontsize; ++} MonitorInfo; ++ ++static void refreshxrandr(const Arg *dummy); ++ + /* X modifiers */ + #define XK_ANY_MOD UINT_MAX +@@ -233,7 +233,12 @@ static XWindow xw; + [PropertyNotify] = propnotify, + [SelectionRequest] = selrequest, + }; + ++static double defaultrelfontsize = 0; ++static MonitorInfo *monitors_info = NULL; ++static int monitors_num = 0; ++static int prev_mindex = -1; ++ + /* Globals */ + static DC dc; + static XWindow xw; +@@ -2280,6 +2280,144 @@ xseturgency(int add) + XFree(h); + } + ++static void ++cachemonitorinfo() ++{ ++ int prev_num = monitors_num; ++ MonitorInfo *prev_info = monitors_info; ++ XRRMonitorInfo *xmonitors = XRRGetMonitors(xw.dpy, XRootWindow(xw.dpy, xw.scr), 1, &monitors_num); ++ if (!monitors_num) ++ die("xrandr found no monitors"); ++ ++ monitors_info = xmalloc(monitors_num * sizeof(MonitorInfo)); ++ ++ for (int i = 0; i < monitors_num; ++i) { ++ XRRMonitorInfo *xm = &xmonitors[i]; ++ MonitorInfo *m = &monitors_info[i]; ++ ++ m->name = xm->name; ++ m->x = xm->x; ++ m->y = xm->y; ++ m->w = xm->width; ++ m->h = xm->height; ++ ++ float px_mm = ((float)m->w / xm->mwidth + (float)m->h / xm->mheight) / 2; ++ float px_pt = 25.4 * px_mm / 72; ++ m->defaultfontsize = defaultrelfontsize * px_pt; ++ ++ // Override defaultfontsize (dpi) by user config ++ char *name = XGetAtomName(xw.dpy, xm->name); ++ for (int j = 0; j < LEN(monitors_config); ++j) ++ if (!strcmp(name, monitors_config[j].name)) { ++ m->defaultfontsize = monitors_config[j].defaultfontsize; ++ if (m->defaultfontsize < 0) ++ m->defaultfontsize *= -px_pt; ++ break; ++ } ++ // fprintf(stderr, "%s: %fpx, %f\n", name, m->defaultfontsize, m->usedfontsize); ++ XFree(name); ++ ++ // Restore usedfontsize (zoom) after re-cache for monitors with the same name ++ m->usedfontsize = m->defaultfontsize; ++ for (int j = 0; j < prev_num; ++j) ++ if (prev_info[j].name == m->name) { ++ m->usedfontsize = prev_info[j].usedfontsize; ++ break; ++ } ++ } ++ ++ XRRFreeMonitors(xmonitors); ++ free(prev_info); ++} ++ ++static int ++getmonitorindex_threshold(int w, int h, int x, int y) ++{ ++ int mindex = -1; ++ float fontsize = 0; ++ int thresholdarea = winmovethreshold * w * h; ++ ++ for (int i = 0; i < monitors_num; ++i) { ++ MonitorInfo *m = &monitors_info[i]; ++ int overlap_w = MAX(0, MIN(x + w, m->x + m->w) - MAX(x, m->x)); ++ int overlap_h = MAX(0, MIN(y + h, m->y + m->h) - MAX(y, m->y)); ++ int area = overlap_w * overlap_h; ++ // Choose monitor with largest dpi (defaultfontsize) ++ // from all "mirrored"/overlapped (e.g. projector) ++ if (area >= thresholdarea && fontsize < m->defaultfontsize) { ++ fontsize = m->defaultfontsize; ++ mindex = i; ++ } ++ } ++ return mindex; ++} ++ ++static int ++getmonitorindex_nearest(int w, int h, int x, int y) ++{ ++ int mindex = -1; ++ float fontsize = 0; ++ int overlaparea = 0; ++ ++ for (int i = 0; i < monitors_num; ++i) { ++ MonitorInfo *m = &monitors_info[i]; ++ int overlap_w = MAX(0, MIN(x + w, m->x + m->w) - MAX(x, m->x)); ++ int overlap_h = MAX(0, MIN(y + h, m->y + m->h) - MAX(y, m->y)); ++ int area = overlap_w * overlap_h; ++ // Choose monitor with largest overlapping area ++ // e.g. when "st" is initially spawned in-between monitors ++ if (area > overlaparea) { ++ overlaparea = area; ++ mindex = i; ++ } ++ } ++ return mindex; ++} ++ ++static void ++adjustmonitorfontsize(int mindex) ++{ ++ if (mindex < 0 || prev_mindex == mindex) ++ return; ++ // Save zoom of current monitor before switching ++ if (prev_mindex >= 0) ++ monitors_info[prev_mindex].usedfontsize = usedfontsize; ++ ++ defaultfontsize = monitors_info[mindex].defaultfontsize; ++ // fprintf(stderr, "Crossing: %fpx\n", defaultfontsize); ++ ++ // NOTE: do nothing if font size differs by less than 1% ++ double fontsize = monitors_info[mindex].usedfontsize; ++ double delta = 0.01 * usedfontsize; ++ if (!BETWEEN(fontsize - usedfontsize, -delta, delta)) { ++ // fprintf(stderr, "Adjusted: %fpx\n", fontsize); ++ xunloadfonts(); ++ xloadfonts(usedfont, fontsize); ++ } ++ prev_mindex = mindex; ++} ++ ++void ++refreshxrandr(const Arg *dummy) ++{ ++ // Reset index to detect change of window association on "xrandr ... --primary" ++ // otherwise: zoom won't be saved on switching and new font size won't be loaded ++ // CRIT!!! event from xrandr may place another monitor into same index ++ if (prev_mindex >= 0) ++ monitors_info[prev_mindex].usedfontsize = usedfontsize; ++ prev_mindex = -1; ++ ++ XWindowAttributes xattr = {0}; ++ cachemonitorinfo(); ++ XGetWindowAttributes(xw.dpy, xw.win, &xattr); ++ ++ int mindex = getmonitorindex_threshold(xattr.width, xattr.height, xattr.x, xattr.y); ++ if (mindex < 0) ++ mindex = getmonitorindex_nearest(xattr.width, xattr.height, xattr.x, xattr.y); ++ adjustmonitorfontsize(mindex); ++} ++ ++ + void + xbell(void) + { +@@ -2437,6 +2437,14 @@ cmessage(XEvent *e) + void + resize(XEvent *e) + { ++ // BAD: no resize on monitor plug/unplug/reconfigure -- until window itself is kept in the same place ++ // NOTE: no resize event on zoomabs() ++ // fprintf(stderr, "Resize: %dx%d+%d+%d\n", ++ // e->xconfigure.width, e->xconfigure.height, e->xconfigure.x, e->xconfigure.y); ++ ++ adjustmonitorfontsize(getmonitorindex_threshold( ++ e->xconfigure.width, e->xconfigure.height, e->xconfigure.x, e->xconfigure.y)); ++ + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) + return; + +@@ -2469,6 +2469,22 @@ run(void) + } + } while (ev.type != MapNotify); + ++ int rr_event_base, rr_error_base, rr_major, rr_minor; ++ if (!XRRQueryExtension (xw.dpy, &rr_event_base, &rr_error_base) || ++ !XRRQueryVersion (xw.dpy, &rr_major, &rr_minor) || ++ rr_major < 1 || (rr_major == 1 && rr_minor < 5)) ++ { ++ die("RandR 1.5 extension isn't available\n"); ++ } ++ XRRSelectInput(xw.dpy, xw.win, RRCrtcChangeNotifyMask); ++ ++ // WARN: can query actual window size/pos only after window is mapped and its width/height are adjusted by WM ++ // * x/y are WM-dependent and can't be determined beforehand anyway ++ // * defaultfontsize isn't available until font is loaded and actual Fc*() size queried ++ // BAD: fonts on startup are always reloaded -- how to specify their size beforehand ? ++ FcPatternGetDouble(dc.font.match->pattern, FC_SIZE, 0, &defaultrelfontsize); ++ refreshxrandr(0); ++ + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); + cresize(w, h); + +@@ -2500,6 +2500,16 @@ run(void) + XNextEvent(xw.dpy, &ev); + if (XFilterEvent(&ev, None)) + continue; ++ if (LASTEvent <= ev.type) { ++ if (rr_event_base + RRNotify == ev.type && ++ RRNotify_CrtcChange == ((XRRNotifyEvent *)&ev)->subtype) ++ { ++ XRRUpdateConfiguration(&ev); ++ // fprintf(stderr, "Monitor change: %d > %d\n", rr_event_base, LASTEvent); ++ refreshxrandr(0); ++ } ++ continue; ++ } + if (handler[ev.type]) + (handler[ev.type])(&ev); + } |
