From c00b5dbbe15d16fe9b85ca27bc1b840de847f12c Mon Sep 17 00:00:00 2001 From: jef Date: Sun, 21 Jun 2020 08:41:58 +0200 Subject: [PATCH] Added anysize & clipboard patch --- config.h | 472 +++++++ patches/st-anysize-0.8.1.diff | 152 +++ patches/st-clipboard-0.8.3.diff | 12 + st | Bin 0 -> 96944 bytes st.o | Bin 0 -> 73160 bytes x.c | 57 +- x.c.orig | 2050 +++++++++++++++++++++++++++++++ x.o | Bin 0 -> 71472 bytes 8 files changed, 2717 insertions(+), 26 deletions(-) create mode 100644 config.h create mode 100644 patches/st-anysize-0.8.1.diff create mode 100644 patches/st-clipboard-0.8.3.diff create mode 100755 st create mode 100644 st.o create mode 100644 x.c.orig create mode 100644 x.o diff --git a/config.h b/config.h new file mode 100644 index 0000000..eda5a3c --- /dev/null +++ b/config.h @@ -0,0 +1,472 @@ +/* See LICENSE file for copyright and license details. */ + +/* + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +static char *font = "MesloLGS NF:style=Regular:size=10"; +static int borderpx = 2; + +/* + * 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 = 8; +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 */ + "black", + "red3", + "green3", + "yellow3", + "blue2", + "magenta3", + "cyan3", + "gray90", + + /* 8 bright colors */ + "gray50", + "red", + "green", + "yellow", + "#5c5cff", + "magenta", + "cyan", + "white", + + [255] = 0, + + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", + "#555555", +}; + + +/* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +unsigned int defaultfg = 7; +unsigned int defaultbg = 0; +static unsigned int defaultcs = 256; +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 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} }, +}; + +/* + * 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 --git a/patches/st-anysize-0.8.1.diff b/patches/st-anysize-0.8.1.diff new file mode 100644 index 0000000..1eaf2ba --- /dev/null +++ b/patches/st-anysize-0.8.1.diff @@ -0,0 +1,152 @@ +diff --git a/x.c b/x.c +index 00cb6b1..8f87c0f 100644 +--- a/x.c ++++ b/x.c +@@ -78,6 +78,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 */ +@@ -311,7 +312,7 @@ zoomreset(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; + } +@@ -319,7 +320,7 @@ evcol(XEvent *e) + int + evrow(XEvent *e) + { +- int y = e->xbutton.y - borderpx; ++ int y = e->xbutton.y - win.vborderpx; + LIMIT(y, 0, win.th - 1); + return y / win.ch; + } +@@ -675,6 +676,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); +@@ -793,8 +797,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; +@@ -1022,8 +1026,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 + cols * win.cw; ++ win.h = 2 * win.vborderpx + rows * win.ch; + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) +@@ -1123,7 +1127,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; +@@ -1259,7 +1263,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; +@@ -1349,17 +1353,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + + /* Intelligent cleaning up of the borders. */ + if (x == 0) { +- xclear(0, (y == 0)? 0 : winy, borderpx, ++ xclear(0, (y == 0)? 0 : winy, win.vborderpx, + winy + win.ch + +- ((winy + win.ch >= borderpx + win.th)? win.h : 0)); ++ ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); + } +- if (winx + width >= borderpx + win.tw) { ++ if (winx + width >= win.hborderpx + win.tw) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, +- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); ++ ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); + } + if (y == 0) +- xclear(winx, 0, winx + width, borderpx); +- if (winy + win.ch >= borderpx + win.th) ++ xclear(winx, 0, winx + width, win.hborderpx); ++ 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. */ +@@ -1452,35 +1456,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); + } + } diff --git a/patches/st-clipboard-0.8.3.diff b/patches/st-clipboard-0.8.3.diff new file mode 100644 index 0000000..c1e0e9e --- /dev/null +++ b/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 b/st new file mode 100755 index 0000000000000000000000000000000000000000..4ec51bc76b46a6e97d394fb2552ed9fe261a11c9 GIT binary patch literal 96944 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 K()}f`|Nj6wG)9R4 literal 0 HcmV?d00001 diff --git a/x.c b/x.c index 210f184..8c5e61a 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; } @@ -673,6 +674,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 @@ -721,6 +723,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); @@ -838,8 +843,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; @@ -1121,8 +1126,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 + cols * win.cw; + win.h = 2 * win.vborderpx + rows * win.ch; if (xw.gm & XNegative) xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; if (xw.gm & YNegative) @@ -1210,7 +1215,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; @@ -1343,7 +1348,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; @@ -1433,17 +1438,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i /* Intelligent cleaning up of the borders. */ if (x == 0) { - xclear(0, (y == 0)? 0 : winy, borderpx, + xclear(0, (y == 0)? 0 : winy, win.vborderpx, winy + win.ch + - ((winy + win.ch >= borderpx + win.th)? win.h : 0)); + ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); } - if (winx + width >= borderpx + win.tw) { + if (winx + width >= win.hborderpx + win.tw) { xclear(winx + width, (y == 0)? 0 : winy, win.w, - ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); + ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); } if (y == 0) - xclear(winx, 0, winx + width, borderpx); - if (winy + win.ch >= borderpx + win.th) + xclear(winx, 0, winx + width, win.hborderpx); + 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. */ @@ -1537,35 +1542,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); } } diff --git a/x.c.orig b/x.c.orig new file mode 100644 index 0000000..ee9247b --- /dev/null +++ b/x.c.orig @@ -0,0 +1,2050 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *argv0; +#include "arg.h" +#include "st.h" +#include "win.h" + +/* types used in config.h */ +typedef struct { + uint mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +typedef struct { + uint mod; + uint button; + void (*func)(const Arg *); + const Arg arg; + uint release; +} MouseShortcut; + +typedef struct { + KeySym k; + uint mask; + char *s; + /* three-valued logic variables: 0 indifferent, 1 on, -1 off */ + signed char appkey; /* application keypad */ + signed char appcursor; /* application cursor */ +} Key; + +/* X modifiers */ +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13) + +/* function definitions used in config.h */ +static void clipcopy(const Arg *); +static void clippaste(const Arg *); +static void numlock(const Arg *); +static void selpaste(const Arg *); +static void zoom(const Arg *); +static void zoomabs(const Arg *); +static void zoomreset(const Arg *); +static void ttysend(const Arg *); + +/* config.h for applying patches and the configuration. */ +#include "config.h" + +/* XEMBED messages */ +#define XEMBED_FOCUS_IN 4 +#define XEMBED_FOCUS_OUT 5 + +/* macros */ +#define IS_SET(flag) ((win.mode & (flag)) != 0) +#define TRUERED(x) (((x) & 0xff0000) >> 8) +#define TRUEGREEN(x) (((x) & 0xff00)) +#define TRUEBLUE(x) (((x) & 0xff) << 8) + +typedef XftDraw *Draw; +typedef XftColor Color; +typedef XftGlyphFontSpec GlyphFontSpec; + +/* Purely graphic info */ +typedef struct { + int tw, th; /* tty width and height */ + int w, h; /* window width and height */ + int ch; /* char height */ + int cw; /* char width */ + int mode; /* window state/mode flags */ + int cursor; /* cursor style */ +} TermWindow; + +typedef struct { + Display *dpy; + Colormap cmap; + Window win; + Drawable buf; + GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ + Atom xembed, wmdeletewin, netwmname, netwmpid; + struct { + XIM xim; + XIC xic; + XPoint spot; + XVaNestedList spotlist; + } ime; + Draw draw; + Visual *vis; + XSetWindowAttributes attrs; + int scr; + int isfixed; /* is fixed geometry? */ + int l, t; /* left and top offset */ + int gm; /* geometry mask */ +} XWindow; + +typedef struct { + Atom xtarget; + char *primary, *clipboard; + struct timespec tclick1; + struct timespec tclick2; +} XSelection; + +/* Font structure */ +#define Font Font_ +typedef struct { + int height; + int width; + int ascent; + int descent; + int badslant; + int badweight; + short lbearing; + short rbearing; + XftFont *match; + FcFontSet *set; + FcPattern *pattern; +} Font; + +/* Drawing Context */ +typedef struct { + Color *col; + size_t collen; + Font font, bfont, ifont, ibfont; + GC gc; +} DC; + +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 xdrawglyph(Glyph, int, int); +static void xclear(int, int, int, int); +static int xgeommasktogravity(int); +static int ximopen(Display *); +static void ximinstantiate(Display *, XPointer, XPointer); +static void ximdestroy(XIM, XPointer, XPointer); +static int xicdestroy(XIC, XPointer, XPointer); +static void xinit(int, int); +static void cresize(int, int); +static void xresize(int, int); +static void xhints(void); +static int xloadcolor(int, const char *, Color *); +static int xloadfont(Font *, FcPattern *); +static void xloadfonts(char *, double); +static void xunloadfont(Font *); +static void xunloadfonts(void); +static void xsetenv(void); +static void xseturgency(int); +static int evcol(XEvent *); +static int evrow(XEvent *); + +static void expose(XEvent *); +static void visibility(XEvent *); +static void unmap(XEvent *); +static void kpress(XEvent *); +static void cmessage(XEvent *); +static void resize(XEvent *); +static void focus(XEvent *); +static uint buttonmask(uint); +static int mouseaction(XEvent *, uint); +static void brelease(XEvent *); +static void bpress(XEvent *); +static void bmotion(XEvent *); +static void propnotify(XEvent *); +static void selnotify(XEvent *); +static void selclear_(XEvent *); +static void selrequest(XEvent *); +static void setsel(char *, Time); +static void mousesel(XEvent *, int); +static void mousereport(XEvent *); +static char *kmap(KeySym, uint); +static int match(uint, uint); + +static void run(void); +static void usage(void); + +static void (*handler[LASTEvent])(XEvent *) = { + [KeyPress] = kpress, + [ClientMessage] = cmessage, + [ConfigureNotify] = resize, + [VisibilityNotify] = visibility, + [UnmapNotify] = unmap, + [Expose] = expose, + [FocusIn] = focus, + [FocusOut] = focus, + [MotionNotify] = bmotion, + [ButtonPress] = bpress, + [ButtonRelease] = brelease, +/* + * Uncomment if you want the selection to disappear when you select something + * different in another window. + */ +/* [SelectionClear] = selclear_, */ + [SelectionNotify] = selnotify, +/* + * PropertyNotify is only turned on when there is some INCR transfer happening + * for the selection retrieval. + */ + [PropertyNotify] = propnotify, + [SelectionRequest] = selrequest, +}; + +/* Globals */ +static DC dc; +static XWindow xw; +static XSelection xsel; +static TermWindow win; + +/* Font Ring Cache */ +enum { + FRC_NORMAL, + FRC_ITALIC, + FRC_BOLD, + FRC_ITALICBOLD +}; + +typedef struct { + XftFont *font; + int flags; + Rune unicodep; +} Fontcache; + +/* Fontcache is an array now. A new font will be appended to the array. */ +static Fontcache *frc = NULL; +static int frclen = 0; +static int frccap = 0; +static char *usedfont = NULL; +static double usedfontsize = 0; +static double defaultfontsize = 0; + +static char *opt_class = NULL; +static char **opt_cmd = NULL; +static char *opt_embed = NULL; +static char *opt_font = NULL; +static char *opt_io = NULL; +static char *opt_line = NULL; +static char *opt_name = NULL; +static char *opt_title = NULL; + +static int oldbutton = 3; /* button event on startup: 3 = release */ + +void +clipcopy(const Arg *dummy) +{ + Atom clipboard; + + free(xsel.clipboard); + xsel.clipboard = NULL; + + if (xsel.primary != NULL) { + xsel.clipboard = xstrdup(xsel.primary); + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); + } +} + +void +clippaste(const Arg *dummy) +{ + Atom clipboard; + + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, + xw.win, CurrentTime); +} + +void +selpaste(const Arg *dummy) +{ + XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); +} + +void +numlock(const Arg *dummy) +{ + win.mode ^= MODE_NUMLOCK; +} + +void +zoom(const Arg *arg) +{ + Arg larg; + + larg.f = usedfontsize + arg->f; + zoomabs(&larg); +} + +void +zoomabs(const Arg *arg) +{ + xunloadfonts(); + xloadfonts(usedfont, arg->f); + cresize(0, 0); + redraw(); + xhints(); +} + +void +zoomreset(const Arg *arg) +{ + Arg larg; + + if (defaultfontsize > 0) { + larg.f = defaultfontsize; + zoomabs(&larg); + } +} + +void +ttysend(const Arg *arg) +{ + ttywrite(arg->s, strlen(arg->s), 1); +} + +int +evcol(XEvent *e) +{ + int x = e->xbutton.x - borderpx; + LIMIT(x, 0, win.tw - 1); + return x / win.cw; +} + +int +evrow(XEvent *e) +{ + int y = e->xbutton.y - borderpx; + LIMIT(y, 0, win.th - 1); + return y / win.ch; +} + +void +mousesel(XEvent *e, int done) +{ + int type, seltype = SEL_REGULAR; + uint state = e->xbutton.state & ~(Button1Mask | forcemousemod); + + for (type = 1; type < LEN(selmasks); ++type) { + if (match(selmasks[type], state)) { + seltype = type; + break; + } + } + selextend(evcol(e), evrow(e), seltype, done); + if (done) + setsel(getsel(), e->xbutton.time); +} + +void +mousereport(XEvent *e) +{ + int len, x = evcol(e), y = evrow(e), + button = e->xbutton.button, state = e->xbutton.state; + char buf[40]; + static int ox, oy; + + /* from urxvt */ + if (e->xbutton.type == MotionNotify) { + if (x == ox && y == oy) + return; + if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) + return; + /* MOUSE_MOTION: no reporting if no button is pressed */ + if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) + return; + + button = oldbutton + 32; + ox = x; + oy = y; + } else { + if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { + button = 3; + } else { + button -= Button1; + if (button >= 3) + button += 64 - 3; + } + if (e->xbutton.type == ButtonPress) { + oldbutton = button; + ox = x; + oy = y; + } else if (e->xbutton.type == ButtonRelease) { + oldbutton = 3; + /* MODE_MOUSEX10: no button release reporting */ + if (IS_SET(MODE_MOUSEX10)) + return; + if (button == 64 || button == 65) + return; + } + } + + if (!IS_SET(MODE_MOUSEX10)) { + button += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod4Mask ) ? 8 : 0) + + ((state & ControlMask) ? 16 : 0); + } + + if (IS_SET(MODE_MOUSESGR)) { + len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", + button, x+1, y+1, + e->xbutton.type == ButtonRelease ? 'm' : 'M'); + } else if (x < 223 && y < 223) { + len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", + 32+button, 32+x+1, 32+y+1); + } else { + return; + } + + ttywrite(buf, len, 0); +} + +uint +buttonmask(uint button) +{ + return button == Button1 ? Button1Mask + : button == Button2 ? Button2Mask + : button == Button3 ? Button3Mask + : button == Button4 ? Button4Mask + : button == Button5 ? Button5Mask + : 0; +} + +int +mouseaction(XEvent *e, uint release) +{ + MouseShortcut *ms; + + /* ignore Buttonmask for Button - it's set on release */ + uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && + (match(ms->mod, state) || /* exact or forced */ + match(ms->mod, state & ~forcemousemod))) { + ms->func(&(ms->arg)); + return 1; + } + } + + return 0; +} + +void +bpress(XEvent *e) +{ + struct timespec now; + int snap; + + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + if (mouseaction(e, 0)) + return; + + if (e->xbutton.button == Button1) { + /* + * If the user clicks below predefined timeouts specific + * snapping behaviour is exposed. + */ + clock_gettime(CLOCK_MONOTONIC, &now); + if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) { + snap = SNAP_LINE; + } else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) { + snap = SNAP_WORD; + } else { + snap = 0; + } + xsel.tclick2 = xsel.tclick1; + xsel.tclick1 = now; + + selstart(evcol(e), evrow(e), snap); + } +} + +void +propnotify(XEvent *e) +{ + XPropertyEvent *xpev; + Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + + xpev = &e->xproperty; + if (xpev->state == PropertyNewValue && + (xpev->atom == XA_PRIMARY || + xpev->atom == clipboard)) { + selnotify(e); + } +} + +void +selnotify(XEvent *e) +{ + ulong nitems, ofs, rem; + int format; + uchar *data, *last, *repl; + Atom type, incratom, property = None; + + incratom = XInternAtom(xw.dpy, "INCR", 0); + + ofs = 0; + if (e->type == SelectionNotify) + property = e->xselection.property; + else if (e->type == PropertyNotify) + property = e->xproperty.atom; + + if (property == None) + return; + + do { + if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, + BUFSIZ/4, False, AnyPropertyType, + &type, &format, &nitems, &rem, + &data)) { + fprintf(stderr, "Clipboard allocation failed\n"); + return; + } + + if (e->type == PropertyNotify && nitems == 0 && rem == 0) { + /* + * If there is some PropertyNotify with no data, then + * this is the signal of the selection owner that all + * data has been transferred. We won't need to receive + * PropertyNotify events anymore. + */ + MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, + &xw.attrs); + } + + if (type == incratom) { + /* + * Activate the PropertyNotify events so we receive + * when the selection owner does send us the next + * chunk of data. + */ + MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, + &xw.attrs); + + /* + * Deleting the property is the transfer start signal. + */ + XDeleteProperty(xw.dpy, xw.win, (int)property); + continue; + } + + /* + * As seen in getsel: + * Line endings are inconsistent in the terminal and GUI world + * copy and pasting. When receiving some selection data, + * replace all '\n' with '\r'. + * FIXME: Fix the computer world. + */ + repl = data; + last = data + nitems * format / 8; + while ((repl = memchr(repl, '\n', last - repl))) { + *repl++ = '\r'; + } + + if (IS_SET(MODE_BRCKTPASTE) && ofs == 0) + ttywrite("\033[200~", 6, 0); + ttywrite((char *)data, nitems * format / 8, 1); + if (IS_SET(MODE_BRCKTPASTE) && rem == 0) + ttywrite("\033[201~", 6, 0); + XFree(data); + /* number of 32-bit chunks returned */ + ofs += nitems * format / 32; + } while (rem > 0); + + /* + * Deleting the property again tells the selection owner to send the + * next data chunk in the property. + */ + XDeleteProperty(xw.dpy, xw.win, (int)property); +} + +void +xclipcopy(void) +{ + clipcopy(NULL); +} + +void +selclear_(XEvent *e) +{ + selclear(); +} + +void +selrequest(XEvent *e) +{ + XSelectionRequestEvent *xsre; + XSelectionEvent xev; + Atom xa_targets, string, clipboard; + char *seltext; + + xsre = (XSelectionRequestEvent *) e; + xev.type = SelectionNotify; + xev.requestor = xsre->requestor; + xev.selection = xsre->selection; + xev.target = xsre->target; + xev.time = xsre->time; + if (xsre->property == None) + xsre->property = xsre->target; + + /* reject */ + xev.property = None; + + xa_targets = XInternAtom(xw.dpy, "TARGETS", 0); + if (xsre->target == xa_targets) { + /* respond with the supported type */ + string = xsel.xtarget; + XChangeProperty(xsre->display, xsre->requestor, xsre->property, + XA_ATOM, 32, PropModeReplace, + (uchar *) &string, 1); + xev.property = xsre->property; + } else if (xsre->target == xsel.xtarget || xsre->target == XA_STRING) { + /* + * xith XA_STRING non ascii characters may be incorrect in the + * requestor. It is not our problem, use utf8. + */ + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + if (xsre->selection == XA_PRIMARY) { + seltext = xsel.primary; + } else if (xsre->selection == clipboard) { + seltext = xsel.clipboard; + } else { + fprintf(stderr, + "Unhandled clipboard selection 0x%lx\n", + xsre->selection); + return; + } + if (seltext != NULL) { + XChangeProperty(xsre->display, xsre->requestor, + xsre->property, xsre->target, + 8, PropModeReplace, + (uchar *)seltext, strlen(seltext)); + xev.property = xsre->property; + } + } + + /* all done, send a notification to the listener */ + if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev)) + fprintf(stderr, "Error sending SelectionNotify event\n"); +} + +void +setsel(char *str, Time t) +{ + if (!str) + return; + + free(xsel.primary); + xsel.primary = str; + + XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); + if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) + selclear(); + clipcopy(NULL); +} + +void +xsetsel(char *str) +{ + setsel(str, CurrentTime); +} + +void +brelease(XEvent *e) +{ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + if (mouseaction(e, 1)) + return; + if (e->xbutton.button == Button1) + mousesel(e, 1); +} + +void +bmotion(XEvent *e) +{ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + mousesel(e, 0); +} + +void +cresize(int width, int height) +{ + int col, row; + + if (width != 0) + win.w = width; + if (height != 0) + win.h = height; + + col = (win.w - 2 * borderpx) / win.cw; + row = (win.h - 2 * borderpx) / win.ch; + col = MAX(1, col); + row = MAX(1, row); + + tresize(col, row); + xresize(col, row); + ttyresize(win.tw, win.th); +} + +void +xresize(int col, int row) +{ + win.tw = col * win.cw; + win.th = row * win.ch; + + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, + DefaultDepth(xw.dpy, xw.scr)); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); + + /* resize to new width */ + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); +} + +ushort +sixd_to_16bit(int x) +{ + return x == 0 ? 0 : 0x3737 + 0x2828 * x; +} + +int +xloadcolor(int i, const char *name, Color *ncolor) +{ + XRenderColor color = { .alpha = 0xffff }; + + if (!name) { + if (BETWEEN(i, 16, 255)) { /* 256 color */ + if (i < 6*6*6+16) { /* same colors as xterm */ + color.red = sixd_to_16bit( ((i-16)/36)%6 ); + color.green = sixd_to_16bit( ((i-16)/6) %6 ); + color.blue = sixd_to_16bit( ((i-16)/1) %6 ); + } else { /* greyscale */ + color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16)); + color.green = color.blue = color.red; + } + return XftColorAllocValue(xw.dpy, xw.vis, + xw.cmap, &color, ncolor); + } else + name = colorname[i]; + } + + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); +} + +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)); + } + + for (i = 0; i < 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); + } + loaded = 1; +} + +int +xsetcolorname(int x, const char *name) +{ + Color ncolor; + + if (!BETWEEN(x, 0, dc.collen)) + return 1; + + if (!xloadcolor(x, name, &ncolor)) + return 1; + + XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); + dc.col[x] = ncolor; + + return 0; +} + +/* + * Absolute coordinates. + */ +void +xclear(int x1, int y1, int x2, int y2) +{ + XftDrawRect(xw.draw, + &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg], + x1, y1, x2-x1, y2-y1); +} + +void +xhints(void) +{ + XClassHint class = {opt_name ? opt_name : termname, + opt_class ? opt_class : termname}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints *sizeh; + + sizeh = XAllocSizeHints(); + + 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->base_height = 2 * borderpx; + sizeh->base_width = 2 * borderpx; + sizeh->min_height = win.ch + 2 * borderpx; + sizeh->min_width = win.cw + 2 * borderpx; + if (xw.isfixed) { + sizeh->flags |= PMaxSize; + sizeh->min_width = sizeh->max_width = win.w; + sizeh->min_height = sizeh->max_height = win.h; + } + if (xw.gm & (XValue|YValue)) { + sizeh->flags |= USPosition | PWinGravity; + sizeh->x = xw.l; + sizeh->y = xw.t; + sizeh->win_gravity = xgeommasktogravity(xw.gm); + } + + XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, + &class); + XFree(sizeh); +} + +int +xgeommasktogravity(int mask) +{ + switch (mask & (XNegative|YNegative)) { + case 0: + return NorthWestGravity; + case XNegative: + return NorthEastGravity; + case YNegative: + return SouthWestGravity; + } + + return SouthEastGravity; +} + +int +xloadfont(Font *f, FcPattern *pattern) +{ + FcPattern *configured; + FcPattern *match; + FcResult result; + XGlyphInfo extents; + int wantattr, haveattr; + + /* + * Manually configure instead of calling XftMatchFont + * so that we can use the configured pattern for + * "missing glyph" lookups. + */ + configured = FcPatternDuplicate(pattern); + if (!configured) + return 1; + + FcConfigSubstitute(NULL, configured, FcMatchPattern); + XftDefaultSubstitute(xw.dpy, xw.scr, configured); + + match = FcFontMatch(NULL, configured, &result); + if (!match) { + FcPatternDestroy(configured); + return 1; + } + + if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { + FcPatternDestroy(configured); + FcPatternDestroy(match); + return 1; + } + + if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == + XftResultMatch)) { + /* + * Check if xft was unable to find a font with the appropriate + * slant but gave us one anyway. Try to mitigate. + */ + if ((XftPatternGetInteger(f->match->pattern, "slant", 0, + &haveattr) != XftResultMatch) || haveattr < wantattr) { + f->badslant = 1; + fputs("font slant does not match\n", stderr); + } + } + + if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) == + XftResultMatch)) { + if ((XftPatternGetInteger(f->match->pattern, "weight", 0, + &haveattr) != XftResultMatch) || haveattr != wantattr) { + f->badweight = 1; + fputs("font weight does not match\n", stderr); + } + } + + XftTextExtentsUtf8(xw.dpy, f->match, + (const FcChar8 *) ascii_printable, + strlen(ascii_printable), &extents); + + f->set = NULL; + f->pattern = configured; + + f->ascent = f->match->ascent; + f->descent = f->match->descent; + f->lbearing = 0; + f->rbearing = f->match->max_advance_width; + + f->height = f->ascent + f->descent; + f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); + + return 0; +} + +void +xloadfonts(char *fontstr, double fontsize) +{ + FcPattern *pattern; + double fontval; + + if (fontstr[0] == '-') + pattern = XftXlfdParse(fontstr, False, False); + else + pattern = FcNameParse((FcChar8 *)fontstr); + + if (!pattern) + die("can't open font %s\n", fontstr); + + if (fontsize > 1) { + FcPatternDel(pattern, FC_PIXEL_SIZE); + FcPatternDel(pattern, FC_SIZE); + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); + usedfontsize = fontsize; + } else { + if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = fontval; + } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = -1; + } else { + /* + * Default font size is 12, if none given. This is to + * have a known usedfontsize value. + */ + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); + usedfontsize = 12; + } + defaultfontsize = usedfontsize; + } + + if (xloadfont(&dc.font, pattern)) + die("can't open font %s\n", fontstr); + + if (usedfontsize < 0) { + FcPatternGetDouble(dc.font.match->pattern, + FC_PIXEL_SIZE, 0, &fontval); + usedfontsize = fontval; + if (fontsize == 0) + defaultfontsize = fontval; + } + + /* Setting character width and height. */ + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); + + FcPatternDel(pattern, FC_SLANT); + 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 (xloadfont(&dc.ibfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadfont(&dc.bfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDestroy(pattern); +} + +void +xunloadfont(Font *f) +{ + XftFontClose(xw.dpy, f->match); + FcPatternDestroy(f->pattern); + if (f->set) + FcFontSetDestroy(f->set); +} + +void +xunloadfonts(void) +{ + /* Free the loaded fonts in the font cache. */ + while (frclen > 0) + XftFontClose(xw.dpy, frc[--frclen].font); + + xunloadfont(&dc.font); + xunloadfont(&dc.bfont); + xunloadfont(&dc.ifont); + xunloadfont(&dc.ibfont); +} + +int +ximopen(Display *dpy) +{ + XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; + XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; + + xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); + if (xw.ime.xim == NULL) + return 0; + + if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) + fprintf(stderr, "XSetIMValues: " + "Could not set XNDestroyCallback.\n"); + + xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, + NULL); + + if (xw.ime.xic == NULL) { + xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, + XNDestroyCallback, &icdestroy, + NULL); + } + if (xw.ime.xic == NULL) + fprintf(stderr, "XCreateIC: Could not create input context.\n"); + + return 1; +} + +void +ximinstantiate(Display *dpy, XPointer client, XPointer call) +{ + if (ximopen(dpy)) + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + +void +ximdestroy(XIM xim, XPointer client, XPointer call) +{ + xw.ime.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + XFree(xw.ime.spotlist); +} + +int +xicdestroy(XIC xim, XPointer client, XPointer call) +{ + xw.ime.xic = NULL; + return 1; +} + +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"); + xw.scr = XDefaultScreen(xw.dpy); + xw.vis = XDefaultVisual(xw.dpy, xw.scr); + + /* font */ + if (!FcInit()) + die("could not init fontconfig.\n"); + + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + + /* colors */ + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xloadcols(); + + /* adjust fixed window geometry */ + win.w = 2 * borderpx + cols * win.cw; + win.h = 2 * borderpx + rows * win.ch; + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) + xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2; + + /* Events */ + xw.attrs.background_pixel = dc.col[defaultbg].pixel; + xw.attrs.border_pixel = dc.col[defaultbg].pixel; + xw.attrs.bit_gravity = NorthWestGravity; + xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask + | ExposureMask | VisibilityChangeMask | StructureNotifyMask + | 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, + 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)); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); + + /* input methods */ + if (!ximopen(xw.dpy)) { + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + } + + /* white cursor, black outline */ + cursor = XCreateFontCursor(xw.dpy, mouseshape); + XDefineCursor(xw.dpy, xw.win, cursor); + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) { + xmousefg.red = 0xffff; + xmousefg.green = 0xffff; + xmousefg.blue = 0xffff; + } + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) { + xmousebg.red = 0x0000; + xmousebg.green = 0x0000; + xmousebg.blue = 0x0000; + } + + XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); + + xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); + xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); + xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); + XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); + + xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (uchar *)&thispid, 1); + + win.mode = MODE_NUMLOCK; + resettitle(); + xhints(); + XMapWindow(xw.dpy, xw.win); + XSync(xw.dpy, False); + + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2); + xsel.primary = NULL; + xsel.clipboard = NULL; + xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); + if (xsel.xtarget == None) + xsel.xtarget = XA_STRING; +} + +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; + ushort mode, prevmode = USHRT_MAX; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; + float runewidth = win.cw; + Rune rune; + FT_UInt glyphidx; + FcResult fcres; + FcPattern *fcpattern, *fontpattern; + FcFontSet *fcsets[] = { NULL }; + FcCharSet *fccharset; + int i, f, numspecs = 0; + + for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + /* Fetch rune and mode for current glyph. */ + rune = glyphs[i].u; + mode = glyphs[i].mode; + + /* Skip dummy wide-character spacing. */ + if (mode == ATTR_WDUMMY) + continue; + + /* Determine font for glyph if different from previous glyph. */ + if (prevmode != mode) { + prevmode = mode; + font = &dc.font; + frcflags = FRC_NORMAL; + runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if (mode & ATTR_ITALIC) { + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if (mode & ATTR_BOLD) { + font = &dc.bfont; + frcflags = FRC_BOLD; + } + yp = winy + font->ascent; + } + + /* Lookup character index with default font. */ + glyphidx = XftCharIndex(xw.dpy, font->match, rune); + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + continue; + } + + /* Fallback on font cache, search the font cache for match. */ + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ + if (glyphidx && frc[f].flags == frcflags) + break; + /* We got a default font for a not found glyph. */ + if (!glyphidx && frc[f].flags == frcflags + && frc[f].unicodep == rune) { + break; + } + } + + /* Nothing was found. Use fontconfig to find matching font. */ + if (f >= frclen) { + if (!font->set) + font->set = FcFontSort(0, font->pattern, + 1, 0, &fcres); + fcsets[0] = font->set; + + /* + * Nothing was found in the cache. Now use + * some dozen of Fontconfig calls to get the + * font for one single character. + * + * Xft and fontconfig are design failures. + */ + fcpattern = FcPatternDuplicate(font->pattern); + fccharset = FcCharSetCreate(); + + FcCharSetAddChar(fccharset, rune); + FcPatternAddCharSet(fcpattern, FC_CHARSET, + fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, 1); + + FcConfigSubstitute(0, fcpattern, + FcMatchPattern); + FcDefaultSubstitute(fcpattern); + + fontpattern = FcFontSetMatch(0, fcsets, 1, + fcpattern, &fcres); + + /* Allocate memory for the new cache entry. */ + if (frclen >= frccap) { + frccap += 16; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); + } + + frc[frclen].font = XftFontOpenPattern(xw.dpy, + fontpattern); + if (!frc[frclen].font) + die("XftFontOpenPattern failed seeking fallback font: %s\n", + strerror(errno)); + frc[frclen].flags = frcflags; + frc[frclen].unicodep = rune; + + glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); + + f = frclen; + frclen++; + + FcPatternDestroy(fcpattern); + FcCharSetDestroy(fccharset); + } + + specs[numspecs].font = frc[f].font; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + } + + return numspecs; +} + +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, + width = charlen * win.cw; + Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; + XRenderColor colfg, colbg; + XRectangle r; + + /* Fallback on color display for attributes not supported by the font */ + if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) { + if (dc.ibfont.badslant || dc.ibfont.badweight) + base.fg = defaultattr; + } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) || + (base.mode & ATTR_BOLD && dc.bfont.badweight)) { + base.fg = defaultattr; + } + + if (IS_TRUECOL(base.fg)) { + colfg.alpha = 0xffff; + colfg.red = TRUERED(base.fg); + colfg.green = TRUEGREEN(base.fg); + colfg.blue = TRUEBLUE(base.fg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg); + fg = &truefg; + } else { + fg = &dc.col[base.fg]; + } + + if (IS_TRUECOL(base.bg)) { + colbg.alpha = 0xffff; + colbg.green = TRUEGREEN(base.bg); + colbg.red = TRUERED(base.bg); + colbg.blue = TRUEBLUE(base.bg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg); + bg = &truebg; + } else { + bg = &dc.col[base.bg]; + } + + /* Change basic system colors [0-7] to bright system colors [8-15] */ + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) + fg = &dc.col[base.fg + 8]; + + if (IS_SET(MODE_REVERSE)) { + if (fg == &dc.col[defaultfg]) { + fg = &dc.col[defaultbg]; + } else { + colfg.red = ~fg->color.red; + colfg.green = ~fg->color.green; + colfg.blue = ~fg->color.blue; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, + &revfg); + fg = &revfg; + } + + if (bg == &dc.col[defaultbg]) { + bg = &dc.col[defaultfg]; + } else { + colbg.red = ~bg->color.red; + colbg.green = ~bg->color.green; + colbg.blue = ~bg->color.blue; + colbg.alpha = bg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, + &revbg); + bg = &revbg; + } + } + + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { + colfg.red = fg->color.red / 2; + colfg.green = fg->color.green / 2; + colfg.blue = fg->color.blue / 2; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); + fg = &revfg; + } + + if (base.mode & ATTR_REVERSE) { + temp = fg; + fg = bg; + bg = temp; + } + + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) + fg = bg; + + 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); + + /* 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 + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, + width, 1); + } + + /* Reset clip to none. */ + XftDrawSetClip(xw.draw, 0); +} + +void +xdrawglyph(Glyph g, int x, int y) +{ + int numspecs; + XftGlyphFontSpec spec; + + numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); + xdrawglyphfontspecs(&spec, g, numspecs, x, y); +} + +void +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) +{ + Color drawcol; + + /* remove the old cursor */ + if (selected(ox, oy)) + og.mode ^= ATTR_REVERSE; + xdrawglyph(og, ox, oy); + + if (IS_SET(MODE_HIDE)) + return; + + /* + * Select the right color for the right mode. + */ + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; + + if (IS_SET(MODE_REVERSE)) { + g.mode |= ATTR_REVERSE; + g.bg = defaultfg; + if (selected(cx, cy)) { + drawcol = dc.col[defaultcs]; + g.fg = defaultrcs; + } else { + drawcol = dc.col[defaultrcs]; + g.fg = defaultcs; + } + } else { + if (selected(cx, cy)) { + g.fg = defaultfg; + g.bg = defaultrcs; + } else { + g.fg = defaultbg; + g.bg = defaultcs; + } + drawcol = dc.col[g.bg]; + } + + /* draw the new one */ + if (IS_SET(MODE_FOCUSED)) { + switch (win.cursor) { + case 7: /* st extension */ + g.u = 0x2603; /* snowman (U+2603) */ + /* FALLTHROUGH */ + case 0: /* Blinking Block */ + case 1: /* Blinking Block (Default) */ + case 2: /* Steady Block */ + xdrawglyph(g, cx, cy); + break; + case 3: /* Blinking Underline */ + 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 */ + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + cursorthickness, win.ch); + break; + } + } else { + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + win.cw - 1, 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + (cx + 1) * win.cw - 1, + borderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - 1, + win.cw, 1); + } +} + +void +xsetenv(void) +{ + char buf[sizeof(long) * 8 + 1]; + + snprintf(buf, sizeof(buf), "%lu", xw.win); + setenv("WINDOWID", buf, 1); +} + +void +xsettitle(char *p) +{ + XTextProperty prop; + DEFAULT(p, opt_title); + + Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop); + XSetWMName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); + XFree(prop.value); +} + +int +xstartdraw(void) +{ + return IS_SET(MODE_VISIBLE); +} + +void +xdrawline(Line line, int x1, int y1, int x2) +{ + int i, x, ox, numspecs; + 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; + } + i++; + } + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1); +} + +void +xfinishdraw(void) +{ + XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, + win.h, 0, 0); + XSetForeground(xw.dpy, dc.gc, + dc.col[IS_SET(MODE_REVERSE)? + defaultfg : defaultbg].pixel); +} + +void +xximspot(int x, int y) +{ + if (xw.ime.xic == NULL) + return; + + xw.ime.spot.x = borderpx + x * win.cw; + xw.ime.spot.y = borderpx + (y + 1) * win.ch; + + XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL); +} + +void +expose(XEvent *ev) +{ + redraw(); +} + +void +visibility(XEvent *ev) +{ + XVisibilityEvent *e = &ev->xvisibility; + + MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); +} + +void +unmap(XEvent *ev) +{ + win.mode &= ~MODE_VISIBLE; +} + +void +xsetpointermotion(int set) +{ + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); +} + +void +xsetmode(int set, unsigned int flags) +{ + int mode = win.mode; + MODBIT(win.mode, set, flags); + if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) + redraw(); +} + +int +xsetcursor(int cursor) +{ + if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ + return 1; + win.cursor = cursor; + return 0; +} + +void +xseturgency(int add) +{ + XWMHints *h = XGetWMHints(xw.dpy, xw.win); + + MODBIT(h->flags, add, XUrgencyHint); + XSetWMHints(xw.dpy, xw.win, h); + XFree(h); +} + +void +xbell(void) +{ + if (!(IS_SET(MODE_FOCUSED))) + xseturgency(1); + if (bellvolume) + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); +} + +void +focus(XEvent *ev) +{ + XFocusChangeEvent *e = &ev->xfocus; + + if (e->mode == NotifyGrab) + return; + + if (ev->type == FocusIn) { + if (xw.ime.xic) + XSetICFocus(xw.ime.xic); + win.mode |= MODE_FOCUSED; + xseturgency(0); + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); + win.mode &= ~MODE_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3, 0); + } +} + +int +match(uint mask, uint state) +{ + return mask == XK_ANY_MOD || mask == (state & ~ignoremod); +} + +char* +kmap(KeySym k, uint state) +{ + Key *kp; + int i; + + /* Check for mapped keys out of X11 function keys. */ + for (i = 0; i < LEN(mappedkeys); i++) { + if (mappedkeys[i] == k) + break; + } + if (i == LEN(mappedkeys)) { + if ((k & 0xFFFF) < 0xFD00) + return NULL; + } + + for (kp = key; kp < key + LEN(key); kp++) { + if (kp->k != k) + continue; + + if (!match(kp->mask, state)) + continue; + + if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) + continue; + if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2) + continue; + + if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) + continue; + + return kp->s; + } + + return NULL; +} + +void +kpress(XEvent *ev) +{ + XKeyEvent *e = &ev->xkey; + KeySym ksym; + char buf[64], *customkey; + int len; + Rune c; + Status status; + Shortcut *bp; + + if (IS_SET(MODE_KBDLOCK)) + return; + + if (xw.ime.xic) + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + else + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { + bp->func(&(bp->arg)); + return; + } + } + + /* 2. custom keys from config.h */ + if ((customkey = kmap(ksym, e->state))) { + ttywrite(customkey, strlen(customkey), 1); + return; + } + + /* 3. composed string from input method */ + if (len == 0) + return; + if (len == 1 && e->state & Mod1Mask) { + if (IS_SET(MODE_8BIT)) { + if (*buf < 0177) { + c = *buf | 0x80; + len = utf8encode(c, buf); + } + } else { + buf[1] = buf[0]; + buf[0] = '\033'; + len = 2; + } + } + ttywrite(buf, len, 1); +} + +void +cmessage(XEvent *e) +{ + /* + * See xembed specs + * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html + */ + if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { + if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { + win.mode |= MODE_FOCUSED; + xseturgency(0); + } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { + win.mode &= ~MODE_FOCUSED; + } + } else if (e->xclient.data.l[0] == xw.wmdeletewin) { + ttyhangup(); + exit(0); + } +} + +void +resize(XEvent *e) +{ + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) + return; + + cresize(e->xconfigure.width, e->xconfigure.height); +} + +void +run(void) +{ + XEvent ev; + int w = win.w, h = win.h; + fd_set rfd; + int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing; + struct timespec seltv, *tv, now, lastblink, trigger; + double timeout; + + /* Waiting for window mapping */ + do { + XNextEvent(xw.dpy, &ev); + /* + * This XFilterEvent call is required because of XOpenIM. It + * does filter out the key event and some client message for + * the input method too. + */ + if (XFilterEvent(&ev, None)) + continue; + if (ev.type == ConfigureNotify) { + w = ev.xconfigure.width; + h = ev.xconfigure.height; + } + } while (ev.type != MapNotify); + + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); + cresize(w, h); + + for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) { + FD_ZERO(&rfd); + FD_SET(ttyfd, &rfd); + FD_SET(xfd, &rfd); + + if (XPending(xw.dpy)) + timeout = 0; /* existing events might not set xfd */ + + seltv.tv_sec = timeout / 1E3; + seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec); + tv = timeout >= 0 ? &seltv : NULL; + + if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + clock_gettime(CLOCK_MONOTONIC, &now); + + if (FD_ISSET(ttyfd, &rfd)) + ttyread(); + + xev = 0; + while (XPending(xw.dpy)) { + xev = 1; + XNextEvent(xw.dpy, &ev); + if (XFilterEvent(&ev, None)) + continue; + if (handler[ev.type]) + (handler[ev.type])(&ev); + } + + /* + * To reduce flicker and tearing, when new content or event + * triggers drawing, we first wait a bit to ensure we got + * everything, and if nothing new arrives - we draw. + * We start with trying to wait minlatency ms. If more content + * arrives sooner, we retry with shorter and shorter periods, + * and eventually draw even without idle after maxlatency ms. + * Typically this results in low latency while interacting, + * maximum latency intervals during `cat huge.txt`, and perfect + * sync with periodic updates from animations/key-repeats/etc. + */ + if (FD_ISSET(ttyfd, &rfd) || xev) { + if (!drawing) { + trigger = now; + drawing = 1; + } + timeout = (maxlatency - TIMEDIFF(now, trigger)) \ + / maxlatency * minlatency; + if (timeout > 0) + continue; /* we have time, try to find idle */ + } + + /* idle detected or maxlatency exhausted -> draw */ + timeout = -1; + if (blinktimeout && tattrset(ATTR_BLINK)) { + timeout = blinktimeout - TIMEDIFF(now, lastblink); + if (timeout <= 0) { + if (-timeout > blinktimeout) /* start visible */ + win.mode |= MODE_BLINK; + win.mode ^= MODE_BLINK; + tsetdirtattr(ATTR_BLINK); + lastblink = now; + timeout = blinktimeout; + } + } + + draw(); + XFlush(xw.dpy); + drawing = 0; + } +} + +void +usage(void) +{ + die("usage: %s [-aiv] [-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]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid] -l line" + " [stty_args ...]\n", argv0, argv0); +} + +int +main(int argc, char *argv[]) +{ + xw.l = xw.t = 0; + xw.isfixed = False; + xsetcursor(cursorshape); + + ARGBEGIN { + case 'a': + allowaltscreen = 0; + break; + case 'c': + opt_class = EARGF(usage()); + break; + case 'e': + if (argc > 0) + --argc, ++argv; + goto run; + case 'f': + opt_font = EARGF(usage()); + break; + case 'g': + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &cols, &rows); + break; + case 'i': + xw.isfixed = 1; + break; + case 'o': + opt_io = EARGF(usage()); + break; + case 'l': + opt_line = EARGF(usage()); + break; + case 'n': + opt_name = EARGF(usage()); + break; + case 't': + case 'T': + opt_title = EARGF(usage()); + break; + case 'w': + opt_embed = EARGF(usage()); + break; + case 'v': + die("%s " VERSION "\n", argv0); + break; + default: + usage(); + } ARGEND; + +run: + if (argc > 0) /* eat all remaining arguments */ + opt_cmd = argv; + + if (!opt_title) + opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; + + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); + xinit(cols, rows); + xsetenv(); + selinit(); + run(); + + return 0; +} diff --git a/x.o b/x.o new file mode 100644 index 0000000000000000000000000000000000000000..67444be4402e874e04fa6b35975bc40d2e81add5 GIT binary patch literal 71472 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 UUs~zDzYPaj$v^iYbEMP%A8L=9i~s-t literal 0 HcmV?d00001