From 96aeb2dad070b33da1de153c4ac923f68e4fb839 Mon Sep 17 00:00:00 2001 From: Sergey Silaev Date: Sat, 19 Dec 2020 03:27:43 +0300 Subject: [PATCH] Merge 0.8.4 --- .Xdefaults | 124 -------------- .gitignore | 3 - FAQ | 250 +++++++++++++++++++++++++++ LEGACY | 17 ++ LICENSE | 2 +- README | 34 ++++ README.md | 34 ---- TODO | 28 +++ config.def.h | 472 +++++++++++++++++++++++++++++++++++++++++++++++++++ config.h | 129 +++++++------- config.mk | 8 +- st | Bin 0 -> 102448 bytes st.1 | 3 +- st.c | 316 +++++++++++++--------------------- st.h | 16 +- st.info | 37 ++-- st.o | Bin 0 -> 73552 bytes win.h | 1 + x.c | 383 ++++++++++++++++++++++++----------------- x.o | Bin 0 -> 73688 bytes 20 files changed, 1250 insertions(+), 607 deletions(-) delete mode 100644 .Xdefaults delete mode 100644 .gitignore create mode 100644 FAQ create mode 100644 LEGACY create mode 100644 README delete mode 100644 README.md create mode 100644 TODO create mode 100644 config.def.h create mode 100755 st create mode 100644 st.o create mode 100644 x.o diff --git a/.Xdefaults b/.Xdefaults deleted file mode 100644 index 05b5e2e..0000000 --- a/.Xdefaults +++ /dev/null @@ -1,124 +0,0 @@ -!! Transparency (0-1): -st.alpha: 0.92 - -!! Set a default font and font size as below: -st.font: Monospace-11; - -! st.termname: st-256color -! st.borderpx: 2 - -!! Set the background, foreground and cursor colors as below: -*.background: #282828 -*.foreground: white -*.cursorColor: white - -/* !! gruvbox: */ -/* *.color0: #1d2021 */ -/* *.color1: #cc241d */ -/* *.color2: #98971a */ -/* *.color3: #d79921 */ -/* *.color4: #458588 */ -/* *.color5: #b16286 */ -/* *.color6: #689d6a */ -/* *.color7: #a89984 */ -/* *.color8: #928374 */ -/* *.color9: #fb4934 */ -/* *.color10: #b8bb26 */ -/* *.color11: #fabd2f */ -/* *.color12: #83a598 */ -/* *.color13: #d3869b */ -/* *.color14: #8ec07c */ -/* *.color15: #ebdbb2 */ - -/* !! gruvbox light: */ -/* *.color0: #fbf1c7 */ -/* *.color1: #cc241d */ -/* *.color2: #98971a */ -/* *.color3: #d79921 */ -/* *.color4: #458588 */ -/* *.color5: #b16286 */ -/* *.color6: #689d6a */ -/* *.color7: #7c6f64 */ -/* *.color8: #928374 */ -/* *.color9: #9d0006 */ -/* *.color10: #79740e */ -/* *.color11: #b57614 */ -/* *.color12: #076678 */ -/* *.color13: #8f3f71 */ -/* *.color14: #427b58 */ -/* *.color15: #3c3836 */ - -/* !! brogrammer: */ -/* *.foreground: #d6dbe5 */ -/* *.background: #131313 */ -/* *.color0: #1f1f1f */ -/* *.color8: #d6dbe5 */ -/* *.color1: #f81118 */ -/* *.color9: #de352e */ -/* *.color2: #2dc55e */ -/* *.color10: #1dd361 */ -/* *.color3: #ecba0f */ -/* *.color11: #f3bd09 */ -/* *.color4: #2a84d2 */ -/* *.color12: #1081d6 */ -/* *.color5: #4e5ab7 */ -/* *.color13: #5350b9 */ -/* *.color6: #1081d6 */ -/* *.color14: #0f7ddb */ -/* *.color7: #d6dbe5 */ -/* *.color15: #ffffff */ -/* *.colorBD: #d6dbe5 */ - -/* ! base16 */ -/* *.color0: #181818 */ -/* *.color1: #ab4642 */ -/* *.color2: #a1b56c */ -/* *.color3: #f7ca88 */ -/* *.color4: #7cafc2 */ -/* *.color5: #ba8baf */ -/* *.color6: #86c1b9 */ -/* *.color7: #d8d8d8 */ -/* *.color8: #585858 */ -/* *.color9: #ab4642 */ -/* *.color10: #a1b56c */ -/* *.color11: #f7ca88 */ -/* *.color12: #7cafc2 */ -/* *.color13: #ba8baf */ -/* *.color14: #86c1b9 */ -/* *.color15: #f8f8f8 */ - -/* !! solarized */ -/* *.color0: #073642 */ -/* *.color1: #dc322f */ -/* *.color2: #859900 */ -/* *.color3: #b58900 */ -/* *.color4: #268bd2 */ -/* *.color5: #d33682 */ -/* *.color6: #2aa198 */ -/* *.color7: #eee8d5 */ -/* *.color9: #cb4b16 */ -/* *.color8: #fdf6e3 */ -/* *.color10: #586e75 */ -/* *.color11: #657b83 */ -/* *.color12: #839496 */ -/* *.color13: #6c71c4 */ -/* *.color14: #93a1a1 */ -/* *.color15: #fdf6e3 */ - -/* !! xterm */ -/* *.color0: #000000 */ -/* *.color1: #cd0000 */ -/* *.color2: #00cd00 */ -/* *.color3: #cdcd00 */ -/* *.color4: #0000cd */ -/* *.color5: #cd00cd */ -/* *.color6: #00cdcd */ -/* *.color7: #e5e5e5 */ -/* *.color8: #4d4d4d */ -/* *.color9: #ff0000 */ -/* *.color10: #00ff00 */ -/* *.color11: #ffff00 */ -/* *.color12: #0000ff */ -/* *.color13: #ff00ff */ -/* *.color14: #00ffff */ -/* *.color15: #aabac8 */ diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 1b2f5a9..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -st.o -x.o -*.tar.gz diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..0f9609d --- /dev/null +++ b/FAQ @@ -0,0 +1,250 @@ +## Why does st not handle utmp entries? + +Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task. + + +## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever! + +It means that st doesn’t have any terminfo entry on your system. Chances are +you did not `make install`. If you just want to test it without installing it, +you can manually run `tic -sx st.info`. + + +## Nothing works, and nothing is said about an unknown terminal! + +* Some programs just assume they’re running in xterm i.e. they don’t rely on + terminfo. What you see is the current state of the “xterm compliance”. +* Some programs don’t complain about the lacking st description and default to + another terminal. In that case see the question about terminfo. + + +## How do I scroll back up? + +* Using a terminal multiplexer. + * `st -e tmux` using C-b [ + * `st -e screen` using C-a ESC +* Using the excellent tool of [scroll](https://git.suckless.org/scroll/). +* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/). + + +## I would like to have utmp and/or scroll functionality by default + +You can add the absolute patch of both programs in your config.h +file. You only have to modify the value of utmp and scroll variables. + + +## Why doesn't the Del key work in some programs? + +Taken from the terminfo manpage: + + If the terminal has a keypad that transmits codes when the keys + are pressed, this information can be given. Note that it is not + possible to handle terminals where the keypad only works in + local (this applies, for example, to the unshifted HP 2621 keys). + If the keypad can be set to transmit or not transmit, give these + codes as smkx and rmkx. Otherwise the keypad is assumed to + always transmit. + +In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that +applications which want to test against keypad keys send these +sequences. + +But buggy applications (like bash and irssi, for example) don't do this. A fast +solution for them is to use the following command: + + $ printf '\033[?1h\033=' >/dev/tty + +or + $ tput smkx + +In the case of bash, readline is used. Readline has a different note in its +manpage about this issue: + + enable-keypad (Off) + When set to On, readline will try to enable the + application keypad when it is called. Some systems + need this to enable arrow keys. + +Adding this option to your .inputrc will fix the keypad problem for all +applications using readline. + +If you are using zsh, then read the zsh FAQ +: + + It should be noted that the O / [ confusion can occur with other keys + such as Home and End. Some systems let you query the key sequences + sent by these keys from the system's terminal database, terminfo. + Unfortunately, the key sequences given there typically apply to the + mode that is not the one zsh uses by default (it's the "application" + mode rather than the "raw" mode). Explaining the use of terminfo is + outside of the scope of this FAQ, but if you wish to use the key + sequences given there you can tell the line editor to turn on + "application" mode when it starts and turn it off when it stops: + + function zle-line-init () { echoti smkx } + function zle-line-finish () { echoti rmkx } + zle -N zle-line-init + zle -N zle-line-finish + +Putting these lines into your .zshrc will fix the problems. + + +## How can I use meta in 8bit mode? + +St supports meta in 8bit mode, but the default terminfo entry doesn't +use this capability. If you want it, you have to use the 'st-meta' value +in TERM. + + +## I cannot compile st in OpenBSD + +OpenBSD lacks librt, despite it being mandatory in POSIX +. +If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and +st will compile without any loss of functionality, because all the functions are +included in libc on this platform. + + +## The Backspace Case + +St is emulating the Linux way of handling backspace being delete and delete being +backspace. + +This is an issue that was discussed in suckless mailing list +. Here is why some old grumpy +terminal users wants its backspace to be how he feels it: + + Well, I am going to comment why I want to change the behaviour + of this key. When ASCII was defined in 1968, communication + with computers was done using punched cards, or hardcopy + terminals (basically a typewriter machine connected with the + computer using a serial port). ASCII defines DELETE as 7F, + because, in punched-card terms, it means all the holes of the + card punched; it is thus a kind of 'physical delete'. In the + same way, the BACKSPACE key was a non-destructive backspace, + as on a typewriter. So, if you wanted to delete a character, + you had to BACKSPACE and then DELETE. Another use of BACKSPACE + was to type accented characters, for example 'a BACKSPACE `'. + The VT100 had no BACKSPACE key; it was generated using the + CONTROL key as another control character (CONTROL key sets to + 0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code + 0x08)), but it had a DELETE key in a similar position where + the BACKSPACE key is located today on common PC keyboards. + All the terminal emulators emulated the difference between + these keys correctly: the backspace key generated a BACKSPACE + (^H) and delete key generated a DELETE (^?). + + But a problem arose when Linus Torvalds wrote Linux. Unlike + earlier terminals, the Linux virtual terminal (the terminal + emulator integrated in the kernel) returned a DELETE when + backspace was pressed, due to the VT100 having a DELETE key in + the same position. This created a lot of problems (see [1] + and [2]). Since Linux has become the king, a lot of terminal + emulators today generate a DELETE when the backspace key is + pressed in order to avoid problems with Linux. The result is + that the only way of generating a BACKSPACE on these systems + is by using CONTROL + H. (I also think that emacs had an + important point here because the CONTROL + H prefix is used + in emacs in some commands (help commands).) + + From point of view of the kernel, you can change the key + for deleting a previous character with stty erase. When you + connect a real terminal into a machine you describe the type + of terminal, so getty configures the correct value of stty + erase for this terminal. In the case of terminal emulators, + however, you don't have any getty that can set the correct + value of stty erase, so you always get the default value. + For this reason, it is necessary to add 'stty erase ^H' to your + profile if you have changed the value of the backspace key. + Of course, another solution is for st itself to modify the + value of stty erase. I usually have the inverse problem: + when I connect to non-Unix machines, I have to press CONTROL + + h to get a BACKSPACE. The inverse problem occurs when a user + connects to my Unix machines from a different system with a + correct backspace key. + + [1] http://www.ibb.net/~anne/keyboard.html + [2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html + + +## But I really want the old grumpy behaviour of my terminal + +Apply [1]. + +[1] https://st.suckless.org/patches/delkey + + +## Why do images not work in st using the w3m image hack? + +w3mimg uses a hack that draws an image on top of the terminal emulator Drawable +window. The hack relies on the terminal to use a single buffer to draw its +contents directly. + +st uses double-buffered drawing so the image is quickly replaced and may show a +short flicker effect. + +Below is a patch example to change st double-buffering to a single Drawable +buffer. + +diff --git a/x.c b/x.c +--- a/x.c ++++ b/x.c +@@ -732,10 +732,6 @@ 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 */ +@@ -1148,8 +1144,7 @@ xinit(int cols, int rows) + gcvalues.graphics_exposures = False; + dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, + &gcvalues); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.buf = xw.win; + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + +@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2) + 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); + + +## BadLength X error in Xft when trying to render emoji + +Xft makes st crash when rendering color emojis with the following error: + +"X Error of failed request: BadLength (poly request too large or internal Xlib length error)" + Major opcode of failed request: 139 (RENDER) + Minor opcode of failed request: 20 (RenderAddGlyphs) + Serial number of failed request: 1595 + Current serial number in output stream: 1818" + +This is a known bug in Xft (not st) which happens on some platforms and +combination of particular fonts and fontconfig settings. + +See also: +https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6 +https://bugs.freedesktop.org/show_bug.cgi?id=107534 +https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + +The solution is to remove color emoji fonts or disable this in the fontconfig +XML configuration. As an ugly workaround (which may work only on newer +fontconfig versions (FC_COLOR)), the following code can be used to mask color +fonts: + + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + +Please don't bother reporting this bug to st, but notify the upstream Xft +developers about fixing this bug. diff --git a/LEGACY b/LEGACY new file mode 100644 index 0000000..bf28b1e --- /dev/null +++ b/LEGACY @@ -0,0 +1,17 @@ +A STATEMENT ON LEGACY SUPPORT + +In the terminal world there is much cruft that comes from old and unsup‐ +ported terminals that inherit incompatible modes and escape sequences +which noone is able to know, except when he/she comes from that time and +developed a graphical vt100 emulator at that time. + +One goal of st is to only support what is really needed. When you en‐ +counter a sequence which you really need, implement it. But while you +are at it, do not add the other cruft you might encounter while sneek‐ +ing at other terminal emulators. History has bloated them and there is +no real evidence that most of the sequences are used today. + + +Christoph Lohmann <20h@r-36.net> +2012-09-13T07:00:36.081271045+02:00 + diff --git a/LICENSE b/LICENSE index c356c39..d80eb47 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT/X Consortium License -© 2014-2018 Hiltjo Posthuma +© 2014-2020 Hiltjo Posthuma © 2018 Devin J. Pohly © 2014-2017 Quentin Rameau © 2009-2012 Aurélien APTEL diff --git a/README b/README new file mode 100644 index 0000000..6a846ed --- /dev/null +++ b/README @@ -0,0 +1,34 @@ +st - simple terminal +-------------------- +st is a simple terminal emulator for X which sucks less. + + +Requirements +------------ +In order to build st you need the Xlib header files. + + +Installation +------------ +Edit config.mk to match your local setup (st is installed into +the /usr/local namespace by default). + +Afterwards enter the following command to build and install st (if +necessary as root): + + make clean install + + +Running st +---------- +If you did not install st with make clean install, you must compile +the st terminfo entry with the following command: + + tic -sx st.info + +See the man page for additional details. + +Credits +------- +Based on Aurélien APTEL bt source code. + diff --git a/README.md b/README.md deleted file mode 100644 index c026fd1..0000000 --- a/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# st - simple terminal emulator for X. - -+ Default font: [Fira Code](https://github.com/tonsky/FiraCode) -+ Default theme: [Solarized](https://ethanschoonover.com/solarized/) - -## Bindings - -+ **Scrollback**: with `shift-↑/↓` or `shift-h/shift-j` -+ **Scrollback mouse**: `shift` while scrolling the mouse -+ **Change font size**:`ctrl+shift-↑/↓` -+ **Reset font size**: `ctrl+shifts-home` returns to default -+ **Copy/Paste text**: with `ctrl+shift-c` and `ctrl+shift+v` or `ctrl+shift-insert` - -## Requirements - -+ `make` tool for building -+ `libXft` library for fonts drawing -+ `Xlib` header files for interacting with an X server -+ `Fira Code` just default font, which you can change it in `config.h` - -## Patches - -+ st-solarized -+ st-scrollback -+ st-scrollback-mouse -+ alpha - -## Simple installation - -``` -git clone https://github.com/ssilaev/st -cd st -sudo make install -``` diff --git a/TODO b/TODO new file mode 100644 index 0000000..5f74cd5 --- /dev/null +++ b/TODO @@ -0,0 +1,28 @@ +vt emulation +------------ + +* double-height support + +code & interface +---------------- + +* add a simple way to do multiplexing + +drawing +------- +* add diacritics support to xdraws() + * switch to a suckless font drawing library +* make the font cache simpler +* add better support for brightening of the upper colors + +bugs +---- + +* fix shift up/down (shift selection in emacs) +* remove DEC test sequence when appropriate + +misc +---- + + $ grep -nE 'XXX|TODO' st.c + diff --git a/config.def.h b/config.def.h new file mode 100644 index 0000000..6f05dce --- /dev/null +++ b/config.def.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 = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +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/config.h b/config.h index 24177f2..6f05dce 100644 --- a/config.h +++ b/config.h @@ -5,19 +5,21 @@ * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -static char *font = "FiraCode:pixelsize=16:antialias=true:autohint=true"; +static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; static int borderpx = 2; /* * What program is execed by st depends of these precedence rules: * 1: program passed with -e - * 2: utmp option + * 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 */ @@ -30,9 +32,9 @@ static float chscale = 1.0; /* * word delimiter string * - * More advanced example: " `'\"()[]{}" + * More advanced example: L" `'\"()[]{}" */ -char *worddelimiters = " "; +wchar_t *worddelimiters = L" "; /* selection timeouts (in milliseconds) */ static unsigned int doubleclicktimeout = 300; @@ -41,9 +43,18 @@ static unsigned int tripleclicktimeout = 600; /* alt screens */ int allowaltscreen = 1; -/* frames per second st should at maximum draw to the screen */ -static unsigned int xfps = 120; -static unsigned int actionfps = 30; +/* 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 @@ -82,28 +93,33 @@ char *termname = "st-256color"; */ unsigned int tabspaces = 8; -/* bg opacity */ -float alpha = 0.9; - /* Terminal colors (16 first used in escape sequence) */ static const char *colorname[] = { - /* solarized dark */ - "#073642", /* 0: black */ - "#dc322f", /* 1: red */ - "#859900", /* 2: green */ - "#b58900", /* 3: yellow */ - "#268bd2", /* 4: blue */ - "#d33682", /* 5: magenta */ - "#2aa198", /* 6: cyan */ - "#eee8d5", /* 7: white */ - "#002b36", /* 8: brblack */ - "#cb4b16", /* 9: brred */ - "#586e75", /* 10: brgreen */ - "#657b83", /* 11: bryellow */ - "#839496", /* 12: brblue */ - "#6c71c4", /* 13: brmagenta*/ - "#93a1a1", /* 14: brcyan */ - "#fdf6e3", /* 15: brwhite */ + /* 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", }; @@ -111,10 +127,10 @@ static const char *colorname[] = { * Default colors (colorname index) * foreground, background, cursor, reverse cursor */ -unsigned int defaultfg = 12; -unsigned int defaultbg = 8; -static unsigned int defaultcs = 14; -static unsigned int defaultrcs = 15; +unsigned int defaultfg = 7; +unsigned int defaultbg = 0; +static unsigned int defaultcs = 256; +static unsigned int defaultrcs = 257; /* * Default shape of cursor @@ -129,8 +145,8 @@ static unsigned int cursorshape = 2; * Default columns and rows numbers */ -static unsigned int cols = 90; -static unsigned int rows = 28; +static unsigned int cols = 80; +static unsigned int rows = 24; /* * Default colour and shape of the mouse cursor @@ -145,48 +161,44 @@ static unsigned int mousebg = 0; */ 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[] = { - /* button mask string */ - { Button4, XK_NO_MOD, "\031" }, - { Button5, XK_NO_MOD, "\005" }, + /* 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) -MouseKey mkeys[] = { - /* button mask function argument */ - { Button4, ShiftMask, kscrollup, {.i = 1} }, - { Button5, ShiftMask, kscrolldown, {.i = 1} }, - { Button4, MODKEY, kscrollup, {.i = 1} }, - { Button5, MODKEY, kscrolldown, {.i = 1} }, - { Button4, TERMMOD, zoom, {.f = +1} }, - { Button5, TERMMOD, zoom, {.f = -1} }, -}; - 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_Up, zoom, {.f = +1} }, - { TERMMOD, XK_Down, zoom, {.f = -1} }, + { 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} }, - { TERMMOD, XK_Insert, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, - { ShiftMask, XK_Up, kscrollup, {.i = -1} }, - { ShiftMask, XK_Down, kscrolldown, {.i = -1} }, - { ShiftMask, XK_k, kscrollup, {.i = -1} }, - { ShiftMask, XK_j, kscrolldown, {.i = -1} }, }; /* @@ -204,10 +216,6 @@ static Shortcut shortcuts[] = { * * 0: no value * * > 0: cursor application mode enabled * * < 0: cursor application mode disabled - * crlf value - * * 0: no value - * * > 0: crlf mode is enabled - * * < 0: crlf mode is 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 @@ -226,13 +234,6 @@ static KeySym mappedkeys[] = { -1 }; */ static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; -/* - * Override mouse-select 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 forceselmod = ShiftMask; - /* * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. diff --git a/config.mk b/config.mk index 1d2f0e2..c070a4a 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # st version -VERSION = 0.8.2 +VERSION = 0.8.4 # Customize below to fit your system @@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ `$(PKG_CONFIG) --cflags freetype2` -LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ +LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ `$(PKG_CONFIG) --libs fontconfig` \ `$(PKG_CONFIG) --libs freetype2` @@ -28,8 +28,8 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) # OpenBSD: #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ -# `pkg-config --libs fontconfig` \ -# `pkg-config --libs freetype2` +# `$(PKG_CONFIG) --libs fontconfig` \ +# `$(PKG_CONFIG) --libs freetype2` # compiler and linker # CC = c99 diff --git a/st b/st new file mode 100755 index 0000000000000000000000000000000000000000..62ad0ef5d03de14b2983504e73566a3b80150ebe GIT binary patch literal 102448 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 c?`] [;]] []] */ typedef struct { char buf[ESC_BUF_SIZ]; /* raw string */ - int len; /* raw string length */ + size_t len; /* raw string length */ char priv; int arg[ESC_ARG_SIZ]; int narg; /* nb of args */ @@ -153,8 +145,9 @@ typedef struct { /* ESC type [[ [] [;]] ] ESC '\' */ typedef struct { char type; /* ESC type ... */ - char buf[STR_BUF_SIZ]; /* raw string */ - int len; /* raw string length */ + char *buf; /* allocated raw string */ + size_t siz; /* allocation size */ + size_t len; /* raw string length */ char *args[STR_ARG_SIZ]; int narg; /* nb of args */ } STREscape; @@ -191,8 +184,8 @@ static void tnewline(int); static void tputtab(int); static void tputc(Rune); static void treset(void); -static void tscrollup(int, int, int); -static void tscrolldown(int, int, int); +static void tscrollup(int, int); +static void tscrolldown(int, int); static void tsetattr(int *, int); static void tsetchar(Rune, Glyph *, int, int); static void tsetdirt(int, int); @@ -217,7 +210,6 @@ static void selsnap(int *, int *, int); static size_t utf8decode(const char *, Rune *, size_t); static Rune utf8decodebyte(char, size_t *); static char utf8encodebyte(Rune, size_t); -static char *utf8strchr(char *, Rune); static size_t utf8validate(Rune *, size_t); static char *base64dec(const char *); @@ -344,23 +336,6 @@ utf8encodebyte(Rune u, size_t i) return utfbyte[i] | (u & ~utfmask[i]); } -char * -utf8strchr(char *s, Rune u) -{ - Rune r; - size_t i, j, len; - - len = strlen(s); - for (i = 0, j = 0; i < len; i += j) { - if (!(j = utf8decode(&s[i], &r, len - i))) - break; - if (r == u) - return &(s[i]); - } - - return NULL; -} - size_t utf8validate(Rune *u, size_t i) { @@ -390,8 +365,9 @@ static const char base64_digits[] = { char base64dec_getc(const char **src) { - while (**src && !isprint(**src)) (*src)++; - return *((*src)++); + while (**src && !isprint(**src)) + (*src)++; + return **src ? *((*src)++) : '='; /* emulate padding if string ends */ } char * @@ -409,6 +385,10 @@ base64dec(const char *src) int c = base64_digits[(unsigned char) base64dec_getc(&src)]; int d = base64_digits[(unsigned char) base64dec_getc(&src)]; + /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */ + if (a == -1 || b == -1) + break; + *dst++ = (a << 2) | ((b & 0x30) >> 4); if (c == -1) break; @@ -434,10 +414,10 @@ tlinelen(int y) { int i = term.col; - if (TLINE(y)[i - 1].mode & ATTR_WRAP) + if (term.line[y][i - 1].mode & ATTR_WRAP) return i; - while (i > 0 && TLINE(y)[i - 1].u == ' ') + while (i > 0 && term.line[y][i - 1].u == ' ') --i; return i; @@ -483,7 +463,7 @@ selextend(int col, int row, int type, int done) selnormalize(); sel.type = type; - if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type) + if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY) tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); sel.mode = done ? SEL_IDLE : SEL_READY; @@ -546,7 +526,7 @@ selsnap(int *x, int *y, int direction) * Snap around if the word wraps around at the end or * beginning of a line. */ - prevgp = &TLINE(*y)[*x]; + prevgp = &term.line[*y][*x]; prevdelim = ISDELIM(prevgp->u); for (;;) { newx = *x + direction; @@ -561,14 +541,14 @@ selsnap(int *x, int *y, int direction) yt = *y, xt = *x; else yt = newy, xt = newx; - if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) + if (!(term.line[yt][xt].mode & ATTR_WRAP)) break; } if (newx >= tlinelen(newy)) break; - gp = &TLINE(newy)[newx]; + gp = &term.line[newy][newx]; delim = ISDELIM(gp->u); if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim || (delim && gp->u != prevgp->u))) @@ -589,14 +569,14 @@ selsnap(int *x, int *y, int direction) *x = (direction < 0) ? 0 : term.col - 1; if (direction < 0) { for (; *y > 0; *y += direction) { - if (!(TLINE(*y-1)[term.col-1].mode + if (!(term.line[*y-1][term.col-1].mode & ATTR_WRAP)) { break; } } } else if (direction > 0) { for (; *y < term.row-1; *y += direction) { - if (!(TLINE(*y)[term.col-1].mode + if (!(term.line[*y][term.col-1].mode & ATTR_WRAP)) { break; } @@ -627,13 +607,13 @@ getsel(void) } if (sel.type == SEL_RECTANGULAR) { - gp = &TLINE(y)[sel.nb.x]; + gp = &term.line[y][sel.nb.x]; lastx = sel.ne.x; } else { - gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; + gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; } - last = &TLINE(y)[MIN(lastx, linelen-1)]; + last = &term.line[y][MIN(lastx, linelen-1)]; while (last >= gp && last->u == ' ') --last; @@ -653,7 +633,8 @@ getsel(void) * st. * FIXME: Fix the computer world. */ - if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP)) + if ((y < sel.ne.y || lastx >= linelen) && + (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR)) *ptr++ = '\n'; } *ptr = 0; @@ -684,7 +665,7 @@ die(const char *errstr, ...) void execsh(char *cmd, char **args) { - char *sh, *prog; + char *sh, *prog, *arg; const struct passwd *pw; errno = 0; @@ -698,13 +679,20 @@ execsh(char *cmd, char **args) if ((sh = getenv("SHELL")) == NULL) sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; - if (args) + if (args) { prog = args[0]; - else if (utmp) + arg = NULL; + } else if (scroll) { + prog = scroll; + arg = utmp ? utmp : sh; + } else if (utmp) { prog = utmp; - else + arg = NULL; + } else { prog = sh; - DEFAULT(args, ((char *[]) {prog, NULL})); + arg = NULL; + } + DEFAULT(args, ((char *[]) {prog, arg, NULL})); unsetenv("COLUMNS"); unsetenv("LINES"); @@ -742,7 +730,7 @@ sigchld(int a) die("child exited with status %d\n", WEXITSTATUS(stat)); else if (WIFSIGNALED(stat)) die("child terminated due to signal %d\n", WTERMSIG(stat)); - exit(0); + _exit(0); } void @@ -835,30 +823,31 @@ ttyread(void) { static char buf[BUFSIZ]; static int buflen = 0; - int written; - int ret; + int ret, written; /* append read bytes to unprocessed bytes */ - if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) + ret = read(cmdfd, buf+buflen, LEN(buf)-buflen); + + switch (ret) { + case 0: + exit(0); + case -1: die("couldn't read from shell: %s\n", strerror(errno)); - buflen += ret; - - written = twrite(buf, buflen, 0); - buflen -= written; - /* keep any uncomplete utf8 char for the next call */ - if (buflen > 0) - memmove(buf, buf + written, buflen); - - return ret; + default: + buflen += ret; + written = twrite(buf, buflen, 0); + buflen -= written; + /* keep any incomplete UTF-8 byte sequence for the next call */ + if (buflen > 0) + memmove(buf, buf + written, buflen); + return ret; + } } void ttywrite(const char *s, size_t n, int may_echo) { const char *next; - Arg arg = (Arg) { .i = term.scr }; - - kscrolldown(&arg); if (may_echo && IS_SET(MODE_ECHO)) twrite(s, n, 1); @@ -1068,53 +1057,15 @@ tswapscreen(void) term.mode ^= MODE_ALTSCREEN; tfulldirt(); } -void -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) +tscrolldown(int orig, int n) { 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); @@ -1128,23 +1079,13 @@ tscrolldown(int orig, int n, int copyhist) } void -tscrollup(int orig, int n, int copyhist) +tscrollup(int orig, int n) { 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); @@ -1163,27 +1104,17 @@ selscroll(int orig, int n) if (sel.ob.x == -1) return; - if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) { - if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) { + if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { + selclear(); + } else if (BETWEEN(sel.nb.y, orig, term.bot)) { + sel.ob.y += n; + sel.oe.y += n; + if (sel.ob.y < term.top || sel.ob.y > term.bot || + sel.oe.y < term.top || sel.oe.y > term.bot) { selclear(); - return; - } - if (sel.type == SEL_RECTANGULAR) { - if (sel.ob.y < term.top) - sel.ob.y = term.top; - if (sel.oe.y > term.bot) - sel.oe.y = term.bot; } else { - if (sel.ob.y < term.top) { - sel.ob.y = term.top; - sel.ob.x = 0; - } - if (sel.oe.y > term.bot) { - sel.oe.y = term.bot; - sel.oe.x = term.col; - } + selnormalize(); } - selnormalize(); } } @@ -1193,7 +1124,7 @@ tnewline(int first_col) int y = term.c.y; if (y == term.bot) { - tscrollup(term.top, 1, 1); + tscrollup(term.top, 1); } else { y++; } @@ -1358,14 +1289,14 @@ void tinsertblankline(int n) { if (BETWEEN(term.c.y, term.top, term.bot)) - tscrolldown(term.c.y, n, 0); + tscrolldown(term.c.y, n); } void tdeleteline(int n) { if (BETWEEN(term.c.y, term.top, term.bot)) - tscrollup(term.c.y, n, 0); + tscrollup(term.c.y, n); } int32_t @@ -1633,6 +1564,7 @@ tsetmode(int priv, int set, int *args, int narg) case 1015: /* urxvt mangled mouse mode; incompatible and can be mistaken for other control codes. */ + break; default: fprintf(stderr, "erresc: unknown private set/reset mode %d\n", @@ -1714,6 +1646,12 @@ csihandle(void) if (csiescseq.arg[0] == 0) ttywrite(vtiden, strlen(vtiden), 0); break; + case 'b': /* REP -- if last char is printable print it more times */ + DEFAULT(csiescseq.arg[0], 1); + if (term.lastc) + while (csiescseq.arg[0]-- > 0) + tputc(term.lastc); + break; case 'C': /* CUF -- Cursor Forward */ case 'a': /* HPR -- Cursor Forward */ DEFAULT(csiescseq.arg[0], 1); @@ -1795,11 +1733,11 @@ csihandle(void) break; case 'S': /* SU -- Scroll line up */ DEFAULT(csiescseq.arg[0], 1); - tscrollup(term.top, csiescseq.arg[0], 0); + tscrollup(term.top, csiescseq.arg[0]); break; case 'T': /* SD -- Scroll line down */ DEFAULT(csiescseq.arg[0], 1); - tscrolldown(term.top, csiescseq.arg[0], 0); + tscrolldown(term.top, csiescseq.arg[0]); break; case 'L': /* IL -- Insert blank lines */ DEFAULT(csiescseq.arg[0], 1); @@ -1837,7 +1775,7 @@ csihandle(void) break; case 'n': /* DSR – Device Status Report (cursor position) */ if (csiescseq.arg[0] == 6) { - len = snprintf(buf, sizeof(buf),"\033[%i;%iR", + len = snprintf(buf, sizeof(buf), "\033[%i;%iR", term.c.y+1, term.c.x+1); ttywrite(buf, len, 0); } @@ -1874,7 +1812,7 @@ csihandle(void) void csidump(void) { - int i; + size_t i; uint c; fprintf(stderr, "ESC["); @@ -1904,7 +1842,7 @@ csireset(void) void strhandle(void) { - char *p = NULL; + char *p = NULL, *dec; int j, narg, par; term.esc &= ~(ESC_STR_END|ESC_STR); @@ -1921,9 +1859,7 @@ strhandle(void) xsettitle(strescseq.args[1]); return; case 52: - if (narg > 2) { - char *dec; - + if (narg > 2 && allowwindowops) { dec = base64dec(strescseq.args[2]); if (dec) { xsetsel(dec); @@ -1941,7 +1877,10 @@ strhandle(void) case 104: /* color reset, here p = NULL */ j = (narg > 1) ? atoi(strescseq.args[1]) : -1; if (xsetcolorname(j, p)) { - fprintf(stderr, "erresc: invalid color %s\n", p); + if (par == 104 && narg <= 1) + return; /* color reset without parameter */ + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); } else { /* * TODO if defaultbg color is changed, borders @@ -1956,7 +1895,6 @@ strhandle(void) xsettitle(strescseq.args[0]); return; case 'P': /* DCS -- Device Control String */ - term.mode |= ESC_DCS; case '_': /* APC -- Application Program Command */ case '^': /* PM -- Privacy Message */ return; @@ -1991,7 +1929,7 @@ strparse(void) void strdump(void) { - int i; + size_t i; uint c; fprintf(stderr, "ESC%c", strescseq.type); @@ -2018,7 +1956,10 @@ strdump(void) void strreset(void) { - memset(&strescseq, 0, sizeof(strescseq)); + strescseq = (STREscape){ + .buf = xrealloc(strescseq.buf, STR_BUF_SIZ), + .siz = STR_BUF_SIZ, + }; } void @@ -2076,7 +2017,7 @@ tdumpline(int n) bp = &term.line[n][0]; end = &bp[MIN(tlinelen(n), term.col) - 1]; if (bp != end || bp->u != ' ') { - for ( ;bp <= end; ++bp) + for ( ; bp <= end; ++bp) tprinter(buf, utf8encode(bp->u, buf)); } tprinter("\n", 1); @@ -2147,12 +2088,9 @@ tdectest(char c) void tstrsequence(uchar c) { - strreset(); - switch (c) { case 0x90: /* DCS -- Device Control String */ c = 'P'; - term.esc |= ESC_DCS; break; case 0x9f: /* APC -- Application Program Command */ c = '_'; @@ -2164,6 +2102,7 @@ tstrsequence(uchar c) c = ']'; break; } + strreset(); strescseq.type = c; term.esc |= ESC_STR; } @@ -2206,6 +2145,7 @@ tcontrolcode(uchar ascii) return; case '\032': /* SUB */ tsetchar('?', &term.c.attr, term.c.x, term.c.y); + /* FALLTHROUGH */ case '\030': /* CAN */ csireset(); break; @@ -2301,7 +2241,7 @@ eschandle(uchar ascii) return 0; case 'D': /* IND -- Linefeed */ if (term.c.y == term.bot) { - tscrollup(term.top, 1, 1); + tscrollup(term.top, 1); } else { tmoveto(term.c.x, term.c.y+1); } @@ -2314,7 +2254,7 @@ eschandle(uchar ascii) break; case 'M': /* RI -- Reverse index */ if (term.c.y == term.top) { - tscrolldown(term.top, 1, 1); + tscrolldown(term.top, 1); } else { tmoveto(term.c.x, term.c.y-1); } @@ -2360,15 +2300,13 @@ tputc(Rune u) Glyph *gp; control = ISCONTROL(u); - if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { + if (u < 127 || !IS_SET(MODE_UTF8)) { c[0] = u; width = len = 1; } else { len = utf8encode(u, c); - if (!control && (width = wcwidth(u)) == -1) { - memcpy(c, "\357\277\275", 4); /* UTF_INVALID */ + if (!control && (width = wcwidth(u)) == -1) width = 1; - } } if (IS_SET(MODE_PRINT)) @@ -2383,25 +2321,12 @@ tputc(Rune u) if (term.esc & ESC_STR) { if (u == '\a' || u == 030 || u == 032 || u == 033 || ISCONTROLC1(u)) { - term.esc &= ~(ESC_START|ESC_STR|ESC_DCS); - if (IS_SET(MODE_SIXEL)) { - /* TODO: render sixel */; - term.mode &= ~MODE_SIXEL; - return; - } + term.esc &= ~(ESC_START|ESC_STR); term.esc |= ESC_STR_END; goto check_control_code; } - - if (IS_SET(MODE_SIXEL)) { - /* TODO: implement sixel mode */ - return; - } - if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q') - term.mode |= MODE_SIXEL; - - if (strescseq.len+len >= sizeof(strescseq.buf)-1) { + if (strescseq.len+len >= strescseq.siz) { /* * Here is a bug in terminals. If the user never sends * some code to stop the str or esc command, then st @@ -2415,7 +2340,10 @@ tputc(Rune u) * term.esc = 0; * strhandle(); */ - return; + if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2) + return; + strescseq.siz *= 2; + strescseq.buf = xrealloc(strescseq.buf, strescseq.siz); } memmove(&strescseq.buf[strescseq.len], c, len); @@ -2434,6 +2362,8 @@ check_control_code: /* * control codes are not shown ever */ + if (!term.esc) + term.lastc = 0; return; } else if (term.esc & ESC_START) { if (term.esc & ESC_CSI) { @@ -2464,7 +2394,7 @@ check_control_code: */ return; } - if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y)) + if (selected(term.c.x, term.c.y)) selclear(); gp = &term.line[term.c.y][term.c.x]; @@ -2483,6 +2413,7 @@ check_control_code: } tsetchar(u, &term.c.attr, term.c.x, term.c.y); + term.lastc = u; if (width == 2) { gp->mode |= ATTR_WIDE; @@ -2506,7 +2437,7 @@ twrite(const char *buf, int buflen, int show_ctrl) int n; for (n = 0; n < buflen; n += charsize) { - if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { + if (IS_SET(MODE_UTF8)) { /* process a complete utf8 char */ charsize = utf8decode(buf + n, &u, buflen - n); if (charsize == 0) @@ -2533,7 +2464,7 @@ twrite(const char *buf, int buflen, int show_ctrl) void tresize(int col, int row) { - int i, j; + int i; int minrow = MIN(row, term.row); int mincol = MIN(col, term.col); int *bp; @@ -2570,14 +2501,6 @@ tresize(int col, int row) term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); - for (i = 0; i < HISTSIZE; i++) { - term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); - for (j = mincol; j < col; j++) { - term.hist[i][j] = term.c.attr; - term.hist[i][j].u = ' '; - } - } - /* resize each row to new width, zero-pad if needed */ for (i = 0; i < minrow; i++) { term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); @@ -2630,19 +2553,20 @@ void drawregion(int x1, int y1, int x2, int y2) { int y; + for (y = y1; y < y2; y++) { if (!term.dirty[y]) continue; term.dirty[y] = 0; - xdrawline(TLINE(y), x1, y, x2); + xdrawline(term.line[y], x1, y, x2); } } void draw(void) { - int cx = term.c.x; + int cx = term.c.x, ocx = term.ocx, ocy = term.ocy; if (!xstartdraw()) return; @@ -2656,11 +2580,13 @@ draw(void) cx--; drawregion(0, 0, term.col, term.row); - if (term.scr == 0) - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], + 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; + term.ocx = cx; + term.ocy = term.c.y; xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) + xximspot(term.ocx, term.ocy); } void diff --git a/st.h b/st.h index c3ecbdc..3d351b6 100644 --- a/st.h +++ b/st.h @@ -74,21 +74,13 @@ typedef union { uint ui; float f; const void *v; + const char *s; } Arg; -typedef struct { - uint b; - uint mask; - void (*func)(const Arg *); - const Arg arg; -} MouseKey; - void die(const char *, ...); void redraw(void); void draw(void); -void kscrolldown(const Arg *); -void kscrollup(const Arg *); void printscreen(const Arg *); void printsel(const Arg *); void sendbreak(const Arg *); @@ -121,13 +113,13 @@ char *xstrdup(char *); /* config.h globals */ extern char *utmp; +extern char *scroll; extern char *stty_args; extern char *vtiden; -extern char *worddelimiters; +extern wchar_t *worddelimiters; extern int allowaltscreen; +extern int allowwindowops; extern char *termname; extern unsigned int tabspaces; extern unsigned int defaultfg; extern unsigned int defaultbg; -extern float alpha; -extern MouseKey mkeys[]; diff --git a/st.info b/st.info index 52fc617..8201ad6 100644 --- a/st.info +++ b/st.info @@ -1,4 +1,4 @@ -st| simpleterm, +st-mono| simpleterm monocolor, acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, am, bce, @@ -10,7 +10,7 @@ st| simpleterm, civis=\E[?25l, clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, - colors#8, + colors#2, cols#80, cr=^M, csr=\E[%i%p1%d;%p2%dr, @@ -158,6 +158,7 @@ st| simpleterm, rc=\E8, rev=\E[7m, ri=\EM, + rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, rmcup=\E[?1049l, @@ -168,13 +169,8 @@ st| simpleterm, rs1=\Ec, rs2=\E[4l\E>\E[?1034l, sc=\E7, - setab=\E[4%p1%dm, - setaf=\E[3%p1%dm, - setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, - setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, - sgr0=\E[0m, - sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, sitm=\E[3m, + sgr0=\E[0m, smacs=\E(0, smcup=\E[?1049h, smir=\E[4h, @@ -188,11 +184,22 @@ st| simpleterm, # XTerm extensions rmxx=\E[29m, smxx=\E[9m, +# disabled rep for now: causes some issues with older ncurses versions. +# rep=%p1%c\E[%p2%{1}%-%db, # tmux extensions, see TERMINFO EXTENSIONS in tmux(1) - Se, - Ss, Tc, Ms=\E]52;%p1%s;%p2%s\007, + Se=\E[2 q, + Ss=\E[%p1%d q, + +st| simpleterm, + use=st-mono, + colors#8, + setab=\E[4%p1%dm, + setaf=\E[3%p1%dm, + setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, + setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, + sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, st-256color| simpleterm with 256 colors, use=st, @@ -220,3 +227,13 @@ st-meta-256color| simpleterm with meta key and 256 colors, smm=\E[?1034h, rs2=\E[4l\E>\E[?1034h, is2=\E[4l\E>\E[?1034h, + +st-bs| simpleterm with backspace as backspace, + use=st, + kbs=\010, + kdch1=\177, + +st-bs-256color| simpleterm with backspace as backspace and 256colors, + use=st-256color, + kbs=\010, + kdch1=\177, diff --git a/st.o b/st.o new file mode 100644 index 0000000000000000000000000000000000000000..bd192bbe7573d33d2940c774de00238763983310 GIT binary patch literal 73552 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 literal 0 HcmV?d00001 diff --git a/win.h b/win.h index 31f327d..a6ef1b9 100644 --- a/win.h +++ b/win.h @@ -36,3 +36,4 @@ void xsetmode(int, unsigned int); void xsetpointermotion(int); void xsetsel(char *); int xstartdraw(void); +void xximspot(int, int); diff --git a/x.c b/x.c index ff0493d..210f184 100644 --- a/x.c +++ b/x.c @@ -15,7 +15,7 @@ #include #include -static char *argv0; +char *argv0; #include "arg.h" #include "st.h" #include "win.h" @@ -29,9 +29,11 @@ typedef struct { } Shortcut; typedef struct { - uint b; - uint mask; - char *s; + uint mod; + uint button; + void (*func)(const Arg *); + const Arg arg; + uint release; } MouseShortcut; typedef struct { @@ -56,6 +58,7 @@ 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" @@ -91,14 +94,17 @@ typedef struct { Drawable buf; GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ Atom xembed, wmdeletewin, netwmname, netwmpid; - XIM xim; - XIC xic; + struct { + XIM xim; + XIC xic; + XPoint spot; + XVaNestedList spotlist; + } ime; Draw draw; Visual *vis; XSetWindowAttributes attrs; int scr; int isfixed; /* is fixed geometry? */ - int depth; /* bit depth */ int l, t; /* left and top offset */ int gm; /* geometry mask */ } XWindow; @@ -140,6 +146,10 @@ 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); @@ -161,6 +171,8 @@ 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 *); @@ -224,13 +236,13 @@ typedef struct { } Fontcache; /* Fontcache is an array now. A new font will be appended to the array. */ -static Fontcache frc[16]; +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_alpha = NULL; static char *opt_class = NULL; static char **opt_cmd = NULL; static char *opt_embed = NULL; @@ -310,6 +322,12 @@ zoomreset(const Arg *arg) } } +void +ttysend(const Arg *arg) +{ + ttywrite(arg->s, strlen(arg->s), 1); +} + int evcol(XEvent *e) { @@ -330,7 +348,7 @@ void mousesel(XEvent *e, int done) { int type, seltype = SEL_REGULAR; - uint state = e->xbutton.state & ~(Button1Mask | forceselmod); + uint state = e->xbutton.state & ~(Button1Mask | forcemousemod); for (type = 1; type < LEN(selmasks); ++type) { if (match(selmasks[type], state)) { @@ -406,34 +424,51 @@ mousereport(XEvent *e) 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; - MouseShortcut *ms; - MouseKey *mk; int snap; - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { mousereport(e); return; } - for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { - if (e->xbutton.button == ms->b - && match(ms->mask, e->xbutton.state)) { - ttywrite(ms->s, strlen(ms->s), 1); - return; - } - } - - for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) { - if (e->xbutton.button == mk->b - && match(mk->mask, e->xbutton.state)) { - mk->func(&mk->arg); - return; - } - } + if (mouseaction(e, 0)) + return; if (e->xbutton.button == Button1) { /* @@ -649,21 +684,21 @@ xsetsel(char *str) void brelease(XEvent *e) { - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { mousereport(e); return; } - if (e->xbutton.button == Button2 || e->xbutton.button == Button3) - selpaste(NULL); - else if (e->xbutton.button == Button1) + 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 & forceselmod)) { + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { mousereport(e); return; } @@ -699,7 +734,7 @@ xresize(int col, int row) XFreePixmap(xw.dpy, xw.buf); xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, - xw.depth); + DefaultDepth(xw.dpy, xw.scr)); XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); @@ -759,13 +794,6 @@ xloadcols(void) else die("could not allocate color %d\n", i); } - - /* set alpha value of bg color */ - if (opt_alpha) - alpha = strtof(opt_alpha, NULL); - dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha); - dc.col[defaultbg].pixel &= 0x00FFFFFF; - dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24; loaded = 1; } @@ -777,7 +805,6 @@ xsetcolorname(int x, const char *name) if (!BETWEEN(x, 0, dc.collen)) return 1; - if (!xloadcolor(x, name, &ncolor)) return 1; @@ -1014,6 +1041,60 @@ xunloadfonts(void) 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) { @@ -1022,23 +1103,11 @@ xinit(int cols, int rows) Window parent; pid_t thispid = getpid(); XColor xmousefg, xmousebg; - XWindowAttributes attr; - XVisualInfo vis; if (!(xw.dpy = XOpenDisplay(NULL))) die("can't open display\n"); xw.scr = XDefaultScreen(xw.dpy); - - if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) { - parent = XRootWindow(xw.dpy, xw.scr); - xw.depth = 32; - } else { - XGetWindowAttributes(xw.dpy, parent, &attr); - xw.depth = attr.depth; - } - - XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis); - xw.vis = vis.visual; + xw.vis = XDefaultVisual(xw.dpy, xw.scr); /* font */ if (!FcInit()) @@ -1048,7 +1117,7 @@ xinit(int cols, int rows) xloadfonts(usedfont, 0); /* colors */ - xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); xloadcols(); /* adjust fixed window geometry */ @@ -1063,20 +1132,24 @@ xinit(int cols, int rows) 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 + 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, xw.depth, InputOutput, + 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; - xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); - dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues); + 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); @@ -1087,22 +1160,10 @@ xinit(int cols, int rows) xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); /* input methods */ - if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { - XSetLocaleModifiers("@im=local"); - if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { - XSetLocaleModifiers("@im="); - if ((xw.xim = XOpenIM(xw.dpy, - NULL, NULL, NULL)) == NULL) { - die("XOpenIM failed. Could not open input" - " device.\n"); - } - } + if (!ximopen(xw.dpy)) { + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); } - xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing - | XIMStatusNothing, XNClientWindow, xw.win, - XNFocusWindow, xw.win, NULL); - if (xw.xic == NULL) - die("XCreateIC failed. Could not obtain input method.\n"); /* white cursor, black outline */ cursor = XCreateFontCursor(xw.dpy, mouseshape); @@ -1133,8 +1194,8 @@ xinit(int cols, int rows) win.mode = MODE_NUMLOCK; resettitle(); - XMapWindow(xw.dpy, xw.win); xhints(); + XMapWindow(xw.dpy, xw.win); XSync(xw.dpy, False); clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); @@ -1244,13 +1305,10 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres); - /* - * Overwrite or create the new cache entry. - */ - if (frclen >= LEN(frc)) { - frclen = LEN(frc) - 1; - XftFontClose(xw.dpy, frc[frclen].font); - frc[frclen].unicodep = 0; + /* Allocate memory for the new cache entry. */ + if (frclen >= frccap) { + frccap += 16; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); } frc[frclen].font = XftFontOpenPattern(xw.dpy, @@ -1468,8 +1526,9 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { - case 7: /* st extension: snowman (U+2603) */ - g.u = 0x2603; + case 7: /* st extension */ + g.u = 0x2603; /* snowman (U+2603) */ + /* FALLTHROUGH */ case 0: /* Blinking Block */ case 1: /* Blinking Block (Default) */ case 2: /* Steady Block */ @@ -1580,6 +1639,18 @@ xfinishdraw(void) 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) { @@ -1619,8 +1690,7 @@ xsetmode(int set, unsigned int flags) int xsetcursor(int cursor) { - DEFAULT(cursor, 1); - if (!BETWEEN(cursor, 0, 6)) + if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ return 1; win.cursor = cursor; return 0; @@ -1654,13 +1724,15 @@ focus(XEvent *ev) return; if (ev->type == FocusIn) { - XSetICFocus(xw.xic); + 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 { - XUnsetICFocus(xw.xic); + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); win.mode &= ~MODE_FOCUSED; if (IS_SET(MODE_FOCUS)) ttywrite("\033[O", 3, 0); @@ -1715,7 +1787,7 @@ kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; KeySym ksym; - char buf[32], *customkey; + char buf[64], *customkey; int len; Rune c; Status status; @@ -1724,7 +1796,10 @@ kpress(XEvent *ev) if (IS_SET(MODE_KBDLOCK)) return; - len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); + 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)) { @@ -1757,7 +1832,6 @@ kpress(XEvent *ev) ttywrite(buf, len, 1); } - void cmessage(XEvent *e) { @@ -1793,10 +1867,9 @@ run(void) XEvent ev; int w = win.w, h = win.h; fd_set rfd; - int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0; - int ttyfd; - struct timespec drawtimeout, *tv = NULL, now, last, lastblink; - long deltatime; + int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing; + struct timespec seltv, *tv, now, lastblink, trigger; + double timeout; /* Waiting for window mapping */ do { @@ -1817,82 +1890,77 @@ run(void) ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); cresize(w, h); - clock_gettime(CLOCK_MONOTONIC, &last); - lastblink = last; - - for (xev = actionfps;;) { + 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)); } - if (FD_ISSET(ttyfd, &rfd)) { - ttyread(); - if (blinktimeout) { - blinkset = tattrset(ATTR_BLINK); - if (!blinkset) - MODBIT(win.mode, 0, MODE_BLINK); - } - } - - if (FD_ISSET(xfd, &rfd)) - xev = actionfps; - clock_gettime(CLOCK_MONOTONIC, &now); - drawtimeout.tv_sec = 0; - drawtimeout.tv_nsec = (1000 * 1E6)/ xfps; - tv = &drawtimeout; - dodraw = 0; - if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) { - tsetdirtattr(ATTR_BLINK); - win.mode ^= MODE_BLINK; - lastblink = now; - dodraw = 1; - } - deltatime = TIMEDIFF(now, last); - if (deltatime > 1000 / (xev ? xfps : actionfps)) { - dodraw = 1; - last = 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); } - if (dodraw) { - while (XPending(xw.dpy)) { - 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 */ + } - draw(); - XFlush(xw.dpy); - - if (xev && !FD_ISSET(xfd, &rfd)) - xev--; - if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) { - if (blinkset) { - if (TIMEDIFF(now, lastblink) \ - > blinktimeout) { - drawtimeout.tv_nsec = 1000; - } else { - drawtimeout.tv_nsec = (1E6 * \ - (blinktimeout - \ - TIMEDIFF(now, - lastblink))); - } - drawtimeout.tv_sec = \ - drawtimeout.tv_nsec / 1E9; - drawtimeout.tv_nsec %= (long)1E9; - } else { - tv = NULL; - } + /* 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; } } @@ -1914,15 +1982,12 @@ main(int argc, char *argv[]) { xw.l = xw.t = 0; xw.isfixed = False; - win.cursor = cursorshape; + xsetcursor(cursorshape); ARGBEGIN { case 'a': allowaltscreen = 0; break; - case 'A': - opt_alpha = EARGF(usage()); - break; case 'c': opt_class = EARGF(usage()); break; diff --git a/x.o b/x.o new file mode 100644 index 0000000000000000000000000000000000000000..47f7c53195e75baffc6585ff2119cb0164cc1777 GIT binary patch literal 73688 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 I}ApZIHv ze@gmc7%&?jzaq|UlDShiy3nbpT>{^CUF^Vz1D)cf@a;nQTMZwCtt*3X-!B_Ge^VLJA zuDr6K$bJ#AuCTngpxP-abn2EAEG}MDzPzdwKg?QFRa{u(lvG1-1s)1PJsh06BKVe_ zlImtoaa~nqO);hwuC0bIITkJlo0oLiT(+dFq9$y!!HP8S^t*LPq)1erAQd@yV zVDb*%Iy9dJuC9edAp?a=ip;UB(j4&fjE?=}VYPE*W#y8Bh22gu0OG?}j4{YTrNu>~ z$C{YtTa*q|8|xU87$#7>WFdS`b98Q2D*hRRf5zgUarh?<|BS~!6Y$TO_$LGZq~o74 zHi{7+W8}w}2xE+vF(%#^6LE}*ImX5^3dWkaV{Ljy!&swXtkE#m#2stmjx}+|nz&<4 z+;JxEI1_iAHP*x(XX1`CamSgs<4oK%BcEm^jh-|sZ?vVESZPLEnu(QWG^Clh<1IIm zu}qPW`0pL!62%4XXye7SRJ zs#8=}jNk3d!ml(3@e9$@u`%=@=EI!M{Q1xd3m4BXEL}Vwzv>C!q_z!f5lV-kiO+A4zqr%edI-i1dAb)1@qB7_w^-nqkJhjAh_4%fv z&w|lGx;78`_~Pnt859xp;n009g7#HhSB7ceRq;jUlf2^d<@q6KZQ){yxZGJ%yri(S z8e>~0Ve7MzxxbgXIC6I05{p_J?e#HlD=W}_AqIr(|^ySz>qJ}qoM!k<5-ycRw~4-N#_wo}`S&MG#|s4EP5Z72lOv`q?Tpsp){Putg&+6JEmCI_K& zF%^GGB~<9@%37FB)WNg`Kl*PQM3((lvazVD61oSd*>+BWHZH;PGx@O@s9Ol1%Z7;_ zObjuv%L>ZFH86vKW?rxmJ2Qxa-50b}v_03HPOB^`D=90khPHr(0QIP<49WmoWypS; z-+|h127p;s7hhgjR#RJm{XhyUbTDD)w)1CJR`O34aLiC~Rk)O^k!?48 zH8so0hq_VT)s1q8Y3m$|nHp;|jY?q}ltovjqcKKcw`mHRgCNfrO@kr|R|2kqt{414 z#XPN`itU)SyrK|2Ra~(YYXtrp0aQus|EAKnz5!Ph!JMvOu@kOb1YNyp#!$h{kvwkC zp*q5(wWg||5IP%ECd*9UQdw2wEUT<8DuM)-KsO8SUm7kef|Ba`);9d~M0F(;XKi>% z72O`dyD)acBi@Uwr|To>$eiDk2`J9;XDPmxu5%Q>hpzc~E$esbxnG5nzn`v`dGM<} zcvSKG_?ptebZ5gplJtCCNo>*o|_Jv)RRe8+7VaC zD?o9Iy>$zRXV^}=-hLWC*@LU@= z43_CWr8uYCsyL_nGI7*#7wnv`PQm{y_+S)-jnn;s?7`>el5=}JMex6X0P9Z|98Zf# z&)LNBuujOkLjJFUFB2S3xxf0g;@mGirTAd-Z$DUv$Bpxa?<3+CQk?ykLmbup4R+2K zK5xa1_1tDJolgYEwO*G0PVmbFKN_Cv;l_IICwuVursUVzOXqjQ(Vn|uXZ?Q?9DTt2 z0m1(+_>)5ae8IN~`F{wG&oOaB^A^C)`tdm?ZfMWFurvQua4ak4UkmQM+bzv8Pcc1C&dbj7bH`N@iNxlbjI_Fx@nd+>QEZfp;yJ5O=ezeI7C z$LFC^56d?x&i4F@INBrY;qR0@>%Yr`|6S<8F`4uAkl+sp-mLVnoi8iS>9#A*^7|C$ zeEmRN=W9R$dZ*jZtmi1jIo-1qXZgE`qy7hB@5--|ugAn-+oCw@d0ObfcMVz33m)=s z3i*eH{Ck2wBKU5hr$F#;g!~yX&m{v2fssc9;g1P zIFD-&3H}$6Za-LW$4%!eQE|@K5sGuZh7i~JI#J70zJ>|@S4f}zP$M|%Vn1K0INP&I zakl4L;@Y0SD|w!`Z&#e_&-03}1)FetQ}J~cI|CB!3H$Rl;zJZ?{U<2CmgG-Yob^vq z{7#b3SNtC0mnqKrs}yJX)r#|crinQE6K&!0`X43FdNwQ0dY%$`9u<0addR;k0JAFuSS^u9B zT(;Ar=pS%#e%b!x6=(YcinIO0iR*STL&kiBw*T6=%Oy2|XKxo?j?=*7HlnSNg-b-_%;vuSA={V$Pa}b zw>O3S7Pw}=edZzmwczM$_Rn`h&sL#l6#Ww#^s`KNEOFE!(_JRGoDW~?!Ef;3{~(U( zN`KxbWD^vHB` z1(*HFm4ZJd^!!@rFA;pL;EM!bC-gim_`O2DRPcv9??hvkBLlJNw#L5i=p*g0Nt)_mh#Hl3q9`%f*a^EAkwDW7BNBSq09<*R|X^&5E^ga9S6v0uR z%Vn(K(*8-rQC8Z2zK8rA5BVYw`3evDI>BW>|BTRsHu1RJD&+qy^81F857GSROTm{2 z`TasqtKjkUf-CxYo8U(ZULp9g#L-4Mew`}hF>E&3GfMDEp=XlN^Mc@6LLT+-ym5x& z=ac>`1(*37J@Mr#n`0PB%kwPWK$*I$c-E zvz{4>v!2;P&l|%2C4#>xc%9Po0EFT8Cn3KRuDPD9^N?>5^36hiFnth0`~Nt_*?vE9 z^ut?1Pon@MR#&<@hLZO!IBQTLs@K_+Ft0CtF&bu#}j9HZl@_8JVSBTpG6$Y>V4Q*e~yypdB`P-bGj9R zuMm1_h@<|Uf?rDEHl|1|H=R*Et(8u|@S;>E3QiFG66yHs}S@5fco*jZ;BltUlqpdHIo^KT2NqoR5 z_9PY#QvVTxuY@qR|1`m+{?UqazRpsd?a3#OI@*N(g@ViWey!5O?dulBxt%^N^t228 z+lBlb!9Nr7p9nr802i>Kf6!KLzqx|X2G0IjMI2?($IRo0!3Au{Wj{Pva4A2QxK4ML zknaFptbc{z(r=AQ57*~4LLTcH>-nwVm{;b15&ToZA5r@6gfQGTDZb8P=V`@nBi^bw z>v>mk*5jONBceY)gPrX>ggE<++oMl$PWLFq?;(4JD!!KZDT)t{u>q$m&VD|FINJF+ z>}=-*5Bakd=jVVk6=y%>E6#qKuQ>O6Ma0pbJ;I&}CC~Y)RlJDud!^8`SLj)(TEY9B4i~U-yXfk-J^1m&IZgIk zhLD%`M}_>4kPgfLM(~FP-zoHP8ff3ULSELN?}hwzLeEhnFqX}ig~u;X?>aZdNl(KejRk<&d#aW3C%#kqWQ73cE3fH>MB%Qs)k zQ$1NCoinIRTD$e?E_t1Zrl4m{tRGia&R&mz6 z*q-IZ?fn$u=zsh+G}o(9N}lfr;bSId<8o&`8A4Bj(37d;)2QD#PjS|Nf#R(HLZSZ< zp?`tk&0rbZf0f|UKdY2}?tku9d??v@WSY${`bYLZuMlTHV4KA4EyeG&*x9T2Zj1=q ze#O}jor?4Qb^q};9;eIxIg~isd6@9e;aZ;ZHB@o#$A$?m`$PCNjoCO|wtu4HY)>X} zv?oc}bH0$5{Z+o;7$=wPEK{7@QH|oWN&afZxqYox{6dnyN%48ae=qniz#gtw>xiR` z_**K>pAhmG_BiR;?!o`9c$nnhRGjO>dy2E4KPHZ8%IEK2DtWf2Q}O#D9&U$EutzRm z<^kfUU(Sa!lsu1j*@|<$TCMnQ%I~ifZzF!2;vW$I8*#Mf2w?30`-S|UAdGpd;L`;^ z=1jPN4fA^x=;7y;mkW+*6rm7oHxNg5v`F_aN`9V^cAS4GPPZG*YM@s)-;&Zi#yOU3co8*bk#zQSTBCf%N(KQUeA{fVRB zjumz$ddMHH_)3U}+tEVLaYD~9!LiR~e~uJ-Fl}xxlRS7(=s8~K$x-rL5Azgf{d0sK z{H+_dXP%NThcMgDTH>g~FYNh? zl8-0*?-BBjkbgkQbHBYo@jEGBTNLMh`+3EAoPA00ugIQVigSKD6zBZ@s5tja12U{( z+#fPOLUGoAg5s<{RdIfg?ko?UDYzUT&llX(XUgv!#a9rYr}*{67b?Dn_!7nWeXTmh zx!kW&{3X(Jt>Uw(e1AtAZ9fTQx!$f*^6bxh6=#3mFZ7%&^lVV_+`cv|&ibEGob|T~ z{ig{1uPS*SuR9dy`uT<8T+jC_&h_Dd;#}Vn&gxkY+0Mg=qdx<}&cRAP5yEggS8>)8 z5_*OSJ?ATVp6|_6ob_C+IQzLmarRGGarVzuinIMIiDQ2Ez|QsOIwe1t^4lc1Y)7{W zj=Fvz`9CSn`TeWnoZo*CM;&s0`>>Md{5C7j`Q4#7r~A6%oUdJqvppXYM|(~c<+xXH zxjwdE>A|rRw@$_5iT9sq!?{1?_H~%zZ0BIb+0J8#qn)P-JN-(&h|)bxan=*^;5kBn ziqL#|6leXbgns0ybo~!_N5{NSy0W0MfwiD8bjj zHOn6_xYU2LhyLM8ekAE1FZeHo{z-yM{Xq}?u98n9{j(M4bmuD0^=+ZzKcEv}TSOdf zK^^Re8X^BH2xESw;L`qUgdXYtsFI&V_WxCJwsXDWKcJDYJwP1O+yy(^^O%z7`QBzB zKT71QRmpR@uPXinq=DN`p=Y$v)8--nsgOTI$bY5eU$W|*148~|V4SahXIlZTw;zza zk2v~4${(fVn@Rp8#kUh5Blxd@ak}Y(%kn*&I5Jtjvz7egq`y#c_VeX}-z3sqA@sj3 zc%zWNS@1PNK2`YnX2Hh@{6gX|dj=Bc^8E_Ja63lGOM6aK@*j}=d5VXu8s}mUJy$7ts(#KdJml|D@@b_1F%S8- zl>A7N-|ZovbgmU(Kk&T$c;e_w>4$)j{}Y69y&WO=Zv-DN^vLIHvxNLDLjDrLF>M-d zoFc_JUsa0FgE+XY68u)UW;?GXj=H5izY_Al74o-u$UiCMQP&T!0YXad9 z`Wg2pMR{Nt^T`xH0U>P6rw~uHxQm}hJX!JS#0M)rllTzDFC;!xaV`(P;+K(pK=Fmd zQxq>D&gI7Wx}12blCL1n^_}IpCCO&ivNk^OBMfy!UavU+e)TTJ z`FGLxD9*o6zF%?veRX_hha20&zsHVifXtKOgny3|@2wy)@&kXjDpm0zq$f}Dp~R~c_Y+^Ec!2nN#rb!7TNNKk@_Q6d zCC>T4;AGg-h;umeiNy2h$UKv-s}v8>^%})px?ZpN47zSrd=_2rQT!6RPR2<#Y;4bb z;`aBTyLk!mJSD%Fc$MPzch((ejpFuq*5UiRieE)~S{45}@jZ%PM?5*cr~TIxPgR`# zn5XzHBwwZYZN%3oeh2aOivNXptK#<%-=jE}Uoy30_CLR`n5ww_{dLF5Q~XiVU#0j4 z;%gM&NPNBGTZy+SZhx;G+OOitB%j>Br~jWPo~k&v(>%p@kbITm+#c5`ZhsFR>W|{w zFSRQE2I=3UIDaoYc|cG5KVj6o=7}7 zp{M;m(vzzAQN;5UKc0A%;`aCB!G6U@ko_`;(sRn>lNqztyOUz zNA@Vr<4$s7Py2a%NmZQ3mpsLJeBtl4azD)D%NiwrJ>_@3;yk{zD$e7}9>sZlNj|Kn z{XD*;D$e6ep5lKce^x1eH}N%!^ZanV;ygcWRh;LCdlcvSVRBMW`+44ysyNSE@)YNJ zOO@h0Z&{-_&s)|j{twD;tKvK#+oL$o$C7h-Z`18c~D9*pfkc^W~*tp*AB>7au-zU!B3uXC_iB~E4&xo&4{A=Rt75{;FtKxAq z@7bgHK;p@RdfJ~vJXP@{iRURklz5fm{Cg5>6hEEh*DF4Tc&p;$iSJQ-67l52d)l8x zJXP`Yi03JO0r4uuFCxB1@%hBpE53+$tKyZ!_bAT4hmm|lPy2sH@~Mh95YJP*i8z11 zk?YmX#MdbKKM-H9_#MPs6~CMK9>wn?o=gj!obF@9Qx)GtJWp}{osTNTUm*E4ioZ^L zz2ff@Z&kdV_#VYSC!Ty{Pyg>Do~n2!@jS%`(7e1#aUbzDiXTaQz2e6cZ&iF4@jZ%< zBA$FyPy5FcPgQ&(@jS(|h*v3oKJhh*&mz8F@wvoX6)zyZNAWV^$w&9J{|e%%iZ3Ug zr#ScLRf==Jx<+yC-_|S6{YE)J4#iY>v^8yTo0=h=X$b6aW2R8 zinE_v73XnnkK#POBp=h$e(vW}73cmoPjT)Ks}$${YK`LDpR8A$+k30x+#dHR&g~`n z*q-)teNGV^r;N9pWaapKW!PUK?>ye}JRy%mCC^(*1()(wf}{K@s-LR`m-1@_M|qyl ztP@i3w|NU^VTXj>iLo6`S+^P57;%9V&br&3~tEB;UC&k>4=Em z#XyuN_;?{-CHMrv*9eYDmX5Swy$5eq{791Dqj(jikxWNCp#G;%vVy6KbA8D3;H;1J zP;!o+PEa?w%#bw2>2}F+6;GvW{k&-o@hT->Lf7?*Uq{!sDt;qf-=p|Cy8cRW&L_X8 z!1;QU{KD_8Fwde)&!%wZi-@y6=5aJ`Ua#b565px#8FZh|_q(j;Wx9V@K(`PzQPf91FO)2RPoJ^Y+5PjP;(SFSj> zyL!dBo!+MSpp$L7ye`V=mYia_pVk$buN-FiB*p(uyj1aLPPOv4DbCOP?pJ*I2(m|U z?w58e&iz{gtskEtJELosFM%Isg(Lh*tvQzRS#@!F!RRpj(62MPs32V6j9yq%i`Wyty2fUKI(7W!Oe@I!xxE6td_qTT z4wybw^R7^iAEz9Hvbgavlg@Sg?Nd<7aefnPkNlVO&+%tN0G=x`XF-mQv4$hkk-FtB zIs?vn^Z&!&Sdj(f81z4O1)M(nzW^Aful?to2N1SYYG?M!ar}HjN1Vs>mj00MNI;~I zs&x9xf%TStCe@o=G=C*+2c;i|fL_!8(Z=BQ0L(wm$#nWR0P8J%e}#>|5(CBN7w32y zg}t}*+XmT)eu|Ij;}Wh;ALnl+h1VE_=n?#*w+0o8<<{@E^OvwwC52Sbl?H=lI-yP)er_$XSCG8@5)uzr^X^?_t;R o(Y%A&9