From 231b5a928b5e1753aa17a0a138d8c25eb55be5cb Mon Sep 17 00:00:00 2001 From: Calin8u <alexis.calin9@etu.univ-lorraine.fr> Date: Sat, 11 Mar 2023 17:19:34 +0100 Subject: [PATCH] re added st --- st/FAQ | 253 +++++ st/LEGACY | 17 + st/LICENSE | 34 + st/Makefile | 57 + st/README | 34 + st/TODO | 28 + st/arg.h | 50 + st/config.def.h | 474 +++++++++ st/config.h | 474 +++++++++ st/config.mk | 36 + st/st | Bin 0 -> 105544 bytes st/st.1 | 177 ++++ st/st.c | 2668 +++++++++++++++++++++++++++++++++++++++++++++++ st/st.h | 126 +++ st/st.info | 239 +++++ st/st.o | Bin 0 -> 78176 bytes st/win.h | 41 + st/x.c | 2099 +++++++++++++++++++++++++++++++++++++ st/x.o | Bin 0 -> 74848 bytes 19 files changed, 6807 insertions(+) create mode 100644 st/FAQ create mode 100644 st/LEGACY create mode 100644 st/LICENSE create mode 100644 st/Makefile create mode 100644 st/README create mode 100644 st/TODO create mode 100644 st/arg.h create mode 100644 st/config.def.h create mode 100644 st/config.h create mode 100644 st/config.mk create mode 100755 st/st create mode 100644 st/st.1 create mode 100644 st/st.c create mode 100644 st/st.h create mode 100644 st/st.info create mode 100644 st/st.o create mode 100644 st/win.h create mode 100644 st/x.c create mode 100644 st/x.o diff --git a/st/FAQ b/st/FAQ new file mode 100644 index 0000000..6287a27 --- /dev/null +++ b/st/FAQ @@ -0,0 +1,253 @@ +## Why does st not handle utmp entries? + +Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task. + + +## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever! + +It means that st doesn’t have any terminfo entry on your system. Chances are +you did not `make install`. If you just want to test it without installing it, +you can manually run `tic -sx st.info`. + + +## Nothing works, and nothing is said about an unknown terminal! + +* Some programs just assume they’re running in xterm i.e. they don’t rely on + terminfo. What you see is the current state of the “xterm compliance”. +* Some programs don’t complain about the lacking st description and default to + another terminal. In that case see the question about terminfo. + + +## How do I scroll back up? + +* Using a terminal multiplexer. + * `st -e tmux` using C-b [ + * `st -e screen` using C-a ESC +* Using the excellent tool of [scroll](https://git.suckless.org/scroll/). +* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/). + + +## I would like to have utmp and/or scroll functionality by default + +You can add the absolute path of both programs in your config.h file. You only +have to modify the value of utmp and scroll variables. + + +## Why doesn't the Del key work in some programs? + +Taken from the terminfo manpage: + + If the terminal has a keypad that transmits codes when the keys + are pressed, this information can be given. Note that it is not + possible to handle terminals where the keypad only works in + local (this applies, for example, to the unshifted HP 2621 keys). + If the keypad can be set to transmit or not transmit, give these + codes as smkx and rmkx. Otherwise the keypad is assumed to + always transmit. + +In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that +applications which want to test against keypad keys send these +sequences. + +But buggy applications (like bash and irssi, for example) don't do this. A fast +solution for them is to use the following command: + + $ printf '\033[?1h\033=' >/dev/tty + +or + $ tput smkx + +In the case of bash, readline is used. Readline has a different note in its +manpage about this issue: + + enable-keypad (Off) + When set to On, readline will try to enable the + application keypad when it is called. Some systems + need this to enable arrow keys. + +Adding this option to your .inputrc will fix the keypad problem for all +applications using readline. + +If you are using zsh, then read the zsh FAQ +<http://zsh.sourceforge.net/FAQ/zshfaq03.html#l25>: + + 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 +<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>. +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 +<https://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy +terminal users wants its backspace to be how he feels it: + + Well, I am going to comment why I want to change the behaviour + of this key. When ASCII was defined in 1968, communication + with computers was done using punched cards, or hardcopy + terminals (basically a typewriter machine connected with the + computer using a serial port). ASCII defines DELETE as 7F, + because, in punched-card terms, it means all the holes of the + card punched; it is thus a kind of 'physical delete'. In the + same way, the BACKSPACE key was a non-destructive backspace, + as on a typewriter. So, if you wanted to delete a character, + you had to BACKSPACE and then DELETE. Another use of BACKSPACE + was to type accented characters, for example 'a BACKSPACE `'. + The VT100 had no BACKSPACE key; it was generated using the + CONTROL key as another control character (CONTROL key sets to + 0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code + 0x08)), but it had a DELETE key in a similar position where + the BACKSPACE key is located today on common PC keyboards. + All the terminal emulators emulated the difference between + these keys correctly: the backspace key generated a BACKSPACE + (^H) and delete key generated a DELETE (^?). + + But a problem arose when Linus Torvalds wrote Linux. Unlike + earlier terminals, the Linux virtual terminal (the terminal + emulator integrated in the kernel) returned a DELETE when + backspace was pressed, due to the VT100 having a DELETE key in + the same position. This created a lot of problems (see [1] + and [2]). Since Linux has become the king, a lot of terminal + emulators today generate a DELETE when the backspace key is + pressed in order to avoid problems with Linux. The result is + that the only way of generating a BACKSPACE on these systems + is by using CONTROL + H. (I also think that emacs had an + important point here because the CONTROL + H prefix is used + in emacs in some commands (help commands).) + + From point of view of the kernel, you can change the key + for deleting a previous character with stty erase. When you + connect a real terminal into a machine you describe the type + of terminal, so getty configures the correct value of stty + erase for this terminal. In the case of terminal emulators, + however, you don't have any getty that can set the correct + value of stty erase, so you always get the default value. + For this reason, it is necessary to add 'stty erase ^H' to your + profile if you have changed the value of the backspace key. + Of course, another solution is for st itself to modify the + value of stty erase. I usually have the inverse problem: + when I connect to non-Unix machines, I have to press CONTROL + + h to get a BACKSPACE. The inverse problem occurs when a user + connects to my Unix machines from a different system with a + correct backspace key. + + [1] http://www.ibb.net/~anne/keyboard.html + [2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html + + +## But I really want the old grumpy behaviour of my terminal + +Apply [1]. + +[1] https://st.suckless.org/patches/delkey + + +## Why do images not work in st using the w3m image hack? + +w3mimg uses a hack that draws an image on top of the terminal emulator Drawable +window. The hack relies on the terminal to use a single buffer to draw its +contents directly. + +st uses double-buffered drawing so the image is quickly replaced and may show a +short flicker effect. + +Below is a patch example to change st double-buffering to a single Drawable +buffer. + +diff --git a/x.c b/x.c +--- a/x.c ++++ b/x.c +@@ -732,10 +732,6 @@ xresize(int col, int row) + win.tw = col * win.cw; + win.th = row * win.ch; + +- XFreePixmap(xw.dpy, xw.buf); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); +- XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); + + /* resize to new width */ +@@ -1148,8 +1144,7 @@ xinit(int cols, int rows) + gcvalues.graphics_exposures = False; + dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, + &gcvalues); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.buf = xw.win; + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + +@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2) + void + xfinishdraw(void) + { +- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, +- win.h, 0, 0); + XSetForeground(xw.dpy, dc.gc, + dc.col[IS_SET(MODE_REVERSE)? + defaultfg : defaultbg].pixel); + + +## BadLength X error in Xft when trying to render emoji + +Xft makes st crash when rendering color emojis with the following error: + +"X Error of failed request: BadLength (poly request too large or internal Xlib length error)" + Major opcode of failed request: 139 (RENDER) + Minor opcode of failed request: 20 (RenderAddGlyphs) + Serial number of failed request: 1595 + Current serial number in output stream: 1818" + +This is a known bug in Xft (not st) which happens on some platforms and +combination of particular fonts and fontconfig settings. + +See also: +https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6 +https://bugs.freedesktop.org/show_bug.cgi?id=107534 +https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + +The solution is to remove color emoji fonts or disable this in the fontconfig +XML configuration. As an ugly workaround (which may work only on newer +fontconfig versions (FC_COLOR)), the following code can be used to mask color +fonts: + + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + +Please don't bother reporting this bug to st, but notify the upstream Xft +developers about fixing this bug. + +As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5: +https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS diff --git a/st/LEGACY b/st/LEGACY new file mode 100644 index 0000000..bf28b1e --- /dev/null +++ b/st/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/st/LICENSE b/st/LICENSE new file mode 100644 index 0000000..3cbf420 --- /dev/null +++ b/st/LICENSE @@ -0,0 +1,34 @@ +MIT/X Consortium License + +© 2014-2022 Hiltjo Posthuma <hiltjo at codemadness dot org> +© 2018 Devin J. Pohly <djpohly at gmail dot com> +© 2014-2017 Quentin Rameau <quinq at fifth dot space> +© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com> +© 2008-2017 Anselm R Garbe <garbeam at gmail dot com> +© 2012-2017 Roberto E. Vargas Caballero <k0ga at shike2 dot com> +© 2012-2016 Christoph Lohmann <20h at r-36 dot net> +© 2013 Eon S. Jeon <esjeon at hyunmu dot am> +© 2013 Alexander Sedov <alex0player at gmail dot com> +© 2013 Mark Edgar <medgar123 at gmail dot com> +© 2013-2014 Eric Pruitt <eric.pruitt at gmail dot com> +© 2013 Michael Forney <mforney at mforney dot org> +© 2013-2014 Markus Teich <markus dot teich at stusta dot mhn dot de> +© 2014-2015 Laslo Hunhold <dev at frign dot de> + +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/st/Makefile b/st/Makefile new file mode 100644 index 0000000..470ac86 --- /dev/null +++ b/st/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 config.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/st/README b/st/README new file mode 100644 index 0000000..6a846ed --- /dev/null +++ b/st/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 <aurelien dot aptel at gmail dot com> bt source code. + diff --git a/st/TODO b/st/TODO new file mode 100644 index 0000000..5f74cd5 --- /dev/null +++ b/st/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/st/arg.h b/st/arg.h new file mode 100644 index 0000000..a22e019 --- /dev/null +++ b/st/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/st/config.def.h b/st/config.def.h new file mode 100644 index 0000000..91ab8ca --- /dev/null +++ b/st/config.def.h @@ -0,0 +1,474 @@ +/* See LICENSE file for copyright and license details. */ + +/* + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +static int borderpx = 2; + +/* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e + * 2: scroll and/or utmp + * 3: SHELL environment variable + * 4: value of shell in /etc/passwd + * 5: value of shell in config.h + */ +static char *shell = "/bin/sh"; +char *utmp = NULL; +/* scroll program: to enable use a string like "scroll" */ +char *scroll = NULL; +char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; + +/* identification sequence returned in DA and DECID */ +char *vtiden = "\033[?6c"; + +/* Kerning / character bounding-box multipliers */ +static float cwscale = 1.0; +static float chscale = 1.0; + +/* + * word delimiter string + * + * More advanced example: L" `'\"()[]{}" + */ +wchar_t *worddelimiters = L" "; + +/* selection timeouts (in milliseconds) */ +static unsigned int doubleclicktimeout = 300; +static unsigned int tripleclicktimeout = 600; + +/* alt screens */ +int allowaltscreen = 1; + +/* allow certain non-interactive (insecure) window operations such as: + setting the clipboard text */ +int allowwindowops = 0; + +/* + * draw latency range in ms - from new content/keypress/etc until drawing. + * within this range, st draws when content stops arriving (idle). mostly it's + * near minlatency, but it waits longer for slow updates to avoid partial draw. + * low minlatency will tear/flicker more, as it can "detect" idle too early. + */ +static double minlatency = 8; +static double maxlatency = 33; + +/* + * blinking timeout (set to 0 to disable blinking) for the terminal blinking + * attribute. + */ +static unsigned int blinktimeout = 800; + +/* + * thickness of underline and bar cursors + */ +static unsigned int cursorthickness = 2; + +/* + * bell volume. It must be a value between -100 and 100. Use 0 for disabling + * it + */ +static int bellvolume = 0; + +/* default TERM value */ +char *termname = "st-256color"; + +/* + * spaces per tab + * + * When you are changing this value, don't forget to adapt the »it« value in + * the st.info and appropriately install the st.info in the environment where + * you use this st version. + * + * it#$tabspaces, + * + * Secondly make sure your kernel is not expanding tabs. When running `stty + * -a` »tab0« should appear. You can tell the terminal to not expand tabs by + * running following command: + * + * stty tabs + */ +unsigned int tabspaces = 8; + +/* Terminal colors (16 first used in escape sequence) */ +static const char *colorname[] = { + /* 8 normal colors */ + "black", + "red3", + "green3", + "yellow3", + "blue2", + "magenta3", + "cyan3", + "gray90", + + /* 8 bright colors */ + "gray50", + "red", + "green", + "yellow", + "#5c5cff", + "magenta", + "cyan", + "white", + + [255] = 0, + + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", + "#555555", + "gray90", /* default foreground colour */ + "black", /* default background colour */ +}; + + +/* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +unsigned int defaultfg = 258; +unsigned int defaultbg = 259; +unsigned int defaultcs = 256; +static unsigned int defaultrcs = 257; + +/* + * Default shape of cursor + * 2: Block ("█") + * 4: Underline ("_") + * 6: Bar ("|") + * 7: Snowman ("☃") + */ +static unsigned int cursorshape = 2; + +/* + * Default columns and rows numbers + */ + +static unsigned int cols = 80; +static unsigned int rows = 24; + +/* + * Default colour and shape of the mouse cursor + */ +static unsigned int mouseshape = XC_xterm; +static unsigned int mousefg = 7; +static unsigned int mousebg = 0; + +/* + * Color used to display font attributes when fontconfig selected a font which + * doesn't match the ones requested. + */ +static unsigned int defaultattr = 11; + +/* + * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). + * Note that if you want to use ShiftMask with selmasks, set this to an other + * modifier, set to 0 to not use it. + */ +static uint forcemousemod = ShiftMask; + +/* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. + */ +static MouseShortcut mshortcuts[] = { + /* mask button function argument release */ + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, + { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, + { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, + { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, +}; + +/* Internal keyboard shortcuts. */ +#define MODKEY Mod1Mask +#define TERMMOD (ControlMask|ShiftMask) + +static Shortcut shortcuts[] = { + /* mask keysym function argument */ + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, + { ControlMask, XK_Print, toggleprinter, {.i = 0} }, + { ShiftMask, XK_Print, printscreen, {.i = 0} }, + { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, + { TERMMOD, XK_Prior, zoom, {.f = +1} }, + { TERMMOD, XK_Next, zoom, {.f = -1} }, + { TERMMOD, XK_Home, zoomreset, {.f = 0} }, + { TERMMOD, XK_C, clipcopy, {.i = 0} }, + { TERMMOD, XK_V, clippaste, {.i = 0} }, + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, +}; + +/* + * Special keys (change & recompile st.info accordingly) + * + * Mask value: + * * Use XK_ANY_MOD to match the key no matter modifiers state + * * Use XK_NO_MOD to match the key alone (no modifiers) + * appkey value: + * * 0: no value + * * > 0: keypad application mode enabled + * * = 2: term.numlock = 1 + * * < 0: keypad application mode disabled + * appcursor value: + * * 0: no value + * * > 0: cursor application mode enabled + * * < 0: cursor application mode disabled + * + * Be careful with the order of the definitions because st searches in + * this table sequentially, so any XK_ANY_MOD must be in the last + * position for a key. + */ + +/* + * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) + * to be mapped below, add them to this array. + */ +static KeySym mappedkeys[] = { -1 }; + +/* + * State bits to ignore when matching key or button events. By default, + * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. + */ +static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; + +/* + * This is the huge key array which defines all compatibility to the Linux + * world. Please decide about changes wisely. + */ +static Key key[] = { + /* keysym mask string appkey appcursor */ + { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, + { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, + { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, + { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, + { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, + { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, + { XK_KP_End, ControlMask, "\033[J", -1, 0}, + { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_KP_End, ShiftMask, "\033[K", -1, 0}, + { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, + { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, + { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, + { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, + { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, + { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, + { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, + { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, + { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, + { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, + { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, + { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, + { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, + { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, + { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, + { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, + { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, + { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, + { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, + { XK_Up, ControlMask, "\033[1;5A", 0, 0}, + { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, + { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, + { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, + { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, + { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, + { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, + { XK_Down, ControlMask, "\033[1;5B", 0, 0}, + { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, + { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, + { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, + { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, + { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, + { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, + { XK_Left, ControlMask, "\033[1;5D", 0, 0}, + { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, + { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, + { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, + { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, + { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, + { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, + { XK_Right, ControlMask, "\033[1;5C", 0, 0}, + { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, + { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, + { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, + { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, + { XK_Return, Mod1Mask, "\033\r", 0, 0}, + { XK_Return, XK_ANY_MOD, "\r", 0, 0}, + { XK_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_Insert, ControlMask, "\033[L", -1, 0}, + { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, + { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_Delete, ControlMask, "\033[M", -1, 0}, + { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, + { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_End, ControlMask, "\033[J", -1, 0}, + { XK_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_End, ShiftMask, "\033[K", -1, 0}, + { XK_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, + { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_Next, ControlMask, "\033[6;5~", 0, 0}, + { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, + { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, + { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, + { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, + { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, + { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, + { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, + { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, + { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, + { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, + { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, + { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, + { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, + { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, + { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, + { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, + { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, + { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, + { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, + { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, + { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, + { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, + { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, + { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, + { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, + { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, + { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, + { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, + { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, + { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, + { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, + { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, + { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, + { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, + { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, + { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, + { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, + { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, + { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, + { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, + { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, + { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, + { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, + { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, + { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, + { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, + { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, + { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, + { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, + { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, + { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, + { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, + { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, + { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, + { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, + { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, + { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, + { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, + { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, + { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, + { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, + { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, + { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, + { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, + { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, + { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, + { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, + { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, + { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, + { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, + { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, + { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, + { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, + { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, + { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, + { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, + { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, + { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, + { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, + { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, + { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, + { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, + { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, + { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, + { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, + { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, +}; + +/* + * Selection types' masks. + * Use the same masks as usual. + * Button1Mask is always unset, to make masks match between ButtonPress. + * ButtonRelease and MotionNotify. + * If no match is found, regular selection is used. + */ +static uint selmasks[] = { + [SEL_RECTANGULAR] = Mod1Mask, +}; + +/* + * Printable characters in ASCII, used to estimate the advance width + * of single wide characters. + */ +static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st/config.h b/st/config.h new file mode 100644 index 0000000..91ab8ca --- /dev/null +++ b/st/config.h @@ -0,0 +1,474 @@ +/* See LICENSE file for copyright and license details. */ + +/* + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +static int borderpx = 2; + +/* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e + * 2: scroll and/or utmp + * 3: SHELL environment variable + * 4: value of shell in /etc/passwd + * 5: value of shell in config.h + */ +static char *shell = "/bin/sh"; +char *utmp = NULL; +/* scroll program: to enable use a string like "scroll" */ +char *scroll = NULL; +char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; + +/* identification sequence returned in DA and DECID */ +char *vtiden = "\033[?6c"; + +/* Kerning / character bounding-box multipliers */ +static float cwscale = 1.0; +static float chscale = 1.0; + +/* + * word delimiter string + * + * More advanced example: L" `'\"()[]{}" + */ +wchar_t *worddelimiters = L" "; + +/* selection timeouts (in milliseconds) */ +static unsigned int doubleclicktimeout = 300; +static unsigned int tripleclicktimeout = 600; + +/* alt screens */ +int allowaltscreen = 1; + +/* allow certain non-interactive (insecure) window operations such as: + setting the clipboard text */ +int allowwindowops = 0; + +/* + * draw latency range in ms - from new content/keypress/etc until drawing. + * within this range, st draws when content stops arriving (idle). mostly it's + * near minlatency, but it waits longer for slow updates to avoid partial draw. + * low minlatency will tear/flicker more, as it can "detect" idle too early. + */ +static double minlatency = 8; +static double maxlatency = 33; + +/* + * blinking timeout (set to 0 to disable blinking) for the terminal blinking + * attribute. + */ +static unsigned int blinktimeout = 800; + +/* + * thickness of underline and bar cursors + */ +static unsigned int cursorthickness = 2; + +/* + * bell volume. It must be a value between -100 and 100. Use 0 for disabling + * it + */ +static int bellvolume = 0; + +/* default TERM value */ +char *termname = "st-256color"; + +/* + * spaces per tab + * + * When you are changing this value, don't forget to adapt the »it« value in + * the st.info and appropriately install the st.info in the environment where + * you use this st version. + * + * it#$tabspaces, + * + * Secondly make sure your kernel is not expanding tabs. When running `stty + * -a` »tab0« should appear. You can tell the terminal to not expand tabs by + * running following command: + * + * stty tabs + */ +unsigned int tabspaces = 8; + +/* Terminal colors (16 first used in escape sequence) */ +static const char *colorname[] = { + /* 8 normal colors */ + "black", + "red3", + "green3", + "yellow3", + "blue2", + "magenta3", + "cyan3", + "gray90", + + /* 8 bright colors */ + "gray50", + "red", + "green", + "yellow", + "#5c5cff", + "magenta", + "cyan", + "white", + + [255] = 0, + + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", + "#555555", + "gray90", /* default foreground colour */ + "black", /* default background colour */ +}; + + +/* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +unsigned int defaultfg = 258; +unsigned int defaultbg = 259; +unsigned int defaultcs = 256; +static unsigned int defaultrcs = 257; + +/* + * Default shape of cursor + * 2: Block ("█") + * 4: Underline ("_") + * 6: Bar ("|") + * 7: Snowman ("☃") + */ +static unsigned int cursorshape = 2; + +/* + * Default columns and rows numbers + */ + +static unsigned int cols = 80; +static unsigned int rows = 24; + +/* + * Default colour and shape of the mouse cursor + */ +static unsigned int mouseshape = XC_xterm; +static unsigned int mousefg = 7; +static unsigned int mousebg = 0; + +/* + * Color used to display font attributes when fontconfig selected a font which + * doesn't match the ones requested. + */ +static unsigned int defaultattr = 11; + +/* + * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). + * Note that if you want to use ShiftMask with selmasks, set this to an other + * modifier, set to 0 to not use it. + */ +static uint forcemousemod = ShiftMask; + +/* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. + */ +static MouseShortcut mshortcuts[] = { + /* mask button function argument release */ + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, + { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, + { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, + { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, +}; + +/* Internal keyboard shortcuts. */ +#define MODKEY Mod1Mask +#define TERMMOD (ControlMask|ShiftMask) + +static Shortcut shortcuts[] = { + /* mask keysym function argument */ + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, + { ControlMask, XK_Print, toggleprinter, {.i = 0} }, + { ShiftMask, XK_Print, printscreen, {.i = 0} }, + { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, + { TERMMOD, XK_Prior, zoom, {.f = +1} }, + { TERMMOD, XK_Next, zoom, {.f = -1} }, + { TERMMOD, XK_Home, zoomreset, {.f = 0} }, + { TERMMOD, XK_C, clipcopy, {.i = 0} }, + { TERMMOD, XK_V, clippaste, {.i = 0} }, + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, +}; + +/* + * Special keys (change & recompile st.info accordingly) + * + * Mask value: + * * Use XK_ANY_MOD to match the key no matter modifiers state + * * Use XK_NO_MOD to match the key alone (no modifiers) + * appkey value: + * * 0: no value + * * > 0: keypad application mode enabled + * * = 2: term.numlock = 1 + * * < 0: keypad application mode disabled + * appcursor value: + * * 0: no value + * * > 0: cursor application mode enabled + * * < 0: cursor application mode disabled + * + * Be careful with the order of the definitions because st searches in + * this table sequentially, so any XK_ANY_MOD must be in the last + * position for a key. + */ + +/* + * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) + * to be mapped below, add them to this array. + */ +static KeySym mappedkeys[] = { -1 }; + +/* + * State bits to ignore when matching key or button events. By default, + * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. + */ +static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; + +/* + * This is the huge key array which defines all compatibility to the Linux + * world. Please decide about changes wisely. + */ +static Key key[] = { + /* keysym mask string appkey appcursor */ + { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, + { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, + { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, + { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, + { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, + { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, + { XK_KP_End, ControlMask, "\033[J", -1, 0}, + { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_KP_End, ShiftMask, "\033[K", -1, 0}, + { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, + { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, + { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, + { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, + { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, + { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, + { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, + { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, + { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, + { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, + { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, + { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, + { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, + { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, + { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, + { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, + { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, + { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, + { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, + { XK_Up, ControlMask, "\033[1;5A", 0, 0}, + { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, + { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, + { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, + { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, + { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, + { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, + { XK_Down, ControlMask, "\033[1;5B", 0, 0}, + { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, + { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, + { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, + { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, + { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, + { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, + { XK_Left, ControlMask, "\033[1;5D", 0, 0}, + { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, + { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, + { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, + { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, + { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, + { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, + { XK_Right, ControlMask, "\033[1;5C", 0, 0}, + { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, + { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, + { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, + { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, + { XK_Return, Mod1Mask, "\033\r", 0, 0}, + { XK_Return, XK_ANY_MOD, "\r", 0, 0}, + { XK_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_Insert, ControlMask, "\033[L", -1, 0}, + { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, + { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_Delete, ControlMask, "\033[M", -1, 0}, + { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, + { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_End, ControlMask, "\033[J", -1, 0}, + { XK_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_End, ShiftMask, "\033[K", -1, 0}, + { XK_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, + { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_Next, ControlMask, "\033[6;5~", 0, 0}, + { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, + { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, + { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, + { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, + { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, + { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, + { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, + { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, + { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, + { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, + { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, + { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, + { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, + { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, + { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, + { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, + { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, + { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, + { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, + { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, + { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, + { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, + { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, + { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, + { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, + { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, + { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, + { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, + { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, + { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, + { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, + { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, + { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, + { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, + { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, + { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, + { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, + { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, + { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, + { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, + { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, + { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, + { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, + { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, + { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, + { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, + { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, + { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, + { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, + { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, + { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, + { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, + { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, + { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, + { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, + { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, + { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, + { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, + { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, + { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, + { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, + { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, + { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, + { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, + { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, + { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, + { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, + { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, + { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, + { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, + { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, + { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, + { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, + { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, + { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, + { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, + { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, + { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, + { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, + { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, + { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, + { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, + { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, + { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, + { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, + { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, +}; + +/* + * Selection types' masks. + * Use the same masks as usual. + * Button1Mask is always unset, to make masks match between ButtonPress. + * ButtonRelease and MotionNotify. + * If no match is found, regular selection is used. + */ +static uint selmasks[] = { + [SEL_RECTANGULAR] = Mod1Mask, +}; + +/* + * Printable characters in ASCII, used to estimate the advance width + * of single wide characters. + */ +static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st/config.mk b/st/config.mk new file mode 100644 index 0000000..1e306f8 --- /dev/null +++ b/st/config.mk @@ -0,0 +1,36 @@ +# st version +VERSION = 0.9 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +PKG_CONFIG = pkg-config + +# includes and libs +INCS = -I$(X11INC) \ + `$(PKG_CONFIG) --cflags fontconfig` \ + `$(PKG_CONFIG) --cflags freetype2` +LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ + `$(PKG_CONFIG) --libs fontconfig` \ + `$(PKG_CONFIG) --libs freetype2` + +# flags +STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 +STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +STLDFLAGS = $(LIBS) $(LDFLAGS) + +# OpenBSD: +#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE +#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ +# `$(PKG_CONFIG) --libs fontconfig` \ +# `$(PKG_CONFIG) --libs freetype2` +#MANPREFIX = ${PREFIX}/man + +# compiler and linker +# CC = c99 diff --git a/st/st b/st/st new file mode 100755 index 0000000000000000000000000000000000000000..cf9044b21fc8c0e7f4214173024326fe4fe24804 GIT binary patch literal 105544 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 T)1N#UqEZ<`!IZ<cQNj5DGuU;# literal 0 HcmV?d00001 diff --git a/st/st.1 b/st/st.1 new file mode 100644 index 0000000..39120b4 --- /dev/null +++ b/st/st.1 @@ -0,0 +1,177 @@ +.TH ST 1 st\-VERSION +.SH NAME +st \- simple terminal +.SH SYNOPSIS +.B st +.RB [ \-aiv ] +.RB [ \-c +.IR class ] +.RB [ \-f +.IR font ] +.RB [ \-g +.IR geometry ] +.RB [ \-n +.IR name ] +.RB [ \-o +.IR iofile ] +.RB [ \-T +.IR title ] +.RB [ \-t +.IR title ] +.RB [ \-l +.IR line ] +.RB [ \-w +.IR windowid ] +.RB [[ \-e ] +.IR command +.RI [ arguments ...]] +.PP +.B st +.RB [ \-aiv ] +.RB [ \-c +.IR class ] +.RB [ \-f +.IR font ] +.RB [ \-g +.IR geometry ] +.RB [ \-n +.IR name ] +.RB [ \-o +.IR iofile ] +.RB [ \-T +.IR title ] +.RB [ \-t +.IR title ] +.RB [ \-w +.IR windowid ] +.RB \-l +.IR line +.RI [ stty_args ...] +.SH DESCRIPTION +.B st +is a simple terminal emulator. +.SH OPTIONS +.TP +.B \-a +disable alternate screens in terminal +.TP +.BI \-c " class" +defines the window class (default $TERM). +.TP +.BI \-f " font" +defines the +.I font +to use when st is run. +.TP +.BI \-g " geometry" +defines the X11 geometry string. +The form is [=][<cols>{xX}<rows>][{+-}<xoffset>{+-}<yoffset>]. 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. +.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), +.BR scroll (1) +.SH BUGS +See the TODO file in the distribution. + diff --git a/st/st.c b/st/st.c new file mode 100644 index 0000000..134e724 --- /dev/null +++ b/st/st.c @@ -0,0 +1,2668 @@ +/* See LICENSE for license details. */ +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pwd.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <termios.h> +#include <unistd.h> +#include <wchar.h> + +#include "st.h" +#include "win.h" + +#if defined(__linux) + #include <pty.h> +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) + #include <util.h> +#elif defined(__FreeBSD__) || defined(__DragonFly__) + #include <libutil.h> +#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 ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f) +#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) +#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) +#define ISDELIM(u) (u && wcschr(worddelimiters, u)) + +enum term_mode { + MODE_WRAP = 1 << 0, + MODE_INSERT = 1 << 1, + MODE_ALTSCREEN = 1 << 2, + MODE_CRLF = 1 << 3, + MODE_ECHO = 1 << 4, + MODE_PRINT = 1 << 5, + MODE_UTF8 = 1 << 6, +}; + +enum cursor_movement { + CURSOR_SAVE, + CURSOR_LOAD +}; + +enum cursor_state { + CURSOR_DEFAULT = 0, + CURSOR_WRAPNEXT = 1, + CURSOR_ORIGIN = 2 +}; + +enum charset { + CS_GRAPHIC0, + CS_GRAPHIC1, + CS_UK, + CS_USA, + CS_MULTI, + CS_GER, + CS_FIN +}; + +enum escape_state { + ESC_START = 1, + ESC_CSI = 2, + ESC_STR = 4, /* DCS, OSC, PM, APC */ + ESC_ALTCHARSET = 8, + ESC_STR_END = 16, /* a final string was encountered */ + ESC_TEST = 32, /* Enter in test mode */ + ESC_UTF8 = 64, +}; + +typedef struct { + Glyph attr; /* current char attributes */ + int x; + int y; + char state; +} TCursor; + +typedef struct { + int mode; + int type; + int snap; + /* + * Selection variables: + * nb – normalized coordinates of the beginning of the selection + * ne – normalized coordinates of the end of the selection + * ob – original coordinates of the beginning of the selection + * oe – original coordinates of the end of the selection + */ + struct { + int x, y; + } nb, ne, ob, oe; + + int alt; +} Selection; + +/* Internal representation of the screen */ +typedef struct { + int row; /* nb row */ + int col; /* nb col */ + Line *line; /* screen */ + Line *alt; /* alternate screen */ + int *dirty; /* dirtyness of lines */ + TCursor c; /* cursor */ + int ocx; /* old cursor col */ + int ocy; /* old cursor row */ + int top; /* top scroll limit */ + int bot; /* bottom scroll limit */ + int mode; /* terminal mode flags */ + int esc; /* escape state flags */ + char trantbl[4]; /* charset table translation */ + int charset; /* current charset */ + int icharset; /* selected charset for sequence */ + int *tabs; + Rune lastc; /* last printed char outside of sequence, 0 if control */ +} Term; + +/* CSI Escape sequence structs */ +/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */ +typedef struct { + char buf[ESC_BUF_SIZ]; /* raw string */ + size_t 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 [[ [<priv>] <arg> [;]] <mode>] ESC '\' */ +typedef struct { + char type; /* ESC type ... */ + char *buf; /* allocated raw string */ + size_t siz; /* allocation size */ + size_t len; /* raw string length */ + char *args[STR_ARG_SIZ]; + int narg; /* nb of args */ +} STREscape; + +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 void osc_color_response(int, int, int); +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(const int *, int); +static void tsetchar(Rune, const Glyph *, int, int); +static void tsetdirt(int, int); +static void tsetscroll(int, int); +static void tswapscreen(void); +static void tsetmode(int, int, const int *, int); +static int twrite(const char *, int, int); +static void tfulldirt(void); +static void tcontrolcode(uchar ); +static void tdectest(char ); +static void tdefutf8(char); +static int32_t tdefcolor(const 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 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 const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const 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; + + if (!(p = malloc(len))) + die("malloc: %s\n", strerror(errno)); + + return p; +} + +void * +xrealloc(void *p, size_t len) +{ + if ((p = realloc(p, len)) == NULL) + die("realloc: %s\n", strerror(errno)); + + return p; +} + +char * +xstrdup(const char *s) +{ + char *p; + + if ((p = strdup(s)) == NULL) + die("strdup: %s\n", strerror(errno)); + + return p; +} + +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]); +} + +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; +} + +char +base64dec_getc(const char **src) +{ + while (**src && !isprint((unsigned char)**src)) + (*src)++; + return **src ? *((*src)++) : '='; /* emulate padding if string ends */ +} + +char * +base64dec(const char *src) +{ + size_t in_len = strlen(src); + char *result, *dst; + static const char base64_digits[256] = { + [43] = 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 + }; + + 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)]; + + /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */ + if (a == -1 || b == -1) + break; + + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (c == -1) + break; + *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.alt = IS_SET(MODE_ALTSCREEN); + 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.oe.x = col; + sel.oe.y = row; + selnormalize(); + sel.type = type; + + if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY) + tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); + + sel.mode = done ? SEL_IDLE : SEL_READY; +} + +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; + const 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; + const 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) || sel.type == SEL_RECTANGULAR)) + *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, *arg; + 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]; + arg = NULL; + } else if (scroll) { + prog = scroll; + arg = utmp ? utmp : sh; + } else if (utmp) { + prog = utmp; + arg = NULL; + } else { + prog = sh; + arg = NULL; + } + DEFAULT(args, ((char *[]) {prog, arg, 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 exited with status %d\n", WEXITSTATUS(stat)); + else if (WIFSIGNALED(stat)) + die("child terminated due to signal %d\n", WTERMSIG(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(const char *line, char *cmd, const 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 '%s' failed: %s\n", + line, 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: %s\n", strerror(errno)); + break; + case 0: + close(iofd); + close(m); + 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)); + if (s > 2) + close(s); +#ifdef __OpenBSD__ + if (pledge("stdio getpw proc exec", NULL) == -1) + die("pledge\n"); +#endif + execsh(cmd, args); + break; + default: +#ifdef __OpenBSD__ + if (pledge("stdio rpath tty proc", NULL) == -1) + die("pledge\n"); +#endif + close(s); + cmdfd = m; + signal(SIGCHLD, sigchld); + break; + } + return cmdfd; +} + +size_t +ttyread(void) +{ + static char buf[BUFSIZ]; + static int buflen = 0; + int ret, written; + + /* append read bytes to unprocessed bytes */ + ret = read(cmdfd, buf+buflen, LEN(buf)-buflen); + + switch (ret) { + case 0: + exit(0); + case -1: + die("couldn't read from shell: %s\n", strerror(errno)); + default: + buflen += ret; + written = twrite(buf, buflen, 0); + buflen -= written; + /* keep any incomplete UTF-8 byte sequence for the next call */ + if (buflen > 0) + memmove(buf, buf + written, buflen); + return ret; + } +} + +void +ttywrite(const char *s, size_t n, int may_echo) +{ + const char *next; + + 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(void) +{ + /* 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.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { + selclear(); + } else if (BETWEEN(sel.nb.y, orig, term.bot)) { + sel.ob.y += n; + sel.oe.y += n; + if (sel.ob.y < term.top || sel.ob.y > term.bot || + sel.oe.y < term.top || sel.oe.y > term.bot) { + selclear(); + } else { + 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, const Glyph *attr, int x, int y) +{ + static const 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(const 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(const 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, const int *args, int narg) +{ + int alt; const int *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. */ + break; + 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 <n> blank char */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblank(csiescseq.arg[0]); + break; + case 'A': /* CUU -- Cursor <n> Up */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y-csiescseq.arg[0]); + break; + case 'B': /* CUD -- Cursor <n> Down */ + case 'e': /* VPR --Cursor <n> 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 'b': /* REP -- if last char is printable print it <n> more times */ + DEFAULT(csiescseq.arg[0], 1); + if (term.lastc) + while (csiescseq.arg[0]-- > 0) + tputc(term.lastc); + break; + case 'C': /* CUF -- Cursor <n> Forward */ + case 'a': /* HPR -- Cursor <n> Forward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x+csiescseq.arg[0], term.c.y); + break; + case 'D': /* CUB -- Cursor <n> Backward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x-csiescseq.arg[0], term.c.y); + break; + case 'E': /* CNL -- Cursor <n> Down and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y+csiescseq.arg[0]); + break; + case 'F': /* CPL -- Cursor <n> 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 <col> */ + case '`': /* HPA */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(csiescseq.arg[0]-1, term.c.y); + break; + case 'H': /* CUP -- Move to <row> <col> */ + 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 <n> 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 <n> line up */ + DEFAULT(csiescseq.arg[0], 1); + tscrollup(term.top, csiescseq.arg[0]); + break; + case 'T': /* SD -- Scroll <n> line down */ + DEFAULT(csiescseq.arg[0], 1); + tscrolldown(term.top, csiescseq.arg[0]); + break; + case 'L': /* IL -- Insert <n> 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 <n> lines */ + DEFAULT(csiescseq.arg[0], 1); + tdeleteline(csiescseq.arg[0]); + break; + case 'X': /* ECH -- Erase <n> 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 <n> char */ + DEFAULT(csiescseq.arg[0], 1); + tdeletechar(csiescseq.arg[0]); + break; + case 'Z': /* CBT -- Cursor Backward Tabulation <n> tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(-csiescseq.arg[0]); + break; + case 'd': /* VPA -- Move to <row> */ + 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 */ + switch (csiescseq.arg[0]) { + case 5: /* Status Report "OK" `0n` */ + ttywrite("\033[0n", sizeof("\033[0n") - 1, 0); + break; + case 6: /* Report Cursor Position (CPR) "<row>;<column>R" */ + len = snprintf(buf, sizeof(buf), "\033[%i;%iR", + term.c.y+1, term.c.x+1); + ttywrite(buf, len, 0); + break; + default: + goto unknown; + } + 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) +{ + size_t 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 +osc_color_response(int num, int index, int is_osc4) +{ + int n; + char buf[32]; + unsigned char r, g, b; + + if (xgetcolor(is_osc4 ? num : index, &r, &g, &b)) { + fprintf(stderr, "erresc: failed to fetch %s color %d\n", + is_osc4 ? "osc4" : "osc", + is_osc4 ? num : index); + return; + } + + n = snprintf(buf, sizeof buf, "\033]%s%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", + is_osc4 ? "4;" : "", num, r, r, g, g, b, b); + if (n < 0 || n >= sizeof(buf)) { + fprintf(stderr, "error: %s while printing %s response\n", + n < 0 ? "snprintf failed" : "truncation occurred", + is_osc4 ? "osc4" : "osc"); + } else { + ttywrite(buf, n, 1); + } +} + +void +strhandle(void) +{ + char *p = NULL, *dec; + int j, narg, par; + const struct { int idx; char *str; } osc_table[] = { + { defaultfg, "foreground" }, + { defaultbg, "background" }, + { defaultcs, "cursor" } + }; + + 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: + if (narg > 1) { + xsettitle(strescseq.args[1]); + xseticontitle(strescseq.args[1]); + } + return; + case 1: + if (narg > 1) + xseticontitle(strescseq.args[1]); + return; + case 2: + if (narg > 1) + xsettitle(strescseq.args[1]); + return; + case 52: + if (narg > 2 && allowwindowops) { + dec = base64dec(strescseq.args[2]); + if (dec) { + xsetsel(dec); + xclipcopy(); + } else { + fprintf(stderr, "erresc: invalid base64\n"); + } + } + return; + case 10: + case 11: + case 12: + if (narg < 2) + break; + p = strescseq.args[1]; + if ((j = par - 10) < 0 || j >= LEN(osc_table)) + break; /* shouldn't be possible */ + + if (!strcmp(p, "?")) { + osc_color_response(par, osc_table[j].idx, 0); + } else if (xsetcolorname(osc_table[j].idx, p)) { + fprintf(stderr, "erresc: invalid %s color: %s\n", + osc_table[j].str, p); + } else { + tfulldirt(); + } + return; + case 4: /* color set */ + if (narg < 3) + break; + p = strescseq.args[2]; + /* FALLTHROUGH */ + case 104: /* color reset */ + j = (narg > 1) ? atoi(strescseq.args[1]) : -1; + + if (p && !strcmp(p, "?")) { + osc_color_response(j, 0, 1); + } else if (xsetcolorname(j, p)) { + if (par == 104 && narg <= 1) { + xloadcols(); + return; /* color reset without parameter */ + } + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); + } else { + /* + * TODO if defaultbg color is changed, borders + * are dirty + */ + tfulldirt(); + } + return; + } + break; + case 'k': /* old title set compatibility */ + xsettitle(strescseq.args[0]); + return; + case 'P': /* DCS -- Device Control String */ + 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) +{ + size_t 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) +{ + strescseq = (STREscape){ + .buf = xrealloc(strescseq.buf, STR_BUF_SIZ), + .siz = STR_BUF_SIZ, + }; +} + +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 +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]; + const 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) +{ + switch (c) { + case 0x90: /* DCS -- Device Control String */ + c = 'P'; + break; + case 0x9f: /* APC -- Application Program Command */ + c = '_'; + break; + case 0x9e: /* PM -- Privacy Message */ + c = '^'; + break; + case 0x9d: /* OSC -- Operating System Command */ + c = ']'; + break; + } + strreset(); + 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); + /* FALLTHROUGH */ + 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 initial 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 (u < 127 || !IS_SET(MODE_UTF8)) { + c[0] = u; + width = len = 1; + } else { + len = utf8encode(u, c); + if (!control && (width = wcwidth(u)) == -1) + 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); + term.esc |= ESC_STR_END; + goto check_control_code; + } + + if (strescseq.len+len >= strescseq.siz) { + /* + * Here is a bug in terminals. If the user never sends + * some code to stop the str or esc command, then st + * 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(); + */ + if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2) + return; + strescseq.siz *= 2; + strescseq.buf = xrealloc(strescseq.buf, strescseq.siz); + } + + memmove(&strescseq.buf[strescseq.len], c, len); + 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) { + /* in UTF-8 mode ignore handling C1 control characters */ + if (IS_SET(MODE_UTF8) && ISCONTROLC1(u)) + return; + tcontrolcode(u); + /* + * control codes are not shown ever + */ + if (!term.esc) + term.lastc = 0; + 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 (selected(term.c.x, term.c.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); + term.lastc = u; + + if (width == 2) { + gp->mode |= ATTR_WIDE; + if (term.c.x+1 < term.col) { + if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) { + gp[2].u = ' '; + gp[2].mode &= ~ATTR_WDUMMY; + } + 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)) { + /* 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, ocx = term.ocx, ocy = term.ocy; + + 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(); + if (ocx != term.ocx || ocy != term.ocy) + xximspot(term.ocx, term.ocy); +} + +void +redraw(void) +{ + tfulldirt(); + draw(); +} diff --git a/st/st.h b/st/st.h new file mode 100644 index 0000000..fd3b0d8 --- /dev/null +++ b/st/st.h @@ -0,0 +1,126 @@ +/* See LICENSE for license details. */ + +#include <stdint.h> +#include <sys/types.h> + +/* 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; + const char *s; +} Arg; + +void die(const char *, ...); +void redraw(void); +void draw(void); + +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(const char *, char *, const 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(const char *); + +/* config.h globals */ +extern char *utmp; +extern char *scroll; +extern char *stty_args; +extern char *vtiden; +extern wchar_t *worddelimiters; +extern int allowaltscreen; +extern int allowwindowops; +extern char *termname; +extern unsigned int tabspaces; +extern unsigned int defaultfg; +extern unsigned int defaultbg; +extern unsigned int defaultcs; diff --git a/st/st.info b/st/st.info new file mode 100644 index 0000000..8201ad6 --- /dev/null +++ b/st/st.info @@ -0,0 +1,239 @@ +st-mono| simpleterm monocolor, + 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#2, + 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, + rin=\E[%p1%dT, + 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, + sitm=\E[3m, + sgr0=\E[0m, + 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, +# disabled rep for now: causes some issues with older ncurses versions. +# rep=%p1%c\E[%p2%{1}%-%db, +# tmux extensions, see TERMINFO EXTENSIONS in tmux(1) + Tc, + Ms=\E]52;%p1%s;%p2%s\007, + Se=\E[2 q, + Ss=\E[%p1%d q, + +st| simpleterm, + use=st-mono, + colors#8, + setab=\E[4%p1%dm, + setaf=\E[3%p1%dm, + setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, + setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, + sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, + +st-256color| simpleterm with 256 colors, + use=st, + 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, + +st-bs| simpleterm with backspace as backspace, + use=st, + kbs=\010, + kdch1=\177, + +st-bs-256color| simpleterm with backspace as backspace and 256colors, + use=st-256color, + kbs=\010, + kdch1=\177, diff --git a/st/st.o b/st/st.o new file mode 100644 index 0000000000000000000000000000000000000000..eee9021f26aa810031db222d861716aa9ba412b3 GIT binary patch literal 78176 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 VtA1^W%JndXP#Pi%<uEWX007?X${_#% literal 0 HcmV?d00001 diff --git a/st/win.h b/st/win.h new file mode 100644 index 0000000..6de960d --- /dev/null +++ b/st/win.h @@ -0,0 +1,41 @@ +/* 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 *); +int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *); +void xseticontitle(char *); +void xsettitle(char *); +int xsetcursor(int); +void xsetmode(int, unsigned int); +void xsetpointermotion(int); +void xsetsel(char *); +int xstartdraw(void); +void xximspot(int, int); diff --git a/st/x.c b/st/x.c new file mode 100644 index 0000000..aa09997 --- /dev/null +++ b/st/x.c @@ -0,0 +1,2099 @@ +/* See LICENSE for license details. */ +#include <errno.h> +#include <math.h> +#include <limits.h> +#include <locale.h> +#include <signal.h> +#include <sys/select.h> +#include <time.h> +#include <unistd.h> +#include <libgen.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/cursorfont.h> +#include <X11/keysym.h> +#include <X11/Xft/Xft.h> +#include <X11/XKBlib.h> + +char *argv0; +#include "arg.h" +#include "st.h" +#include "win.h" + +/* types used in config.h */ +typedef struct { + uint mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +typedef struct { + uint mod; + uint button; + void (*func)(const Arg *); + const Arg arg; + uint release; +} MouseShortcut; + +typedef struct { + KeySym k; + uint mask; + char *s; + /* three-valued logic variables: 0 indifferent, 1 on, -1 off */ + signed char appkey; /* application keypad */ + signed char appcursor; /* application cursor */ +} Key; + +/* X modifiers */ +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13|1<<14) + +/* function definitions used in config.h */ +static void clipcopy(const Arg *); +static void clippaste(const Arg *); +static void numlock(const Arg *); +static void selpaste(const Arg *); +static void zoom(const Arg *); +static void zoomabs(const Arg *); +static void zoomreset(const Arg *); +static void ttysend(const Arg *); + +/* config.h for applying patches and the configuration. */ +#include "config.h" + +/* XEMBED messages */ +#define XEMBED_FOCUS_IN 4 +#define XEMBED_FOCUS_OUT 5 + +/* macros */ +#define IS_SET(flag) ((win.mode & (flag)) != 0) +#define TRUERED(x) (((x) & 0xff0000) >> 8) +#define TRUEGREEN(x) (((x) & 0xff00)) +#define TRUEBLUE(x) (((x) & 0xff) << 8) + +typedef XftDraw *Draw; +typedef XftColor Color; +typedef XftGlyphFontSpec GlyphFontSpec; + +/* Purely graphic info */ +typedef struct { + int tw, th; /* tty width and height */ + int w, h; /* window width and height */ + int ch; /* char height */ + int cw; /* char width */ + int mode; /* window state/mode flags */ + int cursor; /* cursor style */ +} TermWindow; + +typedef struct { + Display *dpy; + Colormap cmap; + Window win; + Drawable buf; + GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ + Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; + struct { + XIM xim; + XIC xic; + XPoint spot; + XVaNestedList spotlist; + } ime; + Draw draw; + Visual *vis; + XSetWindowAttributes attrs; + int scr; + int isfixed; /* is fixed geometry? */ + int l, t; /* left and top offset */ + int gm; /* geometry mask */ +} XWindow; + +typedef struct { + Atom xtarget; + char *primary, *clipboard; + struct timespec tclick1; + struct timespec tclick2; +} XSelection; + +/* Font structure */ +#define Font Font_ +typedef struct { + int height; + int width; + int ascent; + int descent; + int badslant; + int badweight; + short lbearing; + short rbearing; + XftFont *match; + FcFontSet *set; + FcPattern *pattern; +} Font; + +/* Drawing Context */ +typedef struct { + Color *col; + size_t collen; + Font font, bfont, ifont, ibfont; + GC gc; +} DC; + +static inline ushort sixd_to_16bit(int); +static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); +static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); +static void xdrawglyph(Glyph, int, int); +static void xclear(int, int, int, int); +static int xgeommasktogravity(int); +static int ximopen(Display *); +static void ximinstantiate(Display *, XPointer, XPointer); +static void ximdestroy(XIM, XPointer, XPointer); +static int xicdestroy(XIC, XPointer, XPointer); +static void xinit(int, int); +static void cresize(int, int); +static void xresize(int, int); +static void xhints(void); +static int xloadcolor(int, const char *, Color *); +static int xloadfont(Font *, FcPattern *); +static void xloadfonts(const char *, double); +static void xunloadfont(Font *); +static void xunloadfonts(void); +static void xsetenv(void); +static void xseturgency(int); +static int evcol(XEvent *); +static int evrow(XEvent *); + +static void expose(XEvent *); +static void visibility(XEvent *); +static void unmap(XEvent *); +static void kpress(XEvent *); +static void cmessage(XEvent *); +static void resize(XEvent *); +static void focus(XEvent *); +static uint buttonmask(uint); +static int mouseaction(XEvent *, uint); +static void brelease(XEvent *); +static void bpress(XEvent *); +static void bmotion(XEvent *); +static void propnotify(XEvent *); +static void selnotify(XEvent *); +static void selclear_(XEvent *); +static void selrequest(XEvent *); +static void setsel(char *, Time); +static void mousesel(XEvent *, int); +static void mousereport(XEvent *); +static char *kmap(KeySym, uint); +static int match(uint, uint); + +static void run(void); +static void usage(void); + +static void (*handler[LASTEvent])(XEvent *) = { + [KeyPress] = kpress, + [ClientMessage] = cmessage, + [ConfigureNotify] = resize, + [VisibilityNotify] = visibility, + [UnmapNotify] = unmap, + [Expose] = expose, + [FocusIn] = focus, + [FocusOut] = focus, + [MotionNotify] = bmotion, + [ButtonPress] = bpress, + [ButtonRelease] = brelease, +/* + * Uncomment if you want the selection to disappear when you select something + * different in another window. + */ +/* [SelectionClear] = selclear_, */ + [SelectionNotify] = selnotify, +/* + * PropertyNotify is only turned on when there is some INCR transfer happening + * for the selection retrieval. + */ + [PropertyNotify] = propnotify, + [SelectionRequest] = selrequest, +}; + +/* Globals */ +static DC dc; +static XWindow xw; +static XSelection xsel; +static TermWindow win; + +/* Font Ring Cache */ +enum { + FRC_NORMAL, + FRC_ITALIC, + FRC_BOLD, + FRC_ITALICBOLD +}; + +typedef struct { + XftFont *font; + int flags; + Rune unicodep; +} Fontcache; + +/* Fontcache is an array now. A new font will be appended to the array. */ +static Fontcache *frc = NULL; +static int frclen = 0; +static int frccap = 0; +static char *usedfont = NULL; +static double usedfontsize = 0; +static double defaultfontsize = 0; + +static char *opt_class = NULL; +static char **opt_cmd = NULL; +static char *opt_embed = NULL; +static char *opt_font = NULL; +static char *opt_io = NULL; +static char *opt_line = NULL; +static char *opt_name = NULL; +static char *opt_title = NULL; + +static uint buttons; /* bit field of pressed buttons */ + +void +clipcopy(const Arg *dummy) +{ + Atom clipboard; + + free(xsel.clipboard); + xsel.clipboard = NULL; + + if (xsel.primary != NULL) { + xsel.clipboard = xstrdup(xsel.primary); + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); + } +} + +void +clippaste(const Arg *dummy) +{ + Atom clipboard; + + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, + xw.win, CurrentTime); +} + +void +selpaste(const Arg *dummy) +{ + XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); +} + +void +numlock(const Arg *dummy) +{ + win.mode ^= MODE_NUMLOCK; +} + +void +zoom(const Arg *arg) +{ + Arg larg; + + larg.f = usedfontsize + arg->f; + zoomabs(&larg); +} + +void +zoomabs(const Arg *arg) +{ + xunloadfonts(); + xloadfonts(usedfont, arg->f); + cresize(0, 0); + redraw(); + xhints(); +} + +void +zoomreset(const Arg *arg) +{ + Arg larg; + + if (defaultfontsize > 0) { + larg.f = defaultfontsize; + zoomabs(&larg); + } +} + +void +ttysend(const Arg *arg) +{ + ttywrite(arg->s, strlen(arg->s), 1); +} + +int +evcol(XEvent *e) +{ + int x = e->xbutton.x - borderpx; + LIMIT(x, 0, win.tw - 1); + return x / win.cw; +} + +int +evrow(XEvent *e) +{ + int y = e->xbutton.y - borderpx; + LIMIT(y, 0, win.th - 1); + return y / win.ch; +} + +void +mousesel(XEvent *e, int done) +{ + int type, seltype = SEL_REGULAR; + uint state = e->xbutton.state & ~(Button1Mask | forcemousemod); + + for (type = 1; type < LEN(selmasks); ++type) { + if (match(selmasks[type], state)) { + seltype = type; + break; + } + } + selextend(evcol(e), evrow(e), seltype, done); + if (done) + setsel(getsel(), e->xbutton.time); +} + +void +mousereport(XEvent *e) +{ + int len, btn, code; + int x = evcol(e), y = evrow(e); + int state = e->xbutton.state; + char buf[40]; + static int ox, oy; + + if (e->type == MotionNotify) { + if (x == ox && y == oy) + return; + if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) + return; + /* MODE_MOUSEMOTION: no reporting if no button is pressed */ + if (IS_SET(MODE_MOUSEMOTION) && buttons == 0) + return; + /* Set btn to lowest-numbered pressed button, or 12 if no + * buttons are pressed. */ + for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++) + ; + code = 32; + } else { + btn = e->xbutton.button; + /* Only buttons 1 through 11 can be encoded */ + if (btn < 1 || btn > 11) + return; + if (e->type == ButtonRelease) { + /* MODE_MOUSEX10: no button release reporting */ + if (IS_SET(MODE_MOUSEX10)) + return; + /* Don't send release events for the scroll wheel */ + if (btn == 4 || btn == 5) + return; + } + code = 0; + } + + ox = x; + oy = y; + + /* Encode btn into code. If no button is pressed for a motion event in + * MODE_MOUSEMANY, then encode it as a release. */ + if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12) + code += 3; + else if (btn >= 8) + code += 128 + btn - 8; + else if (btn >= 4) + code += 64 + btn - 4; + else + code += btn - 1; + + if (!IS_SET(MODE_MOUSEX10)) { + code += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */ + + ((state & ControlMask) ? 16 : 0); + } + + if (IS_SET(MODE_MOUSESGR)) { + len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", + code, x+1, y+1, + e->type == ButtonRelease ? 'm' : 'M'); + } else if (x < 223 && y < 223) { + len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", + 32+code, 32+x+1, 32+y+1); + } else { + return; + } + + ttywrite(buf, len, 0); +} + +uint +buttonmask(uint button) +{ + return button == Button1 ? Button1Mask + : button == Button2 ? Button2Mask + : button == Button3 ? Button3Mask + : button == Button4 ? Button4Mask + : button == Button5 ? Button5Mask + : 0; +} + +int +mouseaction(XEvent *e, uint release) +{ + MouseShortcut *ms; + + /* ignore Button<N>mask for Button<N> - it's set on release */ + uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && + (match(ms->mod, state) || /* exact or forced */ + match(ms->mod, state & ~forcemousemod))) { + ms->func(&(ms->arg)); + return 1; + } + } + + return 0; +} + +void +bpress(XEvent *e) +{ + int btn = e->xbutton.button; + struct timespec now; + int snap; + + if (1 <= btn && btn <= 11) + buttons |= 1 << (btn-1); + + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + if (mouseaction(e, 0)) + return; + + if (btn == 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) +{ + int btn = e->xbutton.button; + + if (1 <= btn && btn <= 11) + buttons &= ~(1 << (btn-1)); + + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + if (mouseaction(e, 1)) + return; + if (btn == Button1) + mousesel(e, 1); +} + +void +bmotion(XEvent *e) +{ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + mousesel(e, 0); +} + +void +cresize(int width, int height) +{ + int col, row; + + if (width != 0) + win.w = width; + if (height != 0) + win.h = height; + + col = (win.w - 2 * borderpx) / win.cw; + row = (win.h - 2 * borderpx) / win.ch; + col = MAX(1, col); + row = MAX(1, row); + + tresize(col, row); + xresize(col, row); + ttyresize(win.tw, win.th); +} + +void +xresize(int col, int row) +{ + win.tw = col * win.cw; + win.th = row * win.ch; + + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, + DefaultDepth(xw.dpy, xw.scr)); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); + + /* resize to new width */ + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); +} + +ushort +sixd_to_16bit(int x) +{ + return x == 0 ? 0 : 0x3737 + 0x2828 * x; +} + +int +xloadcolor(int i, const char *name, Color *ncolor) +{ + XRenderColor color = { .alpha = 0xffff }; + + if (!name) { + if (BETWEEN(i, 16, 255)) { /* 256 color */ + if (i < 6*6*6+16) { /* same colors as xterm */ + color.red = sixd_to_16bit( ((i-16)/36)%6 ); + color.green = sixd_to_16bit( ((i-16)/6) %6 ); + color.blue = sixd_to_16bit( ((i-16)/1) %6 ); + } else { /* greyscale */ + color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16)); + color.green = color.blue = color.red; + } + return XftColorAllocValue(xw.dpy, xw.vis, + xw.cmap, &color, ncolor); + } else + name = colorname[i]; + } + + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); +} + +void +xloadcols(void) +{ + int i; + static int loaded; + Color *cp; + + if (loaded) { + for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) + XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); + } else { + dc.collen = MAX(LEN(colorname), 256); + dc.col = xmalloc(dc.collen * sizeof(Color)); + } + + for (i = 0; i < dc.collen; i++) + if (!xloadcolor(i, NULL, &dc.col[i])) { + if (colorname[i]) + die("could not allocate color '%s'\n", colorname[i]); + else + die("could not allocate color %d\n", i); + } + loaded = 1; +} + +int +xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b) +{ + if (!BETWEEN(x, 0, dc.collen)) + return 1; + + *r = dc.col[x].color.red >> 8; + *g = dc.col[x].color.green >> 8; + *b = dc.col[x].color.blue >> 8; + + return 0; +} + +int +xsetcolorname(int x, const char *name) +{ + Color ncolor; + + if (!BETWEEN(x, 0, dc.collen)) + return 1; + + if (!xloadcolor(x, name, &ncolor)) + return 1; + + XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); + dc.col[x] = ncolor; + + return 0; +} + +/* + * Absolute coordinates. + */ +void +xclear(int x1, int y1, int x2, int y2) +{ + XftDrawRect(xw.draw, + &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg], + x1, y1, x2-x1, y2-y1); +} + +void +xhints(void) +{ + XClassHint class = {opt_name ? opt_name : termname, + opt_class ? opt_class : termname}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints *sizeh; + + sizeh = XAllocSizeHints(); + + sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; + sizeh->height = win.h; + sizeh->width = win.w; + sizeh->height_inc = win.ch; + sizeh->width_inc = win.cw; + sizeh->base_height = 2 * borderpx; + sizeh->base_width = 2 * borderpx; + sizeh->min_height = win.ch + 2 * borderpx; + sizeh->min_width = win.cw + 2 * borderpx; + if (xw.isfixed) { + sizeh->flags |= PMaxSize; + sizeh->min_width = sizeh->max_width = win.w; + sizeh->min_height = sizeh->max_height = win.h; + } + if (xw.gm & (XValue|YValue)) { + sizeh->flags |= USPosition | PWinGravity; + sizeh->x = xw.l; + sizeh->y = xw.t; + sizeh->win_gravity = xgeommasktogravity(xw.gm); + } + + XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, + &class); + XFree(sizeh); +} + +int +xgeommasktogravity(int mask) +{ + switch (mask & (XNegative|YNegative)) { + case 0: + return NorthWestGravity; + case XNegative: + return NorthEastGravity; + case YNegative: + return SouthWestGravity; + } + + return SouthEastGravity; +} + +int +xloadfont(Font *f, FcPattern *pattern) +{ + FcPattern *configured; + FcPattern *match; + FcResult result; + XGlyphInfo extents; + int wantattr, haveattr; + + /* + * Manually configure instead of calling XftMatchFont + * so that we can use the configured pattern for + * "missing glyph" lookups. + */ + configured = FcPatternDuplicate(pattern); + if (!configured) + return 1; + + FcConfigSubstitute(NULL, configured, FcMatchPattern); + XftDefaultSubstitute(xw.dpy, xw.scr, configured); + + match = FcFontMatch(NULL, configured, &result); + if (!match) { + FcPatternDestroy(configured); + return 1; + } + + if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { + FcPatternDestroy(configured); + FcPatternDestroy(match); + return 1; + } + + if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == + XftResultMatch)) { + /* + * Check if xft was unable to find a font with the appropriate + * slant but gave us one anyway. Try to mitigate. + */ + if ((XftPatternGetInteger(f->match->pattern, "slant", 0, + &haveattr) != XftResultMatch) || haveattr < wantattr) { + f->badslant = 1; + fputs("font slant does not match\n", stderr); + } + } + + if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) == + XftResultMatch)) { + if ((XftPatternGetInteger(f->match->pattern, "weight", 0, + &haveattr) != XftResultMatch) || haveattr != wantattr) { + f->badweight = 1; + fputs("font weight does not match\n", stderr); + } + } + + XftTextExtentsUtf8(xw.dpy, f->match, + (const FcChar8 *) ascii_printable, + strlen(ascii_printable), &extents); + + f->set = NULL; + f->pattern = configured; + + f->ascent = f->match->ascent; + f->descent = f->match->descent; + f->lbearing = 0; + f->rbearing = f->match->max_advance_width; + + f->height = f->ascent + f->descent; + f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); + + return 0; +} + +void +xloadfonts(const char *fontstr, double fontsize) +{ + FcPattern *pattern; + double fontval; + + if (fontstr[0] == '-') + pattern = XftXlfdParse(fontstr, False, False); + else + pattern = FcNameParse((const FcChar8 *)fontstr); + + if (!pattern) + die("can't open font %s\n", fontstr); + + if (fontsize > 1) { + FcPatternDel(pattern, FC_PIXEL_SIZE); + FcPatternDel(pattern, FC_SIZE); + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); + usedfontsize = fontsize; + } else { + if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = fontval; + } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = -1; + } else { + /* + * Default font size is 12, if none given. This is to + * have a known usedfontsize value. + */ + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); + usedfontsize = 12; + } + defaultfontsize = usedfontsize; + } + + if (xloadfont(&dc.font, pattern)) + die("can't open font %s\n", fontstr); + + if (usedfontsize < 0) { + FcPatternGetDouble(dc.font.match->pattern, + FC_PIXEL_SIZE, 0, &fontval); + usedfontsize = fontval; + if (fontsize == 0) + defaultfontsize = fontval; + } + + /* Setting character width and height. */ + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (xloadfont(&dc.ifont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (xloadfont(&dc.ibfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadfont(&dc.bfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDestroy(pattern); +} + +void +xunloadfont(Font *f) +{ + XftFontClose(xw.dpy, f->match); + FcPatternDestroy(f->pattern); + if (f->set) + FcFontSetDestroy(f->set); +} + +void +xunloadfonts(void) +{ + /* Free the loaded fonts in the font cache. */ + while (frclen > 0) + XftFontClose(xw.dpy, frc[--frclen].font); + + xunloadfont(&dc.font); + xunloadfont(&dc.bfont); + xunloadfont(&dc.ifont); + xunloadfont(&dc.ibfont); +} + +int +ximopen(Display *dpy) +{ + XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; + XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; + + xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); + if (xw.ime.xim == NULL) + return 0; + + if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) + fprintf(stderr, "XSetIMValues: " + "Could not set XNDestroyCallback.\n"); + + xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, + NULL); + + if (xw.ime.xic == NULL) { + xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, + XNDestroyCallback, &icdestroy, + NULL); + } + if (xw.ime.xic == NULL) + fprintf(stderr, "XCreateIC: Could not create input context.\n"); + + return 1; +} + +void +ximinstantiate(Display *dpy, XPointer client, XPointer call) +{ + if (ximopen(dpy)) + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + +void +ximdestroy(XIM xim, XPointer client, XPointer call) +{ + xw.ime.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + XFree(xw.ime.spotlist); +} + +int +xicdestroy(XIC xim, XPointer client, XPointer call) +{ + xw.ime.xic = NULL; + return 1; +} + +void +xinit(int cols, int rows) +{ + XGCValues gcvalues; + Cursor cursor; + Window parent; + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; + + if (!(xw.dpy = XOpenDisplay(NULL))) + die("can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); + xw.vis = XDefaultVisual(xw.dpy, xw.scr); + + /* font */ + if (!FcInit()) + die("could not init fontconfig.\n"); + + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + + /* colors */ + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xloadcols(); + + /* adjust fixed window geometry */ + win.w = 2 * borderpx + cols * win.cw; + win.h = 2 * borderpx + rows * win.ch; + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) + xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2; + + /* Events */ + xw.attrs.background_pixel = dc.col[defaultbg].pixel; + xw.attrs.border_pixel = dc.col[defaultbg].pixel; + xw.attrs.bit_gravity = NorthWestGravity; + xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask + | ExposureMask | VisibilityChangeMask | StructureNotifyMask + | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; + xw.attrs.colormap = xw.cmap; + + if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) + parent = XRootWindow(xw.dpy, xw.scr); + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, + win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, + xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity + | CWEventMask | CWColormap, &xw.attrs); + + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; + dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, + &gcvalues); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, + DefaultDepth(xw.dpy, xw.scr)); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); + + /* input methods */ + if (!ximopen(xw.dpy)) { + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + } + + /* white cursor, black outline */ + cursor = XCreateFontCursor(xw.dpy, mouseshape); + XDefineCursor(xw.dpy, xw.win, cursor); + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) { + xmousefg.red = 0xffff; + xmousefg.green = 0xffff; + xmousefg.blue = 0xffff; + } + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) { + xmousebg.red = 0x0000; + xmousebg.green = 0x0000; + xmousebg.blue = 0x0000; + } + + XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); + + xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); + xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); + xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); + xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False); + XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); + + xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (uchar *)&thispid, 1); + + win.mode = MODE_NUMLOCK; + resettitle(); + xhints(); + XMapWindow(xw.dpy, xw.win); + XSync(xw.dpy, False); + + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2); + xsel.primary = NULL; + xsel.clipboard = NULL; + xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); + if (xsel.xtarget == None) + xsel.xtarget = XA_STRING; +} + +int +xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) +{ + float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; + ushort mode, prevmode = USHRT_MAX; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; + float runewidth = win.cw; + Rune rune; + FT_UInt glyphidx; + FcResult fcres; + FcPattern *fcpattern, *fontpattern; + FcFontSet *fcsets[] = { NULL }; + FcCharSet *fccharset; + int i, f, numspecs = 0; + + for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + /* Fetch rune and mode for current glyph. */ + rune = glyphs[i].u; + mode = glyphs[i].mode; + + /* Skip dummy wide-character spacing. */ + if (mode == ATTR_WDUMMY) + continue; + + /* Determine font for glyph if different from previous glyph. */ + if (prevmode != mode) { + prevmode = mode; + font = &dc.font; + frcflags = FRC_NORMAL; + runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if (mode & ATTR_ITALIC) { + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if (mode & ATTR_BOLD) { + font = &dc.bfont; + frcflags = FRC_BOLD; + } + yp = winy + font->ascent; + } + + /* Lookup character index with default font. */ + glyphidx = XftCharIndex(xw.dpy, font->match, rune); + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + continue; + } + + /* Fallback on font cache, search the font cache for match. */ + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ + if (glyphidx && frc[f].flags == frcflags) + break; + /* We got a default font for a not found glyph. */ + if (!glyphidx && frc[f].flags == frcflags + && frc[f].unicodep == rune) { + break; + } + } + + /* Nothing was found. Use fontconfig to find matching font. */ + if (f >= frclen) { + if (!font->set) + font->set = FcFontSort(0, font->pattern, + 1, 0, &fcres); + fcsets[0] = font->set; + + /* + * Nothing was found in the cache. Now use + * some dozen of Fontconfig calls to get the + * font for one single character. + * + * Xft and fontconfig are design failures. + */ + fcpattern = FcPatternDuplicate(font->pattern); + fccharset = FcCharSetCreate(); + + FcCharSetAddChar(fccharset, rune); + FcPatternAddCharSet(fcpattern, FC_CHARSET, + fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, 1); + + FcConfigSubstitute(0, fcpattern, + FcMatchPattern); + FcDefaultSubstitute(fcpattern); + + fontpattern = FcFontSetMatch(0, fcsets, 1, + fcpattern, &fcres); + + /* Allocate memory for the new cache entry. */ + if (frclen >= frccap) { + frccap += 16; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); + } + + frc[frclen].font = XftFontOpenPattern(xw.dpy, + fontpattern); + if (!frc[frclen].font) + die("XftFontOpenPattern failed seeking fallback font: %s\n", + strerror(errno)); + frc[frclen].flags = frcflags; + frc[frclen].unicodep = rune; + + glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); + + f = frclen; + frclen++; + + FcPatternDestroy(fcpattern); + FcCharSetDestroy(fccharset); + } + + specs[numspecs].font = frc[f].font; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + } + + return numspecs; +} + +void +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) +{ + int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); + int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, + width = charlen * win.cw; + Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; + XRenderColor colfg, colbg; + XRectangle r; + + /* Fallback on color display for attributes not supported by the font */ + if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) { + if (dc.ibfont.badslant || dc.ibfont.badweight) + base.fg = defaultattr; + } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) || + (base.mode & ATTR_BOLD && dc.bfont.badweight)) { + base.fg = defaultattr; + } + + if (IS_TRUECOL(base.fg)) { + colfg.alpha = 0xffff; + colfg.red = TRUERED(base.fg); + colfg.green = TRUEGREEN(base.fg); + colfg.blue = TRUEBLUE(base.fg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg); + fg = &truefg; + } else { + fg = &dc.col[base.fg]; + } + + if (IS_TRUECOL(base.bg)) { + colbg.alpha = 0xffff; + colbg.green = TRUEGREEN(base.bg); + colbg.red = TRUERED(base.bg); + colbg.blue = TRUEBLUE(base.bg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg); + bg = &truebg; + } else { + bg = &dc.col[base.bg]; + } + + /* Change basic system colors [0-7] to bright system colors [8-15] */ + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) + fg = &dc.col[base.fg + 8]; + + if (IS_SET(MODE_REVERSE)) { + if (fg == &dc.col[defaultfg]) { + fg = &dc.col[defaultbg]; + } else { + colfg.red = ~fg->color.red; + colfg.green = ~fg->color.green; + colfg.blue = ~fg->color.blue; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, + &revfg); + fg = &revfg; + } + + if (bg == &dc.col[defaultbg]) { + bg = &dc.col[defaultfg]; + } else { + colbg.red = ~bg->color.red; + colbg.green = ~bg->color.green; + colbg.blue = ~bg->color.blue; + colbg.alpha = bg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, + &revbg); + bg = &revbg; + } + } + + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { + colfg.red = fg->color.red / 2; + colfg.green = fg->color.green / 2; + colfg.blue = fg->color.blue / 2; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); + fg = &revfg; + } + + if (base.mode & ATTR_REVERSE) { + temp = fg; + fg = bg; + bg = temp; + } + + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) + fg = bg; + + if (base.mode & ATTR_INVISIBLE) + fg = bg; + + /* Intelligent cleaning up of the borders. */ + if (x == 0) { + xclear(0, (y == 0)? 0 : winy, borderpx, + winy + win.ch + + ((winy + win.ch >= borderpx + win.th)? win.h : 0)); + } + if (winx + width >= borderpx + win.tw) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, + ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); + } + if (y == 0) + xclear(winx, 0, winx + width, borderpx); + if (winy + win.ch >= borderpx + win.th) + xclear(winx, winy + win.ch, winx + width, win.h); + + /* Clean up the region we want to draw to. */ + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); + + /* Set the clip region because Xft is sometimes dirty. */ + r.x = 0; + r.y = 0; + r.height = win.ch; + r.width = width; + XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); + + /* Render the glyphs. */ + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, + width, 1); + } + + /* Reset clip to none. */ + XftDrawSetClip(xw.draw, 0); +} + +void +xdrawglyph(Glyph g, int x, int y) +{ + int numspecs; + XftGlyphFontSpec spec; + + numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); + xdrawglyphfontspecs(&spec, g, numspecs, x, y); +} + +void +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) +{ + Color drawcol; + + /* remove the old cursor */ + if (selected(ox, oy)) + og.mode ^= ATTR_REVERSE; + xdrawglyph(og, ox, oy); + + if (IS_SET(MODE_HIDE)) + return; + + /* + * Select the right color for the right mode. + */ + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; + + if (IS_SET(MODE_REVERSE)) { + g.mode |= ATTR_REVERSE; + g.bg = defaultfg; + if (selected(cx, cy)) { + drawcol = dc.col[defaultcs]; + g.fg = defaultrcs; + } else { + drawcol = dc.col[defaultrcs]; + g.fg = defaultcs; + } + } else { + if (selected(cx, cy)) { + g.fg = defaultfg; + g.bg = defaultrcs; + } else { + g.fg = defaultbg; + g.bg = defaultcs; + } + drawcol = dc.col[g.bg]; + } + + /* draw the new one */ + if (IS_SET(MODE_FOCUSED)) { + switch (win.cursor) { + case 7: /* st extension */ + g.u = 0x2603; /* snowman (U+2603) */ + /* FALLTHROUGH */ + case 0: /* Blinking Block */ + case 1: /* Blinking Block (Default) */ + case 2: /* Steady Block */ + xdrawglyph(g, cx, cy); + break; + case 3: /* Blinking Underline */ + case 4: /* Steady Underline */ + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - \ + cursorthickness, + win.cw, cursorthickness); + break; + case 5: /* Blinking bar */ + case 6: /* Steady bar */ + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + cursorthickness, win.ch); + break; + } + } else { + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + win.cw - 1, 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + (cx + 1) * win.cw - 1, + borderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - 1, + win.cw, 1); + } +} + +void +xsetenv(void) +{ + char buf[sizeof(long) * 8 + 1]; + + snprintf(buf, sizeof(buf), "%lu", xw.win); + setenv("WINDOWID", buf, 1); +} + +void +xseticontitle(char *p) +{ + XTextProperty prop; + DEFAULT(p, opt_title); + + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) + return; + XSetWMIconName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname); + XFree(prop.value); +} + +void +xsettitle(char *p) +{ + XTextProperty prop; + DEFAULT(p, opt_title); + + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) + return; + XSetWMName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); + XFree(prop.value); +} + +int +xstartdraw(void) +{ + return IS_SET(MODE_VISIBLE); +} + +void +xdrawline(Line line, int x1, int y1, int x2) +{ + int i, x, ox, numspecs; + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + + numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; + for (x = x1; x < x2 && i < numspecs; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; + if (i > 0 && ATTRCMP(base, new)) { + xdrawglyphfontspecs(specs, base, i, ox, y1); + specs += i; + numspecs -= i; + i = 0; + } + if (i == 0) { + ox = x; + base = new; + } + i++; + } + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1); +} + +void +xfinishdraw(void) +{ + XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, + win.h, 0, 0); + XSetForeground(xw.dpy, dc.gc, + dc.col[IS_SET(MODE_REVERSE)? + defaultfg : defaultbg].pixel); +} + +void +xximspot(int x, int y) +{ + if (xw.ime.xic == NULL) + return; + + xw.ime.spot.x = borderpx + x * win.cw; + xw.ime.spot.y = borderpx + (y + 1) * win.ch; + + XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL); +} + +void +expose(XEvent *ev) +{ + redraw(); +} + +void +visibility(XEvent *ev) +{ + XVisibilityEvent *e = &ev->xvisibility; + + MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); +} + +void +unmap(XEvent *ev) +{ + win.mode &= ~MODE_VISIBLE; +} + +void +xsetpointermotion(int set) +{ + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); +} + +void +xsetmode(int set, unsigned int flags) +{ + int mode = win.mode; + MODBIT(win.mode, set, flags); + if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) + redraw(); +} + +int +xsetcursor(int cursor) +{ + if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ + return 1; + win.cursor = cursor; + return 0; +} + +void +xseturgency(int add) +{ + XWMHints *h = XGetWMHints(xw.dpy, xw.win); + + MODBIT(h->flags, add, XUrgencyHint); + XSetWMHints(xw.dpy, xw.win, h); + XFree(h); +} + +void +xbell(void) +{ + if (!(IS_SET(MODE_FOCUSED))) + xseturgency(1); + if (bellvolume) + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); +} + +void +focus(XEvent *ev) +{ + XFocusChangeEvent *e = &ev->xfocus; + + if (e->mode == NotifyGrab) + return; + + if (ev->type == FocusIn) { + if (xw.ime.xic) + XSetICFocus(xw.ime.xic); + win.mode |= MODE_FOCUSED; + xseturgency(0); + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); + win.mode &= ~MODE_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3, 0); + } +} + +int +match(uint mask, uint state) +{ + return mask == XK_ANY_MOD || mask == (state & ~ignoremod); +} + +char* +kmap(KeySym k, uint state) +{ + Key *kp; + int i; + + /* Check for mapped keys out of X11 function keys. */ + for (i = 0; i < LEN(mappedkeys); i++) { + if (mappedkeys[i] == k) + break; + } + if (i == LEN(mappedkeys)) { + if ((k & 0xFFFF) < 0xFD00) + return NULL; + } + + for (kp = key; kp < key + LEN(key); kp++) { + if (kp->k != k) + continue; + + if (!match(kp->mask, state)) + continue; + + if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) + continue; + if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2) + continue; + + if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) + continue; + + return kp->s; + } + + return NULL; +} + +void +kpress(XEvent *ev) +{ + XKeyEvent *e = &ev->xkey; + KeySym ksym = NoSymbol; + char buf[64], *customkey; + int len; + Rune c; + Status status; + Shortcut *bp; + + if (IS_SET(MODE_KBDLOCK)) + return; + + if (xw.ime.xic) { + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + if (status == XBufferOverflow) + return; + } else { + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); + } + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { + bp->func(&(bp->arg)); + return; + } + } + + /* 2. custom keys from config.h */ + if ((customkey = kmap(ksym, e->state))) { + ttywrite(customkey, strlen(customkey), 1); + return; + } + + /* 3. composed string from input method */ + if (len == 0) + return; + if (len == 1 && e->state & Mod1Mask) { + if (IS_SET(MODE_8BIT)) { + if (*buf < 0177) { + c = *buf | 0x80; + len = utf8encode(c, buf); + } + } else { + buf[1] = buf[0]; + buf[0] = '\033'; + len = 2; + } + } + ttywrite(buf, len, 1); +} + +void +cmessage(XEvent *e) +{ + /* + * See xembed specs + * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html + */ + if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { + if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { + win.mode |= MODE_FOCUSED; + xseturgency(0); + } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { + win.mode &= ~MODE_FOCUSED; + } + } else if (e->xclient.data.l[0] == xw.wmdeletewin) { + ttyhangup(); + exit(0); + } +} + +void +resize(XEvent *e) +{ + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) + return; + + cresize(e->xconfigure.width, e->xconfigure.height); +} + +void +run(void) +{ + XEvent ev; + int w = win.w, h = win.h; + fd_set rfd; + int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing; + struct timespec seltv, *tv, now, lastblink, trigger; + double timeout; + + /* Waiting for window mapping */ + do { + XNextEvent(xw.dpy, &ev); + /* + * This XFilterEvent call is required because of XOpenIM. It + * does filter out the key event and some client message for + * the input method too. + */ + if (XFilterEvent(&ev, None)) + continue; + if (ev.type == ConfigureNotify) { + w = ev.xconfigure.width; + h = ev.xconfigure.height; + } + } while (ev.type != MapNotify); + + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); + cresize(w, h); + + for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) { + FD_ZERO(&rfd); + FD_SET(ttyfd, &rfd); + FD_SET(xfd, &rfd); + + if (XPending(xw.dpy)) + timeout = 0; /* existing events might not set xfd */ + + seltv.tv_sec = timeout / 1E3; + seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec); + tv = timeout >= 0 ? &seltv : NULL; + + if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + clock_gettime(CLOCK_MONOTONIC, &now); + + if (FD_ISSET(ttyfd, &rfd)) + ttyread(); + + xev = 0; + while (XPending(xw.dpy)) { + xev = 1; + XNextEvent(xw.dpy, &ev); + if (XFilterEvent(&ev, None)) + continue; + if (handler[ev.type]) + (handler[ev.type])(&ev); + } + + /* + * To reduce flicker and tearing, when new content or event + * triggers drawing, we first wait a bit to ensure we got + * everything, and if nothing new arrives - we draw. + * We start with trying to wait minlatency ms. If more content + * arrives sooner, we retry with shorter and shorter periods, + * and eventually draw even without idle after maxlatency ms. + * Typically this results in low latency while interacting, + * maximum latency intervals during `cat huge.txt`, and perfect + * sync with periodic updates from animations/key-repeats/etc. + */ + if (FD_ISSET(ttyfd, &rfd) || xev) { + if (!drawing) { + trigger = now; + drawing = 1; + } + timeout = (maxlatency - TIMEDIFF(now, trigger)) \ + / maxlatency * minlatency; + if (timeout > 0) + continue; /* we have time, try to find idle */ + } + + /* idle detected or maxlatency exhausted -> draw */ + timeout = -1; + if (blinktimeout && tattrset(ATTR_BLINK)) { + timeout = blinktimeout - TIMEDIFF(now, lastblink); + if (timeout <= 0) { + if (-timeout > blinktimeout) /* start visible */ + win.mode |= MODE_BLINK; + win.mode ^= MODE_BLINK; + tsetdirtattr(ATTR_BLINK); + lastblink = now; + timeout = blinktimeout; + } + } + + draw(); + XFlush(xw.dpy); + drawing = 0; + } +} + +void +usage(void) +{ + die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid]" + " [[-e] command [args ...]]\n" + " %s [-aiv] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid] -l line" + " [stty_args ...]\n", argv0, argv0); +} + +int +main(int argc, char *argv[]) +{ + xw.l = xw.t = 0; + xw.isfixed = False; + xsetcursor(cursorshape); + + ARGBEGIN { + case 'a': + allowaltscreen = 0; + break; + case 'c': + opt_class = EARGF(usage()); + break; + case 'e': + if (argc > 0) + --argc, ++argv; + goto run; + case 'f': + opt_font = EARGF(usage()); + break; + case 'g': + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &cols, &rows); + break; + case 'i': + xw.isfixed = 1; + break; + case 'o': + opt_io = EARGF(usage()); + break; + case 'l': + opt_line = EARGF(usage()); + break; + case 'n': + opt_name = EARGF(usage()); + break; + case 't': + case 'T': + opt_title = EARGF(usage()); + break; + case 'w': + opt_embed = EARGF(usage()); + break; + case 'v': + die("%s " VERSION "\n", argv0); + break; + default: + usage(); + } ARGEND; + +run: + if (argc > 0) /* eat all remaining arguments */ + opt_cmd = argv; + + if (!opt_title) + opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; + + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); + xinit(cols, rows); + xsetenv(); + selinit(); + run(); + + return 0; +} diff --git a/st/x.o b/st/x.o new file mode 100644 index 0000000000000000000000000000000000000000..91e8f5c6ef1ac35d6b289fb105a522e82319714d GIT binary patch literal 74848 zcmb<-^>JfjWMqH=Mg}_u1P><4!0<p8A?g4Yc3_ZVkYs2y1#=jf7!G&4J2bywsu1fI z1qt<f{kJ^C?{{$KcUutm@D339`eV1d3t>eb$5}zDL3jtq+QZHD8cZbu-C)t?6O5f; z#$hP`!N1q<npHuH{~ZP^Z~p(kgs<`0`}zO>TmIvpa)5u^fy0jBj$w|Wjv=AJ9?fq! zI=^=N2e@>Xhd4I>V=WhU>HOf)3wE_fGE0*O<AwhZ9QS|>e68lVhk=QK;kBIO9tIW$ zhSy?_dl)zv7+&)^?qLvMV0g{uxCazmj^D31DxUG^l?7??>0P~mfq~&Qr$_T)1s}`T zCAOB?5~ZJ9tczJn-?(&JyL3Kt>HPm9@c;k+tp`elTsogMKl=v~u?LHkobc$a7Wf~` z0rtylR&c<1G#}xJj&+Q2jCG82j6V$WgGV<wU|)c&L<%sdut)3v5_^aoB(!#c)%Aj- z3#tYxeQYOK3KDH7Qq4y=4ucFzf`pn!=WmbBuP7=y!9MoreCYwvz7G^#$SN=dJgmWy zSIQ3Y(qXV8UVnmm3F5rYPaeHs&w>38Rsm8CQX}Ef`O&lULW)N>i>d|#1A|AWiwcL~ zf#WPHAWx(ncTr(sU;t5U|Nncmek(DCI?SURVl;A~b%&^Mq<CnHfDPhrHDzRA@Mu0F zak$t0gYA0;28J>LkL3Rzy<qoxbo2apy}9xKa|Q+m{{B}C3=EyeJ(4eYWL~oDdu-ux z@R#zzAM%=qJdzK2WFA<(YL%A9!50dh7Z3iF*F4e7<G^@wAIN>37c@_laHnM+(9r1J zU~bO9kk)CU;*osaBl8kO&ntz_A7mO-qQc~nd>q;KUk885YhLITabUazj^fTAnipWU zcR+0SQDO1ue26=YUS9wA|9|6qP!yzP{^#OKYdp@uk=ALWlGa(H!U7_gUhf0RGJuj~ z=MT+~j-4kpe>rwufF^=(;LuYjQH7)rkAsg`JQ%Nce(XHt(fJRm2CDxE$6<t`*Edme zY=%c?jf#dx=Z6%JZWC~Pd32VjL>PX9L@WRLbIk{tT=>_6ZF6isz?8=S{`O}_eytlG z$6ZtcKw+Q8|Ng*del4(y&-@XGTQBkV>3|Xo|NE1l`L#}_@xQ<HnP2M~I7N9RUxGOG z0*I?{+(ktMWQOB@5DCrayZ-<G|Nk?;ppS~gXMRB!6`9Zcf*~pfpZNu2R7_sZWME)` zTItO3nLols#RQ_trQ5)xyI8@c^Aoc7TMzKJuro3+bl0eefD!~KoVtBfG&~qjd31X# zcyw}gI&pmF7f1nFrgJ2%(~0LZzmAKFOj@TC-)H`a6tKl9DiY1d89QrKMEJLds0ev9 zyQpvocyzm{aCmh4s3>??p5SkBU}j+O=&n)W@aX)(zuliDt<y(ED6R1)153&IG|P+p zEz$q~|Az(!xJ>-aF8~g-Z%3I*Ku!R2KJ!OjfcTexdyR@v=db2Rtd9GcK{*mq3Z^yx zV&!l7_3!_G$Nk_!p*Q-3!?)us{H@Ra{r~UMYh&-&{G7?*+i^yZUhfkgy@4k@Ixl<h zyWV_x45SBK{5FFN0fu_{*A+g@x}czUwXEeR@$&2qQDL+MJFd>lv-65?=TpyvPgy)5 z6@pi{i3UdKmh6KjayQEwEsoN?uANUikG>XhwJhZ+-2maRcOG@^%~4@=u>@Pi-){{r z5UMp8_**7`nBC4ApwtlH(Oqo-PP3k!N5Hg4=TVS^g-ho*kIv&zp;sP|!q%trIap*D zBox5K5L^u8C!fw|;A90>1(WgUEl~;Z>2*=@@#%aB){0Q$*?AP=Q%i7E@b^l9T$c=X zwFf91AYtXx`3^aSd33rmcqD^$cpQAd;=v4IHd`?8xBLgi8-|=qX9b5#X915#w*gvs zb{=)<23zOY>k6%n;STSvQLzAfrP~LTln;U}>jvds#vi`PZ$S|SjZDw(PzH}qfzAw2 zs>%T;?5k;=0ic8(0!r8cpoE<RPS`mr63qu0JAI%D`=!#~|NlL@iw(db1TNgr!pNi3 zS>vVGzyJT64+uaiK#$}P9tWSXpauyz3|=1i_y0e{$q<)&bRNT~fL`AD_y0ev8~|mh zh!hWPNF7uv-0h+w;?aC01F4Dzn}<|}HNKev3gpfj6#<XV3!OeH60V)cT{?Y0RZusi z3i9ZjqSC>@z+iaE<KR05&(1F%orgURzE=2t4Acg3<ez%fm4Dk?$L6DqkaDu~x+DMk zAHDTVpt9J7e?2cKHMw@4b8J2aDhpq_@UMT>`KkF4D=06P=s0{k#!|uy%~SlX;miyS zj^B<jmdHYdN<@yksPJ%unl4!$P_fd8P8SuPl?)6Fj3uF<YE|$5|IR}PUvX?=Nb3wy z(daw`VQ3wEz>(JJqN3x`o1>E8(d(n4;o12Dn&q(6y|2Y#c6H~d@E|4H?}tHl@wXmh zVqow%_?X3m8Qj8f>3q=qfEi?iTyu>I4|_RRTJsM^{+9Pl3=GgJhQH+wD1aeB1IZuY zq{n!{!}2J9%S$E(2LA1?9N#a1Owr)q?#cyWYVmJ(<$*AD__w?Afu!|7-f$r74X6jv zY&*=~(hIiD8ETsW|8{4nZASdtouRgw@Nahp+h*p`8>12cvdzG=^9IyREP<BRT%#h# z#NXn?1dcg{QcjP~8y=mnJvxs%emf#i!VL)t4iA3UyN=(EIDlx^*8ineE}b8l!HEOn z(B=b7mIqz<eZi%x3*%2v{m^=#^Oz&Q>$hD@3=9mAqDJe-|Nq@CDlBfjHX3k^j+V!3 zOtG2A?+dZPMTG-q79=V_E!+Fw|Nn2UQQ=_VZ@I_Fz~IvPjTu}H!i}{&#@~A%B-0Hx z#kKQ=OXo+I?iv*qm(E`vs0A4)8CpOZc~%Sz5F<d5W|!vDnWJI@3P%ga9iY<IrSp>u zYAd7LM@7P;I|P&m?;)22j^B=O@VAyQf&;dJzjXs60|U6lhOEe=y9Jy-;TfO5^%AJ$ zZ9D?X+DLgHmbPEY|NZ|T<Xp4=|2uDNU;w$&sPo3b7aS0_!NJEIX`L}DCZGgR0CG6~ z1n~0fA8?fL^k#4%<rzq{EAY4e|MUO<%SV6z|A!RLU?q%KUxtB1z}X0#qZlv0-1PVV ze^6#fyZ8d+CU9<mvccH_$|gBKyiEQ3|Nl-<5_0MM1r9$@6ux-y_5c5u?En7%hs3T+ z=P$7ENsuttKX7XU-ZV=CHOCzJwa$I!k2v_5KLT7rf9BUY;kXkNrLLVXx<f#XR+Q*_ z=>{?!td#KpwAFRsGk+Xd1kFSOCb7Zl0%%{+z@yVf1=QH&=)Bx{7Ny^zVR*o!^O;X? zii&_^=ZVgX;3^1I4?2GR|G)E~W9LgpP<A#^0i`$&ki?sxplZuSMFXCMN;y56j~IZ` z4x}dpYDR;r4seGD((mg0i={B|=seu|wnWdPo1x(hqemyRN9Qf9s_w&0i;g`EQvKxL z>kA-Tkot^{;2PAYmz9g1fdR}0_ZGnsh?)VwMF!l&!|)!phDYab&(1F>!6N|*p6?LF zokzhL(xde)e~Szw0|VH6kIr|Hk_J?7d33&lwB=DO?0kfx$g}gP2dJg|160y?9z#{? ztN@mK4U+5iQDK4Df!YWIX?{pZfg~dXgHJDbL;)0OVApjQD}dS>Je>!9Iv=6fd)yh+ z4`uM^%r@}o4p!)9>U8Gl_G0Pu=1Dv5EWyCg9mJE?87#$kqLUeJTIWFz{{5gfL$3?t ze~3H3f9!N-0rz)7sYL>*U-}s2-sU43phV&rd)T8B+#O>82k7fdFs=`Z@NQ6H!r{^F ztl-gIApx-g5)$C}XgyHM2P)bvT~s*ud*6dvHqHW|?BxN;p}V9Q7#JX3cSuJZtP9*S zC&A#B?O=mNkPVi`YH%Ms)4_&lBs@C*rg`$$9YIM_9EJxP>~;BDni&}wz)k|SkXmo^ zw{$WxFr<0%=UqwT*9Z3t_}luyu?TLZf?C3z(2M{H1rI0}q~{2dv`;5E+C4h&K^uTC zB>#ejY4}?Yf^6V_e;|!tA6%;Nx1WHDAUc&g2Ov#NXbA*X_n99i3QtncV7Bi{VPIhJ z>4fu<tX=d6V(nJ2FTjpMQn>2`PK}vRjZ?8}1SMu9gOF@AfNCrSRcX-R0kv~MLnM%P zE`MtgNUr&a1T-mv(-pXsfJMg3ynp}ygX(KYvH_=Ou-wZyu*5^K7HH2177U;G1z1#C z50r|2;ui#m8H|2ef>#q*ZR>%O6VQ%dng@U00W`CbrC!g+>M}KmB~X=E^9$I8Fjs-< z6HvOjlg6)ilfUaHs4i{&{P+KVn1YwjK)sXBchDq+6bMFOtFTA};gTqV<qVJJHx?*) z0aW`yhrK*{S+#zF!X4DnKklL;0E%UgUe+zIAc7M3%Jk0T9*|TEb|+}KFVCa%5m*N_ zEWr`z(R!dn7FImyW6Q-*E#T}2)d?=%!RA8DfLa7D5Sqbt2}6k_sJsJJh>%VYe`^Dz zyt6o*#o*EFq9PIC(+h4C`aqg`9uVFx4i*Lms5Q{?7{elu<|6_gtp`fgVeZz(=5BC7 z`m*f*|NjtH&VOic5L8RPX!!@qh^4IH`WRkOKK%dxKiI$E^bF1dP)C40`uZYhm^lC? zzB~*Mz>-+&0S|r`aO(BwWKqE;>Y~B{Dn!7;N+3c9L|A~vvcSdkaTgU(pC3^M9%qOE z4IY8RsnbIQQj>NT2tb<PodG(Ku<LZzIPUDi!oa|A+}Qy{H6LQ>43=p=z|!d~0gDh} zkK@c0j0_B&#R{Fp5}n>Eo!&B#CMI)<i$^0jBNMFE4XWwD-sp7Zf!Ngi$Y2L(5UBZ= zK#AxMb_NE9=3fdW+|9ojB@Z+|_|bfTv(woF6t19{<p=<g3IV~8V08q?A0kw-HD{WS zD8Nb$P}$^xXh*SmG#?3wMl_;ep=#-_Q6hxkSd^H9W3sv4K%w-7N4L9!NAnMs5`K^7 zAFQQMA=3zdU*Bm4ha?j?{k|ys_W%Fuli-Mj2!OH|QrEuujfH3DAC$<}FgyTG8K?;q zY=md$F~@EemF6GvB|ObPWJ+y)yK_`DUbBKI3*XkaB|3XS=KJ*4s7So@0u{K>I#~u= z;su2QDD%Kd=$9Z3%||RCB{XER0Mx(p;C4|F;BO5ANjHM4lmGws|A*xz(3}RA;C`tL zRt^pe1_lQP0?Iv;uVOLeb*)El1>-RWUQi2F^VdEu23XzQdZ6^lH*or4Ea3z<4R3+6 zesYNliwFPu5)}@QgYTHZjcU+%r35(iVCs21nrl=982DQbfwXkjs6eDWl3l=>K?UK# z7pxwPM`7x=GB7YWhJzBE1UT72NEtBOAs~wZo(4HUlL{|=I$vS&3#hH$dVs$*6EsBG zY@;H>-!kvt|NlOgB`OO1Etf!rILIj;$uTM*FT{Yn@S53!@%PLB|NcW7di&Tw4u({Z zU?08Y{*O~i`Tzg_*hBRtGpu3=_UQbLE3GwGTQHRJdvphDcvv1P;qYkw#aO}=eHfI5 zZ2tcL|N0BKgJI#(`5Qg;zR-K}|37G0^ZpA@5bKajw{t+Zaq~a6lHhLdkY30C%|E#K z+kHXh#EIsAto$w6ASSrE)d{WwATuqFoj)BLAA-iOz!}>S?9%2R?EHP*j0_CDJ{%P< zCo?cGK!;pgK&2W)<M-nN4GawYEuiMS!?)uCh>@$78w?B#E|5&&`0XGgf9n)R21s)l zJks2Gu=xOE^ADa9&d%SLAG@@kE_vID$6d|;SRMJN9BTf-!{1uP$iT2u0aR)oWd44f z!GVFHRMx52q!pAQJ3ll(U~z1Iz~RVwp!u1ABjX1b#)Gb{C;3~>gOXMQq=<Xad?44O z^Es%93vlW6Vsz<sWrWTx?gRA`z-1gb-aC(htEc2|9-Ys@p#l~~&(EOQMGtU(J`5f0 zZ3PWPzP=6%fX0VlXC7~U$<q9jv1~u4SDXK_I`B_9=Ggh$vGFk|CP3bGRQSZ-G8Gh% zohM)N{r~^J`3G}dX|E55%}eJ0|Nl4sy$7D?$_251LD-2PRR<M3I-k4rdMUc}x+-G# z7&wK$1SMT$w;&}1PymCgT1aZ>_2Kyc64V0#hy2U?fB*k?={)J$dDF4;)60v0p_Os4 zN4GpE-GZXRqw^S~Sb#QDqYs1AaRz!ijxam`Y7NPQa$L7Nc<|o9qubp8JXr71?QQ{L zICyl2dw6t)s04U4*E=wjvUqg5JAi6h50F*hn88wtdvqT1=yta7u)I(b<^heFmWd#X znt#aix3q&;-NhOn-PIDHexm?5^@AM^j%H9l^fy?Iiwa^OnZK12RN#UKk`H@8s%(%G zIXt?99Xz1MWif&ZF@XSBfdvZ9ouIlLY_LbSvja#=1SoO6tb`RU*nH3(Y~TSMC<2uW zJRX*ZN_}A>ppLrre^B!g(%bat_O?KFML;Obehzqfj$-vcP+<t|Y(a7~BI&<m1(^)V z!Mi{cx0qec$FSn9xn6^jzhwd_teW3&G~08Q=s;Uqpr$G-*wc`Z>O9o^=r5$~`F2F1 z)B{}4W2i-`+2_3b{~uDLD3n|PNA*5X>jm0y2b=wR2M+NCh|v!YkIvtnUtPM>0~{Nl zfIRL3o6^a-4{kkrg9N|<6@4F+)fgT3g4)22&3FHU()9Ct|NlF79sx18-~0c+^LXb= zm(Eu%ozK87Xnk8M4Dt)4N<R$I`uey>cQkCa;<!iWy%)g`{{Me{9aQjq2iK_*2N)Pi z*uJ?3FqZIx8>laQK%owr(|^JG3tsqx+}@oZ((4K;(98Kd5AOK)|NsBX2Nc1Epcv&G zz*r&+iK@=~FIL_A|G)V!V<}7Pff7N8`@j{;%Af!LzkUx_2AV*A{Q%@FNP>a3;=zM? z(4lUKT1X-R`xs;zXtJLJ9Q4@IZs#!+(>yv4Ld}B4H^La`FrET>*&tzf0M*-|2)X=# z6T7#K!668Wpv`x|G0NKfm$5`0R9b_EYGAD|aF%X9q5z62aA3^&@&Etpn;xCdz%>)Z zRo$Q_zYl2s^^k`)xT^HXy!3(@GF|-1gJ0{AN9QT145+UO5<2yXKMvds`@|n{&~XoF zg!L1@09YiAU;jk0yN5Q|;U1X>kWD(^p$%2@{v^nllgP#(8{o)4`G_n3wkMzY^T96S z7X(vj{P{8}{DP3N<Iejp?C!uC1^gh^ahJ|Vo$tWDdifESVNn{!6)5eB48sGUf>i=k zutKt(1Ai+cBLjnH=O1Xqfiks&M{kIVf={oHiU_Fel-LPcaO4Bc4WRWN%{3|_|M^>v zg9?T292E)ZguGAh>IOyzhSxfvF)9hr45|X8Pq7PP0AwB(WWehau(dhz9+uf0r5_!; zOH=~7tzYc94T{~8haSDv690n*UZ=Zu=YT4PzyC`OAf=3B=P}3TXDp7L#~mA=GcYhQ zsDi3!&@36;6^j+57#Losr#1fl|EK&UsPzr%JA>z|K&?=ZWKh$#w?;()Q6G48yQpNq zJ2U*Pk3e2)K2iZnNYFJu4b>71{PPdI)^DhmWT<n6c;Io#0uO8L(ofyh94?*jUi`fU zcK&16)^8=}`L{Vs9C*Rra-j6GYwQ0KwuWj6rjiq&=`)6s-5^6Mc6)S33wVIW&%!}P z1GF|puU%ip|NsBr@!L@j{uamou=0|nM4f+|i;99xJ%5WfNOLc!3B2zBPXlxU92Cqi z1^@s54_4OUqM~@rMMXjSxQhx0DD}Sl21_rX_NzyCxdJo+fKwBEhTWsPS_70MAmu!? zp63AhrV~7T(E6=}trI+z1nrwZBB?jxPv?!9-z!BrVT;6Gu+02kDbRWw9OV3dw^|SI z`(Nn1+IbD?>CPL_#Uqd*3jXzw79*I%))9b|R*3m@b`R!ukkehd9V{Rf8>B-F)eDkh z08J}Hj7Rn>vTATC1L<R~x%2<ONAhPJQ`V3UKEx3av%w3*ke9hNz5%tdkn&%P$_hpX z2Ezl8I^U%m+zUi@N#|jo-Zd%@Koh`R&3nKM;Sy`m=qQp!U?;)`n_CZ*UW2L>D?QV_ z20SX^(!E3lG{*n>D0J8bRy3ou2EeX%>^$ny`K<H(3zdKW|GV~<+Pk*Cb>;W`>Ui)U z8#tysJFmNRzVy8Oyw};j^)|of;e$WeI$cymI&XShegtZ?aexXG15kkiVpxC}J`kTB zcToZLm>IymX&1}aj{H7%dz~3OT~s7|dcpDf+RLN!g-7Qr$XY*8Q3Gx|Ie^Ud02Lnz zo}Dj2Yuh?sfqHdd7q=eZ?>q`?@pM}>|7YQEode3Oy)K}6?<wF=^8l4hpv7bdI6#f6 z51z@#d^l^4B!GISBA}Hx93GrLM-q_39@MMM`wtpJge<m6^W@Jv^NBz1#3v7aorADy z;KV2X$P*x`BcJ$V4u0Z~1Q+@sB^SWX2aOqlr0=Bh>)-I<cRKnKlsCZ+2PHm8uM^P@ z1NkukQ8R&@+4<8$+2=??DF-A_Uh{%Azy9dB2UI_zy12yNqjwI(!<{J8aiC#VXufJa zP<q58xdp7sv)kn;185v^lSk+M{}*1b?mUcaC8ula6aJRDpx#%FiVQ=k2B=UB05xV6 zK&%K5O9Lr#K@NHe8lD5m27rQ9!9()|Mh)2Qq7ng;)bP+effSC2>J(8AYFzxpA9LXo zf851S{E?6f(38LJ3OH2x^)K+Zi~alme?Mq+6&xy1x3nH8iGn-90-qBM2sz;se+(#k z>&`%}JXkCRwh1}hJ7ZL2UiN~Ao1saCU;khkS0lKh2My#vm*jFVFd&=?abKs4iUo)T z4oU;4^Iy;HcDH~o%H)O=T9)B9CBmR4TX(rl=kXWqps{68yYVontcH}Ztq1D#n_ocJ z{&>s)ue5-!C<3i-0~gL<r^A%jUxc-)xk1K3lH!a1pb1eZ`!f>z`A^uaa1=Al^ADc> z{|_#GAO+;dpU|G+iwUp(|BnW>7bTENJMgm5Ptc`npm<N?*FRV;3i3W;Mx#^$yx{W_ zf7F4`{DLeh9-Yr$Nc{i*|Md;9+dZ1!U>FICna})D?4O`h(<pjDU2`-WKm*4Th+#>H z+ikA={||5Eg8lSj3QP#LP8l{FTjS9UX@5aN5**TuH#{s47h8CA-h`E{kO~17RG?ze zqxrA^tPhE_-plfE(Fxe<9!NiRH%K*XatcyL!wN_%=p-=<BLl;J2Laf?9i$R_y`%G< zPv>`};-vX7qlY!vvBid<(LT^3MrLq60{gM^{tK%spax3mRnKmdJ07jyO7_BPlGleI zYra958rJB6tmbb0UtteghieH=Q$@xe2cN@M`tfgbvEb}rgZdK0<L+QW;_-Gcf?anQ zG#amfk~ky`4}hvihSvWTJRZsSJuD&476VO2fLipB$%s-=H(CKSVD{)m{bkV7Cy1s? zCD*}ADLQX@Ko-{Ei3UitrSa#psPGH2NPr#mdImUsp){2}96SGXeg)M%5+0pADz2U9 ze7e`DfF?tHy7xfWoggiGwlF;4aqyJ_NWFkh=WEb9F_+GBE}({}3#<utsPjhi2Zh#4 z{H{0nx8L?S_*lVX2WZhM1H=FSo{C3(I^TP6-goKz*d3z6<J0-?1?T<${~^v@(ZJto zzzA9~6{8}M*7&%WX@x>bZS!db=(@kocP`LnjjabtOdxu|DHBo#eCE&R;MWALI0btb zWT%HRi;4#?BWQf1lSSoqH8h$&^XE?x5MW^7*9=infRsKSsCqarfF?;^dm&rN-?EK? zfdP+l$Gsq%TsmK%I*Nf`(?vxA()D2CZ_xtHnSiU%<{xbQ{h++r{DXzR|2C)&`oUCJ z?E>*xuP-BPbshiu2adfVDomiNQ^66u)CDEeb-SooAhqKcf&ANi!~>S39phnZoUwTl z8n`cAz#9Q7HhCU=s?cqs;=}n4Bl^H2;vR~}Jvi@!1`8g&@V)#0|LX?O$ZBgjs6CEk zzKe>42QRZ4Xk6PxMdI~J*w7*W`j@@Fpp}B)mLQV1c7R&w$liLX@*kEmI$uJAqWK_G z=OIV_^;en?F@e@EDL@wJxb!;w_dsn9KmxJzApiQa%?FuWIv??`2Nw#>hnQS?J^n-1 zYT?xbavLLD7b8wx81dEX$><7;GKl-o>;bP41!qQ38R39ZMu4(d>wgb^7jVe~T7k|1 zigpfAQ%e9m<OXh|A_r9Kff6wflr&K4<<We^A^I>Vhy*}|B9@XG(gnaJS)(EVcHrw} zU}~ti6B6sq4;Ya<CCzU<96P@|c3$WVQIY68+v%gC;RDIWKAj;d1|G@Bz!|nzhQ0HI z=7-KhogY0wmCW@Q@6P}K?_&9vzb_QDMz8Z&>jC~g(B#;07Zn>&{RM92`*h~0aJ&R9 z9p~TfqGIK7@PUHIK2YHUD)2m%LEUc7W8k%1pg2+h$#;jS$arubase$2bm?|cu>oym zsZlX_;RvdalaGR(!|0-7;HdeoJ48hXxo`qaGI3sT<llb9<KQC&kDYLv6i;}7N-Y-^ z4$z831<>l?PS8?)m(COwE0@k16&tW~n~yR&HXmmMRn#t)H7Xi)#V(d#Yx7+Aw<oit zIX3=bU@5uZ%?w&q+wIH&>h-vEXY+KIs7Qd8RDwL+c?h&F7F5E!@Vh=}eOss9U85pn z30nR?^#EwWzoX?@{;7vJF7UU$1}(F5u})F3;%~kG@BjbTO{ERs&Vf&NjtWQX+j@Qv z)M5$|g5Z4)pb!N01QoA&a2_KZdd!#q|9`y})P&4p$YOvbg#ai88M%Xu%%JrUvE>bL zQQ^^i1X^q>l&C?>0mn?Y2oto2jhqX?O)G?|*EgV*4XE!C0CH3s|9WtqZa&VG1{p|b zKE{~FzaBi2(0q(34Kk(x9<+y5?U0s{N9S>H$qLSjV0%CfPtb^j8O)OA6AsW770@w> zU7%JuE@#4ZJ=p*H1jNmqpEwVFzovMs^*_JsCx}Z7KdewFWdvJ=uo>JIY5vb%&JFPc z*kOmEwOa{9HKcd9<vO&z30<()_=W?VjsALcenu+tT2w#_>kJP-nqr_7hK;o!R69Ui z(aj9^X*P#r^IJxbZf6egD!fae1xk=LbPX1|{H>sATK;VTj4hWSb$7!rT~J9G%D}(P ziE%fm)z@;M)Xbyv#p~RL3MPiqCmzj5!6v>0t%yfB!vnNup!qN(|27t>mIM4Pnj8!a z%`ZZ1l=<65I2aiCw;k|IW@+(ZeDME)N3V+%V}k`lsh~%<E67zPnqVh3ALW3#y7L8C z1hkyC+X1A6zts=a{1<<bdlK5aaBY2CCjwU0e3S#kVfTPcYatrZYuQ07QNRsIkIs9b zRs?Ke24u|{Wb~vJvb==f<p(6TAZfkz8^6m3NF0NM6f!siY4L*vKn*%%Bf-rTa1f_} ztc92jQF#o~E=S1;5FxNUXwJzIp~s^YzPF9v<%b8vQJ~(<i}D-)|3h4d%c#y<@XDA4 zGUEarFza<?f!GMC(!L!ODADss24^degU{HZ=6Nu02f3)bOhWS-r1b9%5&H)*=-WXB zkQPX;Klq3pRzfgO1ZxSB(L4mnCA}_8|Dbk3!UU<4)6D>nVXzz|{eV&#v_r$cK$!uS z^B{)6oYwlkL>xTr0PeDY>|_9K?*T1O!xkn-p}lA<a*%aOff-U73=EDTS&RW$uvu$p zGX)YxkN^M;nIOd_%=x_`DhWG50}kN4?a_Jtv&U-CA_R}li@O*Y7#VPAgP26>=p;C( zAb|@mTp?|Fk8T01W!D=Hh|&O9a}w-Clp+&Lpd|kW_1~bu3bqgy!O(EPq6Z~{UVOd* zF3SW!$+?+@fngtL@jW#5pynP1&(1<p9V93q61_eu0?;{YEM5XdF=(;A1Z2&=6oiub z{~t7+pg>rk24qiy7KG9Pl?k98P%q|g191AnI;{l`5t>RvCf=aCoiPI&x7~-JX%aI3 zEP^`!3|`cNX&NNoF)%Pe3d9%BKyinu44l<aq7YKqLMkr?@bD@)HjxBiMl&!#vouH< zPS-;g0`3B@1mJgpc?C3lxdCK4Bqu_nc%LIksPjHJJ%bYtq?wOc6AZEnEb*e}1t@u- z*E8_?0vcp5CxgbSqz*%?6p!8-DaHnSaK%*10h-=0gjFy;(A~z6vIFWMkKUp`VCx_m z;iW6cv@?gGra=M%RJOgm|AQ#ku!8jW!1QBQlNipw^5g&i7tthWSPasjMS_MRkcOWJ zp<W`wNsb^5C*T^OX$mruh={nCXTSgd|6<|6|Nmbe{tjBq@Zu#mIE=vg3|51e@WA59 z3?vCHh*~d|yzuB|di@wSZV8I@m)#&05Np6u@^ame|NkK^TAyClQ&;gW3w;^z`#)%_ zCCDTwR!~$@R#8<`*U;3`*3s3|H!w6ZHZe6bx3ILbwz0LdcW`uac5!uc_we-c_VM-e z4+snj4hanlkBE$lj){$nPe@EkPDxEm&&bTm&dJToFDNW3E-5W5uc)l5uBokK0L`_6 zw?8v7FfcPRFfcJPfLf!VIZLPuh6d&A;~C)O?-=C5kercNRGeDEP@J5YlbDo~%21q> zm{-D(mY-Lm0A?zr<fj%Z<mHzr<R+FRXK*o;r)H*SKvh847)p{8^VCZe@(WV)6u<_l z7IQHaWLBi+6lYeYGJuJc)Z&t&{7UD<oSdY@<ZOoGg8UMn{N%)v%=|ot<ebdZypr(D zyp;TMhRnQz(vskk%A8aNPe11%2Irj2f~5S!q7;S1oE)eQg|x)XoYWL92I*)c1A{s+ zWeB2dR8y?MNHv*3I@(t?83Y+Z9E03lLxLHkqdgg<qx~85lQQ%4i!&ICQ*%<2OQ42X zDS(`voL`!g0`@-Cwp4}W{G9wE1=SQThJvEh)RfE;$C8qw%%swi)MAF>5(d>`1p_@x zE(QjqP)NxvF33r&<YGV=mzkGY0uG(z{JgZxbUiMH^rFN{O9O_a98h?~N4WYrxw<ff z`^LMt`nZO;#)o_Qx%h`O#QV91#E1LF`#Ji$!a1JK{(h(;0iG@lp&@P-@xdWMo__8O zsyU?$5EDFIK*8h1ARTRJZREiq9Sy>u!1AwPkdAg_koE`RA_nPbCkAPM5H4Ymj&@;? z_6OlI2I**L25En12I**1Ya>t?n}P^e2I**snWk<G($U@!<3UUlkhB>@sTqiE1Yw)x zFi1!HfZSpYHo+tV#0DwwWsr_Gh6oyg3^Imj2mlG!F-ZGoF-ZGoGf4aUGVn4;`{y!9 z`{yx8`{y%A`xh`s`xi1u`xi4v`<F6E`<F9F`&UAo;s~aUA(RP(GKElP5Xu}vSwJWw zCx`|JWdfm0A(R<}GKWwW5XuM?u7=je5XuBXnL;Qt2xShTEFhE-C=3m)jUki?gffLt zW)R98LRo;QC<bX>hI$6+dT_{tgUk#ZNdBOJF|;;<P^J*d3_=-0D3bsNY5zd5hm0VU zDTFeEP{t6-B#=ScKM0}>LYYD+GYDl2p-h4pr2Rp;$I#jcLYYD+GYDl2rob*Vgr*Tg zQ?OH`4Na}VX~59b+87kohUO3w62pe(P*vtoRpwAt7GPBtP*oOCRTfZH7Eo1|U{#h- zRhCdymQYoe5LHId;sK({$N-|s$N-|s$N;Jelp&&x456wFp{fj_stlp3z<w}-rcWbS znl*;1GKQ)G=Kv!Us97dZvrM3>OhBq68CV&LQd5i>(u-14^NblPQ*(0i%Z(Y5a!ON; z7;+QSQ}ap^jTw?F6Z1f75-Uv&K<XjNp{f~_O_NQN)6!td!KxX`Gcrq38I+U3fI-<5 z3>b<_bd5~Sz$F=jbhN!$GNj%rElx~N1r>Y>(YlG5Ww8p;y2%R3If=!^AZ8l4yaKV( z71C4lb5l!-DnYzFg}lVvR1hm)AuTf}HI_>O4x)8K6iPBna=_9h2xhrLIk<SwOo>&9 zj@C_$RY=ay%}vZpQHV|~N-tK>)6<KEo1<DxSNG`VDCA`3r7A=hmy}e-!=1y$zz~sE z;+CIR;$M)O7m!#|l3J7ptt=FZQ&Y1u^U@X4pcNW8s6ZhJTA<Gm5u94$=^K`qQ<_?A zrQi&&Q;Jhd6e9dwQ0qcHE`|u_qSVBaR8MDQ#mQhX1#o?+ker`al3G!s2R5D|G%q7D zFC`~6MIjkpJ3=b6%=|nBg9_E03a~=gqN4mFh2qq_6p&kk!PQ-6ex6@`NoHE5LTXuR zUI|zoqMAah_0(01)wviLd@_?#i@<fYf^U9az7@Q3w>31fO3W+COw7qlEVeBvDowRY zEG@~;$jmDN^B~EL0Ti$bMTzAK1&PJQ77BSe3c9Ju8TksjnW+^esd);z$;Bo41xX6V z7A6J;P(7p6Xb6mkz-S1JhQMeDjE2By2#kgR=^-!`I$j1E-$c<36~`$L)c})+%*`X2 zfTkZq9;$yjR2{lJRGI;oJOfl8PI;&SGok8mnU6~zW<E}NsQJ?fn2$>yW<E}NsQEJp zn2$>yW<E}NsQI&?=0mwi5eQ+z<k7<qBFn%q7pfnZ{2Zt}XagNg4~T{eGvJbkxd$c> z<Ad~qFuHzpc^Dt2AD8=PLk)td2bqnGVe+{2&%>b~W*#nis5S<eJg)G;C68`Cy8F=0 zN0*1`pAS`t%YIz)==x!NSlB_0Wq|2Nmxu9T^62hE*N-j_)4vL;5M3U$h63c4)db{w z$&`m`V^|Ai;Ie-m0r~X=<TntI-$+1y69M_n1mw36kl#u`ej5S#?F8g^5Rl(VKt2d6 z4@)ngG=Yp^@}SM5$l@?IOr8@afJVdQ(en>X8B88LAqEpfqG9qpNMguLm^@_n0kRB) z4U<Ptf3Wf&r#v)3LI{KpOdePGz~pg-4@@3c_`u|Gg%3;~SNOo>afJ^|9#{C_l!t~- zAc63K$>Rzim^`lVfyv_vADBF@@PWzW3Lls}uJD1$;|d>~^3d=JCJ;U_d0gQGlgAZ4 zFnL_z1Cz%UJ}`M);RBP$6+SR|T;YRL9vVIh{~-Ak%7t){NM308;R+v^Jcj*HGm@eD z(anbnGvJbksfWp<hcCK*ba{0B=<Y+;k1h|>51X$?Hy@@Smpr<D7#|ueu;PyarXO7% z#)rwHyAR!dba|M54wyoi#b`849#{MZK=s4SgKLM1<CKSLfXSn~4;BD8<)Qk+q4wYk ze_ZlV?F=w^7$4?-sIfTZVd`P}G29O|C=_ZCy8EEg3@~|^c`$Jp4U@-Zei#AsVe+`l zhsonIe;?F*n0wG^m^?1?Ve+{A50eM&z(+S5#D~e_N`EkU&?zS%_2_s%0r$h?ak(ER zkIVfqd0g&?$>VZAOdgl}4-jxaOdgl}Ve+`#50l5`ewaKi_rv6Ix&I&m_rv6IxgREv z%l$BUT<(X-<8uEY0`7y!<8mKN9+&%I^0?dwlgH)0!vx$1lgH&gm^?1`!Q^qd4<?Vx zeMbnm4<?VxeK2`k?t{tWavw|{m-~(qa34$_m-}GyxZDSm$K^hlJTCVgBj7%mJTCXa z<Z-zVCXdT~FnL_=J5IoTFnL_=gURD^A50#X`(X08+;@V2`(X08+y|4#<vy4^F89IY zak=j#0r$b=ak&pBkIQ{9d0g&;$>Vb0DFW_0O+fw(0r|58<j)b1KTkmZ0s;Ap1mrIf zkiSeo{t5y4s|4h)5s<%5K>h{+`I`jfZxN8cO+fw*0r|TG<nIxXzfVB^0ReeXyB0Q< zirhAY<u?$GD{q0+gY@H*2kFPvcZcc6Cl6AC4}<In$!Fv6C(Lb$IOIX@1L?;l4>KQ^ zJk0H|ehA1c2yU<k(J*;fKLR8M!42SDX)t+MKMo>?AYt;(2q6>}Og;=n6v2VXM<Rq! zSTO&?#tBd)85kH~`s;CoA5y#4fq?<!X9uLB_5;|D3=A4ju@B%dX=u>{Z4qH$IM4(U zKTrgr85E#&CxmwBhtLf$GdmA3xH~&rDQLL+g=#7o8tED787deV7#SNF85n|{4vKG( zn?UY%_X}lUVqiP~5`+1Z5z2>+M~Q%SF)%Pz1u-yI2rx?XuyagcWB^@G$N)b6h=GBD z8>$Ahj|{dp4ZP)_0iw<YDvvA{0TmO3(jdJ#P_`nJ28n^rrvPzb^$$pF3P^x~fk6^V zgUnw6WuF7lPJ9CWOip|feaudL3cV~&d>TEhj(i4fY>s>u&Fn6G4oqA5EFAd^9Qiby z_!OM@B%JsJocK6Ee*FN_&%nTt4WeE61entJICK~o7(n}3K|&cI!i`U$jmeQuqM6x+ zPk||ji%-IlPr#9n!;#yakK^z$kU19600o^s$>72#5YNW}*((7Rp97*nx|6s-`oMBI zATb68hCq-VAiEtPay|?U3>{FpBcRA4<i7=s%*$A~uzArD6jvbgZa~f314;<^&2#6w zz{q@?8Mk?$IM;v{l4T&bJMjthfWoJZ*^y77nZ<=KfGLHGPr(r!PEKI|g2E^Us)rAx z$AwS8laGS|bcSsSR2-Z}98tpB9Vx6CKxQm}ss$gW3JNo4J`T_+UEm`oKw$}zcj6Q1 z1*L}`kbBx#9QibwSzY)7n3EZ~_%s~B4uhlsM{bbbFCaY(3=C4BvpTWsbzq*0sTY*5 z3_yAq7#NB{;R{M>@4#{B#OLA07f{RR0NO7T0#yS(Sipr(z!$89fdLeb1yH$KkbXx# zfo3Kbz654zM!pO;z5+MC3P-*M#$3LH7%pgn1DUr3st0u211PP<LCpj44?yKQL4Lv? z&n|ogOcQa$GBXb&UxgcA1EU*X2csL`1V%T$8H`SR3m7x`3czVs1C%Zq7#P6Y-ofrJ z1iQinbObO|ZWYK4$nhD#9LC5O;mDVe!WWQ%9J35yGi#vw<Ur{IY-S7}s2l+0_Zd*R zThMTV=f?&{rc+2pMM2%0%-6uk6vNlS=*TyLF^&&(jw87IdH^+NHpmV?K7j(TtC^xf z7J<?NtbhlXIoQ*J0aGeQG6K8b29&oL7#Kk12Pj?=z-BXm(>UbbA!s>+93~1(o=DCI zr|}l3ImRG2y6_3)@o|8~=Rn2Xq2f$Vd>o)Ov;`_&2nrjFyy(D`i<TEb<-rT69s^Ju z5lSZ;7@6%EaikOmNZeU~c5E^*Fn|xj1IJx9C`iG64}r=lfZT`TcV=-$a2eqURtxe= z15~XkD4y`U%bo87GdNtfK=o*W!X=7Nzz<sXo`H(b0f~d%#54<J5hxG6fXW4f<Xrd^ z%Aj!tl4AkgGr+*W;188!a)n5O${z)&oG?TVY!^t}0*g2(Jq19;xj}w+;uGitl}o*# zda4IhF13N`sb)5&-{5iyUNb@J(H^K?Pmo;<3=E+1W&u=eI!FxcCl@}0N?7T@zyONd zBTzNHpt1me7`pH^Ff!l46Sp8cK?fm#tOM7%P&)&dBH)&S)L4KrDgy%pE;XQfJO-); zyucoGo&y5|LjhFmCp3KeLE(d|9&cb|o`c7&pt|G$)VxlRgIz$?yo3{<f;*pvJD))X zpFkcYCK<r#<_%PBEJ$qtp8%6L9|t)8p^YJLkhlw<KqXWYD4rFda(W=S6i6Kg@|y)z zTnr@605RVODh58u!4HxyL1lCbRJ<8PV=H6a`8F^yr!n*GU~=U<z~sbtg2{>R0+S=( z4JIeP2TV+!d>fdUTKRS`x$_-hVk!qIu43fd!Q=+wZs6Mh%F<A0U{Ii7W?}e<we`x3 zV;3hg11KS37{$O0y22Vw7*wn<A(;bee}I&L<{KFqSQtPzS%dhXGy|eR?Lm-wm^xUS zQJev^%bO8gM}pMB#6e*RQXdKuWME(b=?5`EaSt*dW;Lw+2D+gIq&^L#h=G9t*48wG znh!cy9V7)!3Jjn+8l=7-B#6}Jbb_h}r*8%Z25`F*s)iX>X+ZfP$`5qyBm*}C=;&S$ zALefmo0$QcK|vfSX5xhSw+s|Pu=Xee0|Tg^0`k`Zs5(%Y0%FF22rTCCK+SmwH3!^& z1*>IXU<U8hg>s-2XxkIWzn;)U18%=EFfe3-<zb-$=75PjXgK6T)q~r$3=9kooS@?) zI2piYJgBUKYORE-=LD7Kp!ONq6b1%RJ0IjP1*kcogJM8Z%~17GQ1#&UF9QPusJsKI z?*S=dV1TE*dEjtnVE`TI4w8ae%diN<VPI!~l{H{40|UcyFoT^z2uvf0HBfUvr^A3m zq1H2O25}fT;Qj)085kHqd%{8CCI`yH3=9n5b~OV7!x^vw0l53XTm}Y)i%@^v0ylmc z7{Kjj1_lPu9it#~0{9^+q0$VGq3YwH;^4M10|Nu-9&wQRZBTJ=JD7oi;TKf>9cTdr zO2;4*K^Fjk)c=F34}^xdFgSg%Gl1?-1F3^y(1jTc4D8^1022eza*Uw(MU(>xAVCHO z20f@buzUp-W-x||qxaJ-L3_p-7#aMb5ddy;gW8Nx^~Ep)pfu=AE|7a_p?nw>0Co=x zLj_a-7Voi8bK;@mFe(|Uz5pr!Qx9&pGYDejj7q3GGr<SPK->2W3=EA>^P8aNz^Hbx zI0yLJB$yb8?gfjpGfV<;knm)v_<STW5OXF}9F!hGd>Eb&7UzKX3t{3*q3)Cb6_^YR z4B&nQ0|UbvMo@gQFu=+Sn14a{zk%`*tXzPJgHFN#rIV?k3Xp+;0aQ<c>;PR#2NM4Y z6$ke#7#J8p7nOqIWjja_5{C3M*%?5GrXdM4fUao;slSOV$iTqx1ne(%2GA+d$WpJM z{%V3IP;ftkfq~&GRD3^F9NfnM<y|I-e_`bpEdR1W#bNagOq?4k4sNR>l_$dB{K3xf z9N96TdH^c^6-`{82~uunf;%k?3{Z+e9V*@q6#(~J7#J9gpyr@gz!qR}4#>4LNOssk z#UFsf2_fMEH9ryRF>rr|fq}sbte%|#boV<#H3LHcR2<w6MUn`En)3&04!GaLz`zg> z6`ugj*syR)hl=lkii5{ZK<zlFxVjR=aB$y+fq|hCDjo$D2lrh-$6-Rn7ed9seHR7> zhAyx>1;PC(h)ED~0#v;aG=jnX7HAutkpa}YfT#m^^g#6mIDTQR3I+yPJv<v~j*}Wh zJ-ELDsu!T*`A~6KJ+>Yy-meZ(5AK&RFfeQeo6o`kD+giuXg5?GRxZQD4}tx~&cKfr zk0+q&Ap?7mvot_9T?DI#wQfKn5PTi19$M*u>RG6H_rdDf8N{J{h-wCgr(khGcsmLv z{u(L{D<5FuE1>>80%|xhFff4oR16FZAEDy!pyJ>@6$1mqPq2Gf!1X!E448kJm?8P1 z3z~4i{VWCs1|F#RU8p#?j|FPSF+=h%s2v9~2bNDE^#eNt=x9}tI1DR*t0E2t@ZtY3 zK?Vi}HK;kDz9dK(<{rp64LgH7TKJfO&0%LqK@*n%w`Z8)<si&GHemCa;qeX=cLa;G zFo4fS0gWGmEC=OBu=yMeu<<geFhc-TJ*-}bxibo^o}B@7-6l*eh)#ft!`fRQF%V9J zih~Y@1@U1x2P(b_&0j@Oaqtm&FvScE3>8puP<f9e%uojvhm~J2xfZDSGc@zNpyHp< z#3w+-zoCgwgNnzXiO+$GN1}-@f{Lf2iLZc)gX(RV8(}mv10uh`#6UDNd?XvhLttj4 z@&q9YYCl68QAmR8!1jWAfJlO%@&PIii&vN|_%=fZLGXAwObkSW?+IcM1o!bld>B3g zHb)RVjsg<{(Wju|uyO+=2ErGh;;`}uBnHCQpyIIf2@(V0JIs)=1`rz=Kg1#a5{LL# z9O9r`H8DenfkB!DyS*wbpgtW7y!?lSpB4`FdN{;Ew^3rVHyDTd6tKO_46ybgEMMp0 zP+tXA51Ye)sc*rdej*O>B{;;l;1EBGL;NNV@mDy+|Kbn_U6_k4+!R=`$Coh<anN<7 z*vtvVp*{hJcqR_<Djed?IK)9?r`X)H5r_H%IK)AxqhT}WG7k0kafm;~A<n{vJ)9+R zh^yidx5OdtfI~bOhj<hY@kAWrxj4kDaESNf5MPKxd>sz)gE+)b;t;=vL;MvE@h>>U zMcF~+6*t2H&<*EE^}ZZC_IT98A#RUD+!Kem9}e*}9O7j-#A|Vgx8V?<i9>u54sp;~ zw%GE^UL5L=;t;=#L;OAt@s~KnKj08&;=mqX0yxAaafpM?560$Sa~$fOaESZk5Kq7% zo`FNW1c!JN4)F;%#Ao3UUxPz@I}Y(9IK)rm5WkE={0<KBCpg3p;V5t4;!ytuhd3iA z1A`C)BZCgK;|QJy0<DRFirb@!3q!?&pyIIpw=5_2^rnSF+z4t;EO_F9fdMurWCImn z1{DX5lY-iDUQlsc(ADY;3=H78AO;48FdXK`bArk-W(L@}5Uf3u2{q@G5y({N{0;*H zLpcs}CgTuaghPBY)chjofB|fLeJ>96C!p%3KoiXj4Dj*Y%TRF@s5p2&iGhLPE>v6= zG~my`zyO{XVqjo+iNpNQIK-K_Ao0EoY7ThL2o&#J*yB+Gs-D>#5^mtRBv5}ED((jr zhejKNF;u(;Dh?gSWw3*aPlAer=089tx<JL(L&d>!Nem1Oo?MW4gpG^B;xPh;JL7PO zXW$U8!6Dv=L%air_*5L?OK^y9#v#57hxln6;+JrU-@_sP28Z}B9O5k8*wceB4sk^s z;>I|{K?{1Y)i1s{)W_fu&%q&Hjzhc&hj<4L@qQfQ({YF|!y&!_hxk4m;-_$kU*?A7 zixN=gK^pJ93l@jv62!dH8?ZPx!wIx@-EXM)1vGIc9+3Im3^&lkdBEZ<@c9K;e^wYO z4vR~eI75YAGDBWzZccu3HbZ%49z$wba()g&YFSZ!IYUKeGW66~hKh2AvdrSlq|BVm zl1hfsyxhbB2JrE;47vHG#i@zO;A3QSi!<_zN|H-UiWw@3Q*#*fe4Gs!z(*W{n1&1$ zIr)hxkTVb~l5<iMix^Up87guUvs2S^Dho0|N7oh?q$U?Lq!lISq~?JrkVX>_VG80U zCl-L%W(*Z6MTzBTn)G~}jgcf6QY#Abi&H@^DJd;VPt8lNWT?o@h5INoH#4ue1blX0 zNh-u?AP0cVw*V1_1`LVC$(fn)1x1;8CE%la^?aNy!BSAKfYcX*1<b&tIYVi2Y6@5s zbndR6kF%i(LrQ8|VrfnZil{NjC7|Pa!P>xP8X17tMuuS02uvD-NfU+&&}n|f4EY5m z@t|`b!3^*jkqpVXsl}iZBtZx1=7G-?1Zyz`lVCR)nS<FD3<X8`1yCj6C@V@W$S*2k z$gj{dWXP}7Ghj$6Eh)**1AE5^>>^_WhLVy>(Ak9`<BL)YOH+$WK&Bak9cc`9q_HtW zT7GgVSer38qKr);X#$i0l5+FG2_vZ}H77N(I2B}2L1J-9D(J-F0thRqpeVH%qTh@m z8^Xy>tz@Vu%>yMDP`EK97o~y^F)k|2gZMr-1x#n=gWO|c2<Cu}kOXlJjTj(@GZuk( zCg4ys2K&gwfT1csKQ}R{7#>kzfudB<iOe7=29TAhDSBYPnSjI2#0+dY_)JZ(f#B3( zYQ#{KUk-^BuoLxsoJ|eDDpPZlQd2-GO~LVC3XTU;uvw-My<o?ffg{`u9F}Ha`^>;j zH3NsDDOlVDtkM)LZVDC$D+HTm2sYgq%r*v_YXX)u0jo0s<(E`Y>MtouDJ@`#@XQ09 zp6OVUp9?-56Mht>e|cVN5krJ~Y6+T9acT}Ek0utSml-gmWTt{n<8%g{#q0<=2ih+& z7fl3w+$KYOd~r!)a&~-jMs_^tlxTPcNC)Y6DM~C4N=+_-i6((Xoih@PJo8dgD;V68 zq33+MlosS<CMTApGPos!q=QpSAZK(U_>L(lAQ^-ns6cRP35u9getr%}7x>)g;L@bx zlFX7)u)!{nyon+PI&U;MwZs>6_%_JJAU@LhqX?6sr-*_~&PXf@PAx$Qfb;}|vR6e> zD)>N8hWPl@qN2R~c-R5j48<iysi4C_K~{hQ1?0b+%mPr@B<7{(q!z;@+(AVn*ua9+ zWSAgSHRwp%qQr7=^o9F+WagC=gJT!Yb}LFvWrzq$P0uVYNiFj9^+XhT@RPtJ(n@fJ z10)dOapIm@0!l{dsYM{?gG%U#w33k2iW1j~lGMDC;?R;b3x?v7l+>akhP3h`&^fqn z$)I!+06Oy=Ipjd`0gY(KloXfzQqW20aC;n6QegH(q?JVEq@|!4;GS9n)e`}V8c$!a zuVDwiGDL(WLeh#~YH>+wice;73F3rThKSI-BD?`ol3J7tE@&gb2|YNoDit|s1B&ts zQj1D5Q;R|6V@6_LdT9YeYDFf<4iGODa*jIEA>|P+sX3`7sZfoT47sVf$r(i;-H<>6 z<vxfexRT;LaJ7>L@>pJqE9jtDh6rb{@o+V1FeRaR#i=Ep&Tim>7<}|ClnpwP78Erp z4C$#QpaMC<IX|x~wFr^d8InO&e|&msNl9idxO^@yNh~U1h{#Ry$<NO&EeI|t%FIh= zh(O_$mZVvv<|XH+fJ*>S;&jdd)wOQPAU0A~D1jE-5uk(^kXZq0H$czYh4Io#K*=BC zHBgYibU5ed<)wn#6@I0;NuV;y50ug%A>o#pQ<7Q)36_$Q%DmKah60dhlS>#P0wAaD zLd;4`VJJx~DFGk3AK{i$TAaa9Qk+_nl34^6W~cz2-<zCYPzi1)fPx6tNC9U+aB&B6 zJE)lgD)ksD(o;*IO_*XR3!GNKEt2HYqT>7_P%W35T#}jsE98>F?V*xP&>6y@qnQ~Z zKmiEKIH05%k`H3RV-*yC;l7^9`FWt61B!oe7K6)I6ocZbBqtRt748dGRRNAQP@@Ra z0s_~C6=|7ynZ+4k(Fo`Kf=b7t)I_i@xBQ~i^rHOIycC9tip*TlT>xNlPiJr$4smWl zekQ2SfL7rkYjZ&n4q`z4S&@{Qlf#gkn3=}_D&@)(b4rSnLFZ{RBqo7Mzv9#qP<aP+ zD(JR>oK)ZZl+3iu)S_aB5>TwAr<N3CrZ9lBu}dcS(0+ypSaAd~3&su0EG|t16&#*< zpu7fE1dbt4vMMeqD#_1bhzQEhhuvfV)9I30P?7;F0U#L-#&dUOh;Yly$$^)<uo4zh zfWVZ2lC?7=azTb>=B2`T;F1aK2v9i-P8l$%;M9_E-+-e0lKkZSoMHxWD+AJui11A; zfVm^MGB25-IJG1-uMCuMK-Uy7M1W0ohaUOO0BVCJ6{RL-GnC|~r{|=C^L=U&1DJ+} zIE0;=!%&i#R9ujloLUTt6UeFG`31!c<@rS^DXBS`xtS%P;4dr5Oi9fHp9~E?a+{$z zxhOv;hoQ72w}1gWT@PO41?i)Ju9*RKWuVKG!1AD83~XK=x=aEt4pVOh(u8CVY+WL3 zJPBkE$Q;=EBiQ^jOdPcC3S<Om9UzE?iEjaMK;uGC8eO~&hd69J2Bsde-j0FcG?IGI ztm_}p#<Tzb|MNrVeL?C$YXN1T{VmwKCy+SE{b!*1o1p4JVxX}xm^qzLahUoOQ1w&L z#E(G5=Rw6m=727Uf|&zae+5zkGY4kxMyPs_IB4B4Og;FHJ*4pe1JcaEz_1sp9%TMZ z1_lP0`ZG{*kU1bZ9w`4Zl!l4J%z>=Gf~1jINaldnO@XX}sfYRN7t|b(*~sC;2vUgT zPMCVox+!FHVD1q|Qx9{G3{)IsKC*jY>mfkWAUT+NU625@e-2vH1Pccfs5poMsfXF? z1QLL%2c><OddPYw&>9p52GAAoF!3m;dJqL#(gqVx0SQ3O0j(*8i7$bQgD8-_pqr~f z{$C9eKnkA{XgF>{6NmY0J5(HG258M6%={-%aS+wbz`!5_HRl9)z8>O!kRF)5=h4Jr z_Cn_O5$a*~-iE3NnE}e{Fnd`+0#N@hL`o+zP;roZKulQtDS<dh{)OdJZ6tBfnp>Fp zp!s)DIKj+;?R9g7ss~Yvk?ais2|&$Xf+XIABo1Q2%CQL`4pcpe2`jHQfjCIwuypes zO<V`$Fa`z&d(eV)B=xXx1I=H9+z-;W6v;iH`CO1VNIOUl=AP$B=783!!@}VUk~nBh zIZRv>y8i@b&J_>?wC)Z~9JW3^8%-Qk_JQ0{gC-7Jzub=|4pToDO&sRmMNn~&pOF2# z7Ag*M9!L&m4ru-qWIs$CX75j^dXU;>Na4l^UGfeR2d%+|g@Xu^IB4u2CJvfEg_#dp zng|nDLsGvI$$TTIILJMqrHL^0R#0(}y{nMa`yh$0MiLJ}5(lLzm^lSV;%kxAS3<=> z_JZta0Xdq1fuSBv92P#XJv}h>F!AYV>S5u$5KSBwU(2B4AUoF~xo0C(9NqjqXyP#Q z&!UOL+;am>9H#y)nmEiopP=F(_aLXA-%xRM_pm|-JkiB@q2eHO)+6~#97!CM=V0*y z+jj&r2j<QxNa{BtnX?Qk4pR?{uPtceFmrZ7#X;`bgk%nEpApO)nEF#l>Oo~B%$*mJ z#6fK(nD}j|ILI7jB=es_#X<HW*GE#&rEDN^<Z`<LDh@ISBnJv3P*Utg69=VfkT_`G z4MfA#!|JnRXzI&B3K$p|ZlQ@khKegdH&}qUAbVl;6zGl=Wb<M56!f|lc)Jvqen9hI zAoU<Kkn1TQH1lEgQ8EtkRy1)?9DvN7j3y2<XC{(3a{cujNgU)Rn7`hkiNpN$6-^xG zFVH*@$bOI+$o^u4E=`7o8_YfINaD!#U?`F}$Sjz9K=V5w^I_(|+>?x^9_F45s5r<B zWcPsPYmm(WrBM)n6;wUUd|3Jc&C7t~Vd5aOK>WRE>Oo~XNc<(5IH;`#690uJ4l|zt zdVnRm`Jnj}kUp3=%zQaC^`Ni=sk1^8hneqyCJu9d5SlnleHNNHtUZ$t6$gbUa(kv3 zDh_ie%$#Lt;xKboL&ZVnY(**u_CdvA=D^e+hKhsKZ$nc57%Gmg{smMVq#m?q16KZo zL6^?M)WgzMESfkhU8SIj!_rkIR2*bJC@f*-H$cT<=EKr?8=5#QpUyxM2gM=GoK;BT z$ocd;k~qk2nEU^siNoB_3f*7@a}Uh@Tu^b48OZK8fQrM^!_u2CnmDYTnS>;c+zzZo z5(n7<i^nFYI7kdR{q#b`VfMnzpN}LC+VchrpW{g4AhTfRpMi>l#E{Luh9r($kNAK( z+gSPqp-AGOy>BpkGoj)zcf$H*1!&^1a4v<4gWLnU+Zkp~KU5suoM~v{Fmq-@#X;um zLQ4OOk;Hc+iSLDq!_4=9_OqU#iNnl)2^9yK58BHFbLR)BILsW_zJae$agcgsdzGLQ zydZJp_OL6GICA^b4=N5b{|(fgp=jbTcSb?QLFVs8@^2QBIOsZLnEM-`;xO}J=Cne^ zLFOR0Cl^D-LFz$UHelwghKhsKgATQUi64QAgVckTJi)}zK*iD3--e2V)PuUJF!hh2 z;vn^)y{|CwA5d|SdXOB<{ePk2AhCl;;a~{eLIV;<Hm3|p9J!s@ibK2?hxl5kILJN7 z;j;-U4zd?Hd@e!7LFx}7x$`lSIB3Zh%)c+7;vjPlBdKSD?w<sigB;G>P;roYWP7!t z;vn_N_SztcgZ9k8>~(~SgUms;*BeP3x!kBm5(kYH!OWQg6$jZn5y|}vk;Fku%V6r) zK*d4!9z{~W87dAk2eecSrhYe699{isB=KWN=3Ih`gUkWxfvpF*gC-6eANYzU4pYw# zUHAtx2euzg5KSD`4wpp}hncUACJt*S=pl(Crz=aSILPhD;p2%UejLfa!BBCSJLiBH z3=9nENaD!prwA&JZhjMzII{UYP;rp4AU&{gj0H&I$nIYa6$hzBcK>c9ab)w4Ld9X` z!^Y`uLB&DlAm?8W&|oXH{sN8Z!qSNpR2*cEDN^{TK*d4kAosH@pyD9)$m!DoDh^VA z63LuEs5nSHNDh`xBGJTQ`$ck*#F5i;DO4O}2D16JP;rp?pf#E>e{~><gO&oq#HS#M zBfEbNR2*bJa=us$6$hD*Y|a)WapZ8@2NegIgB)&Wq2eHOKyp4H25227k~p$^9zn%H zYLWf>9x4vf4w8d~rvP-q111g&PkAJ9WOr&p#X)8uyVC+H4l)N>y%SU%U40-_99?}h zR2*G>Dv~&IIk^KW4l)O%2UdUWg^Gj3P9deM<4|#!dLL+e-~p1jC6fB5P;rnspg9y+ zdiV$x2bqIh{xd-rnu5eZb3-uo>`-x#ImqR|FjO3*9wZ0bw<m=pZjIy~O{h3XEog28 zX1)Pb9A*xz9c6<i9t`zwI+8fDfAf&UL3Y5}pQT9RptBHQ_BJAkgZ7le#5<70LFT~1 zc@k6{Bz6|bUo)ZNF!zT*-MJD;966kKA&J`|nX?}%4l*A(oNpkBBc~r;=stg#y|DBn z1QiFFa}LRT1E@GmJ#=|AgEf-)c_j62Na7%~VCMh?B8elbuZN0*)LuX`rynW~vlrHH znt>(`>f?d>=?l@sVfElDG;vscdKOLmJv97ZqKW^8ivL6t{{j_f0!;!TjsO3EigTlh z|AC6fp^3xNTPm73EMBsp;-K)kh!j3$NaD!-g^5Vw$nic0Dh>-z6{vewqKWH3#V??V z!}`}ZafrW$ii6yF3CW#bk;E?}i7P=5V+6SebUqs_A88_qgUo`3gC0~IB!)b{nFbXH znS-2P%8|rfk?gI3ii6BS&M(`b;vjQCatEN{a1c$r1}c6QO&k`FSJ1>^?!O5Y2bp~Z z$vsb@;^_8%Kof`A`v*-NW-l{z9vfy3%w7(tIJ&(;P;r=gm^qSY;xKdMpyD8Nt|GbL z97+5dlDHF89A-XfObV1wbD-iNbFL$)FM^7rtM7)2gVZCZ^LtQnn0lD|pQ4Gw-2VzH z4l?HklD(GDb3j1mxFLz#LB&Dpk=+>r6$hyYokamlw~<hBboCifagchD9L$~hXyPz; zmO#ZpYLUaa4oMt2U-v=9LFR*+JTUi6MG^;@1v7sZR2(FRoR0*chqHpr0m*^p%s}xa zh9(Z>GRQy~F!iwUUQaY}m^q<n;xP5OXyVXgG8n4S#9`+;tUwconZFKA9Li<b0%f4P zQysby1|;r_6z^tGaZnh5&YFRRrw@`ia(c*xii6An>493uP=h88^Y3IdahUsOqKU)I znU5w8GY58149H&4Sz$1D@<Y#y0l5X){qj(8kb00D%wAPAahScSP;ro2<n&gEB#t~D z(ugFE96m3g;vjoL=hVX7`5s9eWCtvLeu0XE#E{b`yF4g0BGxB>#?(L}#!zvP`ddix z7z-5#*$a|`sqcY`gT!tlsb2*Z2dPKSM;npEL3&{B+y)f~i6Oi5AXFS=4oD6(mH~3- zWi)Y6TNWh#1S$?viyWTp&<FyFBfC=pDh@I~2+95GNaD!#pdnNoWDe-8Fj)B8Ld8Mm zAglL75(k~R0#hFh6$hDvTyMrAi6f_za;P}Se2^Yk`?e7(4idYI<o<T3I7~e(oln9c zz8Fm$X8u~JILQ2aNak;bio?u@wP%i?iNox@fg}z(D-aeAccJ1S^O4i}2dFs6e9+n9 zF!f)d;^^w*L5mEa;|%wa+*yw#4m#5cX3jLIILLgES+I8OZ8ULMIr$Jx9H!m`dR`LD z99VtifF=&hFFt7Eu=F1Y6$iQHA(H#kpyD9&k@Hb5k~l~Y%$y>qI7kdRA2mV6LFRzu zVD9We6NkBTGMYHd{25SjkQvDCyaW}8nGXxM8))LNaMJ@#u0!MN5t4r$q2e%eo`5nn z0|P@en)n;2cn*>{Xb&hXe(R9LL1(?e#JiEiL4E+W9YIDdLK6q&ZIJk8BynW(_ali< zMsojUBynW(Z=s39{Phe?9OfPt=z>v@8IO_7=R*=lE+4F+;;?Xo<wqYhaag|2g^GjB z2e}0nJ{?eTkU70b_O649gVaAo5`PO72dM|i!SXvFXtE93j{~j6fSK<M6$hzB&hO`u z#F5MG`$*!*>c2q6(d`w5o)-o({~3}y?U2Ng!_5~e4l@Uq&V!)hAag)x&%xXujU<jd z&Y6iM{sPI~YN$BOd|3aw6-^x0AMZgEht11RLKBCXvlvYrX3i0)ILQ4kk=%0@Dh_iG zEI(dG6NlM*3r!q04)6d?95hD@$}i8+#6_U}yLV{fuyFni6$iQV6_PuDLB(P2gsEqQ zHfUkuu=zMKG;vrs$e@YC!c7@X99AA`K*d4sd5z>ABd9pcUYNfu(Zpf%ymnA=kU5~T z3YLCcpyDudVD9un6NkAo9Zejz9yJFl4l*Bk9aJ$?9A-XDeI=SWEWYZ|#9{H?0u=|D z{}w46wnD{W=EK~%2TdI2ufu5Kuy{NH6$hFB4$1r%P;r>~F!gVt;vn^)Ggo2Z`3p%L zbaw<yTmf1E!OV#PB~Atg26Z%X&{zpbN)JgKbT%=}98)B5klmoMOOSdis5nUMBa-{4 zLB&D#BF_u#KoSS7D~6f>1}Y9R=M$1SKas>iWjRc}y(Y+ZM7tdpJ}yvkkU5``%n5;t zgWLl;OA=;I1Cls$y|xr84l)N+mc!Jqhl+#D$wD%JCsZ7y9(g?f1d=#%{r(6^{0ovf zAEDwP^Fe08{Phhg4iZE57Z3CxM0E9nP;roY<a8o~B#xX;ilO2lb3kWj!u-1%NgO$R zjw6XrMRNabBynVOen7=R?g5=u3N!ydR2*b4ayqetp63V>N4D1sNgOoC0y8HGDh@LL z8<Kl6q2eHOKyt9~%!7)9#J(e`uZN0*)K5ba??w^_>4DW3Q*nqdhKhsKg3geJxpN;> z9ArMS`%fZ?gY>}4lZ$BLu=3;!nmBBIEF)-A6WZPYnFAB&LlXzJML;=70!<tiKC)18 zkQvDJzA{uC<bIGG%zQmGao9Yv6`D9~p41IZ95(+OgeDG~w@pJ6uK_t8w4NC%4sr|f z`kzHmahN+nVGYu96Dkf;kKF$G3l)c{ht2D0fF_}#?Q>-HF;H=sdT8^NAq`C&wyrD} zO<V<}5p>=xnmBBoSQnZ&Y@OIdG;vsbO@oSq`~?z&rMHDpagcQ&Iheg`(8OWx+<_*p z4ARKJz;GH#98_+@>eEX|;-E9KVfNlc5(kAPO#Bg&ILJM)bJjmV#X(|!k@DSls5r<O zAUT*jIiLsBfW(l?TVbd;Og+rM%4p&+b6lX}=;ru9#bM?^yW0#oXyP#QE78PZ=C|Vz zpNd2L6q-29d}h$%8>D;<GoK4h9F~3r(ZpftM*>Y8lvY6bLKZ3x3I~uFEWT8r;;?Xl z*=q?E2dPKS7c-E=85t4##V$j|VdjA9RFJ)&k;IYLPyU69gUm-ZhaI#S2pSGdNahP6 ziG%dO+-ZYD+#g9C*_;BXILHiSd+VU$AonA?b2*YYNDs{3ZD``4whPF=htb4AWfn;M zA(}X>etC^14(oTY8G>{n+CQ-NHaAop<QC+0l_pSeko!S(3oL#Eki?P0VLOsI$Sjz> z$I!%K?!1d84s*{Vs5r<BWcR#<ii6w(l7pG^4NV+ouQX_J1~lG5>S5+9K*d2~$mXj- z#bM^d%&|ZdhuQ0oCJr+{1S*bheiT$3-TXW>ahUn7XyP#QyP)Fe=1+u*!_0@7GaF4D z=CAE&;xO~~K*iC`KZYcZoPVD|#bNeBt3?Jj&|)B@@CTI<pcKdr6$hCQDtln*$^<G7 zGY8hMv_=z$nd1Nz2bsf)l&{^P;xKb;p#A7TG;x^u5oqEt^JAgnAoJOf%uh!WN1g}F zLlQ?0pFXHK%ssI1S%)SLvv)I89AqzY_}qbt!_0xX|1p|4%$yfcagaG2NbY|R6^EH) z0u7&^XyP#Q8K4U-VCrG!vqHr|<|Bs>Kax0d_=q8iBZrR+R2*hLtekg66Nj}QDnW~! zpzSN<@>U&so*m2_Si4sbO&nB~fzqK9nmFh@caXRzx;Qj^0?@=^;~3#+;;`_Efr^8| z2NagDbe;?qhq)70{^z2J!^;0MByr?=q!mdVYzJu3F#`ib51Kg4JrkkgAho<m>0u63 z9ONEQ*udPm5=k7S2R8n>3r!qW&KyA#hpneNk0uT)e{Q0Q$3esSDVjKJJ=Gf|anPMJ zFn9ihii6w;+EWh`=L0SNLn?ocK+TuLA+CTX4qNA-gC-7&OHev7MiYmHvjtQf<Q~wN zG|W9NP;pQ=gXCcD2|yEvrT=6c;>A#LkQt!10L=Ujs5s1gkQ~UJQ_#d=>FPR~IBXr! zLp1RZ&~ST=CJq}v{0S8Yxkm^oT`@y1WB|DbdEdG`k~nCq0cdUp<jxEvaZyGFh9A&# z5_TeqgY1B<<GKqK2Z@Ox+4~JD4zd>{2OGcoizW{34l{6r7U4nDNjXwKLINrdG6QrM z1uUEuki<cE48g?JpyD8VL0J)YpN1I@aT_#om^<BZi2FdrLGF=6@^27S9A+=foCq{= zn0sQO;vjRRkj%+O5|>62FM^7L%m?X#rSm2n;_XmzkXlfg4GW)ss5s0VSo)cUCJr-y zHdGvBjx3UU7D2^f=D_+X%c0^R^`JYRVD@f<io?`{?iB>3w*yGx)kyJv8c7^v7Hr($ z7MeKB{SVQ^VeWqh6$hCikL3QhP;r=hKy^IGJ)fZBAoahI-18eM4pR>+Z&^T#T%qX} zqz6=XgUsPZ6Ni<zB52~U`cVo^9JW4C4NV;8Uqdu;n17wo#9`%$FAniYG;x^uDQMy_ z^UKi0Ve1<kaEP}diG#uhmL4V|iG#uoR{zdM6K{c*dyCM-Vdtu>Kog$<RlgZc9JYRM zADTEU-jAY*-+`KQ22DH!6uArx3=g2<Ah(0=_JR599aJ2aPGI5r6-^u#p1+{tAafLv z(kBaO(KAxIg5@tRG;x^uf@tC}^TnXzAoG=w%$J3V!`un0XARNBVd>KXO&k=LprEir z6NjY-7c_BLI`l&mhq*HtDh_g|GLk!^pyDuh!s`82G;x?YT~Kk5IiNMIuy~mW6^EMx zsvH;?7-pb}!_1kFCJqbdEokDf@Y#hX4hx@yXyP#UAA^d6+=)C-cNQuRb0@5Qdl^X_ zWH!uS_mIRvX2J5&3p8<9yZSwvILyCapyD7iklUsIpyDw1!2HVwok)U-gWLp44-#nN zFni_E#9{tYLlcL&M;j^*a*rxfdN4;4M;>pqgNno41FG{t?r}vEhvj!4G;vt|3Pux$ zxibn)9Olk=s5r=-YDn%(gNno41MAo4qKU)I>B1r24;2TQua0E?9H=<Vd|0|#j3y2< ze+5(=WR3=sIa{FOAag)>BEr(uZX|J#9$2^?LKBCXe;g_fQmct%{u`(`$b8V5T`==M zBZ-6bz|8-JCJr<IKU5r~7TJ6q(54HdauTNA5GoE*54!6MX0I(&9ORyQr25?jNgSjH zW{xLR93+Ok9w`7S4l)NM2P$ho=`99H9CRls%-&=qagchL`591gkQlQ0`A~6~`LK2P z)kxxvNbYY!5(k+DGrt`w4iZB)zYi)7GaokoFbhc>bSEXu{R@%AL1w|sUj`Kii6NW6 z7Ag)iA2$B86HOfEuLEe}u=IQ!O&n(L8K^kOUTviGb^|I7vKMssE6n}(k;FlIVCFo5 zii5<E-Tw|M4l)NM=K^gH@PRhlAf-2$J4MmNVdhIg#X)AEtlNZ&!_0@ZCpDqsAoZZI zfw|ulDh^W*v)2Yq9A>X0R2*cEE>igTLd9X`z|;pp#X;&pcd)|jjf9HB)Pwrcpmd%L z6$hzDo*&PGio?`{)@Fg!mq5kQ)mKBsVd_C^r$Fl4(8NJ|FG1qdki<b}?ZDhQ7fBps z2h3lKpyD7g<oMkQ6^GdiTQ_(DO&k`^=aIx)k@DR`s5r=c<n`4bpyD9&+mO_Mg^GjJ z>m$X>FC=jTBymN1kgpN*1+adT0aP4h4syRc2r3S;7u3Xo^+O}k#9{r=1SD~gS+Mq7 zCR7|GW{BjTe5g3ce2^ThpHc@E2Z<rOrv)kwQx9uLtw$4wtz+2-6-PJc0aP4j4zxO8 zcn=jvS1$;?$PT6+I*iGn02N19?*tWxsfUdZ2SUZs)fYp>Vd`Q1f+naqy82G2I7mJ6 zILrhjanRXpu=G3&Dh@ISd7g9!R2*auXbvByem{~pNDs8x#&8l%9Okd9XyUMR@(f8F zbe1N}{MS%%klD!Y`3@Baxu**$o&SM~qpMeOL`~1Ie5wf*2dM|;MVP%1)sXZLvIDeN z2P6hk2ckh@APj3iK##csp9cjJ2d!lUse>L@0~ZIa-2sV1k9mNLGeFCE*mxMo3=oEu z1JLbjaP=xsf5P@jfYgHUa;P|L{uv|&!mFX;&}FA^bJjz}q06S=;+vu3uy_NR0m9p% z;?QYExcc2taaei>sRdzJ`hX6<!POszs)yw#kXjHv4i$$|aP_C50<ioFQVYW8q2jQ6 zB0*vxd>JYZE4M&mAUq4|5ZL{ZATbcW4OI`zParW6z7AE7e10rQ{4rELEd7GSKv)$z zUIQ!VKw=>54J|KV<Ch>Y5N?2qgVr*E(gjEigg-;ghpj^aiGlDnsCwA_jvz4*{tZ<R zT04Pk&VQ&l>>eGES`b!(io?dYKw==w4$TjsHYBn+(NOiEx(`|WFVsDtG67j!7-|k| z-4MuZ5Eh4ugU<XxRxb?|2d%Y37MF*LgU+f&7GDB&4{Y5f$ZQZ+hpLCI(*%iuFdtML z)?WmPf$&49Ik5Z)%7!3u*!|3~d;}AR-SZ5~FEDY~J<_mz0TYMaI}J;pFmc#@*RXVm zE)GjSF!2D;U^(c1TTmc??g@vs1wm^rK|-+bgsBIW=^$}f`wk`!yAK((rvoGp6NlYT z4qD>}0x)sdz2BfUX~^QRd(=U5i^$@zd)Gl@Q!sJR(J!$3enEXeWbvucb45XI4`lIK zP;m>8L!kZznX?co?tmt~5-JWm4+$g<QokN54m<A|CcXnI9sv?SG9PwdaRQq7KB)Q( zH1VTQ@d7mQlTh&rH1YFLaoGLdAZd_0uR+B-Kmthaxd#=WfF}M7Dh?ZW1WAL;c?}g; zfSz**6aNSm*FY2h2^BX$6NiO^1)4Z49+C44$lm`Tix?Q-_j7}|AaNE@W@2D~-zN<d zhn>F+E5~5s{807C=^12>2vi(7J%hw0pyHrC`^f1BHXenXo<Zti>&FB@79xc+Y~2)k zI)t6?jGlgA>lM-C9d>>WdVImoJ==h0uLaEgXyP_daoGGDNE+mR2dKCJl!l4BK>0BH zVdCCUao9Q1FmV{a04fg?4}tPQ_tYbYX9QGy1C)lTkB9OvKxvqGGL-)TO2fpnpnL&P zCjlw^^P%F9`^`ajsDtjIVqhqPii7SMM|Mv&RJ;JqoF=F^<eqMXIqgvK4QT4Sq2iGH zrV;8VLB&6ysh<uN7l1YdVg7=xM>RkbUjS7PI~N+JemPXU08RZGs5tCgXqfuVQ1K0D z>S5<`UqBPz16BV4P5b~<TmYKyVdfu!iW{JbpMZ)7poyP?iWi`XpM#1|Koh?N72kj+ zehn&q0ZsfCRQv;)I6VJC&u50Y{~lDm0h%~0p9Y|bKZ2?+Kof`M#|dcS&!FlzpozoE zr3+}{ub}EbpozbOiVHx`6Nb6}D^%P7P5cj3JOE9c8JaF(=Q+d7;ev`!KvORW72kj+ zE&&z4fG!TT7j(}oa=wF=tDyU2k;Ubq<`_UbLNNEJLB#{m#C4(K1!&?XP;t=xt;ptE zL&Z0ssds{kUqBQ0go=Ma6Ni=a0%-Lbtei)$2Vvz-0Gj%6sQCqG;&D*%325S}Q1K0D z;yF<93uxlSQ1K6F;#E*_0q8lsuyBTz`vz#@uzDu|O}r6mP63*D2UL6lns`4{d;^;J zG^qFmH1WAm@egR?OQ7Nc(DQO(?q3ZRH$W4I)q??O;;?$K08M-o)SL-u;@hC&u=9Rl z_QJ}y3ux+L^~eV_aag@00PWbr%z@P}25922`XvBO99F*+pozokmkDU%u=-^KnmDX} zxqv1Pt6x5#iNop_0qD81F!#gi7XvhLSp5=!CcYCIo&{*)yP@I}(8OWw!wqQSu=e2v zG;vt_@B^AStbHf|J@*yneptH&cFrwK9M*0LKvNHEw-lg>!`dwq(8OWwmJMj)`=I{4 zfF=%Wk9|NBhqcE9p#3?RJC8!mF+dZCwToc=KbU%0y9jnZElm6j)SL-u=D^xF8_>kB zL)BkE6Tb%)hn*7(Gyf@6TmaeufQi3>iW{Jbe};+&poxEniWi`X|AUH8Kof`E^RWR< zoCn&zxqv1v3>E)?CN2dP7XUS;k=mbfP;mn^aaE{z0GhZCRJ;I9+!!i80ZrTrD!u_t z+z~2%0ZklszsLtPaUZC90qA+2u<#FtiW{JbM?u8{(8Lp=;st2p=}_?rXyW-$@eOF= z<xuepXyWxy@egR??ND(6=((3L_xD1@4ba4=Ld65n#OFfA3(&-uLd7SbiLZr<Z$J~@ z3>CkCCcYag{sB$=FjQOsI#3I9|7obW0h;(_sCWRH_)VyI0h;(jsQ3gl@t08X4QS#Y zq2d?N#D7A?KcI>Khl<0_pM<%e9oo(|fS#`i6X%DD2cU_IL&Xcw#O0yl6VSv}q2e3R z#C4(K7tq8_q2eFV#BHJC0?=~>VeWK=io?!hgo%4Y#RJgP2SddR(8Qym;uFxslcC}p z(8RN$;up}w3!&m4(8MdD;sVff{9x{Ego?w?IfRLKLd65n)Wgd20yJ@0xjF$&99F(< zKof_RGZ)arVdcOFG;vry6@X4iz}yMTM+Ru(uyh`PCJsx71!&^1bTR==92Soo(8OWk z3_B+f<{ntR_5n>jtbP%Io?i!34=d*l(8OWoZ2+1$tUN406Ni;o6VSwA<;ey#aaex8 zfF=&hkFfLiVD5zF7Xj!waxigNde%S^2X*1pq36hWpowQf&$kLd5(iZ^uy#uZk~qj5 znEC=Fagh3n(Dd1XB#x|p0+KjLJ*+*m0!bWM{RSj)kow6`^ADhjGeY~-uzSrx;m`-_ zFhVixUUQH*$Q)j%df2_@AaPLE%m7)=fVk@(ByI#EpynWt=Nlu5Bahp|*06xIAdhF7 zBB@6n&jeX{7do+qJf4Xxjy#?T67PblM;^}viI+j`KpxKoiAO=>9eF$xBo0dt$m5yF z;>hEfAaRhNKo~X;0ulpZkQfM~&-X#QOAN624v<<9hJ_>gd>QCWE08&`a096YVc5I| z`g{{?UITqT2y`bI$Q;;uXOI~n3|lt{n|B3?fiNuGVDqaWF%W(T4Nus*A&?jddx8iC z1_szZ7!VhPb3p_H0|PAFKwJ>!gx0e?Q1d`yAPj4d!PfbL#6VaM+RulLSAoPp_!hMP zkO1O9=X^j+Sbv}b#6c2|gSO+5@B0HO*#;GdjSGUrK=>b2{0E4GWR5?y-3A+v0ZD^! zCbT||fVR^?Vjz46l$jV97)sE@C7|`k3N&%pJkb#}aoD^PtbGkK8-!u=Qy$Q81&M+1 ze&{)p4QS%9@@fv6IBY)a37R-;K8^)i-hj*o;XlxX?|>!_o7am$6Nk+McA$yF^4$V7 zaacZu%}0Uk1Yy`b;~O;fuz5)vXn6)w3&Kv&bAKYx#PgxzEokEX(DPq*pozog2Vvux zAhSXE9dyIY8#MK>a)|>veh5+v!m#p91x;KBx<B6rP23(T4!gGwWCjQaLB(O?nIJI` zj)m@fUxH@NGN||oG;v$#{%{HCcp%6O5IzOnziNXfUIg6_nSdrP1ugJO(8N`s;z!WL zWug1iVB?S=J3)9ERGb5v??GZ9%naR6rGh5z2NkzL6R&}a!^S5;W`OV{sCWjN`t?w8 z2EF3S+>*p320hUA#$Y-F#wtq9Nz^Mzttes8OGzwAWY9}0E@sdJix%ZWL?ARsuc4kH zgB~*10;&|G5Tr@3C|?hJSu?sgHbG>gO!Q3P+~ndC6pjUhUUGhJZfaf$gI->KNvfW^ zU#M<zNn&y~l%Jkgs#gHHPrVXqacV|<T2W$dDyW*E7=wxhP|*&}4si3J%Ly2apz94_ z5+JoOHi!llTc9EcrXC~)!V#cL2N@U`RzMe`fQnC$UTCsnfHr3tK-n534lO=GTEVyh zYA<YE2Uw7SfdS-R7#l=`niC*1(e*Ppfn*sNVDkbH9;SX!@&(xsN^3ARU>d3)R_}tv zp!;=UY!D6FwvWyK48K6K3=FV&H<159MIgwnAQ_ndLCY3F_CvETND7QsK<yVsix`kv zkOCMDI%^liM%RA;+HjeM<}sN4AUz;+5}{*9=;4>(4U%PGaDe7J2oE#-K<yxG{{H~l zTmYI!hZ+p>KgcMU{V@Mm;;?@KG~GOawwH0)4_YUL&3*;YrfLQT2H1E4$bL|p4&8oG zTN@M>P-nudVQ9#QFk$N(AUsU}gVy+Av;PBV^Cu|1f(&P1U;x<<8UjYQAJqN>DM61v zhC+yqF!c}~<Q{1d8)PSl2Ho8X(hqIsfP}!91F9c7Yz`I!5ior)8njOrn|=wXe%N|3 zkX{gmxd%pr?sfv{hqa4AYCyOEsvowl4<rV{AhpOe=xz;|7)Tt3d!YJZd>D<c7Ia22 zsER~O<_r^{`qAA5b2rR9(3xu>Gtu=Qfa*U1O0+P=3=9nD`ax&ofx;5K{1X6ewgsg> zP^O2*Kd8wG(+^Ak*z5*b*8$qh$-uy{1A1OHNImF2aCH43=b@)vkbVcyVr>Qn1_`tT b0J0Ax55u57B{uyJpc{Z->q}wk(e(oWyk8<I literal 0 HcmV?d00001 -- GitLab