diff --git a/st-0.9.2-tavo.diff b/st-0.9.2-tavo.diff new file mode 100644 index 0000000..6e7695c --- /dev/null +++ b/st-0.9.2-tavo.diff @@ -0,0 +1,1081 @@ +diff '--color=auto' -Nu a/config.def.h b/config.def.h +--- a/config.def.h 2024-04-05 04:19:18.000000000 -0600 ++++ b/config.def.h 2024-05-01 21:06:30.468491132 -0600 +@@ -201,6 +201,8 @@ + { 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 '--color=auto' -Nu a/config.h b/config.h +--- a/config.h 1969-12-31 18:00:00.000000000 -0600 ++++ b/config.h 2024-05-01 21:12:37.535978213 -0600 +@@ -0,0 +1,476 @@ ++/* See LICENSE file for copyright and license details. */ ++ ++/* ++ * appearance ++ * ++ * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html ++ */ ++static char *font = "JetBrainsMono:size=10:antialias=true:autohint=true"; ++static int borderpx = 8; ++ ++/* ++ * What program is execed by st depends of these precedence rules: ++ * 1: program passed with -e ++ * 2: scroll and/or utmp ++ * 3: SHELL environment variable ++ * 4: value of shell in /etc/passwd ++ * 5: value of shell in config.h ++ */ ++static char *shell = "/bin/sh"; ++char *utmp = NULL; ++/* scroll program: to enable use a string like "scroll" */ ++char *scroll = NULL; ++char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; ++ ++/* identification sequence returned in DA and DECID */ ++char *vtiden = "\033[?6c"; ++ ++/* Kerning / character bounding-box multipliers */ ++static float cwscale = 1.0; ++static float chscale = 1.0; ++ ++/* ++ * word delimiter string ++ * ++ * More advanced example: L" `'\"()[]{}" ++ */ ++wchar_t *worddelimiters = L" "; ++ ++/* selection timeouts (in milliseconds) */ ++static unsigned int doubleclicktimeout = 300; ++static unsigned int tripleclicktimeout = 600; ++ ++/* alt screens */ ++int allowaltscreen = 1; ++ ++/* allow certain non-interactive (insecure) window operations such as: ++ setting the clipboard text */ ++int allowwindowops = 0; ++ ++/* ++ * draw latency range in ms - from new content/keypress/etc until drawing. ++ * within this range, st draws when content stops arriving (idle). mostly it's ++ * near minlatency, but it waits longer for slow updates to avoid partial draw. ++ * low minlatency will tear/flicker more, as it can "detect" idle too early. ++ */ ++static double minlatency = 2; ++static double maxlatency = 33; ++ ++/* ++ * blinking timeout (set to 0 to disable blinking) for the terminal blinking ++ * attribute. ++ */ ++static unsigned int blinktimeout = 800; ++ ++/* ++ * thickness of underline and bar cursors ++ */ ++static unsigned int cursorthickness = 2; ++ ++/* ++ * bell volume. It must be a value between -100 and 100. Use 0 for disabling ++ * it ++ */ ++static int bellvolume = 0; ++ ++/* default TERM value */ ++char *termname = "st-256color"; ++ ++/* ++ * spaces per tab ++ * ++ * When you are changing this value, don't forget to adapt the »it« value in ++ * the st.info and appropriately install the st.info in the environment where ++ * you use this st version. ++ * ++ * it#$tabspaces, ++ * ++ * Secondly make sure your kernel is not expanding tabs. When running `stty ++ * -a` »tab0« should appear. You can tell the terminal to not expand tabs by ++ * running following command: ++ * ++ * stty tabs ++ */ ++unsigned int tabspaces = 8; ++ ++/* Terminal colors (16 first used in escape sequence) */ ++static const char *colorname[] = { ++ /* 8 normal colors */ ++ [0] = "#1d2021", /* hard contrast: #1d2021 / soft contrast: #32302f */ ++ [1] = "#cc241d", /* red */ ++ [2] = "#98971a", /* green */ ++ [3] = "#d79921", /* yellow */ ++ [4] = "#458588", /* blue */ ++ [5] = "#b16286", /* magenta */ ++ [6] = "#689d6a", /* cyan */ ++ [7] = "#a89984", /* white */ ++ ++ /* 8 bright colors */ ++ [8] = "#928374", /* black */ ++ [9] = "#fb4934", /* red */ ++ [10] = "#b8bb26", /* green */ ++ [11] = "#fabd2f", /* yellow */ ++ [12] = "#83a598", /* blue */ ++ [13] = "#d3869b", /* magenta */ ++ [14] = "#8ec07c", /* cyan */ ++ [15] = "#ebdbb2", /* white */ ++}; ++ ++ ++/* ++ * Default colors (colorname index) ++ * foreground, background, cursor, reverse cursor ++ */ ++unsigned int defaultfg = 15; ++unsigned int defaultbg = 0; ++unsigned int defaultcs = 15; ++static unsigned int defaultrcs = 257; ++ ++/* ++ * Default shape of cursor ++ * 2: Block ("█") ++ * 4: Underline ("_") ++ * 6: Bar ("|") ++ * 7: Snowman ("☃") ++ */ ++static unsigned int cursorshape = 2; ++ ++/* ++ * Default columns and rows numbers ++ */ ++ ++static unsigned int cols = 80; ++static unsigned int rows = 24; ++ ++/* ++ * Default colour and shape of the mouse cursor ++ */ ++static unsigned int mouseshape = XC_xterm; ++static unsigned int mousefg = 7; ++static unsigned int mousebg = 0; ++ ++/* ++ * Color used to display font attributes when fontconfig selected a font which ++ * doesn't match the ones requested. ++ */ ++static unsigned int defaultattr = 11; ++ ++/* ++ * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). ++ * Note that if you want to use ShiftMask with selmasks, set this to an other ++ * modifier, set to 0 to not use it. ++ */ ++static uint forcemousemod = ShiftMask; ++ ++/* ++ * Internal mouse shortcuts. ++ * Beware that overloading Button1 will disable the selection. ++ */ ++static MouseShortcut mshortcuts[] = { ++ /* mask button function argument release */ ++ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, ++ { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, ++ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, ++ { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, ++ { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, ++}; ++ ++/* Internal keyboard shortcuts. */ ++#define MODKEY Mod1Mask ++#define TERMMOD (ControlMask|ShiftMask) ++ ++static char *urlhandler[] = { "/bin/sh", "-c", "st-urlhandler -c", "externalpipe", NULL }; ++ ++static Shortcut shortcuts[] = { ++ /* mask keysym function argument */ ++ { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, ++ { ControlMask, XK_Print, toggleprinter, {.i = 0} }, ++ { ShiftMask, XK_Print, printscreen, {.i = 0} }, ++ { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, ++ { TERMMOD, XK_Prior, zoom, {.f = +1} }, ++ { TERMMOD, XK_Next, zoom, {.f = -1} }, ++ { TERMMOD, XK_Home, zoomreset, {.f = 0} }, ++ { TERMMOD, XK_C, clipcopy, {.i = 0} }, ++ { TERMMOD, XK_V, clippaste, {.i = 0} }, ++ { 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} }, ++ /* Custom */ ++ { TERMMOD, XK_L, zoom, {.f = +1} }, ++ { TERMMOD, XK_H, zoom, {.f = -1} }, ++ { TERMMOD, XK_K, kscrollup, {.i = -1} }, ++ { TERMMOD, XK_J, kscrolldown, {.i = -1} }, ++ { TERMMOD, XK_U, externalpipe, {.v = urlhandler} }, ++}; ++ ++/* ++ * Special keys (change & recompile st.info accordingly) ++ * ++ * Mask value: ++ * * Use XK_ANY_MOD to match the key no matter modifiers state ++ * * Use XK_NO_MOD to match the key alone (no modifiers) ++ * appkey value: ++ * * 0: no value ++ * * > 0: keypad application mode enabled ++ * * = 2: term.numlock = 1 ++ * * < 0: keypad application mode disabled ++ * appcursor value: ++ * * 0: no value ++ * * > 0: cursor application mode enabled ++ * * < 0: cursor application mode disabled ++ * ++ * Be careful with the order of the definitions because st searches in ++ * this table sequentially, so any XK_ANY_MOD must be in the last ++ * position for a key. ++ */ ++ ++/* ++ * 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 }; ++ ++/* ++ * State bits to ignore when matching key or button events. By default, ++ * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. ++ */ ++static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; ++ ++/* ++ * This is the huge key array which defines all compatibility to the Linux ++ * world. Please decide about changes wisely. ++ */ ++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}, ++ { XK_Up, ControlMask, "\033[1;5A", 0, 0}, ++ { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, ++ { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, ++ { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, ++ { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, ++ { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, ++ { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, ++ { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, ++ { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, ++ { XK_Down, ControlMask, "\033[1;5B", 0, 0}, ++ { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, ++ { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, ++ { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, ++ { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, ++ { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, ++ { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, ++ { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, ++ { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, ++ { XK_Left, ControlMask, "\033[1;5D", 0, 0}, ++ { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, ++ { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, ++ { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, ++ { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, ++ { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, ++ { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, ++ { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, ++ { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, ++ { XK_Right, ControlMask, "\033[1;5C", 0, 0}, ++ { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, ++ { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, ++ { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, ++ { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, ++ { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, ++ { 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_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}, ++ { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, ++ { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, ++ { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, ++ { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, ++ { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, ++ { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, ++ { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, ++ { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, ++ { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, ++ { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, ++ { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, ++ { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, ++ { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, ++ { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, ++ { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, ++ { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, ++ { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, ++ { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, ++ { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, ++ { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, ++ { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, ++ { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, ++ { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, ++ { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, ++ { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, ++ { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, ++ { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, ++ { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, ++ { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, ++ { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, ++ { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, ++ { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, ++ { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, ++ { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, ++ { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, ++ { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, ++ { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, ++ { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, ++ { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, ++ { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, ++ { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, ++ { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, ++ { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, ++ { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, ++ { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, ++ { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, ++ { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, ++ { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, ++ { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, ++ { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, ++ { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, ++ { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, ++ { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, ++ { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, ++ { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, ++ { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, ++ { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, ++ { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, ++ { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, ++ { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, ++ { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, ++ { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, ++ { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, ++ { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, ++ { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, ++ { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, ++ { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, ++ { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, ++ { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, ++ { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, ++ { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, ++ { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, ++ { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, ++ { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, ++ { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, ++ { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, ++ { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, ++ { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, ++ { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, ++ { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, ++ { 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}, ++}; ++ ++/* ++ * Selection types' masks. ++ * Use the same masks as usual. ++ * Button1Mask is always unset, to make masks match between ButtonPress. ++ * ButtonRelease and MotionNotify. ++ * If no match is found, regular selection is used. ++ */ ++static uint selmasks[] = { ++ [SEL_RECTANGULAR] = Mod1Mask, ++}; ++ ++/* ++ * Printable characters in ASCII, used to estimate the advance width ++ * of single wide characters. ++ */ ++static char ascii_printable[] = ++ " !\"#$%&'()*+,-./0123456789:;<=>?" ++ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" ++ "`abcdefghijklmnopqrstuvwxyz{|}~"; +diff '--color=auto' -Nu a/st.c b/st.c +--- a/st.c 2024-04-05 04:19:18.000000000 -0600 ++++ b/st.c 2024-05-01 21:07:32.421079665 -0600 +@@ -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,10 @@ + #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]) ++#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, +@@ -115,6 +120,9 @@ + 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 +193,8 @@ + 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 +417,24 @@ + { + 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; ++} ++ ++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; +@@ -521,7 +543,7 @@ + * 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 +558,14 @@ + 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 +586,14 @@ + *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 +624,13 @@ + } + + 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; + +@@ -718,8 +740,14 @@ + 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 +831,7 @@ + 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); +@@ -844,6 +872,9 @@ + 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,12 +1086,52 @@ + } + + 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 +1142,28 @@ + 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 +1173,8 @@ + term.line[i+n] = temp; + } + +- selscroll(orig, -n); ++ if (term.scr == 0) ++ selscroll(orig, -n); + } + + void +@@ -1120,7 +1203,7 @@ + int y = term.c.y; + + if (y == term.bot) { +- tscrollup(term.top, 1); ++ tscrollup(term.top, 1, 1); + } else { + y++; + } +@@ -1285,14 +1368,14 @@ + 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 +1813,11 @@ + case 'S': /* SU -- Scroll 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 line down */ + DEFAULT(csiescseq.arg[0], 1); +- tscrolldown(term.top, csiescseq.arg[0]); ++ tscrolldown(term.top, csiescseq.arg[0], 0); + break; + case 'L': /* IL -- Insert blank lines */ + DEFAULT(csiescseq.arg[0], 1); +@@ -1992,6 +2075,61 @@ + } + + 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 <= 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 = TLINE_HIST(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) + { + size_t i; +@@ -2306,7 +2444,7 @@ + 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 +2457,7 @@ + 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 +2680,7 @@ + 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 +2717,14 @@ + 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 +2783,7 @@ + continue; + + term.dirty[y] = 0; +- xdrawline(term.line[y], x1, y, x2); ++ xdrawline(TLINE(y), x1, y, x2); + } + } + +@@ -2658,8 +2804,9 @@ + 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 '--color=auto' -Nu a/st.h b/st.h +--- a/st.h 2024-04-05 04:19:18.000000000 -0600 ++++ b/st.h 2024-05-01 21:07:24.961008802 -0600 +@@ -81,6 +81,9 @@ + void redraw(void); + void draw(void); + ++void kscrolldown(const Arg *); ++void kscrollup(const Arg *); ++void externalpipe(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +diff '--color=auto' -Nu a/x.c b/x.c +--- a/x.c 2024-04-05 04:19:18.000000000 -0600 ++++ b/x.c 2024-05-01 21:07:36.289116421 -0600 +@@ -81,6 +81,7 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + + /* 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 @@ + 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); + } + }