From 1c5a44eaf3b9f2622825a3a6d335baf6980e554a Mon Sep 17 00:00:00 2001 From: Howland Owl Date: Tue, 12 Mar 2019 13:56:40 +0200 Subject: [PATCH] Add the version 8 things. --- 8/delkey.patch | 45 + 8/st-0.8.1.tar.gz | Bin 0 -> 45423 bytes 8/st-0.8.1/FAQ | 167 ++ 8/st-0.8.1/LEGACY | 17 + 8/st-0.8.1/LICENSE | 34 + 8/st-0.8.1/Makefile | 57 + 8/st-0.8.1/README | 34 + 8/st-0.8.1/TODO | 28 + 8/st-0.8.1/arg.h | 50 + 8/st-0.8.1/config.def.h | 501 +++++ 8/st-0.8.1/config.def.h.rej | 21 + 8/st-0.8.1/config.h | 501 +++++ 8/st-0.8.1/config.mk | 28 + 8/st-0.8.1/st | Bin 0 -> 103360 bytes 8/st-0.8.1/st.1 | 180 ++ 8/st-0.8.1/st.c | 2618 +++++++++++++++++++++++++ 8/st-0.8.1/st.h | 124 ++ 8/st-0.8.1/st.info | 222 +++ 8/st-0.8.1/win.h | 38 + 8/st-0.8.1/x.c | 2083 ++++++++++++++++++++ 8/st-0.8.1/x.c.rej | 31 + 8/st-alpha-0.8.1.diff | 199 ++ 8/st-clipboard-0.8.1.diff | 13 + 8/st-visualbell-0.8.1.diff | 41 + 8/st-xresources-20180309-c5ba9c0.diff | 183 ++ 25 files changed, 7215 insertions(+) create mode 100644 8/delkey.patch create mode 100644 8/st-0.8.1.tar.gz create mode 100644 8/st-0.8.1/FAQ create mode 100644 8/st-0.8.1/LEGACY create mode 100644 8/st-0.8.1/LICENSE create mode 100644 8/st-0.8.1/Makefile create mode 100644 8/st-0.8.1/README create mode 100644 8/st-0.8.1/TODO create mode 100644 8/st-0.8.1/arg.h create mode 100644 8/st-0.8.1/config.def.h create mode 100644 8/st-0.8.1/config.def.h.rej create mode 100644 8/st-0.8.1/config.h create mode 100644 8/st-0.8.1/config.mk create mode 100755 8/st-0.8.1/st create mode 100644 8/st-0.8.1/st.1 create mode 100644 8/st-0.8.1/st.c create mode 100644 8/st-0.8.1/st.h create mode 100644 8/st-0.8.1/st.info create mode 100644 8/st-0.8.1/win.h create mode 100644 8/st-0.8.1/x.c create mode 100644 8/st-0.8.1/x.c.rej create mode 100644 8/st-alpha-0.8.1.diff create mode 100644 8/st-clipboard-0.8.1.diff create mode 100644 8/st-visualbell-0.8.1.diff create mode 100644 8/st-xresources-20180309-c5ba9c0.diff diff --git a/8/delkey.patch b/8/delkey.patch new file mode 100644 index 0000000..b51045c --- /dev/null +++ b/8/delkey.patch @@ -0,0 +1,45 @@ +diff --git a/config.def.h b/config.def.h +index b41747f..1b52a86 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -261,7 +261,7 @@ static Key key[] = { + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, +- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, ++ { XK_KP_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0, 0}, +@@ -316,8 +316,7 @@ static Key key[] = { + { XK_Delete, ShiftMask, "\033[2K", -1, 0, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, +- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, +- { XK_BackSpace, XK_NO_MOD, "\177", 0, 0, 0}, ++ { XK_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1, 0}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1, 0}, +diff --git a/st.info b/st.info +index b70fefa..d979946 100644 +--- a/st.info ++++ b/st.info +@@ -53,7 +53,7 @@ st| simpleterm, + ka3=\E[5~, + kc1=\E[4~, + kc3=\E[6~, +- kbs=\177, ++ kbs=\010, + kcbt=\E[Z, + kb2=\EOu, + kcub1=\EOD, +@@ -73,7 +73,7 @@ st| simpleterm, + kri=\E[1;2A, + kclr=\E[3;5~, + kdl1=\E[3;2~, +- kdch1=\E[3~, ++ kdch1=\177~, + kich1=\E[2~, + kend=\E[4~, + kf1=\EOP, diff --git a/8/st-0.8.1.tar.gz b/8/st-0.8.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..2a6e54a1a34be492ae5ccef300a3f41b36c7e371 GIT binary patch literal 45423 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

o}qhDY+o;eMAlHbeqQ0=J1o>l(` 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, 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] http://st.suckless.org/patches/delkey + diff --git a/8/st-0.8.1/LEGACY b/8/st-0.8.1/LEGACY new file mode 100644 index 0000000..bf28b1e --- /dev/null +++ b/8/st-0.8.1/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/8/st-0.8.1/LICENSE b/8/st-0.8.1/LICENSE new file mode 100644 index 0000000..c356c39 --- /dev/null +++ b/8/st-0.8.1/LICENSE @@ -0,0 +1,34 @@ +MIT/X Consortium License + +© 2014-2018 Hiltjo Posthuma +© 2018 Devin J. Pohly +© 2014-2017 Quentin Rameau +© 2009-2012 Aurélien APTEL +© 2008-2017 Anselm R Garbe +© 2012-2017 Roberto E. Vargas Caballero +© 2012-2016 Christoph Lohmann <20h at r-36 dot net> +© 2013 Eon S. Jeon +© 2013 Alexander Sedov +© 2013 Mark Edgar +© 2013-2014 Eric Pruitt +© 2013 Michael Forney +© 2013-2014 Markus Teich +© 2014-2015 Laslo Hunhold + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/8/st-0.8.1/Makefile b/8/st-0.8.1/Makefile new file mode 100644 index 0000000..0b3cecd --- /dev/null +++ b/8/st-0.8.1/Makefile @@ -0,0 +1,57 @@ +# st - simple terminal +# See LICENSE file for copyright and license details. +.POSIX: + +include config.mk + +SRC = st.c x.c +OBJ = $(SRC:.c=.o) + +all: options st + +options: + @echo st build options: + @echo "CFLAGS = $(STCFLAGS)" + @echo "LDFLAGS = $(STLDFLAGS)" + @echo "CC = $(CC)" + +config.h: + cp config.def.h config.h + +.c.o: + $(CC) $(STCFLAGS) -c $< + +st.o: config.h st.h win.h +x.o: arg.h st.h win.h + +$(OBJ): config.h config.mk + +st: $(OBJ) + $(CC) -o $@ $(OBJ) $(STLDFLAGS) + +clean: + rm -f st $(OBJ) st-$(VERSION).tar.gz + +dist: clean + mkdir -p st-$(VERSION) + cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\ + config.def.h st.info st.1 arg.h st.h win.h $(SRC)\ + st-$(VERSION) + tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz + rm -rf st-$(VERSION) + +install: st + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f st $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/st + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 + tic -sx st.info + @echo Please see the README file regarding the terminfo entry of st. + +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/st + rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 + +.PHONY: all options clean dist install uninstall diff --git a/8/st-0.8.1/README b/8/st-0.8.1/README new file mode 100644 index 0000000..6a846ed --- /dev/null +++ b/8/st-0.8.1/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/8/st-0.8.1/TODO b/8/st-0.8.1/TODO new file mode 100644 index 0000000..5f74cd5 --- /dev/null +++ b/8/st-0.8.1/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/8/st-0.8.1/arg.h b/8/st-0.8.1/arg.h new file mode 100644 index 0000000..a22e019 --- /dev/null +++ b/8/st-0.8.1/arg.h @@ -0,0 +1,50 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + int i_;\ + for (i_ = 1, brk_ = 0, argv_ = argv;\ + argv[0][i_] && !brk_;\ + i_++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][i_];\ + switch (argc_) + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][i_+1] != '\0')?\ + (&argv[0][i_+1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][i_+1] != '\0')?\ + (&argv[0][i_+1]) :\ + (argc--, argv++, argv[0]))) + +#endif diff --git a/8/st-0.8.1/config.def.h b/8/st-0.8.1/config.def.h new file mode 100644 index 0000000..dfaba5c --- /dev/null +++ b/8/st-0.8.1/config.def.h @@ -0,0 +1,501 @@ +/* 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: utmp option + * 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; +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: " `'\"()[]{}" + */ +char *worddelimiters = " "; + +/* selection timeouts (in milliseconds) */ +static unsigned int doubleclicktimeout = 300; +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; + +/* + * 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; + +/* bg opacity */ +unsigned int alpha = 0xcc; + +/* 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", + "black", +}; + + +/* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +unsigned int defaultfg = 7; +unsigned int defaultbg = 257; +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; + +/* + * Xresources preferences to load at startup + */ +ResourcePref resources[] = { + { "font", STRING, &font }, + { "color0", STRING, &colorname[0] }, + { "color1", STRING, &colorname[1] }, + { "color2", STRING, &colorname[2] }, + { "color3", STRING, &colorname[3] }, + { "color4", STRING, &colorname[4] }, + { "color5", STRING, &colorname[5] }, + { "color6", STRING, &colorname[6] }, + { "color7", STRING, &colorname[7] }, + { "color8", STRING, &colorname[8] }, + { "color9", STRING, &colorname[9] }, + { "color10", STRING, &colorname[10] }, + { "color11", STRING, &colorname[11] }, + { "color12", STRING, &colorname[12] }, + { "color13", STRING, &colorname[13] }, + { "color14", STRING, &colorname[14] }, + { "color15", STRING, &colorname[15] }, + { "background", STRING, &colorname[256] }, + { "foreground", STRING, &colorname[257] }, + { "cursorColor", STRING, &colorname[258] }, + { "termname", STRING, &termname }, + { "shell", STRING, &shell }, + { "xfps", INTEGER, &xfps }, + { "actionfps", INTEGER, &actionfps }, + { "blinktimeout", INTEGER, &blinktimeout }, + { "bellvolume", INTEGER, &bellvolume }, + { "tabspaces", INTEGER, &tabspaces }, + { "cwscale", FLOAT, &cwscale }, + { "chscale", FLOAT, &chscale }, +}; + +/* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. + */ +static MouseShortcut mshortcuts[] = { + /* button mask string */ + { Button4, XK_ANY_MOD, "\031" }, + { Button5, XK_ANY_MOD, "\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} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, + { TERMMOD, XK_I, iso14755, {.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 + * 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 + * 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; + +/* + * 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. + */ +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/8/st-0.8.1/config.def.h.rej b/8/st-0.8.1/config.def.h.rej new file mode 100644 index 0000000..4bb2348 --- /dev/null +++ b/8/st-0.8.1/config.def.h.rej @@ -0,0 +1,21 @@ +--- config.def.h ++++ config.def.h +@@ -261,7 +261,7 @@ static Key key[] = { + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, +- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, ++ { XK_KP_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0, 0}, +@@ -316,8 +316,7 @@ static Key key[] = { + { XK_Delete, ShiftMask, "\033[2K", -1, 0, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0}, +- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0}, +- { XK_BackSpace, XK_NO_MOD, "\177", 0, 0, 0}, ++ { XK_Delete, XK_ANY_MOD, "\177", +1, 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1, 0}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1, 0}, diff --git a/8/st-0.8.1/config.h b/8/st-0.8.1/config.h new file mode 100644 index 0000000..ec45dd1 --- /dev/null +++ b/8/st-0.8.1/config.h @@ -0,0 +1,501 @@ +/* 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: utmp option + * 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; +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: " `'\"()[]{}" + */ +char *worddelimiters = " "; + +/* selection timeouts (in milliseconds) */ +static unsigned int doubleclicktimeout = 300; +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; + +/* + * 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; + +/* bg opacity */ +unsigned int alpha = 0xcc; + +/* 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", + "black", +}; + + +/* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +unsigned int defaultfg = 7; +unsigned int defaultbg = 257; +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 = 7; + +/* + * 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; + +/* + * Xresources preferences to load at startup + */ +ResourcePref resources[] = { + { "font", STRING, &font }, + { "color0", STRING, &colorname[0] }, + { "color1", STRING, &colorname[1] }, + { "color2", STRING, &colorname[2] }, + { "color3", STRING, &colorname[3] }, + { "color4", STRING, &colorname[4] }, + { "color5", STRING, &colorname[5] }, + { "color6", STRING, &colorname[6] }, + { "color7", STRING, &colorname[7] }, + { "color8", STRING, &colorname[8] }, + { "color9", STRING, &colorname[9] }, + { "color10", STRING, &colorname[10] }, + { "color11", STRING, &colorname[11] }, + { "color12", STRING, &colorname[12] }, + { "color13", STRING, &colorname[13] }, + { "color14", STRING, &colorname[14] }, + { "color15", STRING, &colorname[15] }, + { "background", STRING, &colorname[257] }, + { "foreground", STRING, &colorname[256] }, + { "cursorColor", STRING, &colorname[258] }, + { "termname", STRING, &termname }, + { "shell", STRING, &shell }, + { "xfps", INTEGER, &xfps }, + { "actionfps", INTEGER, &actionfps }, + { "blinktimeout", INTEGER, &blinktimeout }, + { "bellvolume", INTEGER, &bellvolume }, + { "tabspaces", INTEGER, &tabspaces }, + { "cwscale", FLOAT, &cwscale }, + { "chscale", FLOAT, &chscale }, +}; + +/* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. + */ +static MouseShortcut mshortcuts[] = { + /* button mask string */ + { Button4, XK_ANY_MOD, "\031" }, + { Button5, XK_ANY_MOD, "\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} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, + { TERMMOD, XK_I, iso14755, {.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 + * 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 + * 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; + +/* + * 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. + */ +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/8/st-0.8.1/config.mk b/8/st-0.8.1/config.mk new file mode 100644 index 0000000..b1fa717 --- /dev/null +++ b/8/st-0.8.1/config.mk @@ -0,0 +1,28 @@ +# st version +VERSION = 0.8.1 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# includes and libs +INCS = -I. -I/usr/include -I${X11INC} \ + `pkg-config --cflags fontconfig` \ + `pkg-config --cflags freetype2` +LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXft -lXrender\ + `pkg-config --libs fontconfig` \ + `pkg-config --libs freetype2` + +# flags +CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 +STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS) +STLDFLAGS = $(LIBS) $(LDFLAGS) + +# compiler and linker +# CC = c99 + diff --git a/8/st-0.8.1/st b/8/st-0.8.1/st new file mode 100755 index 0000000000000000000000000000000000000000..60cf8166b204045cbad6260c4557d7bdffdc7850 GIT binary patch literal 103360 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%0DJFDf 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][{+-}{+-}]. See +.BR XParseGeometry (3) +for further details. +.TP +.B \-i +will fixate the position given with the -g option. +.TP +.BI \-n " name" +defines the window instance name (default $TERM). +.TP +.BI \-o " iofile" +writes all the I/O to +.I iofile. +This feature is useful when recording st sessions. A value of "-" means +standard output. +.TP +.BI \-T " title" +defines the window title (default 'st'). +.TP +.BI \-t " title" +defines the window title (default 'st'). +.TP +.BI \-w " windowid" +embeds st within the window identified by +.I windowid +.TP +.BI \-l " line" +use a tty +.I line +instead of a pseudo terminal. +.I line +should be a (pseudo-)serial device (e.g. /dev/ttyS0 on Linux for serial port +0). +When this flag is given +remaining arguments are used as flags for +.BR stty(1). +By default st initializes the serial line to 8 bits, no parity, 1 stop bit +and a 38400 baud rate. The speed is set by appending it as last argument +(e.g. 'st -l /dev/ttyS0 115200'). Arguments before the last one are +.BR stty(1) +flags. If you want to set odd parity on 115200 baud use for example 'st -l +/dev/ttyS0 parenb parodd 115200'. Set the number of bits by using for +example 'st -l /dev/ttyS0 cs7 115200'. See +.BR stty(1) +for more arguments and cases. +.TP +.B \-v +prints version information to stderr, then exits. +.TP +.BI \-e " command " [ " arguments " "... ]" +st executes +.I command +instead of the shell. If this is used it +.B must be the last option +on the command line, as in xterm / rxvt. +This option is only intended for compatibility, +and all the remaining arguments are used as a command +even without it. +.SH SHORTCUTS +.TP +.B Break +Send a break in the serial line. +Break key is obtained in PC keyboards +pressing at the same time control and pause. +.TP +.B Ctrl-Print Screen +Toggle if st should print to the +.I iofile. +.TP +.B Shift-Print Screen +Print the full screen to the +.I iofile. +.TP +.B Print Screen +Print the selection to the +.I iofile. +.TP +.B Ctrl-Shift-Page Up +Increase font size. +.TP +.B Ctrl-Shift-Page Down +Decrease font size. +.TP +.B Ctrl-Shift-Home +Reset to default font size. +.TP +.B Ctrl-Shift-y +Paste from primary selection (middle mouse button). +.TP +.B Ctrl-Shift-c +Copy the selected text to the clipboard selection. +.TP +.B Ctrl-Shift-v +Paste from the clipboard selection. +.TP +.B Ctrl-Shift-i +Launch dmenu to enter a unicode codepoint and send the corresponding glyph +to st. +.SH CUSTOMIZATION +.B st +can be customized by creating a custom config.h and (re)compiling the source +code. This keeps it fast, secure and simple. +.SH AUTHORS +See the LICENSE file for the authors. +.SH LICENSE +See the LICENSE file for the terms of redistribution. +.SH SEE ALSO +.BR tabbed (1), +.BR utmp (1), +.BR stty (1) +.SH BUGS +See the TODO file in the distribution. + diff --git a/8/st-0.8.1/st.c b/8/st-0.8.1/st.c new file mode 100644 index 0000000..46c954b --- /dev/null +++ b/8/st-0.8.1/st.c @@ -0,0 +1,2618 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "st.h" +#include "win.h" + +#if defined(__linux) + #include +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) + #include +#elif defined(__FreeBSD__) || defined(__DragonFly__) + #include +#endif + +/* Arbitrary sizes */ +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 +#define ESC_BUF_SIZ (128*UTF_SIZ) +#define ESC_ARG_SIZ 16 +#define STR_BUF_SIZ ESC_BUF_SIZ +#define STR_ARG_SIZ ESC_ARG_SIZ + +/* macros */ +#define IS_SET(flag) ((term.mode & (flag)) != 0) +#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) +#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') +#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) +#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) +#define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL) + +/* constants */ +#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: ] [;]] []] */ +typedef struct { + char buf[ESC_BUF_SIZ]; /* raw string */ + int len; /* raw string length */ + char priv; + int arg[ESC_ARG_SIZ]; + int narg; /* nb of args */ + char mode[2]; +} CSIEscape; + +/* STR Escape sequence structs */ +/* ESC type [[ [] [;]] ] ESC '\' */ +typedef struct { + char type; /* ESC type ... */ + char buf[STR_BUF_SIZ]; /* raw string */ + int len; /* raw string length */ + char *args[STR_ARG_SIZ]; + int narg; /* nb of args */ +} STREscape; + +static void execsh(char *, char **); +static void stty(char **); +static void sigchld(int); +static void ttywriteraw(const char *, size_t); + +static void csidump(void); +static void csihandle(void); +static void csiparse(void); +static void csireset(void); +static int eschandle(uchar); +static void strdump(void); +static void strhandle(void); +static void strparse(void); +static void strreset(void); + +static void tprinter(char *, size_t); +static void tdumpsel(void); +static void tdumpline(int); +static void tdump(void); +static void tclearregion(int, int, int, int); +static void tcursor(int); +static void tdeletechar(int); +static void tdeleteline(int); +static void tinsertblank(int); +static void tinsertblankline(int); +static int tlinelen(int); +static void tmoveto(int, int); +static void tmoveato(int, int); +static void tnewline(int); +static void tputtab(int); +static void tputc(Rune); +static void treset(void); +static void tscrollup(int, int); +static void tscrolldown(int, int); +static void tsetattr(int *, int); +static void tsetchar(Rune, Glyph *, int, int); +static void tsetdirt(int, int); +static void tsetscroll(int, int); +static void tswapscreen(void); +static void tsetmode(int, int, int *, int); +static int twrite(const char *, int, int); +static void tfulldirt(void); +static void tcontrolcode(uchar ); +static void tdectest(char ); +static void tdefutf8(char); +static int32_t tdefcolor(int *, int *, int); +static void tdeftran(char); +static void tstrsequence(uchar); + +static void drawregion(int, int, int, int); + +static void selnormalize(void); +static void selscroll(int, int); +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 *); +static char base64dec_getc(const char **); + +static ssize_t xwrite(int, const char *, size_t); + +/* Globals */ +static Term term; +static Selection sel; +static CSIEscape csiescseq; +static STREscape strescseq; +static int iofd = 1; +static int cmdfd; +static pid_t pid; + +static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +ssize_t +xwrite(int fd, const char *s, size_t len) +{ + size_t aux = len; + ssize_t r; + + while (len > 0) { + r = write(fd, s, len); + if (r < 0) + return r; + len -= r; + s += r; + } + + return aux; +} + +void * +xmalloc(size_t len) +{ + void *p = malloc(len); + + if (!p) + die("Out of memory\n"); + + return p; +} + +void * +xrealloc(void *p, size_t len) +{ + if ((p = realloc(p, len)) == NULL) + die("Out of memory\n"); + + return p; +} + +char * +xstrdup(char *s) +{ + if ((s = strdup(s)) == NULL) + die("Out of memory\n"); + + return s; +} + +size_t +utf8decode(const char *c, Rune *u, size_t clen) +{ + size_t i, j, len, type; + Rune udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type != 0) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Rune +utf8decodebyte(char c, size_t *i) +{ + for (*i = 0; *i < LEN(utfmask); ++(*i)) + if (((uchar)c & utfmask[*i]) == utfbyte[*i]) + return (uchar)c & ~utfmask[*i]; + + return 0; +} + +size_t +utf8encode(Rune u, char *c) +{ + size_t len, i; + + len = utf8validate(&u, 0); + if (len > UTF_SIZ) + return 0; + + for (i = len - 1; i != 0; --i) { + c[i] = utf8encodebyte(u, 0); + u >>= 6; + } + c[0] = utf8encodebyte(u, len); + + return len; +} + +char +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) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + + return i; +} + +static const char base64_digits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, + 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +char +base64dec_getc(const char **src) +{ + while (**src && !isprint(**src)) (*src)++; + return *((*src)++); +} + +char * +base64dec(const char *src) +{ + size_t in_len = strlen(src); + char *result, *dst; + + if (in_len % 4) + in_len += 4 - (in_len % 4); + result = dst = xmalloc(in_len / 4 * 3 + 1); + while (*src) { + int a = base64_digits[(unsigned char) base64dec_getc(&src)]; + int b = base64_digits[(unsigned char) base64dec_getc(&src)]; + int c = base64_digits[(unsigned char) base64dec_getc(&src)]; + int d = base64_digits[(unsigned char) base64dec_getc(&src)]; + + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (c == -1) + break; + *dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2); + if (d == -1) + break; + *dst++ = ((c & 0x03) << 6) | d; + } + *dst = '\0'; + return result; +} + +void +selinit(void) +{ + sel.mode = SEL_IDLE; + sel.snap = 0; + sel.ob.x = -1; +} + +int +tlinelen(int y) +{ + int i = term.col; + + if (term.line[y][i - 1].mode & ATTR_WRAP) + return i; + + while (i > 0 && term.line[y][i - 1].u == ' ') + --i; + + return i; +} + +void +selstart(int col, int row, int snap) +{ + selclear(); + sel.mode = SEL_EMPTY; + sel.type = SEL_REGULAR; + sel.snap = snap; + sel.oe.x = sel.ob.x = col; + sel.oe.y = sel.ob.y = row; + selnormalize(); + + if (sel.snap != 0) + sel.mode = SEL_READY; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +selextend(int col, int row, int type, int done) +{ + int oldey, oldex, oldsby, oldsey, oldtype; + + if (sel.mode == SEL_IDLE) + return; + if (done && sel.mode == SEL_EMPTY) { + selclear(); + return; + } + + oldey = sel.oe.y; + oldex = sel.oe.x; + oldsby = sel.nb.y; + oldsey = sel.ne.y; + oldtype = sel.type; + + sel.alt = IS_SET(MODE_ALTSCREEN); + sel.oe.x = col; + sel.oe.y = row; + selnormalize(); + sel.type = type; + + if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type) + tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); + + sel.mode = done ? SEL_IDLE : SEL_READY; +} + +void +selnormalize(void) +{ + int i; + + if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) { + sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x; + sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x; + } else { + sel.nb.x = MIN(sel.ob.x, sel.oe.x); + sel.ne.x = MAX(sel.ob.x, sel.oe.x); + } + sel.nb.y = MIN(sel.ob.y, sel.oe.y); + sel.ne.y = MAX(sel.ob.y, sel.oe.y); + + selsnap(&sel.nb.x, &sel.nb.y, -1); + selsnap(&sel.ne.x, &sel.ne.y, +1); + + /* expand selection over line breaks */ + if (sel.type == SEL_RECTANGULAR) + return; + i = tlinelen(sel.nb.y); + if (i < sel.nb.x) + sel.nb.x = i; + if (tlinelen(sel.ne.y) <= sel.ne.x) + sel.ne.x = term.col - 1; +} + +int +selected(int x, int y) +{ + if (sel.mode == SEL_EMPTY || sel.ob.x == -1 || + sel.alt != IS_SET(MODE_ALTSCREEN)) + return 0; + + if (sel.type == SEL_RECTANGULAR) + return BETWEEN(y, sel.nb.y, sel.ne.y) + && BETWEEN(x, sel.nb.x, sel.ne.x); + + return BETWEEN(y, sel.nb.y, sel.ne.y) + && (y != sel.nb.y || x >= sel.nb.x) + && (y != sel.ne.y || x <= sel.ne.x); +} + +void +selsnap(int *x, int *y, int direction) +{ + int newx, newy, xt, yt; + int delim, prevdelim; + Glyph *gp, *prevgp; + + switch (sel.snap) { + case SNAP_WORD: + /* + * Snap around if the word wraps around at the end or + * beginning of a line. + */ + prevgp = &term.line[*y][*x]; + prevdelim = ISDELIM(prevgp->u); + for (;;) { + newx = *x + direction; + newy = *y; + if (!BETWEEN(newx, 0, term.col - 1)) { + newy += direction; + newx = (newx + term.col) % term.col; + if (!BETWEEN(newy, 0, term.row - 1)) + break; + + if (direction > 0) + yt = *y, xt = *x; + else + yt = newy, xt = newx; + if (!(term.line[yt][xt].mode & ATTR_WRAP)) + break; + } + + if (newx >= tlinelen(newy)) + break; + + gp = &term.line[newy][newx]; + delim = ISDELIM(gp->u); + if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim + || (delim && gp->u != prevgp->u))) + break; + + *x = newx; + *y = newy; + prevgp = gp; + prevdelim = delim; + } + break; + case SNAP_LINE: + /* + * Snap around if the the previous line or the current one + * has set ATTR_WRAP at its end. Then the whole next or + * previous line will be selected. + */ + *x = (direction < 0) ? 0 : term.col - 1; + if (direction < 0) { + for (; *y > 0; *y += direction) { + if (!(term.line[*y-1][term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } else if (direction > 0) { + for (; *y < term.row-1; *y += direction) { + if (!(term.line[*y][term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } + break; + } +} + +char * +getsel(void) +{ + char *str, *ptr; + int y, bufsize, lastx, linelen; + Glyph *gp, *last; + + if (sel.ob.x == -1) + return NULL; + + bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ; + ptr = str = xmalloc(bufsize); + + /* append every set & selected glyph to the selection */ + for (y = sel.nb.y; y <= sel.ne.y; y++) { + if ((linelen = tlinelen(y)) == 0) { + *ptr++ = '\n'; + continue; + } + + if (sel.type == SEL_RECTANGULAR) { + gp = &term.line[y][sel.nb.x]; + lastx = sel.ne.x; + } else { + gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; + lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; + } + last = &term.line[y][MIN(lastx, linelen-1)]; + while (last >= gp && last->u == ' ') + --last; + + for ( ; gp <= last; ++gp) { + if (gp->mode & ATTR_WDUMMY) + continue; + + ptr += utf8encode(gp->u, ptr); + } + + /* + * Copy and pasting of line endings is inconsistent + * in the inconsistent terminal and GUI world. + * The best solution seems like to produce '\n' when + * something is copied from st and convert '\n' to + * '\r', when something to be pasted is received by + * st. + * FIXME: Fix the computer world. + */ + if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP)) + *ptr++ = '\n'; + } + *ptr = 0; + return str; +} + +void +selclear(void) +{ + if (sel.ob.x == -1) + return; + sel.mode = SEL_IDLE; + sel.ob.x = -1; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(1); +} + +void +execsh(char *cmd, char **args) +{ + char *sh, *prog; + const struct passwd *pw; + + errno = 0; + if ((pw = getpwuid(getuid())) == NULL) { + if (errno) + die("getpwuid:%s\n", strerror(errno)); + else + die("who are you?\n"); + } + + if ((sh = getenv("SHELL")) == NULL) + sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; + + if (args) + prog = args[0]; + else if (utmp) + prog = utmp; + else + prog = sh; + DEFAULT(args, ((char *[]) {prog, NULL})); + + unsetenv("COLUMNS"); + unsetenv("LINES"); + unsetenv("TERMCAP"); + setenv("LOGNAME", pw->pw_name, 1); + setenv("USER", pw->pw_name, 1); + setenv("SHELL", sh, 1); + setenv("HOME", pw->pw_dir, 1); + setenv("TERM", termname, 1); + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGALRM, SIG_DFL); + + execvp(prog, args); + _exit(1); +} + +void +sigchld(int a) +{ + int stat; + pid_t p; + + if ((p = waitpid(pid, &stat, WNOHANG)) < 0) + die("Waiting for pid %hd failed: %s\n", pid, strerror(errno)); + + if (pid != p) + return; + + if (!WIFEXITED(stat) || WEXITSTATUS(stat)) + die("child finished with error '%d'\n", stat); + exit(0); +} + +void +stty(char **args) +{ + char cmd[_POSIX_ARG_MAX], **p, *q, *s; + size_t n, siz; + + if ((n = strlen(stty_args)) > sizeof(cmd)-1) + die("incorrect stty parameters\n"); + memcpy(cmd, stty_args, n); + q = cmd + n; + siz = sizeof(cmd) - n; + for (p = args; p && (s = *p); ++p) { + if ((n = strlen(s)) > siz-1) + die("stty parameter length too long\n"); + *q++ = ' '; + memcpy(q, s, n); + q += n; + siz -= n + 1; + } + *q = '\0'; + if (system(cmd) != 0) + perror("Couldn't call stty"); +} + +int +ttynew(char *line, char *cmd, char *out, char **args) +{ + int m, s; + + if (out) { + term.mode |= MODE_PRINT; + iofd = (!strcmp(out, "-")) ? + 1 : open(out, O_WRONLY | O_CREAT, 0666); + if (iofd < 0) { + fprintf(stderr, "Error opening %s:%s\n", + out, strerror(errno)); + } + } + + if (line) { + if ((cmdfd = open(line, O_RDWR)) < 0) + die("open line failed: %s\n", strerror(errno)); + dup2(cmdfd, 0); + stty(args); + return cmdfd; + } + + /* seems to work fine on linux, openbsd and freebsd */ + if (openpty(&m, &s, NULL, NULL, NULL) < 0) + die("openpty failed: %s\n", strerror(errno)); + + switch (pid = fork()) { + case -1: + die("fork failed\n"); + break; + case 0: + close(iofd); + setsid(); /* create a new process group */ + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + if (ioctl(s, TIOCSCTTY, NULL) < 0) + die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); + close(s); + close(m); + execsh(cmd, args); + break; + default: + close(s); + cmdfd = m; + signal(SIGCHLD, sigchld); + break; + } + return cmdfd; +} + +size_t +ttyread(void) +{ + static char buf[BUFSIZ]; + static int buflen = 0; + int written; + int ret; + + /* append read bytes to unprocessed bytes */ + if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) + 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; +} + +void +ttywrite(const char *s, size_t n, int may_echo) +{ + const char *next; + + if (may_echo && IS_SET(MODE_ECHO)) + twrite(s, n, 1); + + if (!IS_SET(MODE_CRLF)) { + ttywriteraw(s, n); + return; + } + + /* This is similar to how the kernel handles ONLCR for ttys */ + while (n > 0) { + if (*s == '\r') { + next = s + 1; + ttywriteraw("\r\n", 2); + } else { + next = memchr(s, '\r', n); + DEFAULT(next, s + n); + ttywriteraw(s, next - s); + } + n -= next - s; + s = next; + } +} + +void +ttywriteraw(const char *s, size_t n) +{ + fd_set wfd, rfd; + ssize_t r; + size_t lim = 256; + + /* + * Remember that we are using a pty, which might be a modem line. + * Writing too much will clog the line. That's why we are doing this + * dance. + * FIXME: Migrate the world to Plan 9. + */ + while (n > 0) { + FD_ZERO(&wfd); + FD_ZERO(&rfd); + FD_SET(cmdfd, &wfd); + FD_SET(cmdfd, &rfd); + + /* Check if we can write. */ + if (pselect(cmdfd+1, &rfd, &wfd, NULL, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + if (FD_ISSET(cmdfd, &wfd)) { + /* + * Only write the bytes written by ttywrite() or the + * default of 256. This seems to be a reasonable value + * for a serial line. Bigger values might clog the I/O. + */ + if ((r = write(cmdfd, s, (n < lim)? n : lim)) < 0) + goto write_error; + if (r < n) { + /* + * We weren't able to write out everything. + * This means the buffer is getting full + * again. Empty it. + */ + if (n < lim) + lim = ttyread(); + n -= r; + s += r; + } else { + /* All bytes have been written. */ + break; + } + } + if (FD_ISSET(cmdfd, &rfd)) + lim = ttyread(); + } + return; + +write_error: + die("write error on tty: %s\n", strerror(errno)); +} + +void +ttyresize(int tw, int th) +{ + struct winsize w; + + w.ws_row = term.row; + w.ws_col = term.col; + w.ws_xpixel = tw; + w.ws_ypixel = th; + if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0) + fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); +} + +void +ttyhangup() +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); +} + +int +tattrset(int attr) +{ + int i, j; + + for (i = 0; i < term.row-1; i++) { + for (j = 0; j < term.col-1; j++) { + if (term.line[i][j].mode & attr) + return 1; + } + } + + return 0; +} + +void +tsetdirt(int top, int bot) +{ + int i; + + LIMIT(top, 0, term.row-1); + LIMIT(bot, 0, term.row-1); + + for (i = top; i <= bot; i++) + term.dirty[i] = 1; +} + +void +tsetdirtattr(int attr) +{ + int i, j; + + for (i = 0; i < term.row-1; i++) { + for (j = 0; j < term.col-1; j++) { + if (term.line[i][j].mode & attr) { + tsetdirt(i, i); + break; + } + } + } +} + +void +tfulldirt(void) +{ + tsetdirt(0, term.row-1); +} + +void +tcursor(int mode) +{ + static TCursor c[2]; + int alt = IS_SET(MODE_ALTSCREEN); + + if (mode == CURSOR_SAVE) { + c[alt] = term.c; + } else if (mode == CURSOR_LOAD) { + term.c = c[alt]; + tmoveto(c[alt].x, c[alt].y); + } +} + +void +treset(void) +{ + uint i; + + term.c = (TCursor){{ + .mode = ATTR_NULL, + .fg = defaultfg, + .bg = defaultbg + }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; + + memset(term.tabs, 0, term.col * sizeof(*term.tabs)); + for (i = tabspaces; i < term.col; i += tabspaces) + term.tabs[i] = 1; + term.top = 0; + term.bot = term.row - 1; + term.mode = MODE_WRAP|MODE_UTF8; + memset(term.trantbl, CS_USA, sizeof(term.trantbl)); + term.charset = 0; + + for (i = 0; i < 2; i++) { + tmoveto(0, 0); + tcursor(CURSOR_SAVE); + tclearregion(0, 0, term.col-1, term.row-1); + tswapscreen(); + } +} + +void +tnew(int col, int row) +{ + term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; + tresize(col, row); + treset(); +} + +void +tswapscreen(void) +{ + Line *tmp = term.line; + + term.line = term.alt; + term.alt = tmp; + term.mode ^= MODE_ALTSCREEN; + tfulldirt(); +} + +void +tscrolldown(int orig, int n) +{ + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + + tsetdirt(orig, term.bot-n); + tclearregion(0, term.bot-n+1, term.col-1, term.bot); + + for (i = term.bot; i >= orig+n; i--) { + temp = term.line[i]; + term.line[i] = term.line[i-n]; + term.line[i-n] = temp; + } + + selscroll(orig, n); +} + +void +tscrollup(int orig, int n) +{ + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + + tclearregion(0, orig, term.col-1, orig+n-1); + tsetdirt(orig+n, term.bot); + + for (i = orig; i <= term.bot-n; i++) { + temp = term.line[i]; + term.line[i] = term.line[i+n]; + term.line[i+n] = temp; + } + + selscroll(orig, -n); +} + +void +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) { + 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(); + } +} + +void +tnewline(int first_col) +{ + int y = term.c.y; + + if (y == term.bot) { + tscrollup(term.top, 1); + } else { + y++; + } + tmoveto(first_col ? 0 : term.c.x, y); +} + +void +csiparse(void) +{ + char *p = csiescseq.buf, *np; + long int v; + + csiescseq.narg = 0; + if (*p == '?') { + csiescseq.priv = 1; + p++; + } + + csiescseq.buf[csiescseq.len] = '\0'; + while (p < csiescseq.buf+csiescseq.len) { + np = NULL; + v = strtol(p, &np, 10); + if (np == p) + v = 0; + if (v == LONG_MAX || v == LONG_MIN) + v = -1; + csiescseq.arg[csiescseq.narg++] = v; + p = np; + if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ) + break; + p++; + } + csiescseq.mode[0] = *p++; + csiescseq.mode[1] = (p < csiescseq.buf+csiescseq.len) ? *p : '\0'; +} + +/* for absolute user moves, when decom is set */ +void +tmoveato(int x, int y) +{ + tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top: 0)); +} + +void +tmoveto(int x, int y) +{ + int miny, maxy; + + if (term.c.state & CURSOR_ORIGIN) { + miny = term.top; + maxy = term.bot; + } else { + miny = 0; + maxy = term.row - 1; + } + term.c.state &= ~CURSOR_WRAPNEXT; + term.c.x = LIMIT(x, 0, term.col-1); + term.c.y = LIMIT(y, miny, maxy); +} + +void +tsetchar(Rune u, Glyph *attr, int x, int y) +{ + static char *vt100_0[62] = { /* 0x41 - 0x7e */ + "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ + 0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */ + "◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */ + "␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */ + "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ + "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ + }; + + /* + * The table is proudly stolen from rxvt. + */ + if (term.trantbl[term.charset] == CS_GRAPHIC0 && + BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) + utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ); + + if (term.line[y][x].mode & ATTR_WIDE) { + if (x+1 < term.col) { + term.line[y][x+1].u = ' '; + term.line[y][x+1].mode &= ~ATTR_WDUMMY; + } + } else if (term.line[y][x].mode & ATTR_WDUMMY) { + term.line[y][x-1].u = ' '; + term.line[y][x-1].mode &= ~ATTR_WIDE; + } + + term.dirty[y] = 1; + term.line[y][x] = *attr; + term.line[y][x].u = u; +} + +void +tclearregion(int x1, int y1, int x2, int y2) +{ + int x, y, temp; + Glyph *gp; + + if (x1 > x2) + temp = x1, x1 = x2, x2 = temp; + if (y1 > y2) + temp = y1, y1 = y2, y2 = temp; + + LIMIT(x1, 0, term.col-1); + LIMIT(x2, 0, term.col-1); + LIMIT(y1, 0, term.row-1); + LIMIT(y2, 0, term.row-1); + + for (y = y1; y <= y2; y++) { + term.dirty[y] = 1; + for (x = x1; x <= x2; x++) { + gp = &term.line[y][x]; + if (selected(x, y)) + selclear(); + gp->fg = term.c.attr.fg; + gp->bg = term.c.attr.bg; + gp->mode = 0; + gp->u = ' '; + } + } +} + +void +tdeletechar(int n) +{ + int dst, src, size; + Glyph *line; + + LIMIT(n, 0, term.col - term.c.x); + + dst = term.c.x; + src = term.c.x + n; + size = term.col - src; + line = term.line[term.c.y]; + + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); +} + +void +tinsertblank(int n) +{ + int dst, src, size; + Glyph *line; + + LIMIT(n, 0, term.col - term.c.x); + + dst = term.c.x + n; + src = term.c.x; + size = term.col - dst; + line = term.line[term.c.y]; + + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + tclearregion(src, term.c.y, dst - 1, term.c.y); +} + +void +tinsertblankline(int n) +{ + if (BETWEEN(term.c.y, term.top, term.bot)) + tscrolldown(term.c.y, n); +} + +void +tdeleteline(int n) +{ + if (BETWEEN(term.c.y, term.top, term.bot)) + tscrollup(term.c.y, n); +} + +int32_t +tdefcolor(int *attr, int *npar, int l) +{ + int32_t idx = -1; + uint r, g, b; + + switch (attr[*npar + 1]) { + case 2: /* direct color in RGB space */ + if (*npar + 4 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + r = attr[*npar + 2]; + g = attr[*npar + 3]; + b = attr[*npar + 4]; + *npar += 4; + if (!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255)) + fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n", + r, g, b); + else + idx = TRUECOLOR(r, g, b); + break; + case 5: /* indexed color */ + if (*npar + 2 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + *npar += 2; + if (!BETWEEN(attr[*npar], 0, 255)) + fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]); + else + idx = attr[*npar]; + break; + case 0: /* implemented defined (only foreground) */ + case 1: /* transparent */ + case 3: /* direct color in CMY space */ + case 4: /* direct color in CMYK space */ + default: + fprintf(stderr, + "erresc(38): gfx attr %d unknown\n", attr[*npar]); + break; + } + + return idx; +} + +void +tsetattr(int *attr, int l) +{ + int i; + int32_t idx; + + for (i = 0; i < l; i++) { + switch (attr[i]) { + case 0: + term.c.attr.mode &= ~( + ATTR_BOLD | + ATTR_FAINT | + ATTR_ITALIC | + ATTR_UNDERLINE | + ATTR_BLINK | + ATTR_REVERSE | + ATTR_INVISIBLE | + ATTR_STRUCK ); + term.c.attr.fg = defaultfg; + term.c.attr.bg = defaultbg; + break; + case 1: + term.c.attr.mode |= ATTR_BOLD; + break; + case 2: + term.c.attr.mode |= ATTR_FAINT; + break; + case 3: + term.c.attr.mode |= ATTR_ITALIC; + break; + case 4: + term.c.attr.mode |= ATTR_UNDERLINE; + break; + case 5: /* slow blink */ + /* FALLTHROUGH */ + case 6: /* rapid blink */ + term.c.attr.mode |= ATTR_BLINK; + break; + case 7: + term.c.attr.mode |= ATTR_REVERSE; + break; + case 8: + term.c.attr.mode |= ATTR_INVISIBLE; + break; + case 9: + term.c.attr.mode |= ATTR_STRUCK; + break; + case 22: + term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT); + break; + case 23: + term.c.attr.mode &= ~ATTR_ITALIC; + break; + case 24: + term.c.attr.mode &= ~ATTR_UNDERLINE; + break; + case 25: + term.c.attr.mode &= ~ATTR_BLINK; + break; + case 27: + term.c.attr.mode &= ~ATTR_REVERSE; + break; + case 28: + term.c.attr.mode &= ~ATTR_INVISIBLE; + break; + case 29: + term.c.attr.mode &= ~ATTR_STRUCK; + break; + case 38: + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.fg = idx; + break; + case 39: + term.c.attr.fg = defaultfg; + break; + case 48: + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.bg = idx; + break; + case 49: + term.c.attr.bg = defaultbg; + break; + default: + if (BETWEEN(attr[i], 30, 37)) { + term.c.attr.fg = attr[i] - 30; + } else if (BETWEEN(attr[i], 40, 47)) { + term.c.attr.bg = attr[i] - 40; + } else if (BETWEEN(attr[i], 90, 97)) { + term.c.attr.fg = attr[i] - 90 + 8; + } else if (BETWEEN(attr[i], 100, 107)) { + term.c.attr.bg = attr[i] - 100 + 8; + } else { + fprintf(stderr, + "erresc(default): gfx attr %d unknown\n", + attr[i]), csidump(); + } + break; + } + } +} + +void +tsetscroll(int t, int b) +{ + int temp; + + LIMIT(t, 0, term.row-1); + LIMIT(b, 0, term.row-1); + if (t > b) { + temp = t; + t = b; + b = temp; + } + term.top = t; + term.bot = b; +} + +void +tsetmode(int priv, int set, int *args, int narg) +{ + int alt, *lim; + + for (lim = args + narg; args < lim; ++args) { + if (priv) { + switch (*args) { + case 1: /* DECCKM -- Cursor key */ + xsetmode(set, MODE_APPCURSOR); + break; + case 5: /* DECSCNM -- Reverse video */ + xsetmode(set, MODE_REVERSE); + break; + case 6: /* DECOM -- Origin */ + MODBIT(term.c.state, set, CURSOR_ORIGIN); + tmoveato(0, 0); + break; + case 7: /* DECAWM -- Auto wrap */ + MODBIT(term.mode, set, MODE_WRAP); + break; + case 0: /* Error (IGNORED) */ + case 2: /* DECANM -- ANSI/VT52 (IGNORED) */ + case 3: /* DECCOLM -- Column (IGNORED) */ + case 4: /* DECSCLM -- Scroll (IGNORED) */ + case 8: /* DECARM -- Auto repeat (IGNORED) */ + case 18: /* DECPFF -- Printer feed (IGNORED) */ + case 19: /* DECPEX -- Printer extent (IGNORED) */ + case 42: /* DECNRCM -- National characters (IGNORED) */ + case 12: /* att610 -- Start blinking cursor (IGNORED) */ + break; + case 25: /* DECTCEM -- Text Cursor Enable Mode */ + xsetmode(!set, MODE_HIDE); + break; + case 9: /* X10 mouse compatibility mode */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEX10); + break; + case 1000: /* 1000: report button press */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEBTN); + break; + case 1002: /* 1002: report motion on button press */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMOTION); + break; + case 1003: /* 1003: enable all mouse motions */ + xsetpointermotion(set); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMANY); + break; + case 1004: /* 1004: send focus events to tty */ + xsetmode(set, MODE_FOCUS); + break; + case 1006: /* 1006: extended reporting mode */ + xsetmode(set, MODE_MOUSESGR); + break; + case 1034: + xsetmode(set, MODE_8BIT); + break; + case 1049: /* swap screen & set/restore cursor as xterm */ + if (!allowaltscreen) + break; + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + /* FALLTHROUGH */ + case 47: /* swap screen */ + case 1047: + if (!allowaltscreen) + break; + alt = IS_SET(MODE_ALTSCREEN); + if (alt) { + tclearregion(0, 0, term.col-1, + term.row-1); + } + if (set ^ alt) /* set is always 1 or 0 */ + tswapscreen(); + if (*args != 1049) + break; + /* FALLTHROUGH */ + case 1048: + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + break; + case 2004: /* 2004: bracketed paste mode */ + xsetmode(set, MODE_BRCKTPASTE); + break; + /* Not implemented mouse modes. See comments there. */ + case 1001: /* mouse highlight mode; can hang the + terminal by design when implemented. */ + case 1005: /* UTF-8 mouse mode; will confuse + applications not supporting UTF-8 + and luit. */ + case 1015: /* urxvt mangled mouse mode; incompatible + and can be mistaken for other control + codes. */ + default: + fprintf(stderr, + "erresc: unknown private set/reset mode %d\n", + *args); + break; + } + } else { + switch (*args) { + case 0: /* Error (IGNORED) */ + break; + case 2: + xsetmode(set, MODE_KBDLOCK); + break; + case 4: /* IRM -- Insertion-replacement */ + MODBIT(term.mode, set, MODE_INSERT); + break; + case 12: /* SRM -- Send/Receive */ + MODBIT(term.mode, !set, MODE_ECHO); + break; + case 20: /* LNM -- Linefeed/new line */ + MODBIT(term.mode, set, MODE_CRLF); + break; + default: + fprintf(stderr, + "erresc: unknown set/reset mode %d\n", + *args); + break; + } + } + } +} + +void +csihandle(void) +{ + char buf[40]; + int len; + + switch (csiescseq.mode[0]) { + default: + unknown: + fprintf(stderr, "erresc: unknown csi "); + csidump(); + /* die(""); */ + break; + case '@': /* ICH -- Insert blank char */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblank(csiescseq.arg[0]); + break; + case 'A': /* CUU -- Cursor Up */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y-csiescseq.arg[0]); + break; + case 'B': /* CUD -- Cursor Down */ + case 'e': /* VPR --Cursor Down */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); + break; + case 'i': /* MC -- Media Copy */ + switch (csiescseq.arg[0]) { + case 0: + tdump(); + break; + case 1: + tdumpline(term.c.y); + break; + case 2: + tdumpsel(); + break; + case 4: + term.mode &= ~MODE_PRINT; + break; + case 5: + term.mode |= MODE_PRINT; + break; + } + break; + case 'c': /* DA -- Device Attributes */ + if (csiescseq.arg[0] == 0) + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 'C': /* CUF -- Cursor Forward */ + case 'a': /* HPR -- Cursor Forward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x+csiescseq.arg[0], term.c.y); + break; + case 'D': /* CUB -- Cursor Backward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x-csiescseq.arg[0], term.c.y); + break; + case 'E': /* CNL -- Cursor Down and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y+csiescseq.arg[0]); + break; + case 'F': /* CPL -- Cursor Up and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y-csiescseq.arg[0]); + break; + case 'g': /* TBC -- Tabulation clear */ + switch (csiescseq.arg[0]) { + case 0: /* clear current tab stop */ + term.tabs[term.c.x] = 0; + break; + case 3: /* clear all the tabs */ + memset(term.tabs, 0, term.col * sizeof(*term.tabs)); + break; + default: + goto unknown; + } + break; + case 'G': /* CHA -- Move to */ + case '`': /* HPA */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(csiescseq.arg[0]-1, term.c.y); + break; + case 'H': /* CUP -- Move to */ + case 'f': /* HVP */ + DEFAULT(csiescseq.arg[0], 1); + DEFAULT(csiescseq.arg[1], 1); + tmoveato(csiescseq.arg[1]-1, csiescseq.arg[0]-1); + break; + case 'I': /* CHT -- Cursor Forward Tabulation tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(csiescseq.arg[0]); + break; + case 'J': /* ED -- Clear screen */ + switch (csiescseq.arg[0]) { + case 0: /* below */ + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + if (term.c.y < term.row-1) { + tclearregion(0, term.c.y+1, term.col-1, + term.row-1); + } + break; + case 1: /* above */ + if (term.c.y > 1) + tclearregion(0, 0, term.col-1, term.c.y-1); + tclearregion(0, term.c.y, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, 0, term.col-1, term.row-1); + break; + default: + goto unknown; + } + break; + case 'K': /* EL -- Clear line */ + switch (csiescseq.arg[0]) { + case 0: /* right */ + tclearregion(term.c.x, term.c.y, term.col-1, + term.c.y); + break; + case 1: /* left */ + tclearregion(0, term.c.y, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, term.c.y, term.col-1, term.c.y); + break; + } + break; + case 'S': /* SU -- Scroll line up */ + DEFAULT(csiescseq.arg[0], 1); + tscrollup(term.top, csiescseq.arg[0]); + break; + case 'T': /* SD -- Scroll line down */ + DEFAULT(csiescseq.arg[0], 1); + tscrolldown(term.top, csiescseq.arg[0]); + break; + case 'L': /* IL -- Insert blank lines */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblankline(csiescseq.arg[0]); + break; + case 'l': /* RM -- Reset Mode */ + tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg); + break; + case 'M': /* DL -- Delete lines */ + DEFAULT(csiescseq.arg[0], 1); + tdeleteline(csiescseq.arg[0]); + break; + case 'X': /* ECH -- Erase char */ + DEFAULT(csiescseq.arg[0], 1); + tclearregion(term.c.x, term.c.y, + term.c.x + csiescseq.arg[0] - 1, term.c.y); + break; + case 'P': /* DCH -- Delete char */ + DEFAULT(csiescseq.arg[0], 1); + tdeletechar(csiescseq.arg[0]); + break; + case 'Z': /* CBT -- Cursor Backward Tabulation tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(-csiescseq.arg[0]); + break; + case 'd': /* VPA -- Move to */ + DEFAULT(csiescseq.arg[0], 1); + tmoveato(term.c.x, csiescseq.arg[0]-1); + break; + case 'h': /* SM -- Set terminal mode */ + tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg); + break; + case 'm': /* SGR -- Terminal attribute (color) */ + tsetattr(csiescseq.arg, csiescseq.narg); + break; + case 'n': /* DSR – Device Status Report (cursor position) */ + if (csiescseq.arg[0] == 6) { + len = snprintf(buf, sizeof(buf),"\033[%i;%iR", + term.c.y+1, term.c.x+1); + ttywrite(buf, len, 0); + } + break; + case 'r': /* DECSTBM -- Set Scrolling Region */ + if (csiescseq.priv) { + goto unknown; + } else { + DEFAULT(csiescseq.arg[0], 1); + DEFAULT(csiescseq.arg[1], term.row); + tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1); + tmoveato(0, 0); + } + break; + case 's': /* DECSC -- Save cursor position (ANSI.SYS) */ + tcursor(CURSOR_SAVE); + break; + case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ + tcursor(CURSOR_LOAD); + break; + case ' ': + switch (csiescseq.mode[1]) { + case 'q': /* DECSCUSR -- Set Cursor Style */ + if (xsetcursor(csiescseq.arg[0])) + goto unknown; + break; + default: + goto unknown; + } + break; + } +} + +void +csidump(void) +{ + int i; + uint c; + + fprintf(stderr, "ESC["); + for (i = 0; i < csiescseq.len; i++) { + c = csiescseq.buf[i] & 0xff; + if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + putc('\n', stderr); +} + +void +csireset(void) +{ + memset(&csiescseq, 0, sizeof(csiescseq)); +} + +void +strhandle(void) +{ + char *p = NULL; + int j, narg, par; + + term.esc &= ~(ESC_STR_END|ESC_STR); + strparse(); + par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0; + + switch (strescseq.type) { + case ']': /* OSC -- Operating System Command */ + switch (par) { + case 0: + case 1: + case 2: + if (narg > 1) + xsettitle(strescseq.args[1]); + return; + case 52: + if (narg > 2) { + char *dec; + + dec = base64dec(strescseq.args[2]); + if (dec) { + xsetsel(dec); + xclipcopy(); + } else { + fprintf(stderr, "erresc: invalid base64\n"); + } + } + return; + case 4: /* color set */ + if (narg < 3) + break; + p = strescseq.args[2]; + /* FALLTHROUGH */ + 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); + } else { + /* + * TODO if defaultbg color is changed, borders + * are dirty + */ + redraw(); + } + return; + } + break; + case 'k': /* old title set compatibility */ + 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; + } + + fprintf(stderr, "erresc: unknown str "); + strdump(); +} + +void +strparse(void) +{ + int c; + char *p = strescseq.buf; + + strescseq.narg = 0; + strescseq.buf[strescseq.len] = '\0'; + + if (*p == '\0') + return; + + while (strescseq.narg < STR_ARG_SIZ) { + strescseq.args[strescseq.narg++] = p; + while ((c = *p) != ';' && c != '\0') + ++p; + if (c == '\0') + return; + *p++ = '\0'; + } +} + +void +strdump(void) +{ + int i; + uint c; + + fprintf(stderr, "ESC%c", strescseq.type); + for (i = 0; i < strescseq.len; i++) { + c = strescseq.buf[i] & 0xff; + if (c == '\0') { + putc('\n', stderr); + return; + } else if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + fprintf(stderr, "ESC\\\n"); +} + +void +strreset(void) +{ + memset(&strescseq, 0, sizeof(strescseq)); +} + +void +sendbreak(const Arg *arg) +{ + if (tcsendbreak(cmdfd, 0)) + perror("Error sending break"); +} + +void +tprinter(char *s, size_t len) +{ + if (iofd != -1 && xwrite(iofd, s, len) < 0) { + perror("Error writing to output file"); + close(iofd); + iofd = -1; + } +} + +void +iso14755(const Arg *arg) +{ + FILE *p; + char *us, *e, codepoint[9], uc[UTF_SIZ]; + unsigned long utf32; + + if (!(p = popen(ISO14755CMD, "r"))) + return; + + us = fgets(codepoint, sizeof(codepoint), p); + pclose(p); + + if (!us || *us == '\0' || *us == '-' || strlen(us) > 7) + return; + if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || + (*e != '\n' && *e != '\0')) + return; + + ttywrite(uc, utf8encode(utf32, uc), 1); +} + +void +toggleprinter(const Arg *arg) +{ + term.mode ^= MODE_PRINT; +} + +void +printscreen(const Arg *arg) +{ + tdump(); +} + +void +printsel(const Arg *arg) +{ + tdumpsel(); +} + +void +tdumpsel(void) +{ + char *ptr; + + if ((ptr = getsel())) { + tprinter(ptr, strlen(ptr)); + free(ptr); + } +} + +void +tdumpline(int n) +{ + char buf[UTF_SIZ]; + Glyph *bp, *end; + + bp = &term.line[n][0]; + end = &bp[MIN(tlinelen(n), term.col) - 1]; + if (bp != end || bp->u != ' ') { + for ( ;bp <= end; ++bp) + tprinter(buf, utf8encode(bp->u, buf)); + } + tprinter("\n", 1); +} + +void +tdump(void) +{ + int i; + + for (i = 0; i < term.row; ++i) + tdumpline(i); +} + +void +tputtab(int n) +{ + uint x = term.c.x; + + if (n > 0) { + while (x < term.col && n--) + for (++x; x < term.col && !term.tabs[x]; ++x) + /* nothing */ ; + } else if (n < 0) { + while (x > 0 && n++) + for (--x; x > 0 && !term.tabs[x]; --x) + /* nothing */ ; + } + term.c.x = LIMIT(x, 0, term.col-1); +} + +void +tdefutf8(char ascii) +{ + if (ascii == 'G') + term.mode |= MODE_UTF8; + else if (ascii == '@') + term.mode &= ~MODE_UTF8; +} + +void +tdeftran(char ascii) +{ + static char cs[] = "0B"; + static int vcs[] = {CS_GRAPHIC0, CS_USA}; + char *p; + + if ((p = strchr(cs, ascii)) == NULL) { + fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii); + } else { + term.trantbl[term.icharset] = vcs[p - cs]; + } +} + +void +tdectest(char c) +{ + int x, y; + + if (c == '8') { /* DEC screen alignment test. */ + for (x = 0; x < term.col; ++x) { + for (y = 0; y < term.row; ++y) + tsetchar('E', &term.c.attr, x, y); + } + } +} + +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 = '_'; + break; + case 0x9e: /* PM -- Privacy Message */ + c = '^'; + break; + case 0x9d: /* OSC -- Operating System Command */ + c = ']'; + break; + } + strescseq.type = c; + term.esc |= ESC_STR; +} + +void +tcontrolcode(uchar ascii) +{ + switch (ascii) { + case '\t': /* HT */ + tputtab(1); + return; + case '\b': /* BS */ + tmoveto(term.c.x-1, term.c.y); + return; + case '\r': /* CR */ + tmoveto(0, term.c.y); + return; + case '\f': /* LF */ + case '\v': /* VT */ + case '\n': /* LF */ + /* go to first col if the mode is set */ + tnewline(IS_SET(MODE_CRLF)); + return; + case '\a': /* BEL */ + if (term.esc & ESC_STR_END) { + /* backwards compatibility to xterm */ + strhandle(); + } else { + xbell(); + } + break; + case '\033': /* ESC */ + csireset(); + term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST); + term.esc |= ESC_START; + return; + case '\016': /* SO (LS1 -- Locking shift 1) */ + case '\017': /* SI (LS0 -- Locking shift 0) */ + term.charset = 1 - (ascii - '\016'); + return; + case '\032': /* SUB */ + tsetchar('?', &term.c.attr, term.c.x, term.c.y); + case '\030': /* CAN */ + csireset(); + break; + case '\005': /* ENQ (IGNORED) */ + case '\000': /* NUL (IGNORED) */ + case '\021': /* XON (IGNORED) */ + case '\023': /* XOFF (IGNORED) */ + case 0177: /* DEL (IGNORED) */ + return; + case 0x80: /* TODO: PAD */ + case 0x81: /* TODO: HOP */ + case 0x82: /* TODO: BPH */ + case 0x83: /* TODO: NBH */ + case 0x84: /* TODO: IND */ + break; + case 0x85: /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 0x86: /* TODO: SSA */ + case 0x87: /* TODO: ESA */ + break; + case 0x88: /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 0x89: /* TODO: HTJ */ + case 0x8a: /* TODO: VTS */ + case 0x8b: /* TODO: PLD */ + case 0x8c: /* TODO: PLU */ + case 0x8d: /* TODO: RI */ + case 0x8e: /* TODO: SS2 */ + case 0x8f: /* TODO: SS3 */ + case 0x91: /* TODO: PU1 */ + case 0x92: /* TODO: PU2 */ + case 0x93: /* TODO: STS */ + case 0x94: /* TODO: CCH */ + case 0x95: /* TODO: MW */ + case 0x96: /* TODO: SPA */ + case 0x97: /* TODO: EPA */ + case 0x98: /* TODO: SOS */ + case 0x99: /* TODO: SGCI */ + break; + case 0x9a: /* DECID -- Identify Terminal */ + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 0x9b: /* TODO: CSI */ + case 0x9c: /* TODO: ST */ + break; + case 0x90: /* DCS -- Device Control String */ + case 0x9d: /* OSC -- Operating System Command */ + case 0x9e: /* PM -- Privacy Message */ + case 0x9f: /* APC -- Application Program Command */ + tstrsequence(ascii); + return; + } + /* only CAN, SUB, \a and C1 chars interrupt a sequence */ + term.esc &= ~(ESC_STR_END|ESC_STR); +} + +/* + * returns 1 when the sequence is finished and it hasn't to read + * more characters for this sequence, otherwise 0 + */ +int +eschandle(uchar ascii) +{ + switch (ascii) { + case '[': + term.esc |= ESC_CSI; + return 0; + case '#': + term.esc |= ESC_TEST; + return 0; + case '%': + term.esc |= ESC_UTF8; + return 0; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ + case '^': /* PM -- Privacy Message */ + case ']': /* OSC -- Operating System Command */ + case 'k': /* old title set compatibility */ + tstrsequence(ascii); + return 0; + case 'n': /* LS2 -- Locking shift 2 */ + case 'o': /* LS3 -- Locking shift 3 */ + term.charset = 2 + (ascii - 'n'); + break; + case '(': /* GZD4 -- set primary charset G0 */ + case ')': /* G1D4 -- set secondary charset G1 */ + case '*': /* G2D4 -- set tertiary charset G2 */ + case '+': /* G3D4 -- set quaternary charset G3 */ + term.icharset = ascii - '('; + term.esc |= ESC_ALTCHARSET; + return 0; + case 'D': /* IND -- Linefeed */ + if (term.c.y == term.bot) { + tscrollup(term.top, 1); + } else { + tmoveto(term.c.x, term.c.y+1); + } + break; + case 'E': /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 'H': /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 'M': /* RI -- Reverse index */ + if (term.c.y == term.top) { + tscrolldown(term.top, 1); + } else { + tmoveto(term.c.x, term.c.y-1); + } + break; + case 'Z': /* DECID -- Identify Terminal */ + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 'c': /* RIS -- Reset to inital state */ + treset(); + resettitle(); + xloadcols(); + break; + case '=': /* DECPAM -- Application keypad */ + xsetmode(1, MODE_APPKEYPAD); + break; + case '>': /* DECPNM -- Normal keypad */ + xsetmode(0, MODE_APPKEYPAD); + break; + case '7': /* DECSC -- Save Cursor */ + tcursor(CURSOR_SAVE); + break; + case '8': /* DECRC -- Restore Cursor */ + tcursor(CURSOR_LOAD); + break; + case '\\': /* ST -- String Terminator */ + if (term.esc & ESC_STR_END) + strhandle(); + break; + default: + fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", + (uchar) ascii, isprint(ascii)? ascii:'.'); + break; + } + return 1; +} + +void +tputc(Rune u) +{ + char c[UTF_SIZ]; + int control; + int width, len; + Glyph *gp; + + control = ISCONTROL(u); + if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { + 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 */ + width = 1; + } + } + + if (IS_SET(MODE_PRINT)) + tprinter(c, len); + + /* + * STR sequence must be checked before anything else + * because it uses all following characters until it + * receives a ESC, a SUB, a ST or any other C1 control + * character. + */ + 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_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) { + /* + * Here is a bug in terminals. If the user never sends + * some code to stop the str or esc command, then st + * will stop responding. But this is better than + * silently failing with unknown characters. At least + * then users will report back. + * + * In the case users ever get fixed, here is the code: + */ + /* + * term.esc = 0; + * strhandle(); + */ + return; + } + + memmove(&strescseq.buf[strescseq.len], c, len); + strescseq.len += len; + return; + } + +check_control_code: + /* + * Actions of control codes must be performed as soon they arrive + * because they can be embedded inside a control sequence, and + * they must not cause conflicts with sequences. + */ + if (control) { + tcontrolcode(u); + /* + * control codes are not shown ever + */ + return; + } else if (term.esc & ESC_START) { + if (term.esc & ESC_CSI) { + csiescseq.buf[csiescseq.len++] = u; + if (BETWEEN(u, 0x40, 0x7E) + || csiescseq.len >= \ + sizeof(csiescseq.buf)-1) { + term.esc = 0; + csiparse(); + csihandle(); + } + return; + } else if (term.esc & ESC_UTF8) { + tdefutf8(u); + } else if (term.esc & ESC_ALTCHARSET) { + tdeftran(u); + } else if (term.esc & ESC_TEST) { + tdectest(u); + } else { + if (!eschandle(u)) + return; + /* sequence already finished */ + } + term.esc = 0; + /* + * All characters which form part of a sequence are not + * printed + */ + return; + } + if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y)) + selclear(); + + gp = &term.line[term.c.y][term.c.x]; + if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { + gp->mode |= ATTR_WRAP; + tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } + + if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) + memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); + + if (term.c.x+width > term.col) { + tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } + + tsetchar(u, &term.c.attr, term.c.x, term.c.y); + + if (width == 2) { + gp->mode |= ATTR_WIDE; + if (term.c.x+1 < term.col) { + gp[1].u = '\0'; + gp[1].mode = ATTR_WDUMMY; + } + } + if (term.c.x+width < term.col) { + tmoveto(term.c.x+width, term.c.y); + } else { + term.c.state |= CURSOR_WRAPNEXT; + } +} + +int +twrite(const char *buf, int buflen, int show_ctrl) +{ + int charsize; + Rune u; + int n; + + for (n = 0; n < buflen; n += charsize) { + if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { + /* process a complete utf8 char */ + charsize = utf8decode(buf + n, &u, buflen - n); + if (charsize == 0) + break; + } else { + u = buf[n] & 0xFF; + charsize = 1; + } + if (show_ctrl && ISCONTROL(u)) { + if (u & 0x80) { + u &= 0x7f; + tputc('^'); + tputc('['); + } else if (u != '\n' && u != '\r' && u != '\t') { + u ^= 0x40; + tputc('^'); + } + } + tputc(u); + } + return n; +} + +void +tresize(int col, int row) +{ + int i; + int minrow = MIN(row, term.row); + int mincol = MIN(col, term.col); + int *bp; + TCursor c; + + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); + return; + } + + /* + * slide screen to keep cursor where we expect it - + * tscrollup would work here, but we can optimize to + * memmove because we're freeing the earlier lines + */ + for (i = 0; i <= term.c.y - row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + /* ensure that both src and dst are not NULL */ + if (i > 0) { + memmove(term.line, term.line + i, row * sizeof(Line)); + memmove(term.alt, term.alt + i, row * sizeof(Line)); + } + for (i += row; i < term.row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + + /* resize to new height */ + term.line = xrealloc(term.line, row * sizeof(Line)); + term.alt = xrealloc(term.alt, row * sizeof(Line)); + term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); + term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); + + /* 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)); + term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); + } + + /* allocate any new rows */ + for (/* i = minrow */; i < row; i++) { + term.line[i] = xmalloc(col * sizeof(Glyph)); + term.alt[i] = xmalloc(col * sizeof(Glyph)); + } + if (col > term.col) { + bp = term.tabs + term.col; + + memset(bp, 0, sizeof(*term.tabs) * (col - term.col)); + while (--bp > term.tabs && !*bp) + /* nothing */ ; + for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) + *bp = 1; + } + /* update terminal size */ + term.col = col; + term.row = row; + /* reset scrolling region */ + tsetscroll(0, row-1); + /* make use of the LIMIT in tmoveto */ + tmoveto(term.c.x, term.c.y); + /* Clearing both screens (it makes dirty all lines) */ + c = term.c; + for (i = 0; i < 2; i++) { + if (mincol < col && 0 < minrow) { + tclearregion(mincol, 0, col - 1, minrow - 1); + } + if (0 < col && minrow < row) { + tclearregion(0, minrow, col - 1, row - 1); + } + tswapscreen(); + tcursor(CURSOR_LOAD); + } + term.c = c; +} + +void +resettitle(void) +{ + xsettitle(NULL); +} + +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(term.line[y], x1, y, x2); + } +} + +void +draw(void) +{ + int cx = term.c.x; + + if (!xstartdraw()) + return; + + /* adjust cursor position */ + LIMIT(term.ocx, 0, term.col-1); + LIMIT(term.ocy, 0, term.row-1); + if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY) + term.ocx--; + if (term.line[term.c.y][cx].mode & ATTR_WDUMMY) + cx--; + + drawregion(0, 0, term.col, term.row); + xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], + term.ocx, term.ocy, term.line[term.ocy][term.ocx]); + term.ocx = cx, term.ocy = term.c.y; + xfinishdraw(); +} + +void +redraw(void) +{ + tfulldirt(); + draw(); +} diff --git a/8/st-0.8.1/st.h b/8/st-0.8.1/st.h new file mode 100644 index 0000000..433c74f --- /dev/null +++ b/8/st-0.8.1/st.h @@ -0,0 +1,124 @@ +/* See LICENSE for license details. */ + +#include +#include + +/* macros */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define LEN(a) (sizeof(a) / sizeof(a)[0]) +#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) +#define DEFAULT(a, b) (a) = (a) ? (a) : (b) +#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) +#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \ + (a).bg != (b).bg) +#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ + (t1.tv_nsec-t2.tv_nsec)/1E6) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) + +#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +#define IS_TRUECOL(x) (1 << 24 & (x)) + +enum glyph_attribute { + ATTR_NULL = 0, + ATTR_BOLD = 1 << 0, + ATTR_FAINT = 1 << 1, + ATTR_ITALIC = 1 << 2, + ATTR_UNDERLINE = 1 << 3, + ATTR_BLINK = 1 << 4, + ATTR_REVERSE = 1 << 5, + ATTR_INVISIBLE = 1 << 6, + ATTR_STRUCK = 1 << 7, + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, +}; + +enum selection_mode { + SEL_IDLE = 0, + SEL_EMPTY = 1, + SEL_READY = 2 +}; + +enum selection_type { + SEL_REGULAR = 1, + SEL_RECTANGULAR = 2 +}; + +enum selection_snap { + SNAP_WORD = 1, + SNAP_LINE = 2 +}; + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned short ushort; + +typedef uint_least32_t Rune; + +#define Glyph Glyph_ +typedef struct { + Rune u; /* character code */ + ushort mode; /* attribute flags */ + uint32_t fg; /* foreground */ + uint32_t bg; /* background */ +} Glyph; + +typedef Glyph *Line; + +typedef union { + int i; + uint ui; + float f; + const void *v; +} Arg; + +void die(const char *, ...); +void redraw(void); +void draw(void); + +void iso14755(const Arg *); +void printscreen(const Arg *); +void printsel(const Arg *); +void sendbreak(const Arg *); +void toggleprinter(const Arg *); + +int tattrset(int); +void tnew(int, int); +void tresize(int, int); +void tsetdirtattr(int); +void ttyhangup(void); +int ttynew(char *, char *, char *, char **); +size_t ttyread(void); +void ttyresize(int, int); +void ttywrite(const char *, size_t, int); + +void resettitle(void); + +void selclear(void); +void selinit(void); +void selstart(int, int, int); +void selextend(int, int, int, int); +int selected(int, int); +char *getsel(void); + +size_t utf8encode(Rune, char *); + +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +char *xstrdup(char *); + +/* config.h globals */ +extern char *utmp; +extern char *stty_args; +extern char *vtiden; +extern char *worddelimiters; +extern int allowaltscreen; +extern char *termname; +extern unsigned int tabspaces; +extern unsigned int alpha; +extern unsigned int defaultfg; +extern unsigned int defaultbg; diff --git a/8/st-0.8.1/st.info b/8/st-0.8.1/st.info new file mode 100644 index 0000000..52fc617 --- /dev/null +++ b/8/st-0.8.1/st.info @@ -0,0 +1,222 @@ +st| simpleterm, + acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + am, + bce, + bel=^G, + blink=\E[5m, + bold=\E[1m, + cbt=\E[Z, + cvvis=\E[?25h, + civis=\E[?25l, + clear=\E[H\E[2J, + cnorm=\E[?12l\E[?25h, + colors#8, + cols#80, + cr=^M, + csr=\E[%i%p1%d;%p2%dr, + cub=\E[%p1%dD, + cub1=^H, + cud1=^J, + cud=\E[%p1%dB, + cuf1=\E[C, + cuf=\E[%p1%dC, + cup=\E[%i%p1%d;%p2%dH, + cuu1=\E[A, + cuu=\E[%p1%dA, + dch=\E[%p1%dP, + dch1=\E[P, + dim=\E[2m, + dl=\E[%p1%dM, + dl1=\E[M, + ech=\E[%p1%dX, + ed=\E[J, + el=\E[K, + el1=\E[1K, + enacs=\E)0, + flash=\E[?5h$<80/>\E[?5l, + fsl=^G, + home=\E[H, + hpa=\E[%i%p1%dG, + hs, + ht=^I, + hts=\EH, + ich=\E[%p1%d@, + il1=\E[L, + il=\E[%p1%dL, + ind=^J, + indn=\E[%p1%dS, + invis=\E[8m, + is2=\E[4l\E>\E[?1034l, + it#8, + kel=\E[1;2F, + ked=\E[1;5F, + ka1=\E[1~, + ka3=\E[5~, + kc1=\E[4~, + kc3=\E[6~, + kbs=\177, + kcbt=\E[Z, + kb2=\EOu, + kcub1=\EOD, + kcud1=\EOB, + kcuf1=\EOC, + kcuu1=\EOA, + kDC=\E[3;2~, + kent=\EOM, + kEND=\E[1;2F, + kIC=\E[2;2~, + kNXT=\E[6;2~, + kPRV=\E[5;2~, + kHOM=\E[1;2H, + kLFT=\E[1;2D, + kRIT=\E[1;2C, + kind=\E[1;2B, + kri=\E[1;2A, + kclr=\E[3;5~, + kdl1=\E[3;2~, + kdch1=\E[3~, + kich1=\E[2~, + kend=\E[4~, + kf1=\EOP, + kf2=\EOQ, + kf3=\EOR, + kf4=\EOS, + kf5=\E[15~, + kf6=\E[17~, + kf7=\E[18~, + kf8=\E[19~, + kf9=\E[20~, + kf10=\E[21~, + kf11=\E[23~, + kf12=\E[24~, + kf13=\E[1;2P, + kf14=\E[1;2Q, + kf15=\E[1;2R, + kf16=\E[1;2S, + kf17=\E[15;2~, + kf18=\E[17;2~, + kf19=\E[18;2~, + kf20=\E[19;2~, + kf21=\E[20;2~, + kf22=\E[21;2~, + kf23=\E[23;2~, + kf24=\E[24;2~, + kf25=\E[1;5P, + kf26=\E[1;5Q, + kf27=\E[1;5R, + kf28=\E[1;5S, + kf29=\E[15;5~, + kf30=\E[17;5~, + kf31=\E[18;5~, + kf32=\E[19;5~, + kf33=\E[20;5~, + kf34=\E[21;5~, + kf35=\E[23;5~, + kf36=\E[24;5~, + kf37=\E[1;6P, + kf38=\E[1;6Q, + kf39=\E[1;6R, + kf40=\E[1;6S, + kf41=\E[15;6~, + kf42=\E[17;6~, + kf43=\E[18;6~, + kf44=\E[19;6~, + kf45=\E[20;6~, + kf46=\E[21;6~, + kf47=\E[23;6~, + kf48=\E[24;6~, + kf49=\E[1;3P, + kf50=\E[1;3Q, + kf51=\E[1;3R, + kf52=\E[1;3S, + kf53=\E[15;3~, + kf54=\E[17;3~, + kf55=\E[18;3~, + kf56=\E[19;3~, + kf57=\E[20;3~, + kf58=\E[21;3~, + kf59=\E[23;3~, + kf60=\E[24;3~, + kf61=\E[1;4P, + kf62=\E[1;4Q, + kf63=\E[1;4R, + khome=\E[1~, + kil1=\E[2;5~, + krmir=\E[2;2~, + knp=\E[6~, + kmous=\E[M, + kpp=\E[5~, + lines#24, + mir, + msgr, + npc, + op=\E[39;49m, + pairs#64, + mc0=\E[i, + mc4=\E[4i, + mc5=\E[5i, + rc=\E8, + rev=\E[7m, + ri=\EM, + ritm=\E[23m, + rmacs=\E(B, + rmcup=\E[?1049l, + rmir=\E[4l, + rmkx=\E[?1l\E>, + rmso=\E[27m, + rmul=\E[24m, + 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, + smacs=\E(0, + smcup=\E[?1049h, + smir=\E[4h, + smkx=\E[?1h\E=, + smso=\E[7m, + smul=\E[4m, + tbc=\E[3g, + tsl=\E]0;, + xenl, + vpa=\E[%i%p1%dd, +# XTerm extensions + rmxx=\E[29m, + smxx=\E[9m, +# tmux extensions, see TERMINFO EXTENSIONS in tmux(1) + Se, + Ss, + Tc, + Ms=\E]52;%p1%s;%p2%s\007, + +st-256color| simpleterm with 256 colors, + use=st, + ccc, + colors#256, + oc=\E]104\007, + pairs#32767, +# Nicked from xterm-256color + initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\, + setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, + setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, + +st-meta| simpleterm with meta key, + use=st, + km, + rmm=\E[?1034l, + smm=\E[?1034h, + rs2=\E[4l\E>\E[?1034h, + is2=\E[4l\E>\E[?1034h, + +st-meta-256color| simpleterm with meta key and 256 colors, + use=st-256color, + km, + rmm=\E[?1034l, + smm=\E[?1034h, + rs2=\E[4l\E>\E[?1034h, + is2=\E[4l\E>\E[?1034h, diff --git a/8/st-0.8.1/win.h b/8/st-0.8.1/win.h new file mode 100644 index 0000000..31f327d --- /dev/null +++ b/8/st-0.8.1/win.h @@ -0,0 +1,38 @@ +/* See LICENSE for license details. */ + +enum win_mode { + MODE_VISIBLE = 1 << 0, + MODE_FOCUSED = 1 << 1, + MODE_APPKEYPAD = 1 << 2, + MODE_MOUSEBTN = 1 << 3, + MODE_MOUSEMOTION = 1 << 4, + MODE_REVERSE = 1 << 5, + MODE_KBDLOCK = 1 << 6, + MODE_HIDE = 1 << 7, + MODE_APPCURSOR = 1 << 8, + MODE_MOUSESGR = 1 << 9, + MODE_8BIT = 1 << 10, + MODE_BLINK = 1 << 11, + MODE_FBLINK = 1 << 12, + MODE_FOCUS = 1 << 13, + MODE_MOUSEX10 = 1 << 14, + MODE_MOUSEMANY = 1 << 15, + MODE_BRCKTPASTE = 1 << 16, + MODE_NUMLOCK = 1 << 17, + MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ + |MODE_MOUSEMANY, +}; + +void xbell(void); +void xclipcopy(void); +void xdrawcursor(int, int, Glyph, int, int, Glyph); +void xdrawline(Line, int, int, int); +void xfinishdraw(void); +void xloadcols(void); +int xsetcolorname(int, const char *); +void xsettitle(char *); +int xsetcursor(int); +void xsetmode(int, unsigned int); +void xsetpointermotion(int); +void xsetsel(char *); +int xstartdraw(void); diff --git a/8/st-0.8.1/x.c b/8/st-0.8.1/x.c new file mode 100644 index 0000000..0de60d5 --- /dev/null +++ b/8/st-0.8.1/x.c @@ -0,0 +1,2083 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static 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 b; + uint mask; + char *s; +} 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; + +/* Xresources preferences */ +enum resource_type { + STRING = 0, + INTEGER = 1, + FLOAT = 2 +}; + +typedef struct { + char *name; + enum resource_type type; + void *dst; +} ResourcePref; + +/* X modifiers */ +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13) + +/* alpha */ +#define OPAQUE 0Xff +#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) + +/* 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 *); + +/* 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; + XIM xim; + XIC xic; + 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; + +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 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 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[16]; +static int frclen = 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); + } +} + +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 | forceselmod); + + 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); +} + +void +bpress(XEvent *e) +{ + struct timespec now; + MouseShortcut *ms; + int snap; + + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + 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; + } + } + + 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(); +} + +void +xsetsel(char *str) +{ + setsel(str, CurrentTime); +} + +void +brelease(XEvent *e) +{ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + mousereport(e); + return; + } + + if (e->xbutton.button == Button2) + selpaste(NULL); + else if (e->xbutton.button == Button1) + mousesel(e, 1); +} + +void +bmotion(XEvent *e) +{ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + 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; + + tresize(col, row); + xresize(col, row); + ttyresize(win.tw, win.th); +} + +void +xresize(int col, int row) +{ + win.tw = MAX(1, col * win.cw); + win.th = MAX(1, row * win.ch); + + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, + xw.depth); + 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; + + dc.collen = MAX(LEN(colorname), 256); + dc.col = xmalloc(dc.collen * sizeof(Color)); + + if (loaded) { + for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) + XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); + } + + 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); + } + + /* set alpha value of bg color */ + if (USE_ARGB) { + dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE; + dc.col[defaultbg].pixel &= 0x00111111; + dc.col[defaultbg].pixel |= alpha << 24; + } + 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; +} + +void +xtermclear(int col1, int row1, int col2, int row2) +{ + XftDrawRect(xw.draw, + &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], + borderpx + col1 * win.cw, + borderpx + row1 * win.ch, + (col2-col1+1) * win.cw, + (row2-row1+1) * win.ch); +} + +/* + * 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 : "st", + opt_class ? opt_class : "St"}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints *sizeh; + + sizeh = XAllocSizeHints(); + + sizeh->flags = PSize | PResizeInc | PBaseSize; + 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; + if (xw.isfixed) { + sizeh->flags |= PMaxSize | PMinSize; + 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("st: 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("st: 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("st: 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("st: 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("st: can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (xloadfont(&dc.ibfont, pattern)) + die("st: can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadfont(&dc.bfont, pattern)) + die("st: 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); +} + +void +xinit(int cols, int rows) +{ + XGCValues gcvalues; + Cursor cursor; + Window parent; + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; + + xw.scr = XDefaultScreen(xw.dpy); + xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr); + if (!USE_ARGB) + xw.vis = XDefaultVisual(xw.dpy, xw.scr); + else { + XVisualInfo *vis; + XRenderPictFormat *fmt; + int nvi; + int i; + + XVisualInfo tpl = { + .screen = xw.scr, + .depth = 32, + .class = TrueColor + }; + + vis = XGetVisualInfo(xw.dpy, + VisualScreenMask | VisualDepthMask | VisualClassMask, + &tpl, &nvi); + xw.vis = NULL; + for (i = 0; i < nvi; i++) { + fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual); + if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) { + xw.vis = vis[i].visual; + break; + } + } + + XFree(vis); + + if (!xw.vis) { + fprintf(stderr, "Couldn't find ARGB visual.\n"); + exit(1); + } + } + + /* font */ + if (!FcInit()) + die("Could not init fontconfig.\n"); + + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + + /* colors */ + if (!USE_ARGB) + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + else + xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr), + xw.vis, None); + 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 + | 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, + 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, (USE_ARGB) ? xw.buf: parent, + GCGraphicsExposures, &gcvalues); + 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 ((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"); + } + } + } + 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); + 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(); + XMapWindow(xw.dpy, xw.win); + xhints(); + 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); + + /* + * 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; + } + + 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: snowman (U+2603) */ + // g.u = 0x2592; + g.u = 0x25A7; + // g.u = 0x2603; + 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 +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) +{ + DEFAULT(cursor, 1); + if (!BETWEEN(cursor, 0, 6)) + 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) { + XSetICFocus(xw.xic); + win.mode |= MODE_FOCUSED; + xseturgency(0); + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); + } else { + XUnsetICFocus(xw.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[32], *customkey; + int len; + Rune c; + Status status; + Shortcut *bp; + + if (IS_SET(MODE_KBDLOCK)) + return; + + len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); + /* 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), xev, blinkset = 0, dodraw = 0; + int ttyfd; + struct timespec drawtimeout, *tv = NULL, now, last, lastblink; + long deltatime; + + /* 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); + + clock_gettime(CLOCK_MONOTONIC, &last); + lastblink = last; + + for (xev = actionfps;;) { + FD_ZERO(&rfd); + FD_SET(ttyfd, &rfd); + FD_SET(xfd, &rfd); + + 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 (dodraw) { + while (XPending(xw.dpy)) { + XNextEvent(xw.dpy, &ev); + if (XFilterEvent(&ev, None)) + continue; + if (handler[ev.type]) + (handler[ev.type])(&ev); + } + + 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; + } + } + } + } +} + +int +resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) +{ + char **sdst = dst; + int *idst = dst; + float *fdst = dst; + + char fullname[256]; + char fullclass[256]; + char *type; + XrmValue ret; + + snprintf(fullname, sizeof(fullname), "%s.%s", + opt_name ? opt_name : "st", name); + snprintf(fullclass, sizeof(fullclass), "%s.%s", + opt_class ? opt_class : "St", name); + fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0'; + + XrmGetResource(db, fullname, fullclass, &type, &ret); + if (ret.addr == NULL || strncmp("String", type, 64)) + return 1; + + switch (rtype) { + case STRING: + *sdst = ret.addr; + break; + case INTEGER: + *idst = strtoul(ret.addr, NULL, 10); + break; + case FLOAT: + *fdst = strtof(ret.addr, NULL); + break; + } + return 0; +} + +void +config_init(void) +{ + char *resm; + XrmDatabase db; + ResourcePref *p; + + XrmInitialize(); + resm = XResourceManagerString(xw.dpy); + if (!resm) + return; + + db = XrmGetStringDatabase(resm); + for (p = resources; p < resources + LEN(resources); p++) + resource_load(db, p->name, p->type, p->dst); +} + +void +usage(void) +{ + 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; + win.cursor = 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 " (c) 2010-2016 st engineers\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(""); + + if(!(xw.dpy = XOpenDisplay(NULL))) + die("Can't open display\n"); + + config_init(); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); + xinit(cols, rows); + xsetenv(); + selinit(); + run(); + + return 0; +} diff --git a/8/st-0.8.1/x.c.rej b/8/st-0.8.1/x.c.rej new file mode 100644 index 0000000..8c6e806 --- /dev/null +++ b/8/st-0.8.1/x.c.rej @@ -0,0 +1,31 @@ +--- x.c ++++ x.c +@@ -1614,15 +1613,6 @@ xbell(void) + xseturgency(1); + if (bellvolume) + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); +- +- /* visual bell*/ +- if (!bellon) { +- bellon = 1; +- MODBIT(win.mode, !IS_SET(MODE_REVERSE), MODE_REVERSE); +- redraw(); +- XFlush(xw.dpy); +- MODBIT(win.mode, !IS_SET(MODE_REVERSE), MODE_REVERSE); +- } + } + + void +@@ -1849,11 +1839,7 @@ run(void) + (handler[ev.type])(&ev); + } + +- if (bellon) { +- bellon = 0; +- redraw(); +- } +- else draw(); ++ draw(); + XFlush(xw.dpy); + + if (xev && !FD_ISSET(xfd, &rfd)) diff --git a/8/st-alpha-0.8.1.diff b/8/st-alpha-0.8.1.diff new file mode 100644 index 0000000..aafa9a1 --- /dev/null +++ b/8/st-alpha-0.8.1.diff @@ -0,0 +1,199 @@ +diff --git a/config.def.h b/config.def.h +index 82b1b09..2c721e8 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -82,6 +82,9 @@ char *termname = "st-256color"; + */ + unsigned int tabspaces = 8; + ++/* bg opacity */ ++unsigned int alpha = 0xcc; ++ + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { + /* 8 normal colors */ +@@ -109,6 +112,7 @@ static const char *colorname[] = { + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", + "#555555", ++ "black", + }; + + +@@ -117,7 +121,7 @@ static const char *colorname[] = { + * foreground, background, cursor, reverse cursor + */ + unsigned int defaultfg = 7; +-unsigned int defaultbg = 0; ++unsigned int defaultbg = 257; + static unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; + +diff --git a/config.mk b/config.mk +index 039c42c..b1fa717 100644 +--- a/config.mk ++++ b/config.mk +@@ -11,10 +11,10 @@ X11INC = /usr/X11R6/include + X11LIB = /usr/X11R6/lib + + # includes and libs +-INCS = -I$(X11INC) \ ++INCS = -I. -I/usr/include -I${X11INC} \ + `pkg-config --cflags fontconfig` \ + `pkg-config --cflags freetype2` +-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ ++LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXft -lXrender\ + `pkg-config --libs fontconfig` \ + `pkg-config --libs freetype2` + +diff --git a/st.h b/st.h +index dac64d8..433c74f 100644 +--- a/st.h ++++ b/st.h +@@ -119,5 +119,6 @@ extern char *worddelimiters; + extern int allowaltscreen; + extern char *termname; + extern unsigned int tabspaces; ++extern unsigned int alpha; + extern unsigned int defaultfg; + extern unsigned int defaultbg; +diff --git a/x.c b/x.c +index c0bd890..0562571 100644 +--- a/x.c ++++ b/x.c +@@ -48,6 +48,10 @@ typedef struct { + #define XK_NO_MOD 0 + #define XK_SWITCH_MOD (1<<13) + ++/* alpha */ ++#define OPAQUE 0Xff ++#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL) ++ + /* function definitions used in config.h */ + static void clipcopy(const Arg *); + static void clippaste(const Arg *); +@@ -98,6 +102,7 @@ typedef struct { + XSetWindowAttributes attrs; + int scr; + int isfixed; /* is fixed geometry? */ ++ int depth; /* bit depth */ + int l, t; /* left and top offset */ + int gm; /* geometry mask */ + } XWindow; +@@ -686,7 +691,7 @@ xresize(int col, int row) + + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.depth); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); + +@@ -746,6 +751,13 @@ xloadcols(void) + else + die("could not allocate color %d\n", i); + } ++ ++ /* set alpha value of bg color */ ++ if (USE_ARGB) { ++ dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE; ++ dc.col[defaultbg].pixel &= 0x00111111; ++ dc.col[defaultbg].pixel |= alpha << 24; ++ } + loaded = 1; + } + +@@ -767,6 +779,17 @@ xsetcolorname(int x, const char *name) + return 0; + } + ++void ++xtermclear(int col1, int row1, int col2, int row2) ++{ ++ XftDrawRect(xw.draw, ++ &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], ++ borderpx + col1 * win.cw, ++ borderpx + row1 * win.ch, ++ (col2-col1+1) * win.cw, ++ (row2-row1+1) * win.ch); ++} ++ + /* + * Absolute coordinates. + */ +@@ -1004,7 +1027,40 @@ xinit(int cols, int rows) + if (!(xw.dpy = XOpenDisplay(NULL))) + die("can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); +- xw.vis = XDefaultVisual(xw.dpy, xw.scr); ++ xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr); ++ if (!USE_ARGB) ++ xw.vis = XDefaultVisual(xw.dpy, xw.scr); ++ else { ++ XVisualInfo *vis; ++ XRenderPictFormat *fmt; ++ int nvi; ++ int i; ++ ++ XVisualInfo tpl = { ++ .screen = xw.scr, ++ .depth = 32, ++ .class = TrueColor ++ }; ++ ++ vis = XGetVisualInfo(xw.dpy, ++ VisualScreenMask | VisualDepthMask | VisualClassMask, ++ &tpl, &nvi); ++ xw.vis = NULL; ++ for (i = 0; i < nvi; i++) { ++ fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual); ++ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) { ++ xw.vis = vis[i].visual; ++ break; ++ } ++ } ++ ++ XFree(vis); ++ ++ if (!xw.vis) { ++ fprintf(stderr, "Couldn't find ARGB visual.\n"); ++ exit(1); ++ } ++ } + + /* font */ + if (!FcInit()) +@@ -1014,7 +1070,11 @@ xinit(int cols, int rows) + xloadfonts(usedfont, 0); + + /* colors */ +- xw.cmap = XDefaultColormap(xw.dpy, xw.scr); ++ if (!USE_ARGB) ++ xw.cmap = XDefaultColormap(xw.dpy, xw.scr); ++ else ++ xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr), ++ xw.vis, None); + xloadcols(); + + /* adjust fixed window geometry */ +@@ -1037,16 +1097,15 @@ xinit(int cols, int rows) + if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) + parent = XRootWindow(xw.dpy, xw.scr); + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, +- win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, ++ win.w, win.h, 0, xw.depth, InputOutput, + xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity + | CWEventMask | CWColormap, &xw.attrs); + + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; +- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, +- &gcvalues); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); ++ dc.gc = XCreateGC(xw.dpy, (USE_ARGB) ? xw.buf: parent, ++ GCGraphicsExposures, &gcvalues); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + diff --git a/8/st-clipboard-0.8.1.diff b/8/st-clipboard-0.8.1.diff new file mode 100644 index 0000000..604c480 --- /dev/null +++ b/8/st-clipboard-0.8.1.diff @@ -0,0 +1,13 @@ +diff --git a/x.c b/x.c +index c343ba2..f2a4f65 100644 +--- a/x.c ++++ b/x.c +@@ -627,6 +627,8 @@ 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/8/st-visualbell-0.8.1.diff b/8/st-visualbell-0.8.1.diff new file mode 100644 index 0000000..9be7c3e --- /dev/null +++ b/8/st-visualbell-0.8.1.diff @@ -0,0 +1,41 @@ +diff --git a/x.c b/x.c +index c343ba2..26bb9bb 100644 +--- a/x.c ++++ b/x.c +@@ -239,6 +239,7 @@ static char *opt_name = NULL; + static char *opt_title = NULL; + + static int oldbutton = 3; /* button event on startup: 3 = release */ ++static int bellon = 0; /* visual bell status */ + + void + clipcopy(const Arg *dummy) +@@ -1614,6 +1615,15 @@ xbell(void) + xseturgency(1); + if (bellvolume) + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); ++ ++ /* visual bell*/ ++ if (!bellon) { ++ bellon = 1; ++ MODBIT(win.mode, !IS_SET(MODE_REVERSE), MODE_REVERSE); ++ redraw(); ++ XFlush(xw.dpy); ++ MODBIT(win.mode, !IS_SET(MODE_REVERSE), MODE_REVERSE); ++ } + } + + void +@@ -1840,7 +1850,11 @@ run(void) + (handler[ev.type])(&ev); + } + +- draw(); ++ if (bellon) { ++ bellon = 0; ++ redraw(); ++ } ++ else draw(); + XFlush(xw.dpy); + + if (xev && !FD_ISSET(xfd, &rfd)) diff --git a/8/st-xresources-20180309-c5ba9c0.diff b/8/st-xresources-20180309-c5ba9c0.diff new file mode 100644 index 0000000..03da7fb --- /dev/null +++ b/8/st-xresources-20180309-c5ba9c0.diff @@ -0,0 +1,183 @@ +From 9ba79c106145759de6b436dac2e4b8ff5a12bc2e Mon Sep 17 00:00:00 2001 +From: "Devin J. Pohly" +Date: Fri, 9 Mar 2018 14:56:34 -0600 +Subject: [PATCH] Port Xresources patch by @dcat to st-git + +--- + config.def.h | 35 +++++++++++++++++++++++++++ + x.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 109 insertions(+), 4 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 82b1b09..471fe57 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -150,6 +150,41 @@ static unsigned int mousebg = 0; + */ + static unsigned int defaultattr = 11; + ++/* ++ * Xresources preferences to load at startup ++ */ ++ResourcePref resources[] = { ++ { "font", STRING, &font }, ++ { "color0", STRING, &colorname[0] }, ++ { "color1", STRING, &colorname[1] }, ++ { "color2", STRING, &colorname[2] }, ++ { "color3", STRING, &colorname[3] }, ++ { "color4", STRING, &colorname[4] }, ++ { "color5", STRING, &colorname[5] }, ++ { "color6", STRING, &colorname[6] }, ++ { "color7", STRING, &colorname[7] }, ++ { "color8", STRING, &colorname[8] }, ++ { "color9", STRING, &colorname[9] }, ++ { "color10", STRING, &colorname[10] }, ++ { "color11", STRING, &colorname[11] }, ++ { "color12", STRING, &colorname[12] }, ++ { "color13", STRING, &colorname[13] }, ++ { "color14", STRING, &colorname[14] }, ++ { "color15", STRING, &colorname[15] }, ++ { "background", STRING, &colorname[256] }, ++ { "foreground", STRING, &colorname[257] }, ++ { "cursorColor", STRING, &colorname[258] }, ++ { "termname", STRING, &termname }, ++ { "shell", STRING, &shell }, ++ { "xfps", INTEGER, &xfps }, ++ { "actionfps", INTEGER, &actionfps }, ++ { "blinktimeout", INTEGER, &blinktimeout }, ++ { "bellvolume", INTEGER, &bellvolume }, ++ { "tabspaces", INTEGER, &tabspaces }, ++ { "cwscale", FLOAT, &cwscale }, ++ { "chscale", FLOAT, &chscale }, ++}; ++ + /* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. +diff --git a/x.c b/x.c +index d43a529..7f29cc2 100644 +--- a/x.c ++++ b/x.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + static char *argv0; + #include "arg.h" +@@ -43,6 +44,19 @@ typedef struct { + signed char appcursor; /* application cursor */ + } Key; + ++/* Xresources preferences */ ++enum resource_type { ++ STRING = 0, ++ INTEGER = 1, ++ FLOAT = 2 ++}; ++ ++typedef struct { ++ char *name; ++ enum resource_type type; ++ void *dst; ++} ResourcePref; ++ + /* X modifiers */ + #define XK_ANY_MOD UINT_MAX + #define XK_NO_MOD 0 +@@ -778,8 +792,8 @@ xclear(int x1, int y1, int x2, int y2) + void + xhints(void) + { +- XClassHint class = {opt_name ? opt_name : termname, +- opt_class ? opt_class : termname}; ++ XClassHint class = {opt_name ? opt_name : "st", ++ opt_class ? opt_class : "St"}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints *sizeh; + +@@ -999,8 +1013,6 @@ xinit(int cols, int rows) + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; + +- if (!(xw.dpy = XOpenDisplay(NULL))) +- die("Can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); + xw.vis = XDefaultVisual(xw.dpy, xw.scr); + +@@ -1864,6 +1876,59 @@ run(void) + } + } + ++int ++resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) ++{ ++ char **sdst = dst; ++ int *idst = dst; ++ float *fdst = dst; ++ ++ char fullname[256]; ++ char fullclass[256]; ++ char *type; ++ XrmValue ret; ++ ++ snprintf(fullname, sizeof(fullname), "%s.%s", ++ opt_name ? opt_name : "st", name); ++ snprintf(fullclass, sizeof(fullclass), "%s.%s", ++ opt_class ? opt_class : "St", name); ++ fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0'; ++ ++ XrmGetResource(db, fullname, fullclass, &type, &ret); ++ if (ret.addr == NULL || strncmp("String", type, 64)) ++ return 1; ++ ++ switch (rtype) { ++ case STRING: ++ *sdst = ret.addr; ++ break; ++ case INTEGER: ++ *idst = strtoul(ret.addr, NULL, 10); ++ break; ++ case FLOAT: ++ *fdst = strtof(ret.addr, NULL); ++ break; ++ } ++ return 0; ++} ++ ++void ++config_init(void) ++{ ++ char *resm; ++ XrmDatabase db; ++ ResourcePref *p; ++ ++ XrmInitialize(); ++ resm = XResourceManagerString(xw.dpy); ++ if (!resm) ++ return; ++ ++ db = XrmGetStringDatabase(resm); ++ for (p = resources; p < resources + LEN(resources); p++) ++ resource_load(db, p->name, p->type, p->dst); ++} ++ + void + usage(void) + { +@@ -1937,6 +2002,11 @@ run: + } + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); ++ ++ if(!(xw.dpy = XOpenDisplay(NULL))) ++ die("Can't open display\n"); ++ ++ config_init(); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); +-- +2.16.2 +